Translate Browser Extension
messages.json Files

Upload your extension's messages.json file, translate each message, and export straight into a _locales/{lang}/ folder.

No credit card required14-day free trialTracking-free service
_locales/pl/messages.json
{ "appName": { "message": "Moje rozszerzenie", "description": "The name of the extension" }, "appDescription": { "message": "Przydatne rozszerzenie do przeglądarki.", "description": "The description shown in the extension store" }, "greeting": { "message": "Witaj, $USER$! Masz $COUNT$ nowych wiadomości.", "description": "Greets the user and shows the number of new messages", "placeholders": { "user": { "content": "$1", "example": "Anna" }, "count": { "content": "$2", "example": "5" } } }, "buttonSave": { "message": "Zapisz" } }
{
  "appName": {
    "message": "Moje rozszerzenie",
    "description": "The name of the extension"
  },
  "appDescription": {
    "message": "Przydatne rozszerzenie do przeglądarki.",
    "description": "The description shown in the extension store"
  },
  "greeting": {
    "message": "Witaj, $USER$! Masz $COUNT$ nowych wiadomości.",
    "description": "Greets the user and shows the number of new messages",
    "placeholders": {
      "user": { "content": "$1", "example": "Anna" },
      "count": { "content": "$2", "example": "5" }
    }
  },
  "buttonSave": {
    "message": "Zapisz"
  }
}

Not a plain key-value JSON file

Chrome, Firefox, Edge and Safari all read extension translations from the same _locales/{lang}/messages.json layout, but the value under each key is an object, not a string: a required message field and an optional description field the browser ignores at runtime but translators actually rely on for context.

Placeholders follow their own convention too, written as $NAME$ in the message text and defined separately in a placeholders object that maps each name to a positional value like $1. SimpleLocalize keeps translators editing just the message text while the surrounding structure stays intact.

manifest.json
{ "name": "__MSG_appName__", "description": "__MSG_appDescription__", "default_locale": "en" }
{
  "name": "__MSG_appName__",
  "description": "__MSG_appDescription__",
  "default_locale": "en"
}

Two kinds of description

Your code and your translators, kept separate

Code description

Uploaded from your source, stored as reference context, and never silently overwritten.

Translator description

Written by a translator in the editor, kept separate from whatever your codebase originally sent.

Named placeholders

Each $NAME$ in a message maps to a positional value, and both round-trip on export.

End-to-end workflow

Translate a messages.json file end to end

Follow these steps to translate a messages.json file from start to finish using SimpleLocalize.

Terminal
simplelocalize upload \ --apiKey PROJECT_API_KEY \ --uploadFormat browser-extension-json \ --uploadLanguageKey en \ --uploadPath ./_locales/en/messages.json
simplelocalize upload \
  --apiKey PROJECT_API_KEY \
  --uploadFormat browser-extension-json \
  --uploadLanguageKey en \
  --uploadPath ./_locales/en/messages.json

Upload your default locale

1
Point the CLI at _locales/en/messages.json. Message and description fields import correctly without extra configuration.
Translation editor
Key: greeting Source: Hello, $USER$! You have $COUNT$ new messages. Code description: Greets the user and shows the number of new messages
Key: greeting
Source: Hello, $USER$! You have $COUNT$
        new messages.
Code description: Greets the user and
  shows the number of new messages

Descriptions land as context, not overwrites

2
The description from your source file is stored as a code description, kept separate from anything a translator writes directly in the editor.
messages.json (pl, auto-translated)
"greeting": { "message": "Witaj, $USER$! Masz $COUNT$ nowych wiadomości." }
"greeting": {
  "message": "Witaj, $USER$! Masz $COUNT$
    nowych wiadomości."
}

Auto-translate, placeholders protected

3
Run auto-translation across every target locale. Named placeholders like $USER$ and $COUNT$ stay exactly where they belong in the translated text.
Terminal
simplelocalize download \ --apiKey PROJECT_API_KEY \ --downloadFormat browser-extension-json \ --downloadLanguageKey pl,de,es \ --downloadPath ./_locales/{lang}/messages.json
simplelocalize download \
  --apiKey PROJECT_API_KEY \
  --downloadFormat browser-extension-json \
  --downloadLanguageKey pl,de,es \
  --downloadPath ./_locales/{lang}/messages.json

Download into every _locales/{lang}/ folder

4
Export drops files exactly where Chrome, Firefox, Edge and Safari expect to find them, ready to ship in your next release.

For developers

A localization platform,
not just a JSON transformer

A description written by a translator in the editor is worth protecting, even when your codebase uploads a new one.

Code vs. translator descriptions

A description uploaded from your codebase is stored separately from one a translator writes in the editor, so a new code upload never silently overwrites their notes.

Placeholders stay intact

Named placeholders and their positional mappings round-trip exactly, so substitutions still work after translation.

AI auto-translation

Translate new and changed messages with DeepL, Google Translate, OpenAI, Claude or Gemini.

CLI and REST API

Upload and download messages.json files from the CLI, or automate the same logic through the REST API.

SimpleLocalize connects your code to professional translations

More conversions

Convert messages.json to other formats

Free online converter, no account required. Upload a messages.json file and download it in the format you need.

Start translating extension messages

  • Correct message/description object structure
  • Code and translator descriptions kept separate
  • Exports the exact _locales/{lang}/ layout browsers expect
Start for free
No credit card required5-minute setup
"The product
and support
are fantastic."
Laars Buur|CTO
"The support is
blazing fast,
thank you Jakub!"
Stefan|Developer
"Interface that
makes any dev
feel at home!"
Dario De Cianni|CTO
"Excellent app,
saves my time
and money"
Dmitry Melnik|Developer

Frequently asked questions about extension translations

Why isn't this just a plain JSON key-value file?

Browser extensions require each key to hold an object with a message field, and often a description field for translator context. A plain string value would not load correctly in the extension.

Does this work for Firefox, Edge and Safari, not just Chrome?

Yes. All four follow the same WebExtensions _locales/{lang}/messages.json specification, so one exported file works across them.

Will re-uploading my source file overwrite a translator's notes?

Not by default. A description uploaded from your code is kept separate as a code description and won't overwrite what a translator wrote manually, unless you explicitly add the UPDATE_DESCRIPTIONS option.

Are placeholders like $1 preserved during translation?

Yes. Named placeholders and their positional content mappings are protected during auto-translation and stay valid in the exported file.