Skip to content

Latest commit

 

History

History
140 lines (109 loc) · 4.6 KB

i18n.md

File metadata and controls

140 lines (109 loc) · 4.6 KB

UI localization (i18n)

The LeafWiki application UI (buttons, labels, navigation, dialogs, settings, system messages) is translatable. Wiki page content is not affected by this — it is always shown exactly as written.

This document explains the setup and the exact steps to add a new language. Related issue: #789.

How it works

  • The frontend uses i18next via react-i18next.
  • Strings live in per-feature namespace catalogs: ui/leafwiki-ui/src/locales/<lang>/<namespace>.json (for example en/editor.json, en/settings.json). There are 19 namespace files today.
  • ui/leafwiki-ui/src/lib/i18n.ts globs src/locales/*/*.json at build time. A new language folder is picked up automatically — there is no list of languages to register in the frontend, and the language switcher in Settings → Account → Preferences is generated from what it finds.
  • English (en/) is the fallback language. Any key missing in another language falls back to English at runtime.
  • ui/leafwiki-ui/src/lib/i18n.test.ts enforces key parity: every namespace file must exist for every language with an identical set of keys. The test suite fails on any missing or extra key.
  • The name shown for a language in the switcher comes from that language's own common.json → language.selfName (e.g. "Deutsch", "Español").

Components read strings with useTranslation('<namespace>'); code outside React uses i18next.t(key, { ns: '<namespace>' }).

Shipped languages

Code Language Notes
en English default / fallback
de Deutsch
es Español

Add a new language

Example: adding French (fr).

1. Create the locale folder

Copy the full English set as a starting point and translate every value. Keep every key exactly as in English — do not rename, add, or drop keys.

cd ui/leafwiki-ui/src/locales
cp -r en fr

Then translate the values in fr/*.json. In fr/common.json, set the language's own name:

"language": {
  "selfName": "Français"
}

Leaving a value in English is acceptable as an interim state (English is the fallback anyway), but the key must be present in every file or the parity test fails.

2. Extend the backend language allow-list

internal/usersettings/language.go has an allow-list that user-settings validation checks when a user saves their language choice. The frontend discovers the locale by glob, so the language appears in the switcher immediately — but without this step, saving the choice fails validation and the UI snaps back with an error (this is exactly what happened for Spanish in #1526).

var allowedLanguages = map[string]bool{
	DefaultLanguage: true,
	"de":            true,
	"es":            true,
	"fr":            true, // add this
}

Update the expectations in internal/usersettings/language_test.go to include the new code.

3. Wire up date/time formatting

ui/leafwiki-ui/src/lib/dateLocale.ts keeps date-fns (relative times like "3 days ago") and Intl.DateTimeFormat in sync with the UI language. It has two small maps that must gain an entry, otherwise dates stay English for the new language:

import { de, enUS, fr, type Locale } from 'date-fns/locale'

const DATE_FNS_LOCALES: Record<string, Locale> = {
  en: enUS,
  de,
  fr, // add this
}

const BCP47_TAGS: Record<string, string> = {
  en: 'en-US',
  de: 'de-DE',
  fr: 'fr-FR', // add this
}

4. Run the checks

# frontend: key parity + language discovery
cd ui/leafwiki-ui
npm run test
npm run format

# backend: allow-list + user-settings validation
cd ../..
go test ./internal/usersettings/...

5. (Optional) make it the server default

Operators can point new users at the language with --default-language=fr / LEAFWIKI_DEFAULT_LANGUAGE=fr. Once the locale folder ships, this value is picked up automatically; an unknown value is ignored with a console warning.

Update or add strings in an existing language

  1. Never hardcode a user-facing string in React/TS — always go through a key.
  2. Add or change the key in ui/leafwiki-ui/src/locales/en/<namespace>.json first, then make the same change in every other ui/leafwiki-ui/src/locales/<lang>/<namespace>.json.
  3. A brand-new namespace only needs en/<namespace>.json plus a matching file under every other language folder — i18n.ts globs them, there is nothing else to register.
  4. npm run test in ui/leafwiki-ui confirms parity still holds.