Purpose: This document describes the internationalization (i18n) and localization (l10n) system that enables uBlock Origin to support 50+ languages across its user interface. It covers the storage format for localized strings, the runtime mechanisms for loading and applying translations, and how different parts of the codebase access localized text.
For information about the user interface components that display these localized strings, see User Interface.
The localization system follows the standard WebExtension i18n pattern, storing translations in JSON files organized by locale and providing both declarative HTML attributes and programmatic JavaScript APIs for accessing localized strings.
Sources: src/_locales/en/messages.json1-13 src/_locales/de/messages.json1-13 src/_locales/zh_CN/messages.json1-13 src/_locales/zh_TW/messages.json1-13
Localized strings are stored in a standardized directory hierarchy following the WebExtension specification:
src/
└── _locales/
├── en/
│ └── messages.json # English (base language)
├── es/
│ └── messages.json # Spanish
├── zh_CN/
│ └── messages.json # Simplified Chinese
├── zh_TW/
│ └── messages.json # Traditional Chinese
├── de/
│ └── messages.json # German
├── fr/
│ └── messages.json # French
├── ja/
│ └── messages.json # Japanese
└── [50+ other locales]/
└── messages.json
Each locale directory is named using standard language/region codes (e.g., en, pt_BR, zh_TW). The messages.json file within each directory contains all UI strings for that locale.
Supported Language Codes (partial list):
bg, ca, cs, da, de, el, en, es, et, fi, fr, he, hi, hr, hu, id, it, ja, ka, ko, lt, lv, nb, nl, pl, pt_BR, pt_PT, ro, ru, sk, sl, sq, sr, sv, tr, uk, vi, zh_CN, zh_TWSources: src/_locales/en/messages.json1 src/_locales/sq/messages.json1 src/_locales/es/messages.json1 src/_locales/zh_TW/messages.json1 src/_locales/de/messages.json1
Each messages.json file contains a top-level JSON object where each key represents a message identifier, and the value is an object with localization metadata.
Fields:
message (required): The localized string displayed to usersdescription (optional): Explanation for translators about where/how the string is usedSources: src/_locales/en/messages.json2-13 src/_locales/en/messages.json82-85
| Message Key | Example Value (English) | Usage Location |
|---|---|---|
extName | "uBlock Origin" | Extension name in browser UI |
extShortDesc | "Finally, an efficient blocker..." | Store listing (≤132 chars) |
dashboardName | "uBlock₀ — Dashboard" | Dashboard page <title> |
settingsPageName | "Settings" | Settings tab label |
3pPageName | "Filter lists" | Filter lists tab label |
1pPageName | "My filters" | My filters tab label |
rulesPageName | "My rules" | My rules tab label |
whitelistPageName | "Trusted sites" | Trusted sites tab label |
popupPowerSwitchInfo | "Click: disable/enable uBlock₀..." | Power button tooltip |
popupBlockedRequestPrompt | "requests blocked" | Popup stats label |
pickerContextMenuEntry | "Block element…" | Browser context menu entry |
Sources: src/_locales/en/messages.json2-100
Many messages contain dynamic content using placeholder syntax for variable substitution.
Placeholders use double curly braces: {{placeholderName}}
Common Placeholder Names:
{{count}} — Numeric counters{{percent}} — Percentage values{{input}} — User-configurable numeric values (e.g., media size threshold){{total}} — Total counts{{datetime}} — Timestamp strings (used in export filenames){{ago}} — Relative time strings (e.g., "2 hours ago"){{filter}}, {{type}}, {{url}}, {{origin}}, {{br}} — Filter wizard sentence partsSources: src/_locales/en/messages.json90-93 src/_locales/en/messages.json270-273 src/_locales/en/messages.json382-385 src/_locales/en/messages.json559-561 src/_locales/en/messages.json526-528
data-i18nHTML elements can be automatically localized using the data-i18n attribute, which references a message key from messages.json.
data-i18nIn HTML pages, the data-i18n attribute sets the textContent of the element. A companion data-tip attribute is used to bind tooltip text to the element's title attribute. The i18n initialization code processes all such attributes at page load.
Substitutions for placeholder variables (e.g., {{count}}) are applied in JavaScript at the point where the message is used, not inline in the attribute value.
Sources: src/_locales/en/messages.json26-29 src/_locales/en/messages.json114-117
JavaScript code accesses localized strings through wrapper functions that abstract the browser's i18n API.
vAPI.i18n()Simple message lookup:
With array substitutions:
With object substitutions:
Common prefixes organize related messages:
| Prefix | Purpose | Examples |
|---|---|---|
popup* | Popup panel UI | popupPowerSwitchInfo, popupBlockedRequestPrompt |
settings* | Settings page | settingsPageName, settingsAdvancedUserPrompt |
3p* | Third-party filter lists | 3pPageName, 3pAutoUpdatePrompt1 |
1p* | User's custom filters | 1pPageName, 1pEnableMyFiltersLabel |
rules* | Dynamic filtering rules | rulesPageName, rulesPermanentHeader |
picker* | Element picker tool | pickerCreate, pickerContextMenuEntry |
logger* | Request logger | loggerCurrentTab, loggerClearTip |
whitelist* | Trusted sites | whitelistPageName, whitelistPrompt |
support* | Support pane | supportPageName, supportS1H |
Sources: src/_locales/en/messages.json70-285 src/_locales/en/messages.json286-610 src/_locales/en/messages.json650-900
en) serves as the base locale - all messages must exist in EnglishvAPI.i18n() always returns a stringSources: src/_locales/en/messages.json1-13 src/_locales/de/messages.json1-13 src/_locales/pt_BR/messages.json1-13 src/_locales/zh_TW/messages.json1-13
Certain messages are used by the browser itself in the extension manifest:
These messages are referenced in manifest.json using the __MSG_keyName__ syntax:
The browser resolves these references at extension load time, before any script runs.
Some messages have strict length requirements noted in their description fields:
| Message Key | Limit | Reason |
|---|---|---|
extShortDesc | 132 chars | Chrome Web Store requirement (stated in description field) |
Sources: src/_locales/en/messages.json2-9 src/_locales/de/messages.json2-9 src/_locales/es/messages.json2-9
The messages.json file organizes approximately 1000+ messages in a logical sequence:
Sources: src/_locales/en/messages.json1-1000
The English file at src/_locales/en/messages.json is the canonical source. New message keys are added in English first. Community contributors provide translations by updating the locale-specific messages.json files for their languages via pull requests.
Diagram: Translation contribution flow
description field: It states where the string appears and any length constraints.{{placeholderName}} tokens exactly as-is — do not translate the names inside {{}}.\n line breaks, HTML tags (e.g., <code>, <a>), and Unicode characters intact.extShortDesc message must not exceed 132 characters.Sources: src/_locales/en/messages.json1-9 src/_locales/sq/messages.json1-9 src/_locales/ar/messages.json1-9
| Entity | Type | Purpose |
|---|---|---|
_locales/ | Directory | Root directory for all locale files |
_locales/{locale}/messages.json | File | Contains all translated strings for a locale |
data-i18n | HTML Attribute | Declaratively binds HTML elements to message keys |
data-tip | HTML Attribute | Binds tooltip (title attribute) to message key |
vAPI.i18n() | Function | JavaScript API to retrieve localized strings |
chrome.i18n.getMessage() | Browser API | Underlying browser API for message lookup |
browser.i18n.getUILanguage() | Browser API | Detects user's preferred language |
| Message key | String | Identifier for a specific localized string (e.g., popupBlockedStats) |
{{placeholder}} | Syntax | Variable substitution in message strings |
Sources: src/_locales/en/messages.json1-100 src/about.html1-50
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.