In this article, we will discuss how to localize Firefox OS apps — both internal Gaia apps, and third party apps. This article provides a detailed guide, but can be considered a good starting point for those new to Firefox OS localization.
Currently Firefox OS Gaia uses a modified version of the L10n.js library to localize the default apps that are available in Firefox OS. L10n.js is available in the Gaia source tree. The library relies on a key/value-based properties format.
There are many other frameworks and technologies to pick from when it comes to localization. For example, the Jed Gettext-style library is a popular traditional option. There are also new localization platforms in development that extend the capabilities available in current libraries. For example, at Mozilla we have L20n, a very promising localization project that extends L10n with a variety of compelling new features. Gaia will be moving to L20n fairly soon, but this documentation will still be useful for legacy Firefox OS installs, and other projects.
Note: If you do decide to use the L10n approach, bear in mind that some features of the library are not cross-browser compatible (for example l10n_date.js uses the non-standard toLocaleFormat()
method.)
The localization procedure
We'll localize the strings that appear in the app's HTML as well as the name
and description
in the app manifest. The process will take five steps:
- Create translations: Create a file for each language we need to support that contains the translated strings.
- Mark up the HTML: Add a new attribute to each string in the HTML that will need localization.
- Include l10n.js: Include the l10n.js JavaScript library in the app, which inserts the correct strings into the HTML depending on locale.
- Update manifest.webapp: Add the translations for "name" and "description" to the app manifest.
- Link resources: Make sure the translation files can be found, and the app manifest is linked.
Create translations
First, we need to create a new directory in your app's root named locales
, and a directory under there for each language you need to support. Then in each of those directories, we create a file with an extension of .properties
. As an example of how it works examine one of our Gaia apps. The Bluetooth App might look like this with some translations added:
This App contains .properties
files for four locales (ar
, en-US
, fr
, and zh-TW
). A portion of the bluetooth.en-US.properties
file is listed below:
bluetooth = Bluetooth confirmation = Confirmation bluetooth-status-description = Bluetooth is disabled turn-bluetooth-on = Do you want to turn Bluetooth on? cancel = Cancel turn-on = Turn On
As you can see, it’s a simple key/value property file containing the set of strings to localize. Each line is the translation of a single string in name=value
format:
name
is an identifier for this string, matching the value for adata-l10n-id
attribute in the app's HTML.value
is the translation of the string in this particular language.
The other .properties
files will contain the same string names, but the values will be translated into the particular language for each file.
Usually, the app developer won't create the contents of app.properties
: a translator will create it, given the set of string identifiers and their value in the original language. For more on this, see the article on working with Transifex.
Mark up the HTML
You'll need to add a new attribute to every element in your HTML whose content needs to be translated. The name of the attribute is data-l10n-id
, and its value is an identifier for the string. This identifier is used as a key to look up the correct translation of the string. Here's an example:
<h2 data-l10n-id="label1">Label One</h2>
When all your attributes have been set, on page load the l10n.js
library will:
- Find all elements which have the
data-l10n-id
attribute set. - Use the attribute's value as a key to look up the correct translation of the string, given the current device language.
- Assign this translation as the element's
textContent.
There is also an attribute called data-l10n-args
, which can be used to hold values like the default value for an argument. You'll learn about this later on, in Argument substitution.
The value of the label1
attribute serves as the key into the properties file. Complex strings can be created in the properties files using argument substitution and the Plural macro.
The binding between each l10n-id
and its associated HTML Element is a one-to-one model. Entities should not be reused because although they may have the same value in your source language, different contexts will often require different translations.
Localizable elements should also not have any content or child elements because the localization will overwrite them.
Argument substitution
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, for example "Hello, Bob!".
Argument substitution is achieved by surrounding the argument with double curly braces: {{arg}}
. A message can then be customized for a specific user using syntax similar to the following:
label1 = Hello {{ user }}, glad you decided to visit
Default values for arguments can be set using the data-l10n-args
attribute. This attribute expects a JSON-formatted value. In the above example, a default value could be set for the user argument using the HTML below:
<h2 data-l10n-id="label1" data-l10n-args='{ "user": "Guest" }'></h2>
This will result in the element's content being set as "Hello Guest, glad you decided to visit".
You can also reference other entities in the same way:
brandShortName = Firefox OS helloWorld = Welcome to {{ brandShortName }}
Note: You can also retrieve argument-substituted strings using JavaScript.
Plural macro
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. For this, we have the Plural macro.
L10n.js currently supports very limited macro functionality and multi-variant strings. The plural macro can be used to customize messages based on an argument value. The macro takes a number value and returns zero, one, two, few, many, or other. The return value depends on the value passed in and the current locale’s Unicode Plural Rules. As an example, a customized mail message for the en-US
locale may look something like this:
mailMessage = {[ plural(n) ]} mailMessage[zero] = you have no messages mailMessage[one] = you have one message mailMessage[two] = you have two messages mailMessage[other] = you have {{ n }} messages
<h3 data-l10n-id="mailMessage" data-l10n-args='{ "n": "6" }'></h3>
This will result in the element's content being set as "You have 6 messages".
Note: You can also resolve plurals using JavaScript.
Include l10n.js
To find nodes in the HTML marked with data-l10n-id
and replace their contents with values from app.properties
, we need to include l10n.js
alongside the other JavaScript files in your app (including it in the <head>
is recommended):
<script src="js/l10n.js"></script>
Update manifest.webapp
To localize the app's name
and description
, we need to update the manifest.webapp
file. You need to add two new fields:
default_locale
: this is assigned a language code which will be the default. When the device is set to this language or any language not explicitly supported by the app, thename
anddescription
already specified in the manifest will be usedlocales
: this contains one property for each supported language apart from the default, listing the values to be used forname
anddescription
in that language
In this case we want to make English (en
) the default, and support the other languages as well, so we would add the following lines to manifest.webapp
, adding translations into the appropriate places:
"default_locale": "en", "locales": { "ar": { "name" : " ... ", "description" : " ... " } "fr": { "name" : " ... ", "description" : " ... " } "zh-TW": { "name" : " ... ", "description" : " ... " } }
name
and description
in separate files called manifest.properties
, stored alongside your other .properties
files.Link resources
In order for the resources to be used to localize your HTML file, you need to link them from your HTML <head>
element, like this:
<link rel="localization" href="locales/bluetooth.{locale}.properties" />
L10n.js uses the URL Template scheme, where the {locale}
portion of the path will be replaced with a locale code selected as the result of language negotiation.
On top of that, you need to link to your manifest file as follows:
<link rel="manifest" href="./manifest.webapp" />
Alternatively, you can list available locales and the default locale within the HTML file using <meta>
elements:
<meta name="locales" content="en-US, fr, de"> <meta name="default_locale" content="en-US">
L10n.js will do language negotiation between user-selected languages (see
) and the list of available languages provided in the manifest, select the language fallback chain and loading the resources for the most preferred locale.NavigatorLanguage.languages
Testing it out/How to view different locales
Finally, test that the localization worked. Using a real Firefox OS device or the Simulator, change the device language to Spanish using one of these options:
To view your app with a different locale, change the language in Firefox or Firefox OS:
- All platforms
- Set the desired locale to test in JavaScript, e.g:
document.webL10n.setLanguage("es");
- Firefox OS (or Firefox OS Simulator via WebIDE)
- Language setting in the Settings app
- Firefox
- Choose language under
Preferences > Content > Languages
. More information in Set content language in Firefox
In WebIDE, Firefox, or your Firefox OS phone, you should then be able to install or update your app, and open it — The strings it contains should now appear in the language you chose, provided of course there is a translation available for that language! If not, you'll just get the English versions.
See also
- There is a lot more to know about translating Firefox OS apps. A good place to start might be our L10n.js reference; you can also learn some advanced tricks and best practices in App localization code best practices.
- Most of the time, app developers don't translate strings themselves: they work with translators who are fluent in the target language. The developer supplies a set of string identifiers and their value in the source language, and the translator then supplies the translations. 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.
- For further reading on general good localization practices (not Firefox OS-specific), see Creating localizable web applications and Localization content best practices.
- And after you’ve finished localizing your own Firefox OS app, why not help with the localization of Firefox OS itself? Take a look at Localizing Firefox OS for more information on how to contribute.