Skip to content

Add German translation and browser language detection - #55

Merged
suitux merged 4 commits into
suitux:mainfrom
Hellraiser28:german-translation
Oct 13, 2026
Merged

suitux merged 4 commits into
suitux:mainfrom
Hellraiser28:german-translation

Conversation

@Hellraiser28

Copy link
Copy Markdown
Contributor

What

Adds a German translation (messages/de.json) and lets Tagr choose the UI language from the browser's Accept-Language header instead of the hard-coded en.

How

  • src/i18n/locale.ts (new) — the list of supported locales (en, de), the default (en) and negotiateLocale(), which walks the Accept-Language entries by quality value, matches regional tags to their base language (de-AT → de) and falls back to English for anything unsupported or malformed.
  • src/i18n/request.ts — uses negotiateLocale((await headers()).get('accept-language')) instead of const locale = 'en'.
  • src/app/layout.tsx — <html lang> now reflects the active locale (getLocale()), so the layout is async. No other change in that file.
  • messages/de.json (new) — all 420 keys of en.json, same structure, same placeholders and plural branches, ICU syntax unchanged.
  • src/i18n/locale.test.ts (new) — tests for the negotiation, plus a check that every non-English message file has exactly the keys and placeholders of en.json, so a future key added only to en.json shows up in CI.
  • README.md — one bullet under Additional describing the language selection and how to add a language.

Browsers asking for any other language keep getting English, so nothing changes for existing users.

Testing

  • vitest run: all test files pass, including the 6 new tests.
  • eslint and prettier --check pass on the new and changed files. (src/app/layout.tsx was already not Prettier-formatted on main; I only changed the lines above and left the rest untouched to keep the diff small.)
  • tsc --noEmit reports the same two errors in detail-panel-preview-card.tsx on main and on this branch — none are introduced here.
  • Built the Docker image from this branch and ran it: with a German browser the login page, folder tree, song list and detail panel are German; with Accept-Language: en or fr everything stays English.

Not included

Dates in the song list are still formatted with a fixed 'en-US' in src/components/panels/main-content/utils.ts. That could follow the active locale too, but I kept this PR to the translation itself.

The translation was prepared with the help of an AI assistant (Claude) and reviewed by me as a native German speaker.

@suitux

suitux commented Oct 13, 2026

Copy link
Copy Markdown
Owner

Thanks for the German translation 🙌

Right now the language comes only from the browser's Accept-Language, so users can't change it by hand. Could you add a language setting to the Settings dialog?

  • Add a locale key to ConfigKey and a language section in SETTINGS_SECTIONS (minimumRole: 'listener'). It should be a Select with Automatic / English / Deutsch, built from locales, read with useConfig and saved with useUpdateConfig.
  • In src/i18n/request.ts, use the user's saved locale when it's set, otherwise fall back to negotiateLocale.
  • Call router.refresh() after saving, and add the new strings to en.json / de.json.

Thanks!

German for the Insights settings and notice, the song panel field settings and the hidden custom tags hint.
A Language section (listener and up) offers Automatic, English and Deutsch, built from the locales in
src/i18n/locale.ts. The choice is stored under the 'locale' config key; request.ts uses it when it names
a supported locale and otherwise negotiates from Accept-Language as before. Saving refreshes the router so
the server renders the new language.
@Hellraiser28

Copy link
Copy Markdown
Contributor Author

Done, thanks for the detailed pointers!

  • Setting: a locale config key and a Language section in SETTINGS_SECTIONS (minimumRole: 'listener') with a Select for Automatic / English / Deutsch.
    • The options are built from locales, with the display names in a new localeNames map next to them.
    • The choice is read with useConfig, saved with useUpdateConfig and followed by router.refresh().
    • "Automatic" is stored as auto.
  • src/i18n/request.ts: uses the saved locale when it names a supported one, otherwise negotiateLocale as before.
    • The rule lives in resolveLocale() in locale.ts and has its own tests.
    • Pages without a session, like the login page, still follow the browser.
  • New strings: I merged current main into the branch (no conflicts) and added German for the 34 strings that came in since: Insights, the song panel fields and the hidden custom tags hint. The new setting's strings are in en.json / de.json as well.

Checked:

  • vitest run: 296 tests pass.
  • eslint and prettier --check: clean on the new and changed files.
    • The two tsc errors in detail-panel-preview-card.tsx are the same on main.
    • So are the prettier warnings on layout.tsx, domain.ts and settings-modal.tsx.
  • In a Docker build:
    • Switching to Deutsch with an English browser changes the UI right away and survives a reload.
    • Back on Automatic it follows the browser again.
    • A saved English wins over a German browser.

@suitux
suitux merged commit 85b595a into suitux:main Oct 13, 2026
@suitux

suitux commented Oct 13, 2026

Copy link
Copy Markdown
Owner

There you go

https://github.com/suitux/Tagr/releases/tag/v1.14.0

😄

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.

2 participants