Creating Translations

amCharts 4 replies on locale files for localization of the charts. Locales are responsible for both translations of prompts and setting date/number formats. This tutorial will explain how you can make changes to existing translations, and create the new ones.

If you ended up here, you probably already know how locales are used. On the off chance you don't, refer to our "Locales" article for a quick intro.

Intro

amCharts 4 is written in TypeScript (TS). This means that locale files are in TypeScript as well.

During the course of this tutorial we will be editing TS files, in a way that is suitable for contributing your translation/edit for the whole amCharts community, and for inclusion in the official distribution.

If you would like to make a quick edit or a locale file for your only for yourself (without contributing it), there's a section about it at the end of this tutorial.

This tutorial also assumes you have basic knowledge of GitHub and GIT in general.

Updating bundled locale

All locales bundled with amCharts 4 are located in the amcharts4 GitHub repository.

Locale files are located under src/lang.

  • To start, clone amcharts4;
  • Open .ts language file you'd like to edit, and make your modifications;
  • Commit the change with a meaningful comment, like "Fixed a typo in French translation";
  • Create a Pull Request to amcharts4 with your changes.

Creating a new translation

  • Clone amcharts4;
  • Make a copy of the en.ts;
  • Name the file using syntax language_COUNTRY.ts (e.g. pt_BR meaning Brazilian Portuguese);
  • Open the newly created .ts file and make your translations;
  • Update header;
  • Commit the change with a meaningful comment, like "Added a French translation";
  • Create a Pull Request to amcharts4 with your changes.

Structure of a locale file

A local comes as a single object. Its keys are phrases or keywords in English. Values - translations.

It looks something like this:

export default {
  "English prompt": "Translation",
  "Another English prompt": "Another translation",
  "Yet another prompt in English": "Yet another translation",
  // ...
}

An example of what part of Spanish translation could look like:

export default {
  // ...
  "January": "Enero",
  "February": "Febrero",
  "March": "Marzo",
  // ...
}

Types of the translatable prompts

As you explore the template en.js, you'll notice that some keys are not English phrases or words, and that some of the values are not actually strings.

Let's explore these different types of translatable elements.

Basic phrases and words

Those are the base of the translations. They come in a very predictable pattern: English phrase or word as a key, and exact translation as a value. E.g.:

export default {
  // ...
  "Zoom Out": "Uitzoomen",
  "Play": "Afspelen",
  "Stop": "Stoppen",
  // ...
}

Special keys

Each locale is responsible not only for translating words and phrases, but also defining number and date/time formats for the target country.

Some keys in the translation files are not phrases in English, but rather some internal code, denoting a specific format, e.g.:

Those are the base of the translations. They come in a very predictable pattern: English phrase or word as a key, and exact translation as a value. E.g.:

export default {
  // ...
  "_decimalSeparator": ",",
  "_thousandSeparator": " ",
  // ...
  "_date_day": "yyyy-MM-dd",
  // ...
}

The "_decimalSeparator" above instructs that we want to use a comma as a decimal separator in numbers. The "_thousandSeparator" says we want our thousands to be separate by a space.

"_date_day" set the default date format when we want to show a particular date.

en.ts file might contain further tips and guidelines for each group of such special translations.

Ordinals

These are not basic values, but rather functions, that return a prompt, based on the actual value.

For example, a number suffix which denotes number's position. E.g 1st, 2nd, 3rd, 4th, 21st, etc.

The reason why we need to use a function, as opposed to just translating "st", "nd", is that those might not necessarily be like this in other languages.

We can't predict how different languages treat ordinals, so we must leave to a translator to come up with a function that generates a proper ordinal for a number, supplied as a parameter.

Here's how ordinal function looks like for English:

export default {
  // ...
  "_dateOrd": function(day: number): string {
    let res = "th";
    if ((day < 11) || (day > 13)) {
      switch (day % 10) {
        case 1:
          res = "st";
          break;
        case 2:
          res = "nd";
          break;
        case 3:
          res = "rd"
          break;
      }
    }
    return res;
  }",
  // ...
}

For some languages, like Lithuanian, ordinals do not differ for numbers, so the function would look quite straightforward:

export default {
  // ...
  "_dateOrd": function(day: number): string {
    return "-a(s)";
  },",
  // ...
}

Placeholders

You will also notice, that some prompts contain numbers prefixed with a percent sign, e.g.:

export default {
  // ...
  "From %1 to %2": "",
  "From %1": "",
  "To %1": "",
  // ...
}

Those are placeholders, that will be replaced with actual values.

IMPORTANT The translation must include all the same placeholders, however their position is not important. Choose the position which suits the translation best.

Here's how Spanish translation might look for the above:

export default {
  // ...
  "From %1 to %2": "De %1 a %2",
  "From %1": "Desde %1",
  "To %1": "Hasta %1",
  // ...
}

Untranslated prompts

An empty string "" in translation means "use default English" prompt.

If the translation is not necessary, e.g. as most prompts and formats in variations of English, or if you can't translate some of the prompts right now, simply leave the translation as an empty string. The chart will fall back to English for just those untranslated ones.

Empty prompts

If for some reason you want to display nothing instead of an English phrase, use null instead:

export default {
  // ...
  "AM": null,
  "PM": null,
  // ...
}

Locale file header

A header of the locale file conveys information about the language this file is for.

It can also contain information about the author of the translation.

Make sure you include appropriate header with your locale file.

The template en.ts already includes a header placeholder, which you can use as a template.

Example:

/**
 * amCharts 4 Translation file
 * Locale: nl_NL
 * Language: Dutch
 * Author: Robbert Breij
 */

Contributing your translation

Please note, that we can and will accept translations as TypeScript (.ts) files only.

If you created a translation as an ES6 module, you can just change the extension of the file from .js to .ts before committing and creating a Pull Request.

If you don't think your translation or edit would be useful to anyone else, or if you can't make it public, you can skip the Pull Request.

Standalone translations

Using TypeScript

The process of creating a TypeScript translation is pretty much described in the beginning of the this tutorial in "Creating a new translation".

You can create it as a separate file, or simply define translation object in your own app, then assign it to your chart.language.locale.

Using ES6 modules

Usage is pretty much the same in ES6 - the locale files in amCharts 4 are identical in TypeScript and ES6 modules.

If you'd like to create a translation to be used in an ES6 app, you can follow the instructions for creating a translation from earlier in this tutorial. Just name your file with a .js extension.

Once you're done with your translation, and would like to contribute it to amCharts community, make a copy of your file with a .ts extension, and follow instructions outlined in "Creating a new translation" section.

Using vanilla JavaScript

If you are using amCharts 4 in a plain JavaScript application, and do not want to go through the process of creating the locale via TypeScript, here's what you can do.

If you want your translation to be a standalone file, you will need to modify the default syntax to define a global variable.

Let's take en.js as a base for the translation. It looks something like this:

export default {
  "English prompt": "Translation",
  "Another English prompt": "Another translation",
  "Yet another prompt in English": "Yet another translation",
  // ...
}

Plain JavaScript does not understand the export default notation, which is an instruction for ES6/TS modules.

We have to replace it with a  declaration of a global variable:

var am4lang_xx_XX = {
  "English prompt": "Translation",
  "Another English prompt": "Another translation",
  "Yet another prompt in English": "Yet another translation",
  // ...
}

Now, when you load your file via <script> tag, you will have locale declaration in a global variable am4lang_xx_XX which, in turn, can be use to set chart.language.locale:

<script src="xx_XX.js"></script>
<script>
 var chart = am4core.create("chartdiv", am4charts.XYChart);
 chart.language.locale = am4lang_xx_XX;
</script>

NOTE Unfortunately, we won't be able to accept translations, created in JavaScript, for inclusion into amCharts 4.