The article covers the basic setup you need to do to make your app localizable. The files you create here will be used to provide localized forms of strings appearing in your app's HTML and in its JavaScript.

There are three sorts of files you need to create:

First, you'll need to create a new directory under the app root called locales, and a directory under there for each language your app needs to support. Then in each of those directories, you'll need a new file called

  • my-app
    • css
    • js
    • locales
      • en
      • es
    • index.html
    • manifest.webapp

You don't have to use these names for files and directories, but you do have to use names that match the names you specify in your locales.ini file.

These files contain the translations of strings used in the app. Each line is the translation of a single string in name=value format:

  • name is an identifier for this string, and is used in your app's HTML or JavaScript to reference the string.
  • value is the translation of the string in this particular language.

For example, en/ might look like this:

app-heading = TranslationTester
winter-is-coming = Winter is coming

The corresponding might look like this:

app-heading = Tester Traducción
winter-is-coming = Se acerca el invierno

You can refer to a particular line from HTML and from JavaScript:

<p data-l10n-id="winter-is-coming">Winter is coming</p>
var quotation = window.document.webL10n.get("winter-is-coming")


Sometimes your app needs to insert a string that should not be localized into a string that should be localized. For example, if you want to greet the user, their name should not be localized but the greeting itself should: "Hello, Bob!". So the localization system needs a way to indicate how these parts should be combined.

In the file, translations of strings can include named placeholders by enclosing them in double curly brackets:

// en/
greeting=Hello {{person}}!
// fr/
greeting=Bonjour {{person}} !

See using placeholders in HTML and using placeholders in JavaScript to learn how to use placeholders in the app's code.


Most languages use different forms of words depending on how many of a thing there are. Some languages, like English, have just two forms: singular, for "one", and plural, for "everything else, including zero":

You have no tomatoes :(.
You have one tomato.
You have five tomatoes.

Other languages have more than two forms, and some have just one.

When your app is constructing strings dynamically and their forms depend on how many of a thing there are, the localization system needs a way to represent these rules, and the app needs a way to pass the number to the localization system.

You can represent plural forms using an file like this:

tomatoCount={[ plural(n) ]}
tomatoCount[zero]=Vous n'avez pas de tomates :(.
tomatoCount[one]=Vous avez une tomate.
tomatoCount[other] = Vouz avez {{n}} tomates.

The first line of this file says that when the app asks for the value for tomatoCount, we should return one of the three values underneath, depending on which of the keywords zero, one, or other the input argument n is mapped to.

The argument n is the number of tomatoes, passed in by the app. The keywords zero, one, or other , and the mapping between n and a keyword, are taken from the Unicode plural rules. The l10n.js library implements the mapping: so it knows that when you pass 5 as the value of n, then in French it needs to return the value for other.

This means that the creator of for a language needs to understand the plural rules for that language: but they must anyway be a fluent speaker of the language, this is not a great burden.

See using plurals in HTML and using plurals in JavaScript to learn how to use plurals in the app's code.

Working with translators

Most of the time, the app developer will only create one file, for their native language. A translator fluent in the target language will create files for other languages.

We're working with Transifex to put app developers in touch with translators. Read about how to use the Transifex service to connect with translators.


The locales.ini file tells the app:

  • which locale is the default, in case the app does not support the current device language
  • which other locales the app supports
  • for each supported locale, where in the app the translated strings can be found

It's organized as a collection of @import statements, each of which is labeled with the name of the language in square brackets, and includes the path from locales.ini to a properties file containing the translations for that language.

We indicate the default language by making its import statement the first line in the file and omitting its language label. For example, this locales.ini makes English the default and declares that we also support French:

@import url(en/

@import url(fr/

You can save locales.ini in your locales directory:

  • my-app
    • css
    • js
    • locales
      • en
      • es
      • locales.ini
    • index.html
    • manifest.webapp

You need to include it in the app's HTML using a <link> tag in the <head> section, like this:

<link rel="resource" type="application/l10n" href="locales/locales.ini" />


This JavaScript library does two things for you:

The version of l10n.js we'll use was written by a Mozilla engineer and we can copy it from GitHub. Save this file as l10n.js alongside your other JavaScript files, and include it in the app by adding a line like this in the <head> section of index.html:

<script src="js/l10n.js"></script>

What's next?

Now you're ready to localize strings in your app's HTML and in its JavaScript.

Document Tags and Contributors

Contributors to this page: wbamberg, necrophcodr
Last updated by: necrophcodr,