Skip to content

feat(i18n): move all UI strings and prompts to chrome.i18n - #2

Open
RedCreepster wants to merge 1 commit into
ericosmic:mainfrom
RedCreepster:i18n-migrate-to-chrome-i18n
Open

feat(i18n): move all UI strings and prompts to chrome.i18n#2
RedCreepster wants to merge 1 commit into
ericosmic:mainfrom
RedCreepster:i18n-migrate-to-chrome-i18n

Conversation

@RedCreepster

Copy link
Copy Markdown

Problem

The extension had two parallel translation mechanisms that had drifted apart:

  1. chrome.i18n + _locales/ — read only by manifest.json and the two context menu items in background.js. The other ~45 keys in messages.json were never read.
  2. An inline dictionary in i18n.js — 4 languages hard-coded in JS, wired up through data-i18n attributes, loaded only by popup.html and viewer.html.

Everything the extension drew on the page was hard-coded Chinese, because i18n.js is not a content script: the selection tooltip, the sidebar, the full-page translation banner, PDF overlays, popup status messages and all error text.

The two catalogues had also diverged — shortcutHint was one sentence in _locales but split in two in i18n.js, and aboutTitle read "Universal Translator" / "万能翻訳機" / "만능 번역기" instead of "Easy Translator".

What changed

Everything now reads from _locales/ through chrome.i18n.getMessage.

  • i18n.js becomes a thin wrapper over chrome.i18n. The data-i18n / -placeholder / -title attribute API is unchanged; i18nGet(key, ...subs) now supports substitutions and returns the key itself when a message is missing, so a gap stays visible instead of collapsing into an empty label.
  • Localized: content.js, pdf-content.js, popup.js, prompt-manager.js, popup.html, viewer.js, translator.js, background.js.
  • The system prompts are localized too (promptNatural, promptFormal, promptBatch, promptBatchSuffix, promptSrcAuto), so the prompt sent to the model follows the extension's UI language.
  • The catalogue grows from 51 to 143 keys, identical across en, zh_CN, ja, ko.

Content scripts call chrome.i18n directly via a small local helper rather than pulling i18n.js into content_scripts, so no extra script is injected into every page.

Bugs fixed along the way

  • popup.js + prompt-manager.js are classic scripts in the same document. A top-level const t alias in both would have thrown SyntaxError: Identifier 't' has already been declared and broken the popup entirely — they call i18nGet directly instead.
  • viewer.js derived its toggle state from toggleBtn.textContent.includes(origLabel). Localization itself would have broken this; replaced with an explicit panelsVisible flag.
  • viewer.html had no Русский option even though getDefaultTargetLang() returns it for a ru locale, leaving the select empty.

Deliberately unchanged

  • <option value="中文"> values. These are endonyms and double as the language name interpolated into the prompt. Changing them would break stored settings and the prompt.
  • Chinese code comments.

Verification

  • node --check passes on all 8 JS files; all locale files and manifest.json are valid JSON.
  • Script-checked that every key reference (data-i18n*, i18nGet(, t(, __MSG_*__) resolves, and that no key is unused.
  • Simulated chrome.i18n placeholder substitution across all 4 locales: substitutions expand correctly, and the progress-bar regex in updateBanner (/(\d+)\/(\d+)/) still matches the intended done/total pair in every language.

Not loaded in Chrome — needs a manual check of the popup, the selection tooltip, full-page translation and the PDF viewer.

Note

There is no ru locale, so a Russian browser falls back to en via default_locale. Easy to add if wanted.

The extension had two parallel translation mechanisms: an inline
dictionary in i18n.js and _locales/*/messages.json. Only the manifest
and the context menu read _locales, so most of its keys were dead,
the two catalogues had already drifted apart, and everything the
extension drew on the page was hard-coded Chinese.

Everything now reads from _locales via chrome.i18n.getMessage:

- i18n.js becomes a thin wrapper over chrome.i18n and keeps the
  data-i18n attribute API; i18nGet now supports substitutions and
  returns the key when a message is missing, so gaps stay visible
- localize content.js, pdf-content.js, popup.js, prompt-manager.js,
  popup.html, viewer.js, translator.js and background.js
- localize the system prompts, so the prompt sent to the model
  follows the extension's UI language
- grow the catalogue from 51 to 143 keys, identical across en, zh_CN,
  ja and ko

Fixes found along the way:

- popup.js and prompt-manager.js are classic scripts in one document,
  so a top-level `const t` in both would have thrown a redeclaration
  SyntaxError and broken the popup; they call i18nGet directly
- viewer.js derived its toggle state from the button label, which the
  localization itself would have broken; use an explicit flag
- viewer.html was missing the Русский option that getDefaultTargetLang
  can return, leaving the select empty on a ru locale
- align aboutTitle on "Easy Translator" and split shortcutHint, which
  had drifted between the two catalogues

Language option values stay as they are: they are endonyms and double
as the language name sent to the model, so changing them would break
stored settings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant