Skip to content

feat(desktop): add German (de) locale - #51762

Closed
oliverhees wants to merge 7 commits into
NousResearch:mainfrom
oliverhees:feat/desktop-german-locale
Closed

oliverhees wants to merge 7 commits into
NousResearch:mainfrom
oliverhees:feat/desktop-german-locale

Conversation

@oliverhees

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a complete German (de) locale for the Hermes Desktop UI, taking the desktop app from four to five shipped languages.

The translation reaches full parity with the existing ja / zh / zh-hant locales — every section of en.ts is covered, including the settings fieldLabels / fieldDescriptions (via defineFieldCopy). It uses the existing defineLocale() merge helper, so any future English-only string still falls back cleanly to English.

Translation approach: UI chrome is in German; established product/tech terms stay English where that reads natural to German-speaking developers (Gateway, Skill, Toolset, Agent, Cron, Token, MCP, Provider, YOLO, Pet).

Related Issue

N/A — new locale contribution. Happy to open a tracking issue if preferred.

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)

Changes Made

  • apps/desktop/src/i18n/de.ts — new: full German translation via defineLocale() (incl. settings.fieldLabels / fieldDescriptions via defineFieldCopy)
  • apps/desktop/src/i18n/types.ts — add 'de' to the Locale union
  • apps/desktop/src/i18n/languages.ts — add the Deutsch picker option + aliases (de, de-de, de-at, de-ch, de-li, de-lu)
  • apps/desktop/src/i18n/catalog.ts — register de in TRANSLATIONS
  • apps/desktop/src/i18n/languages.test.ts — cover de normalization / support / config value
  • apps/desktop/DESIGN.md — update the i18n contract + checklist to five locales

How to Test

  1. npm run dev in apps/desktop
  2. Settings → Language → Deutsch (or set any de* locale)
  3. The UI switches to German across navigation, settings, skills, messaging, cron, onboarding and the status bar.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this feature
  • pytest tests/ -q — N/A (desktop / TypeScript-only change). Verified instead with tsc -p . --noEmit (0 errors), eslint src/ electron/ (clean), prettier --check (clean) and vitest run src/i18n (i18n unit tests pass).
  • I've added tests (languages.test.ts covers the new locale)
  • I've tested on my platform: Pop!_OS 24.04 — ran the desktop app and visually verified the German UI across the shell, settings and onboarding.

Documentation & Housekeeping

  • I've updated relevant documentation (apps/desktop/DESIGN.md i18n section)
  • cli-config.yaml.example — N/A (no config keys changed)
  • CONTRIBUTING.md / AGENTS.md — N/A (DESIGN.md covers the locale contract)
  • Cross-platform impact — N/A (pure string catalog)
  • Tool descriptions/schemas — N/A

Screenshots / Logs

Verified locally on Pop!_OS 24.04 — the full UI renders in German. Happy to add in-app screenshots if useful.

@alt-glitch alt-glitch added type/feature New feature or request comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have labels Jun 24, 2026
@oliverhees
oliverhees force-pushed the feat/desktop-german-locale branch from 9fd78df to aaa014b Compare July 8, 2026 19:05
@oliverhees

oliverhees commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor Author

Re: the P3 / low — cosmetic, nice to have label — wanted to add some context that might help with prioritization.

@alt-glitch

Demand signal: The originating issue (#51217) cites ~80M+ German speakers across Germany/Austria/Switzerland, with zero existing German locale option today. For a desktop product aiming at broader reach, "the UI doesn't render in my language" is often the actual adoption blocker for non-English-first users — not cosmetic polish, but the reason someone quietly bounces off an install.

Re: #38846 — I see that PR also proposes German (among 15 locales) via a JSON + sync-script architecture, still open/unmerged since June. This PR is intentionally narrower: one locale, using the existing per-file defineLocale() TS pattern already shipped for ja/zh/zh-hant — no new build tooling or sync step. Happy to close this in favor of #38846 if that's the preferred direction, or keep it as the smaller, faster-to-review increment — whichever's easier to land. Mostly flagging so this doesn't sit at P3-by-default while the real open question is architecture direction, not whether German support matters.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the focused use of the existing defineLocale() path. German is still absent from current main (apps/desktop/src/i18n/types.ts:8, catalog.ts:7-12), so this remains a useful, narrow contribution.

Problems

  • apps/desktop/src/i18n/de.ts:84 supplies remoteSignInHint as a string. Current main requires (signInLabel: string) => string (apps/desktop/src/i18n/types.ts:140) and calls it at apps/desktop/src/components/boot-failure-overlay.tsx:248; the salvaged German locale would fail on remote reauthentication.

Suggested changes

  • Preserve the current contract when resolving the conflict: make the German hint a callback, and add signOutAndSignIn, gatewaySettings, back, and remoteFailureHint copy alongside it.
  • Add a regression assertion for the German remote-reauth path.

Automated hermes-sweeper review.

Comment thread apps/desktop/src/i18n/de.ts Outdated
openLogs: 'Logs öffnen',
repairHint:
'Die Reparatur führt den Installer erneut aus und kann auf einem frischen Rechner einige Minuten dauern.',
remoteSignInHint:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current main changed this contract to (signInLabel: string) => string (types.ts:140) and calls it at boot-failure-overlay.tsx:248. Please preserve that callback shape when this locale is salvaged; a string here would fail during remote reauthentication.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 15, 2026
@oliverhees
oliverhees force-pushed the feat/desktop-german-locale branch from aaa014b to ce55225 Compare July 15, 2026 06:16
@oliverhees

oliverhees commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor Author

@teknium1 Good catch, thanks — you were right, I was checking against a stale local checkout. Rebased onto current main (was 625 commits behind) and fixed:

  • remoteSignInHint is now (signInLabel: string) => string, matching the current type and the call site in boot-failure-overlay.tsx.
  • Added German copy for the 4 new failure-screen strings that landed since: gatewaySettings, back, signOutAndSignIn, remoteFailureHint.

Re-verified: tsc -p . --noEmit && tsc -p tsconfig.electron.json --noEmit (0 errors), eslint src/i18n (clean), vitest run src/i18n (21/21 pass). Pushed.

@Luna161

Luna161 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Just want to add a voice of support for this PR — I went looking for a German locale in Hermes Desktop today and was surprised to find it missing, given that the CLI/backend layer (locales/de.yaml) already ships complete German translations.

I tested this PR branch locally on Debian and it works flawlessly. The translation reads naturally, uses the informal "du" consistently, and the defineLocale() approach means future keys degrade to English gracefully. All i18n tests pass, no type errors.

The number of duplicate PRs this has spawned (#62592, #67077, #71161, #81775, #82411 and counting) is a pretty clear demand signal — ~80M+ German speakers and zero UI locale. Every new duplicate wastes contributor time that could go into other features.

@teknium1's review feedback on the remoteSignInHint callback was addressed, the branch is rebased on current main. This looks merge-ready to me.

Thanks @oliverhees for the thorough implementation!

@Luna161

Luna161 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Quick heads-up: this branch now has merge conflicts with main. I pulled both and checked — the conflicts are all trivial, same root cause:

The i18n conflicts (4 files): main added Arabic (ar) as a locale after this PR was opened. Every conflict is just de vs ar where both need to exist. The fix is mechanical:

File Main has PR has Resolution
types.ts:8 ... | 'ja' | 'ar' ... | 'ja' | 'de' ... | 'ja' | 'ar' | 'de'
catalog.ts import { ar }, ar in record import { de }, de in record both imports + both entries
languages.ts ar locale option + aliases de locale option + aliases both blocks
languages.test.ts ar test assertions de test assertions both

The 4 non-i18n conflicts (gateway/run.py, tools/delegate_tool.py, two provider plugin files, website/docs/integrations/providers.md): these look like they're from the two EU Router commits (448d690, fe9073c) that got mixed into this branch — they're unrelated to the German locale feature. A clean rebase of only the locale commits onto current main should make those disappear.

Happy to help with a PR to your branch if you'd prefer, but it's a straightforward fix. The translations themselves are solid.

@Luna161

Luna161 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

@oliverhees I took the liberty of rebasing your branch onto current main and filling in all the missing translations that landed in en.ts since June. Opened as a PR to your branch: oliverhees#1

If you merge that, your #51762 will be current and merge-ready.

@oliverhees

Copy link
Copy Markdown
Contributor Author

Rebased onto current main and cleaned up. This branch is now conflict-free and scoped to the locale only.

What changed since the last push

  • Dropped two unrelated commits (an EU Router provider) that had been sitting on this branch by mistake. That was the source of the conflicts in gateway/run.py, tools/delegate_tool.py, the provider plugins and website/docs/. The diff is now 7 files, all i18n/desktop.
  • Resolved the ar collision. languages.test.ts keeps every existing Arabic assertion and adds German alongside it — nothing was replaced.
  • Filled in the surfaces that landed in en.ts since June: starmap, webhooks (incl. deliverOptions), zones.
  • Callback-valued strings now match the current type contract: remoteSignInHint, webhooks.enabled/disabled/toggleFailed, starmap.subtitle/importSuccess, webhooks.subscriptions/createFailed/restartFailed/deleteFailed, and the mobile sidebar.toggle.

Two small fixes that aren't strictly the feature

  • context.test.tsx used 'de' as its example of an unsupported language. Adding German silently inverts that assertion, so it now uses 'xx' — it stays meaningful as more locales land.
  • DESIGN.md still described four locales after ar shipped. Updated to six.

Verification against current main

tsc -p . --noEmit          → no errors from src/i18n
eslint src/i18n            → 0 errors (4 warnings, one fewer than baseline)
vitest run src/i18n        → 28/28 pass

On the duplicates

There are several other open German locale PRs (#82411, #81775, #79085, #71161, #67077, #62592). Happy to defer if any of them is preferred — I care more about German shipping than about whose branch it lands from. If this one is the canonical path per the earlier triage, it's ready now.

Thanks @Luna161 for flagging the missing keys and the ar conflict breakdown — credited as co-author. I rewrote the added sections against the current Translations interface, since the version on the fork PR carried unresolved conflict markers in types.ts/languages.ts/languages.test.ts and placeholder values for the callback-typed keys, which wouldn't have type-checked. The set of missing sections you identified was correct and saved me the diff.

@oliverhees

Copy link
Copy Markdown
Contributor Author

@teknium1 — this one is ready whenever someone has a slot for it. Current state:

  • MERGEABLE, no conflicts against main
  • 7 files, all under apps/desktop/src/i18n/ plus the DESIGN.md i18n contract
  • One commit, no unrelated work on the branch
  • tsc -p . --noEmit clean for src/i18n, eslint src/i18n 0 errors, vitest run src/i18n 28/28

It stays deliberately narrow: no new build tooling, no sync step, no renderer changes — just de.ts via the existing defineLocale() path plus registration in the Locale union, alias table and catalog, the same shape ja/zh/zh-hant/ar already use. Nothing outside src/i18n is touched, so the blast radius is a locale that doesn't exist yet.

Why I keep pushing on this one: we're building Hermes plugins for the German-speaking community and the desktop UI locale is the piece they sit on top of. Right now that's the blocker for shipping them. Beyond this PR, we'd like to support Hermes properly in the DACH region — translation upkeep as en.ts grows, German docs, and community-side onboarding. If there's a maintainer preference for how that should run, tell me and I'll work to it.

Also happy to take on more of the load here if it helps: reviewing the other open German locale PRs (#85236, #82411, #81775, #79085, #71161, #67077, #62592) and consolidating them into whichever branch you consider canonical, or acting as a reviewer for area/i18n German going forward so this doesn't land on your queue every time. Say the word and I'll start.

If a different branch is preferred over this one, that's fine too — I care more about German shipping than about whose PR it lands from.

@oliverhees
oliverhees force-pushed the feat/desktop-german-locale branch 2 times, most recently from babd989 to 68bfe6b Compare August 19, 2026 18:05
@oliverhees

Copy link
Copy Markdown
Contributor Author

Rebased onto main at dc77f2c and brought the locale up to every string
that landed since 2026-08-10. Head is now 68bfe6b.

What changed

  • 1080 missing entries translated: 902 plain strings, 178 callback-valued.
    Covers Hermes Cloud sign-in and agent discovery, registered gateways, the
    SSH connection mode, desktop/agent plugins, cron blueprints, the skill hub,
    projects and worktrees in the sidebar, the working-tree status stack, quick
    entry, and the per-tool assistant labels.
  • 6 stale keys dropped that no longer exist in en.ts.
  • titlebar.layoutEditorTitle is now the callback the type expects.
  • Two pre-existing defects fixed along the way. skills.toggleToolset was
    dropping its enabled argument, so the a11y label never named the target
    state, while en, ja, zh, zh-hant, and ar all interpolate it.
    rightSidebar.folderTip appended an invented "click to change folder" hint
    where all five other locales return the bare path.

Coverage against en.ts (2920 leaf keys)

locale missing extra coverage
de 0 0 100.0 %
zh 6 19 99.8 %
ja 581 0 80.1 %
zh-hant 581 0 80.1 %
ar 759 123 74.0 %

Verified against that base: prettier clean · tsc -p . --noEmit 0 errors ·
eslint src/i18n 0 errors (4 pre-existing warnings in context.test.tsx,
unchanged from baseline) · vitest run src/i18n 28/28 pass. All 376 callback
entries were checked against their English counterparts for matching arity and
interpolation variables.


One ask, and it isn't a review slot.

No CI job has ever run on this branch. Every workflow run it has ever
triggered:

$ gh api "repos/NousResearch/hermes-agent/actions/runs?branch=feat/desktop-german-locale" \
    --jq '.workflow_runs[] | "\(.name) | \(.conclusion) | \(.created_at)"'

Nix flake check               | action_required | 2026-08-19T09:44:50Z
CI                            | action_required | 2026-08-19T09:44:50Z
Docker Build, Test, Publish   | action_required | 2026-08-19T09:44:49Z
CI                            | action_required | 2026-08-14T10:44:16Z
Docker Build, Test, Publish   | action_required | 2026-08-14T10:44:15Z
Docker Build, Test, Publish   | action_required | 2026-08-10T20:21:30Z
CI                            | action_required | 2026-08-10T20:21:30Z
CI                            | action_required | 2026-08-10T08:14:09Z
Docker Build, Test, Publish   | action_required | 2026-08-10T08:14:08Z

Nine runs, nine times action_required, zero check runs on any head commit.
ci.yaml gates merges on All required checks pass, and that job cannot
report while the runs sit unapproved. That is why mergeStateStatus reads
BLOCKED regardless of what the diff contains. The other four open German
locale PRs (#85236, #82411, #81775, #79085) sit in exactly the same state.
For contrast, #70870 (the ar locale) had 50 check runs, All required checks pass: success, and merged the day it was opened.

I can't see your Actions settings, so I won't guess at the exact policy. From
the outside it looks like the fork-PR approval gate rather than review
bandwidth. Could someone approve the workflow runs? If CI then finds anything,
I'll fix it the same day.

Separately, an offer: there are eight open German locale PRs. This is the
earliest (2026-06-24). I'm glad to consolidate them: fold in whatever the
others do better, credit their authors as co-authors, and leave you one
decision instead of eight. Say the word and I'll do the legwork.

andrexibiza added a commit to andrexibiza/hermes-agent that referenced this pull request Aug 23, 2026
One-shot current-main workflow that applies the exact two-key locale contract migration to the NousResearch#51762 materializer and removes itself.
@oliverhees
oliverhees force-pushed the feat/desktop-german-locale branch from c470f9e to fcc3631 Compare August 23, 2026 12:19
@alt-glitch alt-glitch removed the sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades label Aug 23, 2026
@goetterbote2342

Copy link
Copy Markdown

Hi! Flagging that there's now a parallel PR adding the same German desktop locale: #81775.

Quick comparison (both add de.ts, locale registration in catalog.ts/languages.ts/types.ts, and the required languages.test.ts updates):

this PR (#51762) #81775
de.ts size ~3,817 lines ~3,229 lines
Kanban plugin i18n (src/plugins/kanban/i18n.ts) not covered covered (~193 lines, all 167 KanbanMessages keys)

Both were verified with strict tsc --noEmit and the vitest suite passing locally. Since they're complementary in one spot — the Kanban bundle — I'd suggest either:

  1. merging whichever locale review prefers as the base, and
  2. taking the Kanban translation from the other PR as an immediate follow-up,

so neither contributor's work is lost. Happy to rebase/extract whatever helps maintainers decide. (Also noting #81775 currently carries a duplicate label pointing here.)

@oliverhees

Copy link
Copy Markdown
Contributor Author

Thanks for flagging it, and for doing the comparison properly instead of just asserting overlap.

I checked your numbers rather than taking them on trust. de.ts is 3,817 lines here and 3,229 in #81775, exactly as you say. The Kanban gap is real too: KANBAN_LOCALES on current main is { en, ja, zh, 'zh-hant': zhHant } with no de, and this PR never touches plugins/kanban/i18n.ts. I read a good chunk of your bundle. That's real German, not machine output.

Something you'll want to know, because it isn't visible from this thread: review has moved to #92909. This PR has sat behind the fork workflow-approval gate since June, which is why it reads as dormant. @andrexibiza rebased the same implementation onto current main so CI could actually run. I verified the de.ts blob hash on both sides, it came across byte for byte, attribution intact. #92909 is the one worth comparing against.

On the line delta, I'd rather not let it stand as a quality claim. #81775 branches off Aug 8 and this one off Aug 23, and en.ts grew in between, so a good part of that difference is base age. I have not diffed the two locale files string by string, so I'm not going to tell you mine covers more of the core than yours.

Your proposal is the right shape and I'll go one step further than splitting it down the middle. The Kanban bundle is yours. It's the one piece that neither this PR nor #92909 covers, and it should land under your name. I'm not going to reimplement it just to close a gap you already filled.

@Euterer

Euterer commented Sep 2, 2026

Copy link
Copy Markdown

Independent verification, from someone who built a German locale separately before finding this PR.

I had translated apps/desktop/src/i18n/ on my own tree, then went looking for prior art and found this plus #92909, #85236, #81775, #67077. Rather than open a sixth competing PR, here is what my parallel work says about the approach here — it converged on the same design without knowing about it.

The defineLocale() per-file pattern is the right call. I ended up at the identical structure independently: one file per locale, missing keys falling back to en. That fallback is what makes the locale safe to ship partial. During an upstream sync my de.ts briefly lost ~120 keys to new en.ts additions (starmap, webhooks, Local Models) and the UI kept working, just with English patches. Under a JSON+sync-script architecture the same gap would have been a build break.

On settings.fieldLabels / fieldDescriptions: using defineFieldCopy rather than importing the constants is not optional. en.ts references FIELD_LABELS/FIELD_DESCRIPTIONS from app/settings/constants.ts, so a locale that re-exports them renders English labels in the settings pane while everything around it is translated. This PR does it correctly; worth calling out because it is easy to miss in review.

Numbers from my parallel implementation, verified on a clean clone of origin/main (d3e2ace), not my working tree:

  • 3,378 translated leaves compared key-by-key against en — 0 missing, 0 type mismatches, 0 functions throwing, 0 return-shape differences
  • tsc --noEmit on tsconfig.json: clean
  • vitest run src/i18n/: 4 files, 28 tests passed
  • vite build produced a bundle with the German strings present, checked in the packed app.asar rather than dist/

Two things I hit that are worth knowing for whoever reviews:

  1. The unsupported-locale test fixtures. languages.test.ts and context.test.tsx use 'de' as their example of an unsupported language, so adding German silently inverts the assertion. This PR already switched to 'xx' — that is the right fix and it stays correct as more locales land.
  2. .toLowerCase() on interpolated tool prefixes produces broken German ("Browser klickt läuft"). ja.ts avoids this by not lowercasing; German needs the same treatment. Not a blocker, just a class of bug that survives review easily.

I have opened two PRs that deliberately do not overlap with this one, covering surfaces none of the five German PRs touch:

Happy to help however is useful — rebasing, filling in keys that landed since, or reviewing. The thing that would help German-speaking users most is one of these five landing, not a sixth.

oliverhees and others added 7 commits September 21, 2026 13:08
Adds German as a desktop UI locale using the existing per-file
defineLocale() pattern already shipped for ja/zh/zh-hant/ar. No new
build tooling, no sync step.

- New apps/desktop/src/i18n/de.ts covering every Translations section,
  including the surfaces that landed since June (starmap, webhooks,
  zones) and the settings field labels.
- Register `de` in the Locale union (types.ts), the picker and alias
  table (languages.ts: de, de-DE, de-AT, de-CH, de-LI, de-LU, german,
  deutsch), and the catalog (catalog.ts).
- languages.test.ts extends the existing `ar` assertions rather than
  replacing them; both locales are covered side by side.
- context.test.tsx used 'de' as its example of an *unsupported*
  language, which this change would silently invert. Switched to 'xx'
  so the assertion stays meaningful as more locales land.
- DESIGN.md's i18n contract now lists all six locales (it still said
  four after `ar` shipped).

UI chrome is translated; established product/tech terms stay English
(Gateway, Skill, Toolset, Agent, Cron, Token, MCP, Provider, Worktree).
Informal "du" throughout. Callback-valued strings keep their signatures
so remote-reauth, webhook toggles and the sidebar toggle format
correctly.

Verified against current main: tsc -p . --noEmit clean for this locale,
eslint src/i18n reports no errors (one fewer warning than baseline),
vitest run src/i18n 28/28 pass.

Co-authored-by: Luna <luna161@users.noreply.github.com>
The Contributor Attribution Check fails on any commit whose author email
is neither a GitHub id+login noreply address nor mapped under
contributors/emails/. This branch's commit is authored from
oliverhees@gmail.com, which is neither, so the job would exit 1.

Adds the mapping file per contributors/README.md: one file per email,
no AUTHOR_MAP edit.
Rebased onto current main and filled in every string that landed in
`en.ts` since the branch was last refreshed on 2026-08-10.

- 1080 missing entries translated (902 plain strings, 178 callback-valued),
  covering the surfaces that shipped since: Hermes Cloud sign-in and agent
  discovery (`settings.gateway.cloud*`), registered gateways
  (`settings.connections.*`), desktop and agent plugins
  (`settings.plugins.*`), the SSH connection mode, cron blueprints, the
  skill hub, projects and worktrees in the sidebar, the working-tree
  status stack, quick entry, and the per-tool assistant labels.
- 6 stale keys dropped. `settings.gateway.{appliesTo,allProfiles,
  defaultConnection,profileConnection}` moved to `settings.profileScope`
  upstream, `onboarding.flowSubtitles.loopback` and
  `keybinds.actions.'view.closePreviewTab'` were removed.
- `titlebar.layoutEditorTitle` became `(modifier: string) => string`
  upstream; the German entry is now a callback and interpolates the
  modifier instead of hardcoding ⌘.
- Fixed two pre-existing defects this pass surfaced: `skills.toggleToolset`
  dropped its `enabled` argument, so the accessibility label said
  "umschalten" without naming the target state (every other locale
  interpolates it); `rightSidebar.folderTip` appended an invented
  "click to change folder" hint, while `en`, `ja`, `zh`, `zh-hant`, and
  `ar` all return the bare path.

`de.ts` now covers 2920 of 2920 leaf keys: no missing entries, and no keys
that no longer exist in `en.ts`.

Verified against current main: prettier clean, `tsc -p . --noEmit` reports
0 errors, `eslint src/i18n` reports 0 errors (4 pre-existing warnings in
context.test.tsx, unchanged from baseline), `vitest run src/i18n` 28/28
pass. Every callback entry was checked against its English counterpart for
matching arity and interpolation variables.

Co-authored-by: Luna <luna161@users.noreply.github.com>
…int/fade, intro splash, voice controls, update dialog)
upstream renamed zones.showHeader/hideHeader to showTabStrip/hideTabStrip
when tab-strip hiding got its own command. de.ts still carried the old
names, which fails the desktop typecheck (TS2353) on current main.

Verified locally against upstream/main bdf1047:
  tsc -p . --noEmit               clean
  tsc -p tsconfig.electron.json   clean
  tsc -p tsconfig.e2e.json        clean
  npm run lint                    0 errors
  vitest src/i18n/                4 files, 28 tests, all pass
defineLocale() merges every locale onto the English base, so a key that was
never translated silently renders in English and nothing reports it. A value
comparison against en.ts found 230 German leaves still holding the English
string, including the whole sendDiagnostics block, the cloud-down boot
failure copy, and a long tail of settings labels.

This translates every one of them that has a German form. What remains
identical to English is only words that are identical in German (Repository,
System, Auto, Updates, Navigation), proper nouns (GitHub Issues, Hermes
Desktop) and format-only helpers (`Version ${value}`).

Additions only, no existing translation touched: 102 insertions, 0 deletions.

Verified locally against upstream/main bdf1047:
  tsc -p . --noEmit               clean
  tsc -p tsconfig.electron.json   clean
  tsc -p tsconfig.e2e.json        clean
  npm run lint                    0 errors
  vitest src/i18n/                4 files, 28 tests pass
  value-comparison coverage       92.7% -> 95.3%
Carry forward the later German locale refresh from NousResearch#106287 while retaining NousResearch#51762 as the canonical PR line. Remove only keys no longer present in the current locale contract.

Co-authored-by: gustl-clawbot <gustl-clawbot@gmx.at>
@oliverhees
oliverhees force-pushed the feat/desktop-german-locale branch from 39b2683 to 9644e4a Compare September 21, 2026 11:21
@oliverhees

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (2026-09-21)

This PR remains the canonical German Desktop locale line: it is the earliest open PR for this feature.

I rebased the original six commits onto current main and resolved the locale-registry evolution (including the later ru locale) without dropping the German registration.

The follow-up sync in 9644e4ada6 carries forward the later German locale refresh from #106287 with explicit Co-authored-by: gustl-clawbot <gustl-clawbot@gmx.at> attribution, then removes only keys that no longer exist in the current locale contract.

Verified locally on this exact head

  • npx tsc -p . --noEmit — passed
  • npx vitest run src/i18n/ — 4 files / 32 tests passed
  • npx eslint src/i18n/ — 0 errors (4 existing test warnings)
  • npx prettier --check src/i18n/de.ts — passed

If maintainers prefer one canonical PR for this duplicate cluster, please use #51762. The branch is current and ready for CI/review.

@OutThisLife

Copy link
Copy Markdown
Contributor

Superseded by #120829, now merged. French, German and Spanish now ship as full Desktop catalogs and appear in Settings → Appearance → Language. The strings that still matched current keys were reused from the contributor PRs, and their authors are credited with Co-authored-by on the per-language commits. Thank you @oliverhees. String corrections are welcome as small PRs against the new catalogs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/i18n Localization, locales, translations comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants