Files
learnharness/docs/localization.md
T
sorokin.oleg.edu a50ca4b867
CI / Typecheck, tests, lint (push) Canceled after 0s
CI / Standalone (mac-arm64) (push) Canceled after 0s
CI / Standalone (linux-x64) (push) Canceled after 0s
CI / Standalone (windows-x64) (push) Canceled after 0s
feat: add Russian localization and independent STT languages
2026-10-25 17:18:44 +03:00

3.3 KiB

Language support

LearnHarness supports English and Russian. Settings → General contains independent interface and speech recognition language selectors. The microphone also has a speech language selector. Each offers System default, English, and Русский.

System default uses the preferred browser language (the operating system's preferred language in the desktop app); Russian locales select Russian and other locales select English. Explicit choices persist in settings.json as general.language and general.sttLanguage. Removing a field restores automatic selection. Changing one preference preserves the other general settings.

The interface changes immediately, including accessibility labels and the desktop menu. New AI teaching, questions, plans, practice, graph descriptions, research, figures, and demos use the interface language. Existing conversations and imported source material retain their authored text. A session retains the language of its latest foreground turn so automatic follow-ups can use the same language after a restart; an explicit app language preference takes precedence.

Speech recognition uses Deepgram Nova-3 with an explicit language=en or language=ru. A recording captures the selected language when it starts and keeps that language through reconnections. The selector is disabled while recording; changes elsewhere take effect on the next recording. Audio capture, deferred transcript insertion, stopping, and cancellation retain their existing behavior.

Maintaining translations

The pure localization functions live in src/core/i18n.ts and are exported through the core barrel. English and Russian catalogs are in src/core/locales/en.json and ru.json. English source phrases are message keys. Add every new app-owned message to both catalogs, use named interpolation parameters, and use plural entries with Intl.PluralRules for counts. Russian entries may use one, few, many, and other forms. Keep code, provider/model names, identifiers, and user-authored text out of translation lookups.

React components use useI18n() from components/i18n.tsx. The root provider gets server-resolved initial settings and locale to preserve hydration. General-setting writes share a serialized read-modify-write path; other surfaces use the existing settings-saved signal. Server and agent code receive an explicit language rather than depending on a mutable global translation state.

Some existing protocol errors arrive preformatted in English. Localization can recognize cataloged application templates at the display boundary, preserving the canonical error values used for classification and any third-party diagnostics. Raw technical instructions, code, and user overrides remain editable source data.

The desktop shell has its own small catalog in electron/language.cjs, packaged with the shell. Its narrow lh:language channel accepts only en and ru from a trusted application window. Russian prose uses Noto Sans because Source Sans 3 has no Cyrillic subset. Explicit font choices continue to take precedence.

tests/i18n.test.tsx covers preference validation, automatic selection, independent STT requests, catalog parity and interpolation, Russian plural forms, SSR locale isolation, translated dialogs and exports, agent instructions, and native labels.