How to Internationalize Your XD Plugin

Did you know that Adobe XD supports 8 languages?

As of this writing, XD supports English, French, German, Japanese, Chinese, Korean, Brazilian Portuguese, and Spanish. This means that many users around the world are already running XD in their native languages.

If, as a plugin developer, you want to reach those users and provide the best experience, internationalization and localization are two things you should consider on your journey to creating an XD plugin.

The Adobe XD start screen in Japanese, Spanish, and Korean.

As is usually the case with code, there are a number of ways you could handle the internationalization of your XD plugin. In this post, I’ll show you a very simple approach using nothing more than a POJO (Plain Ol’ JavaScript Object). This approach is probably best suited for plugins that don’t have complex UI and only a few strings to translate.

In the future, we’ll show you some other ways you could go about internationalization, and if you have your own approach you’d like to share, let us know in the comments.

The repo for this example

I’ve whipped up a simple repo so we can focus on the goal of internationalizing a plugin. You can follow along with this article by grabbing the full code on GitHub.

When running the plugin from the repo, if your machine is set to Japanese, you’ll see this:

If your machine is set to any other language, you’ll see this:

It’s probably also a good idea to have the Adobe XD Platform documentation site handy as well.

Steps to follow

We’ll go over these steps for internationalizing an XD plugin in this section:

  1. First things first: check your manifest
  2. Move your UI strings to a new file
  3. Get the application language
  4. Import your strings
  5. Show local strings
  6. Have a default to fall back on

Let’s jump in!

1. First things first: check your manifest

Before we get into any code, let’s make sure your manifest is ready to go.

You can learn all about the manifest in our manifest reference. Here, I’ll just call out the things you need to do specifically when supporting multiple languages.

Side bar: speaking of manifests, we’ve recently updated the I/O Console and our manifest requirements. If you’ve already built a plugin before March 2019, learn about changes to the I/O Console workflow and how to update your manifests for existing plugins.
If you’re just following along with this article, don’t worry! We’ll use the updated manifest format.

Manifest fields to check

As a first step to supporting new locales, you’ll need to update two fields in your manifest:

  • languages
  • label (within uiEntryPoints)

For this example, the plugin I’m going to show you supports English and Japanese. So I’ve done two things to reflect that in the manifest:

  1. Added the language code for each supported language to the languages field ("en" and "ja")
  2. Set my label field to be an object with localized values for a default language (in this case, my default is English), and any other language I support (in this case, Japanese)

Here is the end result for that part of my manifest:

"languages": ["en", "ja"],
"uiEntryPoints": [
{
"type": "menu",
"label": {
"default": "[Sample] Internationalizing a plugin",
"ja": "[サンプル] プラグインを多言語対応する方法"
},
"commandId": "mainCommand"
}
]

So if a user is running XD in Japanese, they’ll see my Japanese label in the Plugins menu. Otherwise, they’ll see English, my default language.

Limitations for manifest fields today

I’ll quickly note that there are a few limitations today in terms of fields that are localizable in the manifest. Fields that don’t support localization include:

  • Name
  • Author
  • Summary
  • Description

If these are important to you (and I’d imagine they are!), let us know in the comments, or in our developer forums. And be sure to keep an eye out; some of these will become localizable in the future.

2. Move your UI strings to a new file

As developers, we generally aim to avoid hardcoding, but HTML doesn’t make it easy out of the box.

If you have some markup on your website like this:

<h1>My website</h1>

… you have a hardcoded string.

As part of internationalizing an XD plugin, we’re going to grab all of those “hardcoded” strings from the markup in our main.js file and place them in a separate JSON file. We’ll name this JSON file strings.json and it will sit next to our main.js file in our code base.

If in the beginning if we had markup that looks like this:

<h1>Internationalizing your XD plugin</h1>
<p>You can do this with a standard JavaScript object.</p>
<footer>
<button uxp-variant="primary" id="cancel-button">Cancel</button>
<button type="submit" uxp-variant="cta" id="ok-button">OK</button>
</footer>

… we’d take the text content of the h1, p, and button elements, and put it all into our new strings.json file using the following structure, namespacing based on language code:

{
"en": {
"h1": "Internationalizing your XD plugin",
"p": "You can do this with a standard JavaScript object.",
"cancelButton": "Cancel",
"okButton": "OK"
},
"ja": {
"h1": "",
"p": "",
"cancelButton": "",
"okButton": ""
}
}

After this, it becomes a matter of localizing the strings into the next language, or adding a namespace for a new language code when you want to support more languages.

In the next section, I’ll assume you’ve already localized the Japanese strings (you can get them as part of the GitHub repo).

3. Get the application language

In order to know what language strings to show in your plugin UI, we need to know what language the XD application UI is displaying in.

The XD plugin API makes this a breeze. Simply put this at the top of main.js:

const { appLanguage } = require("application");

… and the application.appLanguage property will give you a string, like "en" or "ja", indicating XD’s current display language.

Potential values for this are currently:

  • "en" - English
  • "de" - German
  • "fr" - French
  • "ja" - Japanese
  • "ko" - Korean
  • "zh" - Chinese
  • "es" - Spanish
  • "pt" - Portuguese

Knowing the application language, you’re ready to start displaying localized strings via your markup.

4. Import your strings

This is a quick step. At the top of main.js, import your strings from strings.json:

const strings = require("./strings.json");

The API parses the JSON automatically for you, giving your strings variable the Plain Ol’ JavaScript Object we’ve been after from the start:

{
en: {/* strings */},
ja: {/* strings */}
}

Now let’s tie all of this together!

5. Show local strings

Let’s refactor the markup in main.js to dynamically interpolate values from strings.

Here’s a quick example:

<h1>${strings[appLanguage].h1}</h1>

In other words, if appLanguage is "ja", the above JavaScript evaluates as strings["ja"].h1, or more simply: strings.ja.h1.

Going back to the markup we looked at above, we would now have this:

<h1>${strings[appLanguage].h1}</h1>
<p>${strings[appLanguage].p}</p>
<footer>
<button uxp-variant="primary" id="cancel-button">
${strings[appLanguage].cancelButton}
</button>
<button type="submit" uxp-variant="cta" id="ok-button">
${strings[appLanguage].okButton}
</button>
</footer>

Except there’s one problem…

6. Have a default to fall back on

Our plugin currently supports English and Japanese only. So what’s going to happen if our user is running XD in, say, Spanish?

We’ll have a plugin that refuses to run, and errors in the developer console!

Understanding the errors

The errors in the developer console will look like this:

Plugin TypeError: Cannot read property 'h1' of undefined

That’s because this code:

<h1>${strings[appLanguage].h1}</h1>

… is evaluating as strings["es"].h1 (or more simply: strings.es.h1).

The "es" there is for “Spanish”, but since our example plugin doesn’t support Spanish, our strings.json file doesn’t have a namespace for it. Hence the undefined error.

Solving the problem

Let’s make sure the plugin has a way to fall back to a default language.

There are two things we’ll do here:

  1. Get the array of languages you support from your manifest.
  2. Check if appLanguage is among those supported languages, and if not, default to the first language.

For the first step, we’ll import the languages field from your manifest:

const supportedLanguages = require("./manifest.json").languages;

In this example, supportedLanguages will be ["en", "ja"].

For the second step, we need to check if appLanguage is among the supportedLanguages:

const uiLang = supportedLanguages.includes(appLanguage)
? appLanguage
: supportedLanguages[0];

In other words, if appLanguage is supported by your plugin, use it; if not, default to your first supported language.

Note that now, the language string we want to pass into our markup is not appLanguage directly, but the new uiLangvariable we just created. So we have to update our markup accordingly:

<h1>${strings[uiLang].h1}</h1>
<p>${strings[uiLang].p}</p>
<footer>
<button uxp-variant="primary" id="cancel-button">
${strings[uiLang].cancelButton}
</button>
<button type="submit" uxp-variant="cta" id="ok-button">
${strings[uiLang].okButton}
</button>
</footer>

We’ve now provided a fallback language since our plugin doesn’t support every language that XD does.


And that’s it! At this point you’ll have a plugin that supports English and Japanese, and defaults to English for all other langauges.

Is your XD plugin ready to go global?

As I mentioned at the outset, there are many ways you could accomplish this same outcome. Depending on your plugin, you might decide to structure your strings.json file differently, use a JavaScript file instead, use the localization helper for XD plugins, or go with a module built for your JS framework of choice.

If you’ve already got some experience with internationalizing XD plugins and want to share your approach, please reach out!

I’d love to hear from you if you want to internationalize your XD plugin and still have questions about how to set it up.

You can find everything you need to build your XD plugin and join the XD plugin developer community through AdobeXDPlatform.com.