Skip to main content
Extension.js reads the _locales folder at your project root and validates that each declared locale has a messages.json. It emits locale JSON assets into the browser-specific build. During development, it picks up edits to any locale file without a full restart.

Template example

action-locales

action-locales template screenshot See localized extension metadata and UI strings with _locales support.
Repository: extension-js/examples/action-locales

Locale capabilities

Expected structure

default_locale in manifest.json should map to an existing _locales/<default>/messages.json.

Legacy layout: _locales next to the manifest

The project root is the canonical place for _locales, even when your manifest lives in a subfolder such as src/. A _locales folder next to a nested manifest still builds. The compiler emits a LocalesLayoutWarning that asks you to move it to the root. Browsers read locales from the extension root, so the root placement matches what ships.

Sample locales declaration in manifest.json

Here is how to declare locales in manifest.json:
You would then include JSON files for each locale inside the _locales folder:

Sample messages.json file

Example messages.json file for translations:

Output path

Extension.js emits locale JSON files under:

Development behavior

  • Extension.js adds locale JSON files to compilation dependencies and watches them.
  • Locale changes trigger extension reload behavior (hard reload), not component-style hot module replacement (HMR).
  • Extension.js fails validation with actionable diagnostics when required locale files are missing or invalid.

Validation behavior

Extension.js validates:
  • A _locales folder without default_locale in the manifest fails the build, because browsers reject that combination
  • Existence of _locales/<default> and its messages.json
  • JSON validity for every locale’s messages.json
  • __MSG_*__ references in the manifest against default locale keys
Two details of the __MSG_*__ scan:
  • Predefined @@ messages, such as __MSG_@@ui_locale__, are exempt because the browser provides them.
  • The @ character is allowed inside message keys, matching Chrome’s grammar for message names.

Troubleshooting missing locale keys

If your manifest uses __MSG_extension_description__, ensure the default locale file contains extension_description:
If the default locale does not define the key, Extension.js surfaces a diagnostic explaining the mismatch.

Packaging behavior

When you build with --zip or --zip-source, Extension.js checks the default locale again at zip time. A manifest that declares default_locale without a matching messages.json produces a warning, because stores reject packages without their default locale. Zip filenames come from the manifest name. A __MSG_*__ name resolves against the default locale’s messages.json, so the archive carries the translated name, not the placeholder.

Best practices

  • Keep messages.json keys consistent across locales.
  • Update default locale first, then propagate keys to other locales.
  • Validate locale JSON in continuous integration (CI) to catch malformed files before packaging.
  • Keep _locales at the project root, the placement that browsers and the packaging step read.

Next steps