Skip to main content

Version: 24.04

Locales

Internationalization (i18n) appears to be simple but can be complex. Some considerations are:

  • Front-end internationalization
  • Internationalization of server
  • Internationalized resource file management
  • How to collaborate between projects, developers and translators
  • Internationalization of dates and times

Internationalization implementations are often tied to specific technology stacks. This internationalization setup is only for the React technology stack and does not involve server-side internationalization.

Front-end internationalization

The core steps of internationalization are as follows:

  1. Add the desired locale to the transact-config configuration. If omitted, the default locale is en.

  2. Create and import a messages file, stored as a key-value object in the src/locales folder.

  3. Import and re-export those locale message files in src/locales/index.ts. For example:

    src/locales/index.ts
    import en from './en';
    import es from './es';
    import pt from './pt';
    import zhCN from './zh-cn';
    import zhTW from './zh-tw';

    export default {
    en,
    es,
    pt,
    'zh-CN': zhCN,
    'zh-TW': zhTW,
    };
    note

    Some locales include a region code as well as the language code, such as Chinese locales like zh-CN and zh-TW. The sample src/locales/index.ts file above shows how to add locales with a region code. For example, for the Chinese locale zh-CN, add 'zh-CN': zhCN to the exported locales.

  4. Pass the configs and messages to the App init.

The Workspaces app allows the user to select a language for static text in the UI. The list of languages offered is generated by matching the exported locales against the following list.

{value: 'en', id: 'eng', key: 'English',label: 'English'},
{value: 'ar', id: 'ara', key: 'Arabic',label: 'Arabic'},
{value: 'af', id: 'afr', key: 'Afrikaans locale',label: 'Afrikaans'},
{value: 'ar-DZ', id: 'ara', key: 'Arabic locale (Algerian Arabic)',label: 'Algerian Arabic'},
{value: 'ar-MA', id: 'ara', key: 'Arabic locale (Moroccan Arabic)',label: 'Moroccan Arabic'},
{value: 'ar-SA', id: 'ara', key: 'Arabic locale (Sauid Arabic)',label: 'Arabic'},
{value: 'ar-TN', id: 'ara', key: 'Arabic locale (Tunisian Arabic)',label: 'Arabic'},
{value: 'az', id: 'aze', key: 'Azerbaijani locale',label: 'Azerbaijani'},
{value: 'be', id: 'bel', key: 'Belarusian locale',label: 'Belarusian'},
{value: 'bg', id: 'bul', key: 'Bulgarian locale',label: 'Bulgarian'},
{value: 'bn', id: 'ben', key: 'Bengali locale',label: 'Bengali'},
{value: 'bs', id: 'bos', key: 'Bosnian locale',label: 'Bosnian'},
{value: 'ca', id: 'cat', key: 'Catalan locale',label: 'Catalan'},
{value: 'cs', id: 'ces', key: 'Czech locale',label: 'Czech'},
{value: 'cy', id: 'cym', key: 'Welsh locale',label: 'Welsh'},
{value: 'da', id: 'dan', key: 'Danish locale',label: 'Danish'},
{value: 'de', id: 'deu', key: 'German locale',label: 'German'},
{value: 'de-AT', id: 'deu', key: 'German locale (Austria)',label: 'German'},
{value: 'el', id: 'ell', key: 'Greek locale',label: 'Greek'},
{value: 'en-AU', id: 'eng', key: 'English locale (Australia)',label: 'English'},
{value: 'en-CA', id: 'eng', key: 'English locale (Canada)',label: 'English'},
{value: 'en-GB', id: 'eng', key: 'English locale (United Kingdom)',label: 'English'},
{value: 'en-IN', id: 'eng', key: 'English locale (India)',label: 'English'},
{value: 'en-NZ', id: 'eng', key: 'English locale (New Zealand)',label: 'English'},
{value: 'en-US', id: 'eng', key: 'English locale (United States)',label: 'English'},
{value: 'en-ZA', id: 'eng', key: 'English locale (South Africa)',label: 'English'},
{value: 'eo', id: 'epo', key: 'Esperanto locale',label: 'Esperanto'},
{value: 'es', id: 'spa', key: 'Spanish locale',label: 'Spanish'},
{value: 'et', id: 'est', key: 'Estonian locale',label: 'Estonian'},
{value: 'eu', id: 'eus', key: 'Basque locale',label: 'Basque'},
{value: 'fa-IR', id: 'ira', key: 'Persian/Farsi locale (Iran)',label: 'Persian'},
{value: 'fi', id: 'fin', key: 'Finnish locale',label: 'Finnish'},
{value: 'fr', id: 'fra', key: 'French locale',label: 'French'},
{value: 'fr-CA', id: 'fra', key: 'French locale (Canada)',label: 'French'},
{value: 'fr-CH', id: 'fra', key: 'French locale',label: 'French'},
{value: 'gd', id: 'gla', key: 'Scottish Gaelic',label: 'Scottish Gaelic'},
{value: 'gl', id: 'glg', key: 'Galician locale',label: 'Galician'},
{value: 'gu', id: 'guj', key: 'Gujarati locale (India)',label: 'Gujarati'},
{value: 'he', id: 'heb', key: 'Hebrew locale',label: 'Hebrew'},
{value: 'hi', id: 'hin', key: 'Hindi locale (India)',label: 'Hindi'},
{value: 'hr', id: 'hrv', key: 'Croatian locale',label: 'Croatian'},
{value: 'ht', id: 'hat', key: 'Haitian Creole locale',label: 'Haitian Creole'},
{value: 'hu', id: 'hun', key: 'Hungarian locale',label: 'Hungarian'},
{value: 'hy', id: 'arm', key: 'Armenian locale',label: 'Armenian'},
{value: 'id', id: 'ind', key: 'Indonesian locale',label: 'Indonesian'},
{value: 'is', id: 'isl', key: 'Icelandic locale',label: 'Icelandic'},
{value: 'it', id: 'ita', key: 'Italian locale',label: 'Italian'},
{value: 'ja', id: 'jpn', key: 'Japanese locale',label: 'Japanese'},
{value: 'ja-Hira', id: 'jpn', key: 'Japanese (Hiragana) locale',label: 'Japanese (Hiragana)'},
{value: 'ka', id: 'geo', key: 'Georgian locale',label: 'Georgian'},
{value: 'kk', id: 'kaz', key: 'Kazakh locale',label: 'Kazakh'},
{value: 'kn', id: 'kan', key: 'Kannada locale (India)',label: 'Kannada'},
{value: 'ko', id: 'kor', key: 'Korean locale',label: 'Korean'},
{value: 'lb', id: 'ltz', key: 'Luxembourgish locale',label: 'Luxembourgish'},
{value: 'lt', id: 'lit', key: 'Lithuanian locale',label: 'Lithuanian'},
{value: 'lv', id: 'lav', key: 'Latvian locale (Latvia)',label: 'Latvian'},
{value: 'mk', id: 'mkd', key: 'Macedonian locale',label: 'Macedonian'},
{value: 'mn', id: 'mon', key: 'Mongolian locale',label: 'Mongolian'},
{value: 'ms', id: 'msa', key: 'Malay locale',label: 'Malay'},
{value: 'mt', id: 'mlt', key: 'Maltese locale',label: 'Maltese'},
{value: 'nb', id: 'nob', key: 'Norwegian Bokmål locale',label: 'Norwegian Bokmål'},
{value: 'nl', id: 'nld', key: 'Dutch locale',label: 'Dutch'},
{value: 'nl-BE', id: 'nld', key: 'Dutch locale',label: 'Dutch'},
{value: 'nn', id: 'nno', key: 'Norwegian Nynorsk locale',label: 'Norwegian Nynorsk'},
{value: 'pl', id: 'pol', key: 'Polish locale',label: 'Polish'},
{value: 'pt', id: 'por', key: 'Portuguese locale',label: 'Portuguese'},
{value: 'pt-BR', id: 'por', key: 'Portuguese locale (Brazil)',label: 'Portuguese'},
{value: 'ro', id: 'ron', key: 'Romanian locale',label: 'Romanian'},
{value: 'ru', id: 'rus', key: 'Russian locale',label: 'Russian'},
{value: 'sk', id: 'slk', key: 'Slovak locale',label: 'Slovak'},
{value: 'sl', id: 'slv', key: 'Slovenian locale',label: 'Slovenian'},
{value: 'sq', id: 'sqi', key: 'Albanian locale',label: 'Shqip'},
{value: 'sr', id: 'srp', key: 'Serbian cyrillic locale',label: 'Serbian'},
{value: 'sr-Latn', id: 'srp', key: 'Serbian latin locale',label: 'Serbian'},
{value: 'sv', id: 'swe', key: 'Swedish locale',label: 'Swedish'},
{value: 'ta', id: 'tam', key: 'Tamil locale (India)',label: 'Tamil'},
{value: 'te', id: 'tel', key: 'Telugu locale',label: 'Telugu'},
{value: 'th', id: 'tha', key: 'Thai locale',label: 'Thai'},
{value: 'tr', id: 'tur', key: 'Turkish locale',label: 'Turkish'},
{value: 'ug', id: 'uig', key: 'Uighur locale',label: 'Uighur'},
{value: 'uk', id: 'ukr', key: 'Ukrainian locale',label: 'Ukrainian'},
{value: 'uz', id: 'uzb', key: 'Uzbek locale',label: 'Uzbek'},
{value: 'vi', id: 'vie', key: 'Vietnamese locale (Vietnam)',label: 'Vietnamese'},
{value: 'zh-CN', id: 'zho', key: 'Chinese Simplified locale',label: 'Chinese Simplified'},
{value: 'zh-TW', id: 'zho', key: 'Chinese Traditional locale',label: 'Chinese Traditional'},

Date translations use the date-fns library which requires some unique locale data when doing internationalization, mainly for relative time translation such as yesterday, today, tomorrow, N minutes ago, or N months ago. Consequently, it's important to import the correct locale at the beginning of the file. To learn more, see Internationalization in the date-fns documentation.

Internationalized resource file management

The above document discusses the steps of how to internationalize after the introduction of messages files. Next, let's talk about the management of international resource files.

Currently we manage the resource file in the src/locales folder:

.
├── en.ts
├── es.ts
└── pt.ts

\*.ts is a resource file that returns an object; the key for our translation id, and the value for the specific language translation. For example:

src/locales/en.ts
export default {
Home: 'Home',
All: 'All',
Apply: 'Apply',
Process: 'Process',
Helpdesk: 'Helpdesk',
...
}
src/locales/es.ts
export default {
Home: 'Hogar',
All: 'Todos',
Applications: 'Aplicaciones',
Review: 'Revisar',
Funding: 'Fondos',
...
}

Right-to-left languages

note

Workspaces supports the following right-to-left languages based on the list included in the article Right-To-Left vs Left-To-Right. If any issues are discovered with this behaviour or another ISO language code needs to be added, you can contact us to discuss your requirements.

If the locale specified in your transact-config matches one of the ISO language codes listed below, the application will display in right-to-left mode. For more information about locales, see Locales.

ISO Language CodeLanguage Name
arArabic
arcAramaic
dvDivehi
faPersian
haHausa
heHebrew
khwKhowar
ksKashmiri
kuKurdish
psPashto
urUrdu
yiYiddish