The documentation here is targeted at developers, writing localizable code for Firefox and Firefox for Android, as well as Thunderbird and SeaMonkey.

If you haven’t dealt with localization in gecko code before, it’s a good idea to check the Glossary for what localization is, and which terms we use for what.

Exposing strings

Localizers only handle a few file formats in well-known locations in the source tree.

The locations are specified by TOML files. They’re part of the bigger localization ecosystem at Mozilla, and the documentation about the file format explains how to set them up, and what the entries mean. In short, you find

    reference = browser/locales/en-US/**
    l10n = {l}browser/**

to add a directory for all localizations. Changes to these files are best submitted for review by :Pike or :flod.

These configuration files are the future, and right now, we still have support for the previous way to configuring l10n, which is described below.

The locations are commonly in directories like


The first thing to note is that only files beneath locales/en-US are exposed to localizers. The second thing to note is that only a few directories are exposed. Which directories are exposed is defined in files called l10n.ini, which are at a few places in the source code.

An example looks like this

depth = ../..

dirs = browser

toolkit = toolkit/locales/l10n.ini

This tells the l10n infrastructure three things: Resolve the paths against the directory two levels up, include files in browser/locales/en-US and browser/branding/official/locales/en-US, and load more data from toolkit/locales/l10n.ini.

For projects like Thunderbird and SeaMonkey in comm-central, additional data needs to be provided when including an l10n.ini from a different repository:

type = hg
mozilla = mozilla-central
repo = https://hg.mozilla.org/
l10n.ini = toolkit/locales/l10n.ini

This tells the l10n pieces where to find the repository, and where inside that repository the l10n.ini file is. This is needed because for local builds, mail/locales/l10n.ini references mozilla/toolkit/locales/l10n.ini, which is where the comm-central build setup expects toolkit to be.

Now that the directories exposed to l10n are known, we can talk about the supported file formats.

File formats

This is just a quick overview, please check the XUL Tutorial for an in-depth tour.

The following file formats are known to the l10n tool chains:

Used in XUL and XHTML. Also for Android native strings.
Used from JavaScript and C++. When used from js, also comes with plural support.
Used by the crashreporter and updater, avoid if possible.
Used during builds, for example to create install.rdf for language packs.

Adding new formats involves changing various different tools, and is strongly discouraged.


Generally, anything that exists in en-US needs a one-to-one mapping in all localizations. There are a few cases where that’s not wanted, notably around search settings and spell-checking dictionaries.

To enable tools to adjust to those exceptions, there’s a python-coded filter.py, implementing test(), with the following signature

def test(mod, path, entity = None):
    if does_not_matter:
        return "ignore"
    if show_but_do_not_merge:
        return "report"
    # default behavior, localizer or build need to do something
    return "error"

For any missing file, this function is called with mod being the module, and path being the relative path inside locales/en-US. The module is the top-level dir as referenced in l10n.ini.

For missing strings, the entity parameter is the key of the string in the en-US file.


Gecko doesn’t support fallback from a localization to en-US at runtime. Thus, the build needs to ensure that the localization as it’s built into the package has all required strings, and that the strings don’t contain errors. To ensure that, we’re merging the localization and en-US at build time, nick-named l10n-merge.

The process can be manually triggered via

$> ./mach build merge-de

It creates another directory in the object dir, merge-dir/ab-CD, in which the modified files are stored. The actual repackaging process looks for the localized files in the merge dir first, then the localized file, and then in en-US. Thus, for the de localization of browser/locales/en-US/chrome/browser/browser.dtd, it checks

  1. $objdir/browser/locales/merge-de/browser/chrome/browser/browser.dtd
  2. $(LOCALE_BASEDIR)/de/browser/chrome/browser/browser.dtd
  3. browser/locales/en-US/chrome/browser/browser.dtd

and will include the first of those files it finds.

l10n-merge modifies a file if it supports the particular file type, and there are missing strings which are not filtered out, or if an existing string shows an error. See the Checks section below for details.


As part of the build and other localization tool chains, we run a variety of source-based checks. Think of them as linters.

The suite of checks is usually determined by file type, i.e., there’s a suite of checks for DTD files and one for properties files, etc. An exception are Android-specific checks.


For Android, we need to localize strings.xml. We’re doing so via DTD files, which is mostly OK. But the strings inside the XML file have to satisfy additional constraints about quotes etc, that are not part of XML. There’s probably some historic background on why things are the way they are.

The Android-specific checks are enabled for DTD files that are in mobile/android/base/locales/en-US/.


Now that we talked in-depth about how to expose content to localizers, where are the localizations?

We host a mercurial repository per locale and per branch. All of our localizations can be found on https://hg.mozilla.org/l10n-central/.

You can search inside our localized files on Transvision and https://dxr.mozilla.org/l10n-central/source/.