Any string internationalization or localization must happen inside your extension code. As a convenience, the extension SDK provides access to a full-featured i18n library. This section describes how to use this library, but you are welcome to use any i18n mechanism that works well for you.

Providing and using i18n strings

There is an i18n object in the global namespace that provides a few methods you'll commonly use:

i18n.getLanguageReturns the language code currently selected by the user in Lucid, e.g. "en" or "es-LA"
i18n.setDataAdds new strings to the currently active i18n dictionary, and updates the active language
i18n.getGets a string from the currently active i18n dictionary and performs interpolations as necessary

Here is a minimal example of using the library:

const language = i18n.getLanguage();

// Set the English strings as fallbacks, in case other languages
// don't have all the strings translated yet
i18n.setData({
    "a": "ay",
    "b": "bee",
}, language);

// If the language is set to a language that
// have a dictionary for, set those strings as replacements
if(language == "es-LA") {
    i18n.setData({
        "a": "ah",
        "b": "bay",
    }, language);
}

// Later...
const client = new EditorClient();
client.alert(i18n.get("a"));

Use JSON files for string dictionaries

Inlining your i18n strings into your source code isn't a scalable solution. Instead, you can put your dictionaries into .json files under your resources directory. For example, if you add the files resources/i18n/en.json, resources/i18n/es-LA.json, etc., your code could look like this instead:

import en from '../resources/i18n/en.json';
import de from '../resources/i18n/de.json';
import esLa from '../resources/i18n/es-LA.json';

const language = i18n.getLanguage();
i18n.setData(en, language);
if (language == 'de') {
    i18n.setData(de, language);
} else if (language == 'es-LA') {
    i18n.setData(esLa, language);
}

In order to import JSON files like this, you'll need to make sure your resources/resource.d.ts file specifies their type:

declare module '*.json' {
    const content: Record<string, string>;
    export default content;
}

You must also have exclude: /\.json$/ in the raw-loader rule for the resources directory in webpack.config.js.

String interpolation

You can mark sections of your string to be replaced with curly braces:

i18n.setData(
    {
        'title': 'Send an email to {name}',
    },
    i18n.getLanguage(),
);

// "Send an email to Ben"
console.log(i18n.get('title', {'name': 'Ben'}));

Pluralization

count is a reserved string interpolation ID, to be used only for pluralization.

You can provide entries in your i18n dictionary that support pluralization by appending (in most languages) .one or .other to the key:

i18n.setData(
    {
        'title.one': 'Send an email to {count} person',
        'title.other': 'Send an email to {count} people',
    },
    i18n.getLanguage(),
);

// "Send an email to 1 person"
console.log(i18n.get('title', {'count': 1}));

// "Send an email to 4 people"
console.log(i18n.get('title', {'count': 4}));

You can learn more about pluralization rules on this site from the Unicode CLDR Project. You can see a full list of which pluralization rules you should specify for every possible language here.

For convenience, here is the list of pluralization suffixes you should provide (only for strings interpolating a count) for each language supported by Lucid:

LanguageSuffixes
Chineseother
Dutchone, other
Englishone, other
Frenchone, other
Germanone, other
Italianone, other
Japaneseother
Koreanone, other
Polishone, other
Portugueseone, other
Russianone, few, many
Spanishone, other
Swedishone, other

List of strings

You can provide a list of strings for expansion into a comma-separated list.

i18n.setData(
    {
        'shopping-list': 'Purchase {shoplist} today',
    },
    i18n.getLanguage(),
);

// "Purchase bread today"
const shoppingList1 = ['bread'];
console.log(i18n.get('shopping-list', {'shoplist': shoppingList}));

// "Purchase bread, apples, fish, and butter today"
const shoppingList2 = ['bread', 'apples', 'fish', 'butter'];
console.log(i18n.get('shopping-list', {'shoplist': shoppingList2}));

By default, the list expansion will add commas and will default to and. You can change the list options by specifying formatOptions. Available options include ListStyles as

List StyleExample
LONGa, b, and c
SHORTa, b, & c
NARROWa, b, c
List TypeExample
ANDa, b, and c
ORa, b, or c
UNIT_LISTa b c

If the text will change based on the length of the list, it can be combined with the Pluralization rules by also providing a count field.

i18n.setData(
    {
        'invite-list.one': 'You might invite your friend {friendlist} to the party',
        'invite-list.many': 'You might invite your friends, {friendlist}, to the party',
    },
    i18n.getLanguate(),
);

// "You might invite your friend Anna to the party"
const friendList1 = ['Anna'];
console.log(i18n.get('invite-list', {'count': friendList1.length, 'friendlist': i18n.formatList(friendList2, {style: ListStyles.LONG, type: ListTypes.OR})}));

// "You might invite your friends, Anna, Betty, Carl, or Dave, to the party"
const friendList2 = ['Anna', 'Betty', 'Carl', 'Dave'];
console.log(i18n.get('invite-list', {'count': friendList2.length, 'friendlist': i18n.formatList(friendList2, {style: ListStyles.LONG, type: ListTypes.OR})}));

Wrapped strings

You can "wrap" sections of your i18n strings in markup, often used for producing HTML links and other simple markup:

i18n.setData(
    {
        'message': 'Send an email to <w0>{name}</w0>',
    },
    i18n.getLanguage(),
);

// Send an email to <a href="mailto:[email protected]">Ben</a>
console.log(i18n.get(
    'message',
    {'name': 'Ben'},
    ['<a href="mailto:[email protected]">{}</a>']
));

Here, you're replacing the first wrapping tag w0 with the email link, with the content of w0 being placed where the {} is in the replacement text. If you need to do multiple wrapping tags in the same i18n string, number them w0, w1, w2, etc.

Supported languages

i18n.getLanguage() will tell you the user's currently-selected language in Lucid. This will be one of the following values:

LanguageCode
Chinese (simplified)zh-CN
Chinese (traditional)zh-TW
Dutchnl
Englishen
Frenchfr-FR
Germande
Italianit-IT
Japaneseja
Koreanko
Polishpl-PL
Portuguesept-BR
Russianru
Spanishes-LA
Swedishsv-SE