Open
Conversation
Replace hand-rolled i18n with i18next + react-i18next so that adding a new language only requires dropping a JSON file in lib/i18n/locales/. - Add i18next, react-i18next, i18next-browser-languagedetector deps - Generate zh-CN.json / en-US.json from existing TS translation modules - Rewrite lib/i18n/index.ts as a thin wrapper around i18n.t() - Rewrite use-i18n hook to delegate to useTranslation(); external API (locale, setLocale, t) is unchanged so consumers need no changes - SSR-safe: LanguageDetector only loaded on client side Closes #327 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace string concatenation (greeting + displayName) with two
i18next keys: greetingWithName (with {{name}} interpolation) and
greetingDefault (standalone, no name).
This lets each locale choose natural phrasing independently:
- zh-CN: "嗨,同学" / "嗨,Alice"
- en-US: "Hi there" / "Hi, Alice"
- Future locales can avoid gender issues by choosing genderless defaults
Also widen the t() type signature to accept interpolation options.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded zh-CN/en-US imports with i18next-resources-to-backend
and dynamic import(`./locales/${language}.json`). Bundler scans the
locales/ directory at build time, so adding a new language now requires
only dropping a JSON file — zero changes to existing code.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
LanguageDetector ran during i18next init(), detecting browser language before React hydrated — server rendered zh-CN while client switched to en-US immediately, causing a hydration mismatch. Fix: remove i18next-browser-languagedetector; init with a fixed lng (zh-CN) so server and client agree on the first render. Language detection is now done in I18nProvider's useEffect after hydration. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace manual locale validation and startsWith('zh') prefix matching
with i18next's built-in fallback mechanism. Now changeLanguage() is
called with navigator.language directly — if the exact locale has no
JSON file, i18next automatically falls back to fallbackLng.
Also widen Locale type from union to string so adding new languages
doesn't require modifying types.ts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add lib/i18n/course-languages.ts with curated language list
(zh-CN, zh-TW, en-US, ja, ko, fr, de, es, pt, ru, ar) including
native labels and English prompt names
- Course language defaults to UI locale on first visit; once user
explicitly picks a language, that choice persists across sessions
- Replace toggle button with dropdown selector showing native labels
- Widen language types from 'zh-CN'|'en-US' to string throughout
- Fix hardcoded language ternaries in LLM prompt injection:
- prompt-builder.ts: use getCourseLanguagePromptName()
- classroom-generation.ts: remove normalizeLanguage() that forced
all non-English to zh-CN
- PBL system prompt, agent templates, generate-pbl: append language
instruction for non-zh/en languages
- quiz-grade API: add language suffix for grading feedback
Closes #327
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
quiz-view was passing the UI locale to the grading API, causing AI feedback to follow the student's answer language instead of the course language. Now reads stage.language from the store. Also strengthen the grading prompt: explicitly instruct the LLM to write comments in the course language regardless of the student's input language. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These files are replaced by lib/i18n/locales/*.json and are no longer imported anywhere in the codebase. Removed: chat.ts, common.ts, generation.ts, settings.ts, stage.ts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Migrate the hand-rolled i18n system to i18next + react-i18next. Adding a new language now only requires dropping a JSON file in
lib/i18n/locales/— zero changes to existing code.Related Issues
Closes #327
Changes
i18next,react-i18next,i18next-resources-to-backenddependencieszh-CN.json,en-US.json)lib/i18n/index.tsas a thin wrapper aroundi18n.t()use-i18nhook to delegate touseTranslation(); external API (locale,setLocale,t) unchanged — all 59+ consumer files need no changesimport()— bundler scanslocales/at build timeuseEffectafter hydration (fixes SSR mismatch)greetingWithName/greetingDefault) to support natural phrasing across languagesLocaletype from'zh-CN' | 'en-US'tostringfor extensibilityType of Change
Verification
Steps to reproduce / test
pnpm dev)What you personally verified
Evidence
pnpm format && pnpm lint --fix && npx tsc --noEmit)Checklist