feat: german translation

This commit is contained in:
zhom committed 2026-09-26 10:37:23 +04:00
1 parent d6657eac98
commit 9f7d8d3690
5 files changed
+3554 -4

No files matched your search

+2 -2
View File
@@ -34,7 +34,7 @@ donutbrowser/
│ ├── components/ # 50+ React components (dialogs, tables, UI)
│ │ └── tips/ # Feature tips: SVG scene primitives and one looping scene per tip
│ ├── hooks/ # Event-driven React hooks
│ ├── i18n/locales/ # Translations (en, es, fr, ja, ko, pt, ru, tr, vi, zh)
│ ├── i18n/locales/ # Translations (de, en, es, fr, ja, ko, pt, ru, tr, vi, zh)
│ ├── generated/ # Build-generated third-party license inventory
│ ├── lib/ # Utilities (themes, toast, browser-utils)
│ └── types.ts # Shared TypeScript interfaces
@@ -180,7 +180,7 @@ Linux/Windows swap `~/Library/Logs/com.donutbrowser/` for the platform-appropria
- Never write user-facing strings as raw English literals in JSX, toast messages, dialog titles/descriptions, button labels, placeholders, table headers, tooltips, or empty-state text. Always go through `t("namespace.key")` from `useTranslation()`.
- This applies to every component under `src/`, including new ones. If a component doesn't already import `useTranslation`, add it.
- Adding a new string means adding the key to EVERY locale file in `src/i18n/locales/` (currently en, es, fr, ja, ko, pt, ru, tr, vi, zh), not just `en.json`. The English version alone is incomplete work. Don't trust this list: enumerate `src/i18n/locales/*.json` and update every file you find, because a newly added locale is exactly what a hardcoded list silently skips.
- Adding a new string means adding the key to EVERY locale file in `src/i18n/locales/` (currently de, en, es, fr, ja, ko, pt, ru, tr, vi, zh), not just `en.json`. The English version alone is incomplete work. Don't trust this list: enumerate `src/i18n/locales/*.json` and update every file you find, because a newly added locale is exactly what a hardcoded list silently skips.
- Reuse existing keys (`common.buttons.*`, `common.labels.*`, `createProfile.*`, etc.) before creating new namespaces. Check `en.json` first.
- Strings excluded from this rule: `console.log/warn/error`, dev-only debug labels, internal IDs, CSS class names, type names. If unsure whether a string renders to the user, assume it does and translate it.
- Never use `t(key, "fallback")` with a default-value second argument. The 2-arg form is forbidden: every key must exist in every locale file before the call site lands. Fallbacks mask missing translations, so a key missing from `ru.json` silently renders the English fallback to Russian users and the bug never surfaces in CI or review. Only call `t("namespace.key")`. If a translation is missing for any locale, that's a bug to fix at the JSON, not a hole to paper over at the call site.
+1 -1
View File
@@ -83,7 +83,7 @@ codeql database analyze /tmp/codeql-rust --format=sarifv2.1.0 --output=/tmp/rust
## Key Rules
- Translations: Any UI text change must be reflected in all 9 locale files (`src/i18n/locales/`)
- Translations: Any UI text change must be reflected in all 11 locale files (`src/i18n/locales/`)
- Tauri commands: If you modify Tauri commands, the `test_no_unused_tauri_commands` test will catch unused ones
- No hardcoded colors: Use theme CSS variables (see `src/lib/themes.ts`), never Tailwind color classes like `text-red-500`
- No lock file changes: Don't update `pnpm-lock.yaml` or `Cargo.lock` unless updating dependencies is the purpose of the PR
+8
View File
@@ -1,6 +1,7 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import de from "./locales/de.json";
import en from "./locales/en.json";
import es from "./locales/es.json";
import fr from "./locales/fr.json";
@@ -17,6 +18,7 @@ export const SUPPORTED_LANGUAGES = [
{ code: "es", name: "Spanish", nativeName: "Español" },
{ code: "pt", name: "Portuguese", nativeName: "Português" },
{ code: "fr", name: "French", nativeName: "Français" },
{ code: "de", name: "German", nativeName: "Deutsch" },
{ code: "zh", name: "Chinese", nativeName: "中文" },
{ code: "ja", name: "Japanese", nativeName: "日本語" },
{ code: "ko", name: "Korean", nativeName: "한국어" },
@@ -40,6 +42,11 @@ const LANGUAGE_FALLBACKS: Record<string, string[]> = {
"es-ES": ["es", "en"],
"fr-CA": ["fr", "en"],
"fr-FR": ["fr", "en"],
"de-DE": ["de", "en"],
"de-AT": ["de", "en"],
"de-CH": ["de", "en"],
"de-LU": ["de", "en"],
"de-LI": ["de", "en"],
"vi-VN": ["vi", "en"],
};
@@ -66,6 +73,7 @@ const resources = {
es: { translation: es },
pt: { translation: pt },
fr: { translation: fr },
de: { translation: de },
zh: { translation: zh },
ja: { translation: ja },
ko: { translation: ko },
File diff suppressed because it is too large. Load diff
+13 -1
View File
@@ -149,7 +149,19 @@ test("both keys of every pair have a sentence in every locale", () => {
inTheClear,
undecided,
]);
const codes = ["en", "es", "fr", "ja", "ko", "pt", "ru", "tr", "vi", "zh"];
const codes = [
"de",
"en",
"es",
"fr",
"ja",
"ko",
"pt",
"ru",
"tr",
"vi",
"zh",
];
for (const code of codes) {
const bundle = JSON.parse(
readFileSync(path.join(LOCALES, `${code}.json`), "utf8"),