Skip to content

feat(i18n): add Spanish (es-MX) locale support#280

Open
ellaguno wants to merge 4 commits intoTHU-MAIC:mainfrom
ellaguno:feat/i18n-spanish
Open

feat(i18n): add Spanish (es-MX) locale support#280
ellaguno wants to merge 4 commits intoTHU-MAIC:mainfrom
ellaguno:feat/i18n-spanish

Conversation

@ellaguno
Copy link

Summary

  • Add complete Spanish (es-MX) translations for all UI modules (~1,000 new translation strings)
  • Add Spanish to language selector, browser auto-detection, and content generation pipeline
  • Zero new dependencies; follows existing i18n architecture exactly

Closes #279

Changes

  • 5 i18n translation files: Added *EsMX exports with full Spanish translations (common, stage, chat, generation, settings)
  • Core i18n system: Updated Locale type, VALID_LOCALES, browser detection, and getClientTranslation
  • UI: Added "Español" option to header language selector, 3-language cycle in generation toolbar
  • Generation pipeline: Updated all 'zh-CN' | 'en-US' unions to include 'es-MX', updated normalizeLanguage()

Test plan

  • Select "Español" from language picker → entire UI should display in Spanish
  • Set browser language to es-* → app should auto-detect and default to Spanish
  • Generate a course with language set to "ES" → content should be generated in Spanish
  • Verify TTS works with Spanish content (OpenAI, Azure, Qwen providers)
  • Run npx tsc --noEmit — passes with 0 errors
  • Run pnpm lint — 0 new errors (only pre-existing warnings)

🤖 AI-assisted with Claude Code — reviewed by @ellaguno

ellaguno and others added 4 commits March 25, 2026 10:35
Add complete Spanish (Mexican) translations for the entire UI:
- All 5 i18n translation files (common, stage, chat, generation, settings)
- Language selector in header with ES option
- Browser language auto-detection for Spanish
- Generation toolbar supports es-MX for course content language
- Updated all type definitions to accept 'es-MX' locale
- Updated normalizeLanguage and all language validation checks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Browser extensions (translators, Grammarly, etc.) can modify bare text
nodes in the DOM. When React tries to swap button content between a
text label and a spinner, it fails with "removeChild: node is not a
child" because the extension replaced the original text node.

Wrapping `{t(...)}` calls inside `<span>` elements gives React a
stable element reference that survives external DOM mutations.

Fixed in: provider-config-panel, pdf-settings, model-edit-dialog,
video-settings, image-settings, tts-settings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The language selector showed 'CN' momentarily on page load because
the SSR default locale is zh-CN and localStorage is only read in
useEffect after mount. Now shows '...' until client hydration
completes, then displays the correct locale label (CN/EN/ES).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…is resolved

The server always renders with defaultLocale (zh-CN) but the client
may detect a different locale from localStorage or browser language.
This caused React hydration mismatches on every translated string.

Fix: render children with visibility:hidden until the useEffect
hydrates the correct locale from localStorage/browser, then reveal.
This prevents the SSR zh-CN text from conflicting with client-side
es-MX/en-US text, and also prevents browser translator extensions
from intercepting the wrong-language text during the flash.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

feat(i18n): Add Spanish (es-MX) locale support

1 participant