Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5cd4019
i18n: what git stores stays English, whole plural sentences, and a CI…
antonarnaudov Oct 1, 2026
04b4803
i18n: one catalog for every product, Merge Studio and desktop wired
antonarnaudov Oct 1, 2026
1e33ad6
i18n: 13 languages for the extension and Merge Studio
antonarnaudov Oct 1, 2026
5b32edf
i18n(desktop): translate the main process
antonarnaudov Oct 1, 2026
099d246
i18n(desktop): translate the renderer modules
antonarnaudov Oct 1, 2026
69e8406
i18n(desktop): translate renderer.ts
antonarnaudov Oct 1, 2026
c3ced62
i18n(desktop): translate the views
antonarnaudov Oct 1, 2026
cb3b7f1
Merge remote-tracking branch 'origin/i18n-wrap-renderer' into feat/i1…
antonarnaudov Oct 1, 2026
0de4bdb
Merge remote-tracking branch 'origin/i18n-wrap-modules' into feat/i18…
antonarnaudov Oct 1, 2026
872c4c9
Merge remote-tracking branch 'origin/i18n-wrap-views' into feat/i18n-…
antonarnaudov Oct 1, 2026
3b7aa85
Merge remote-tracking branch 'origin/i18n-translations' into feat/i18…
antonarnaudov Oct 1, 2026
ac407d3
Merge remote-tracking branch 'origin/main' into feat/i18n-products
antonarnaudov Oct 1, 2026
00d6b11
i18n(desktop): counts, support lines and branch-row titles; batches c…
antonarnaudov Oct 1, 2026
1f9d1e0
i18n: counts as whole messages, and the real ellipsis the extractor c…
antonarnaudov Oct 1, 2026
cc1e4da
i18n: desktop messages in all 14 languages, and a context review
antonarnaudov Oct 1, 2026
0b2396a
Merge remote-tracking branch 'origin/feat/i18n-products' into i18n-tr…
antonarnaudov Oct 1, 2026
03a1379
i18n: the whole-count messages in every language; stale keys dropped
antonarnaudov Oct 1, 2026
f48cfaf
i18n: pull request words, review verdicts, and a harness that speaks …
antonarnaudov Oct 1, 2026
bf1fb61
fix(merge-studio): add the l10n boot its entry point imports
antonarnaudov Oct 1, 2026
cfcd864
docs: 14 languages in all three changelogs
antonarnaudov Oct 1, 2026
481611b
fix(desktop): the renderer type-checks with translated messages
antonarnaudov Oct 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,13 @@ jobs:
- name: Engine purity guard
run: npm run check-purity

# Every message the code asks for is in the English source bundle (a new
# l10n.t() that nobody re-extracted fails here), and every translation
# covers it with the same placeholders and no added markup.
# Every message the code asks for is in its product's English source
# bundle (a new l10n.t() that nobody re-extracted fails here), and every
# translation covers it with the same placeholders and no added markup.
- name: Translations are complete
run: |
node scripts/i18n/bundle-nls.mjs --write
git diff --exit-code -- apps/extension/l10n/bundle.l10n.json
git diff --exit-code -- apps/extension/l10n apps/merge-studio/l10n apps/desktop/l10n
npm run i18n

- name: Package extension (smoke-test the build)
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ downloads/

# c8 coverage reports (CI uploads them to Codecov)
coverage/

# Translation work batches (scripts/i18n/todo.mjs)
l10n/.todo/
8 changes: 8 additions & 0 deletions apps/desktop/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ The VS Code / Cursor extension has its own changelog at
separately — desktop releases are tagged `app-v*`, extension releases `ext-v*` —
but they share the same engine, so most Git behaviour lands in both at once.

## [Unreleased]

### Added
- **GitStudio in 14 languages.** Settings ▸ Appearance ▸ Language picks one,
or follows your OS: Simplified and Traditional Chinese, Japanese, Korean, German, French, Spanish, Italian, Portuguese (Brazil), Russian, Turkish, Polish and Czech, besides English. A change applies after a
restart. Translations other than English are machine drafts — corrections
are welcome on GitHub.

## [2.4.0] - 2026-09-29

### Added
Expand Down
23 changes: 23 additions & 0 deletions apps/desktop/esbuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,29 @@ function copyStaticAssets() {
fs.copyFileSync(abs, path.join(distDir, "renderer", dest));
}
}
writeLanguageBundles();
}

/**
* dist/l10n/bundle.l10n.<locale>.json: each language in the shared catalog
* (l10n/<locale>.json at the repository root) cut down to the messages the
* desktop asks for (l10n/bundle.l10n.json here, made by
* scripts/i18n/bundle-nls.mjs --write). main/language.ts loads one at start.
*/
function writeLanguageBundles() {
const out = path.join(distDir, "l10n");
fs.rmSync(out, { recursive: true, force: true });
fs.mkdirSync(out, { recursive: true });
const source = JSON.parse(fs.readFileSync(path.join(__dirname, "l10n/bundle.l10n.json"), "utf8"));
const catalog = path.join(repoRoot, "l10n");
for (const name of fs.existsSync(catalog) ? fs.readdirSync(catalog) : []) {
const locale = /^(.+)\.json$/.exec(name)?.[1];
if (!locale) continue;
const all = JSON.parse(fs.readFileSync(path.join(catalog, name), "utf8"));
const cut = {};
for (const key of Object.keys(source)) if (key in all) cut[key] = all[key];
fs.writeFileSync(path.join(out, `bundle.l10n.${locale}.json`), JSON.stringify(cut));
}
}

/** A plugin that re-copies the static assets after each (re)build, for watch. */
Expand Down
10 changes: 10 additions & 0 deletions apps/desktop/harness/gen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ cp "$DIST/renderer.js.map" "$PAGE/renderer.js.map" 2>/dev/null || true
cp "$HARNESS/checks.js" "$PAGE/checks.js"
# The owner's requests, as executable clauses — see validate.mjs.
cp "$HARNESS/requirements.js" "$PAGE/requirements.js"
# GS_LANG=de (any locale the build has a bundle for): the page gets that
# language's bundle the way the preload hands it over in the app.
if [ -n "$GS_LANG" ]; then
BUNDLE="$HARNESS/../dist/l10n/bundle.l10n.$GS_LANG.json"
[ -f "$BUNDLE" ] || { echo "gen.sh: no bundle for GS_LANG=$GS_LANG ($BUNDLE)" >&2; exit 1; }
{ printf 'window.__gitstudioLocale="%s";window.__gitstudioL10n=' "$GS_LANG"; cat "$BUNDLE"; printf ';\n'; } > "$PAGE/l10n.js"
else
: > "$PAGE/l10n.js"
fi
# The launch screen is the app's own (dist/renderer/index.html, between its
# launch:* markers), so every scene starts the way the app does — covered by
# it — and every check runs after the real hand-off has removed it. Taken
Expand Down Expand Up @@ -72,6 +81,7 @@ HTML
<script src="./checks.js"></script>
<script src="./requirements.js"></script>
<script src="./perf.js"></script>
<script src="./l10n.js"></script>
<script src="./shim.js"></script>
<script src="./renderer.js"></script>
</body>
Expand Down
42 changes: 42 additions & 0 deletions apps/desktop/harness/page-de/brand-icon-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions apps/desktop/harness/page-de/brand-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading