Skip to content

GitStudio in 14 languages: the extensions and the desktop app - #74

Merged
antonarnaudov merged 21 commits into
mainfrom
feat/i18n-products
Oct 1, 2026
Merged

antonarnaudov merged 21 commits into
mainfrom
feat/i18n-products

Conversation

@antonarnaudov

Copy link
Copy Markdown
Contributor

GitStudio, the desktop app and Merge Studio in 14 languages: English plus Simplified and Traditional Chinese, Japanese, Korean, German, French, Spanish, Italian, Portuguese (Brazil), Russian, Turkish, Polish and Czech. Builds on #70 (extension, Simplified Chinese — thanks @AutumnPizazz) and #73.

How it works

  • One catalog per language — l10n/<locale>.json holds every message once (6,022 across the three products); scripts/i18n/bundle-nls.mjs --write extracts each product's English source bundle and cuts the catalog down to each extension's bundle.l10n.<locale>.json. The desktop's cut is made by its build (dist/l10n).
  • Extensions follow VS Code's display language (vscode.l10n), commands and settings via package.nls.<locale>.json. Merge Studio now boots translations like the extension does.
  • Desktop: main picks the language at start — Settings ▸ Appearance ▸ Language or the OS — loads its bundle for main and the shared packages, and the preload hands it to the page before the first script. A change applies after a restart.
  • What git stores stays English: reflog, stash and revert-commit messages are turned back into English (englishOf) whatever the UI language.

Quality gates

  • CI re-extracts every source bundle and fails on drift; npm run i18n checks every catalog for completeness, placeholder parity, and that no translation adds < > & " (translations reach innerHTML).
  • Every desktop change that wrapped a string was checked for byte-identical English (2,127 messages; 352 restructurings reviewed by hand — none changed).
  • Translations are machine drafts done per language with a glossary drawn from git's and VS Code's own translations (l10n/glossary/), translated with the source line beside each message, then a context review of every short message and fragment. A per-catalog language check guards against wrong-language batches. Corrections from native speakers are welcome — Settings says so.
  • scripts/i18n/todo.mjs <locale> makes numbered batches (with source context) of whatever a language is missing, and merges answers back with the same checks.
  • Harness: GS_LANG=de ./gen.sh screenshots the desktop in any language (checked de, ja, zh-cn: Changes, Branches, Settings, a PR page).

Also fixed

  • Counts as whole messages (plural(), "Undo {0} local commits", branch/tag counts) instead of English nouns spliced into translated sentences.
  • … in three desktop messages was mis-extracted, so no translation could match; PR states/actions/tabs/verdicts in the shared engine tables were still English.

Tests

desktop 1977/1977 · extension 1920 · git-service 1403 · webview-ui 543 · engine 469 · merge-studio 62 + 54 · Merge Studio export builds and tests standalone; both VSIXs ship all 14 bundles.

Known follow-ups (native review): Czech uses two verbs for "stage"; some count messages in Polish/Czech/Russian use one plural form; a few fragments joined by code read stiffly in SOV languages.

🤖 Generated with Claude Code

antonarnaudov and others added 21 commits October 1, 2026 17:01
… gate

- Reflog entries, stash messages and the revert commit are built from the
  label the UI showed; englishOf() turns a translated label back into its
  English message, so a Chinese session no longer writes Chinese into the
  repository's history.
- The merge dashboard's NO_OP abort verb is the English sentinel again, so
  abortLabel() gives "Cancel the merge" in every language.
- The rewritten-branch hint is four whole sentences, not words spliced in.
- bundle-nls refuses a translation that adds < > & or " the English does
  not have (translations reach innerHTML and attributes).
- CI re-extracts the source bundle and fails on drift, then gates every
  translation.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- l10n/<locale>.json holds each translation once; bundle-nls --write
  extracts each product's English source bundle and cuts the catalog down
  to each extension's own bundle.l10n.<locale>.json (the desktop's cut is
  made by its build). The extension's zh-cn bundle is byte-identical.
- Merge Studio: l10n boot as the first import, its manifest keyed into
  package.nls.json (brand category kept literal), its support links and
  pick translated.
- Desktop: main picks the language at start (Settings ▸ Appearance ▸
  Language, or the OS), loads its bundle for main and the shared
  packages, and the preload hands it to the page before the first script.
- scripts/i18n/todo.mjs: numbered translation batches and the merge back.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
zh-tw, ja, ko, de, fr, es, it, pt-br, ru, tr, pl, cs translated over
the shared catalog (3227 messages each) and both manifests, each with a
glossary in l10n/glossary/ drawn from git's and VS Code's own
translations; zh-cn gains the desktop's first messages and Merge
Studio's manifest. Machine drafts: corrections welcome.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	.github/workflows/ci.yml
#	scripts/i18n/bundle-nls.mjs
…arry their source line

- plural() gives whole translated messages for the nouns the app counts
  ("{0} commits"), so a count reads right in languages that change the noun
  with the number.
- The support sentence and Home's support lead are functions, read after
  the language loads; the branch rows' push/pull titles are translated.
- todo.mjs batches carry the first source line that asks for each message.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…an read

- "Undo {0} local {1}" and six more places passed an English "commit(s)",
  "file(s)", "branch(es)" or "tag(s)" into a translated sentence, or
  showed it untranslated; each is now a whole message per count.
- Three desktop messages spelled … as \u2026, which @vscode/l10n-dev
  extracts as a different character, so no translation could ever match.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every language now covers the desktop app's 2789 new messages, translated
with the source line beside each one; the earlier short messages and
fragments were re-checked against their code (Polish staging terms, French
reset modes, German formal address, Japanese and Chinese terms, Italian
fragment spacing and more). zh-tw follows zh-cn through OpenCC s2twp with
Taiwan terms (儲存庫, 簽出, 儲藏, 追蹤, 存取, 建置).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…any language

- PR state words, action labels, tabs and review verdicts in the shared
  engine tables were still English; the desktop's review badges showed
  GitHub's raw state.
- harness: GS_LANG=<locale> ./gen.sh builds the page in that language, and
  the shim answers language:get.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
l10n.t takes no undefined argument; each possibly-undefined value goes in
as String(value), which prints what the template literal printed. The
Pull branch of the sync failure message was unreachable (Pull returns
earlier) and is gone.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@antonarnaudov
antonarnaudov merged commit 1071cfb into main Oct 1, 2026
10 checks passed
antonarnaudov added a commit that referenced this pull request Oct 1, 2026
* release: extension 1.18.0, desktop 2.5.0, Merge Studio 1.3.0

Versions, changelog headings (1 Oct 2026) and release notes for 14
languages across all three products (#70, #73, #74).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(rebase): a reword keeps the commit's description (#75)

The interactive rebase workspace read each commit's subject only, so a
reword's message box started from the subject and applying it dropped the
description. It now reads the whole message (%B, NUL-separated records, as
the desktop's rebase view does), seeds the box from it, sizes the box to
show it, and the commit counter is translated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* release: the reword fix in 1.18.0's notes

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat: Edit Message… on a commit, in the extension and the desktop app (#75)

A commit's menu offers Edit Message… where it can work: on the current
branch's line, not a merge or below one. It opens the whole message in an
editor, then rewords the commit with a rebase that replays what came after
— git-service's multiCommit.ts with a third verb, the path Squash already
takes — asks whether branches on rewritten commits come along, and offers
Undo. Uncommitted changes and an operation in progress refuse it first.

Also: publishedWarning was handed English verbs inside translated
sentences, and the too-far refusal spliced in a raw verb; both are whole
translated messages now.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* i18n: Edit Message… in all 14 languages

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* release: Edit Message… in 1.18.0 and 2.5.0's notes

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <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