Skip to content

feat: add Traditional Chinese (zh-TW) language support#95

Open
alvinets wants to merge 16 commits intoTHU-MAIC:mainfrom
alvinets:feature/traditional-chinese-support
Open

feat: add Traditional Chinese (zh-TW) language support#95
alvinets wants to merge 16 commits intoTHU-MAIC:mainfrom
alvinets:feature/traditional-chinese-support

Conversation

@alvinets
Copy link
Copy Markdown

@alvinets alvinets commented Mar 18, 2026

  • Add zh-TW locale to i18n system with full translations for all UI text
  • Add Traditional Chinese option to UI language selector (header dropdown)
  • Add 3-option course generation language selector (简体/繁体/EN)
  • Auto-select Cantonese TTS voice when generating in Traditional Chinese
  • Add zh-HK-HiuGaNeural and zh-HK-HiuManNeural Cantonese voices to Azure TTS
  • Add LANGUAGE_TO_TTS_VOICE mapping and getVoiceForLanguage() helper
  • Sync TTS config to audio player for browser-native-tts support
  • Add export guard with toast warning for empty slides
  • fixed browser-native-tts when no tts voice data, supports cantonese, mandarin and english

Summary

Add full Traditional Chinese (zh-TW) language support across the OpenMAIC platform, including UI translations, course generation language selection, and Cantonese TTS auto-switching.

Changes

i18n & UI

  • Added zh-TW locale with complete translations for common, stage, chat, generation, and settings modules (~900 Traditional Chinese strings)
  • Added 繁體中文 option to header and home page language dropdowns; toggle display changed from CN/EN to 简/繁/EN

Course Generation

  • Extended language type from zh-CN | en-US to zh-CN | zh-TW | en-US
  • Course generation toolbar cycles through 简体 → 繁体 → EN
  • Updated SceneOutline, pblConfig, and generateInteractiveContent language types to include zh-TW

Browser TTS Voice

  • Browser-native-tts voice follows UI locale (top-right language button)
  • LOCALE_TO_BROWSER_VOICE: zh-TW → zh-HK (Cantonese), zh-CN → zh-CN (Mandarin), en-US → en-US
  • setLocale() auto-switches TTS voice when user changes UI locale
  • Engine playBrowserTTSChunk: sets utterance.lang = ttsVoice when no exact voice match found, so browser uses best available voice for that language
  • playWithFallback: prioritizes browser TTS over pre-generated audio
  • play(): skips audioUrl when browser TTS configured (prevents stale server audio)

Azure TTS

  • Added Cantonese voices: zh-HK-HiuGaNeural (曉佳) and zh-HK-HiuManNeural (曉曼)
  • Added LANGUAGE_TO_TTS_VOICE mapping + getVoiceForLanguage() for all 5 TTS providers

Bug Fixes

  • Adapted to upstream server-side TTS API: play(audioId, audioUrl) and audioUrl field in SpeechAction
  • Fixed export guard: toast warning instead of silent failure when no slides
  • Removed unused imports to pass lint

Files Changed

File Change
lib/i18n/types.ts Added zh-TW to Locale union
lib/hooks/use-i18n.tsx LOCALE_TO_BROWSER_VOICE sync on setLocale + hydration
lib/i18n/common.ts commonZhTW translations
lib/i18n/stage.ts stageZhTW translations
lib/i18n/chat.ts chatZhTW translations
lib/i18n/generation.ts generationZhTW translations
lib/i18n/settings.ts settingsZhTW translations
lib/i18n/index.ts Registered zh-TW in translations
lib/audio/constants.ts Cantonese voices + LANGUAGE_TO_TTS_VOICE + LOCALE_TO_BROWSER_VOICE + getVoiceForLanguage + getBrowserVoiceForLocale
lib/types/generation.ts SceneOutline.language and pblConfig.language include zh-TW
lib/generation/scene-generator.ts generateInteractiveContent param type includes zh-TW
lib/types/action.ts Added audioUrl field to SpeechAction
lib/playback/engine.ts playBrowserTTS respects ttsVoice lang; adapted to play(audioId, audioUrl)
lib/utils/audio-player.ts play() skips audioUrl when browser TTS; playWithFallback prioritizes browser TTS; playBrowserTTS respects user preference
lib/export/use-export-pptx.ts Empty slides guard with toast
components/header.tsx 繁體中文 button
components/generation/generation-toolbar.tsx 3-option language toggle
components/stage.tsx BrowserTTSConfig sync
app/page.tsx 繁體中文 dropdown option

Type of Change

  • New feature
  • Bug fix
  • Breaking change
  • Documentation update
  • Refactoring
  • CI/CD or build changes

Verification

  • npx tsc --noEmit passes (0 errors)
  • npx eslint passes (0 errors, 0 warnings)
  • Browser TTS Cantonese voice works when switching to 繁體中文 UI locale

Checklist

  • My code follows the project coding style
  • I have performed a self-review of my code
  • I have added/updated documentation as needed
  • My changes do not introduce new warnings
  • Lint & Typecheck

@alvinets alvinets force-pushed the feature/traditional-chinese-support branch from 949e1ba to 1976887 Compare March 19, 2026 10:03
@alvinets
Copy link
Copy Markdown
Author

Lint & Typecheck done

- Add zh-TW locale to i18n system with full translations for all UI text
- Add Traditional Chinese option to UI language selector (header dropdown)
- Add 3-option course generation language selector (简体/繁体/EN)
- Auto-select Cantonese TTS voice when generating in Traditional Chinese
- Add zh-HK-HiuGaNeural and zh-HK-HiuManNeural Cantonese voices to Azure TTS
- Add LANGUAGE_TO_TTS_VOICE mapping and getVoiceForLanguage() helper
- Sync TTS config to audio player for browser-native-tts support
- Add export guard with toast warning for empty slides
Fix TS2345 errors in scene-generator.ts and outline-generator.ts
where 'zh-TW' was not assignable to SceneOutline.language type
- Add LOCALE_TO_BROWSER_VOICE mapping and getBrowserVoiceForLocale() helper
- use-i18n.tsx: auto-switch TTS voice when user changes UI locale
- use-i18n.tsx: sync TTS voice on initial locale hydration from localStorage
- Remove course-language TTS auto-switch from app/page.tsx (UI locale controls browser TTS instead)
Previously, playBrowserTTS would override the user's explicit voice setting
(e.g. zh-HK for Traditional Chinese locale) with text auto-detection,
causing Cantonese text to be spoken in Mandarin.

Now: user-selected voice always takes priority.
1. Try exact voice name/URI match
2. Try language code match (zh-HK, zh-CN, en-US)
3. If no match but user set preference → set utterance.lang directly
   (browser uses its best voice for that language)
4. Only use text auto-detection when user has NO preference
…thFallback

Pre-generated audio (from IndexedDB) was played first even when browser TTS
was selected, causing stale Mandarin audio to play after switching locale.

Now: if browser-native-tts is configured, always use playBrowserTTS directly
so the user's current voice setting (locale-synced) is respected.
Previously, engine called play(audioId, audioUrl) where audioUrl (server-generated
Mandarin audio) took priority over browser TTS, making locale voice switch ineffective.

Now play() skips audioUrl when browserTTSConfig is set, letting playWithFallback
use browser TTS with the current locale-synced voice (zh-HK for 繁體中文).
…ice found

Previously, if ttsVoice was set to 'zh-HK' but no voice had that exact voiceURI,
the engine fell back to text auto-detection (Mandarin or English only), ignoring
the user's explicit voice preference.

Now: when user sets a non-default voice preference but no matching voice is found,
utterance.lang is set directly to the user's preferred language code (zh-HK),
so the browser uses its best available voice for that language.
@alvinets alvinets force-pushed the feature/traditional-chinese-support branch from 314036f to 7d3a1db Compare March 19, 2026 23:53
@alvinets alvinets force-pushed the feature/traditional-chinese-support branch from c507183 to 7d3a1db Compare April 1, 2026 16:48
alvinets added 3 commits April 2, 2026 03:34
… TTS

- Add zh-TW locale type and translation files (re-export zh-CN as base)
- Register zh-TW in i18n translations registry
- Add LOCALE_TO_BROWSER_VOICE mapping: zh-TW → zh-HK (Cantonese)
- use-i18n.tsx: auto-switch TTS voice when user changes UI locale
- useBrowserTTS hook: respect ttsVoice setting with language code fallback
- action/engine.ts: add browser TTS fallback for lecture speech when no pre-generated audio
- speakWithBrowserTTS: respects user's ttsVoice, sets utterance.lang when no voice match

Browser TTS voice now follows UI locale (top-right language button):
- 繁體中文 → zh-HK (Cantonese)
- 简体中文 → zh-CN (Mandarin)
- EN → en-US
Resolved merge conflicts while preserving TW (Traditional Chinese) support:
- components/stage.tsx: Use local version with BrowserTTSConfig import
- lib/audio/constants.ts: Added TW voice mappings and locale-to-voice functions
- TW translations preserved in lib/i18n/

TW-specific changes preserved:
- LOCALE_TO_BROWSER_VOICE maps 'zh-TW' to 'zh-HK' (Cantonese)
- LANGUAGE_TO_TTS_VOICE maps 'zh-TW' to Cantonese voices for each provider
- getBrowserVoiceForLocale() function for UI locale voice resolution
- TW voice entries in browser-native-tts provider
Resolved merge conflicts while preserving TW (Traditional Chinese) support:
- components/stage.tsx: Use local version with BrowserTTSConfig import
- lib/audio/constants.ts: Added TW voice mappings and locale-to-voice functions
- TW translations preserved in lib/i18n/

TW-specific changes preserved:
- LOCALE_TO_BROWSER_VOICE maps 'zh-TW' to 'zh-HK' (Cantonese)
- LANGUAGE_TO_TTS_VOICE maps 'zh-TW' to Cantonese voices for each provider
- getBrowserVoiceForLocale() function for UI locale voice resolution
- TW voice entries in browser-native-tts provider
@alvinets alvinets closed this Apr 2, 2026
@alvinets alvinets deleted the feature/traditional-chinese-support branch April 2, 2026 16:17
@alvinets alvinets restored the feature/traditional-chinese-support branch April 2, 2026 16:45
alvinets added 3 commits April 3, 2026 00:47
- Add onSoftPause?: () => void to RoundtableProps interface
- Add onSoftPause to Roundtable component destructuring props

Fixes type error in Stage component
@alvinets alvinets reopened this Apr 2, 2026
alvinets and others added 3 commits April 3, 2026 03:29
- TW (zh-TW) language support with 繁體中文 translations
- Cantonese (zh-HK) TTS voice for TW locale
- Browser-native-tts auto-switch on locale change
- TW translations embedded in lib/i18n/ files
- LOCALE_TO_BROWSER_VOICE mapping for UI locale resolution
- Added missing onSoftPause prop to RoundtableProps
- Resolved conflicts in components/stage.tsx and lib/audio/constants.ts
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.

1 participant