feat(localization): added zh_TW - #2913
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughSplit Chinese locale support into explicit Simplified (zh-CN) and Traditional (zh-TW) variants across backend and frontend i18n, added Traditional Chinese translations and README, and adjusted README language navigation/blockquote formatting. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Frontend as Frontend (React)
participant Backend as API Server
participant I18n as i18n Service/Files
rect rgba(100,150,240,0.5)
User->>Frontend: select language (zh-CN / zh-TW)
Frontend->>I18n: load resource (zh-CN.json / zh-TW.json)
Frontend->>Backend: request data (Accept-Language: zh-CN / zh-TW)
Backend->>I18n: normalizeLang -> map to zh-CN / zh-TW
Backend->>Frontend: localized response/content
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
web/src/components/settings/personal/cards/PreferencesSettings.jsx (1)
41-41:⚠️ Potential issue | 🟡 MinorStale default language code
'zh'.The fallback
'zh'no longer corresponds to any registered i18n resource. After aligning the keys, update this to'zh-CN':- const [currentLanguage, setCurrentLanguage] = useState(i18n.language || 'zh'); + const [currentLanguage, setCurrentLanguage] = useState(i18n.language || 'zh-CN');i18n/i18n.go (2)
200-215:⚠️ Potential issue | 🔴 CriticalBug:
strings.ToLoweron Line 202 makes thezh_CN/zh_TWprefix checks dead code.After
strings.ToLower, the input becomes"zh_cn"/"zh_tw", which never matches the mixed-case prefixes"zh_CN"/"zh_TW"on Lines 206 and 208. Every Chinese input falls through toDefaultLang(English), completely breaking Chinese localization.Additional gaps:
- Bare
"zh"(no region) is no longer handled — this is a regression for existing users whoseAccept-Languageis just"zh".- Standard BCP 47 tags sent by browsers use hyphens (
zh-CN,zh-TW,zh-Hans,zh-Hant), not underscores. These won't match either.🐛 Proposed fix
func normalizeLang(lang string) string { lang = strings.ToLower(strings.TrimSpace(lang)) + lang = strings.ReplaceAll(lang, "-", "_") // Handle common variations switch { - case strings.HasPrefix(lang, "zh_CN"): + case strings.HasPrefix(lang, "zh_cn"): return LangZhCN - case strings.HasPrefix(lang, "zh_TW"): + case strings.HasPrefix(lang, "zh_tw"), + strings.HasPrefix(lang, "zh_hant"): return LangZhTW + case strings.HasPrefix(lang, "zh"): + return LangZhCN // bare "zh" defaults to Simplified Chinese case strings.HasPrefix(lang, "en"): return LangEn default: return DefaultLang } }
42-55:⚠️ Potential issue | 🔴 CriticalLoad
zh_CN.yamlandzh_TW.yamlinstead of the non-existentzh.yaml— initialization will fail.Line 43 attempts to load
"locales/zh.yaml", which does not exist in the codebase. Onlyzh_CN.yamlandzh_TW.yamlexist. This causesbundle.LoadMessageFileFS()to return an error on line 45, which setsinitErr, causingInit()to fail and breaking all i18n functionality.The localizers created for
zh_CNandzh_TW(lines 53–54) will have no translation data because their corresponding files are never loaded.🔧 Fix — load the correct locale files
// Load embedded translation files - files := []string{"locales/zh.yaml", "locales/en.yaml"} + files := []string{"locales/zh_CN.yaml", "locales/zh_TW.yaml", "locales/en.yaml"}
🤖 Fix all issues with AI agents
In `@web/src/i18n/i18n.js`:
- Around line 36-46: The fallback language key and UI language values are
inconsistent with the resource keys and BCP-47 format; update the i18n
configuration by changing fallbackLng from 'zhCN' to 'zh-CN' (referencing the
fallbackLng setting and resources object in i18n.js) and ensure the Chinese
locale tags use hyphens not underscores in the UI by updating the language
option values in PreferencesSettings.jsx (where i18n.changeLanguage is called or
language option values are defined) from 'zh_CN'/'zh_TW' to 'zh-CN'/'zh-TW' so
they exactly match the resource keys while keeping load: 'currentOnly'.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
controller/model_sync.go (1)
29-37:⚠️ Potential issue | 🔴 CriticalBug:
strings.ToLowermakes"zh-CN"and"zh-TW"cases unreachable.Line 30 lowercases the input, so
lwill be"zh-cn"or"zh-tw", which never matches the mixed-case literals on line 32. Chinese locales will always fall through to the default branch, silently returning("", false).Match against the lowercased forms, and return the canonical (correctly-cased) value for use in upstream URL paths:
🐛 Proposed fix
func normalizeLocale(locale string) (string, bool) { l := strings.ToLower(strings.TrimSpace(locale)) switch l { - case "en", "zh-CN", "zh-TW", "ja": - return l, true + case "en": + return "en", true + case "zh-cn": + return "zh-CN", true + case "zh-tw": + return "zh-TW", true + case "ja": + return "ja", true default: return "", false } }web/src/components/layout/headerbar/LanguageSelector.jsx (1)
32-38:⚠️ Potential issue | 🔴 CriticalBug: Language code
'zh'doesn't match any i18n resource; zh-TW option is missing.With
load: 'currentOnly'ini18n.js,onLanguageChange('zh')will look forresources['zh']which doesn't exist — only'zh-CN'and'zh-TW'do. ThecurrentLang === 'zh'check will also never highlight. Additionally,TWis imported (line 23) but no zh-TW dropdown item is rendered.🐛 Proposed fix — update zh-CN and add zh-TW option
<Dropdown.Item - onClick={() => onLanguageChange('zh')} - className={`!flex !items-center !gap-2 !px-3 !py-1.5 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${currentLang === 'zh' ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600'}`} + onClick={() => onLanguageChange('zh-CN')} + className={`!flex !items-center !gap-2 !px-3 !py-1.5 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${currentLang === 'zh-CN' ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600'}`} > <CN title='简体中文' className='!w-5 !h-auto' /> <span>简体中文</span> </Dropdown.Item> + <Dropdown.Item + onClick={() => onLanguageChange('zh-TW')} + className={`!flex !items-center !gap-2 !px-3 !py-1.5 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${currentLang === 'zh-TW' ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600'}`} + > + <TW title='繁體中文' className='!w-5 !h-auto' /> + <span>繁體中文</span> + </Dropdown.Item>
🤖 Fix all issues with AI agents
In `@web/src/pages/Home/index.jsx`:
- Line 82: The isChinese check currently uses i18n.language.startsWith('zh-CN'),
which excludes Traditional Chinese; update the condition used to compute
isChinese to i18n.language.startsWith('zh') so it covers both zh-CN and zh-TW
(this variable is used to toggle the tracking-wide class near the tracking-wide
usage in the component).
🧹 Nitpick comments (1)
web/src/components/table/models/modals/SyncWizardModal.jsx (1)
118-123: Nit: Both Chinese radio buttons display "ZH" — consider differentiating.The
extratext distinguishes the options, but using "CN" / "TW" (or "ZH-CN" / "ZH-TW") as the primary label would make selection clearer at a glance.Suggested diff
- <Radio value='zh-CN' extra='简体中文'> - ZH - </Radio> - <Radio value='zh-TW' extra='繁體中文'> - ZH + <Radio value='zh-CN' extra='简体中文'> + CN + </Radio> + <Radio value='zh-TW' extra='繁體中文'> + TW </Radio>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
i18n/i18n.go (3)
200-215:⚠️ Potential issue | 🔴 CriticalBug:
strings.ToLoweron line 202 makes Chinese variant matching on lines 206–209 impossible.
langis lowercased to e.g."zh-cn"or"zh-tw", then compared viaHasPrefixagainst"zh-CN"and"zh-TW"(mixed-case). These prefixes will never match, so all Chinese inputs fall through todefault, returningDefaultLang(English). This breaks Chinese language support entirely.Use lowercase prefixes in the comparisons:
Proposed fix
func normalizeLang(lang string) string { lang = strings.ToLower(strings.TrimSpace(lang)) // Handle common variations switch { - case strings.HasPrefix(lang, "zh-CN"): + case strings.HasPrefix(lang, "zh-cn"): return LangZhCN - case strings.HasPrefix(lang, "zh-TW"): + case strings.HasPrefix(lang, "zh-tw"): return LangZhTW case strings.HasPrefix(lang, "en"): return LangEn default: return DefaultLang } }
200-215:⚠️ Potential issue | 🟠 MajorBare
"zh"input now resolves to English instead of Chinese — regression for common Accept-Language values.After fixing the case issue above, inputs like
"zh"or"zh-Hans"won't match either"zh-cn"or"zh-tw"prefixes (sinceHasPrefix("zh", "zh-cn")isfalse). Many browsers and API clients send bare"zh". Previously this mapped toLangZh; now it falls through to English.Add a catch-all for bare
zh:Proposed fix (on top of the case fix)
switch { - case strings.HasPrefix(lang, "zh-cn"): + case strings.HasPrefix(lang, "zh-tw"): + return LangZhTW + case strings.HasPrefix(lang, "zh"): return LangZhCN - case strings.HasPrefix(lang, "zh-tw"): - return LangZhTW case strings.HasPrefix(lang, "en"): return LangEnNote:
zh-twmust be checked before thezhprefix catch-all, otherwise"zh-tw"would match"zh"first.
42-54:⚠️ Potential issue | 🔴 CriticalFix the translation file loading: incorrect filename for Simplified Chinese and missing Traditional Chinese translation.
Line 43 tries to load
locales/zh.yamlwhich does not exist—the actual file islocales/zh-CN.yaml. Additionally,locales/zh-TW.yamlis missing from the files list even though a localizer for it is created on line 54. This will cause the Init() function to fail at runtime or leave the Traditional Chinese localizer without translations.Proposed fix
// Load embedded translation files - files := []string{"locales/zh.yaml", "locales/en.yaml"} + files := []string{"locales/zh-CN.yaml", "locales/zh-TW.yaml", "locales/en.yaml"}
|
没有考虑现有数据的兼容处理,用户如果已选语言偏好zh,你改完会直接变成en |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
i18n/i18n.go (1)
200-215:⚠️ Potential issue | 🟠 MajorMissing handling for
zh-Hant/zh-Hanslanguage tags.Browsers and OS-level language settings commonly send
zh-Hant(Traditional Chinese) andzh-Hans(Simplified Chinese) in addition tozh-TW/zh-CN. After lowercasing,"zh-hant"has prefix"zh"but not"zh-tw", so it falls through toLangZhCN— incorrectly mapping Traditional Chinese users to Simplified Chinese.Proposed fix
func normalizeLang(lang string) string { lang = strings.ToLower(strings.TrimSpace(lang)) // Handle common variations switch { - case strings.HasPrefix(lang, "zh-tw"): + case strings.HasPrefix(lang, "zh-tw"), strings.HasPrefix(lang, "zh-hant"): return LangZhTW - case strings.HasPrefix(lang, "zh"): + case strings.HasPrefix(lang, "zh"): // zh, zh-cn, zh-hans, etc. return LangZhCN case strings.HasPrefix(lang, "en"): return LangEn default: return DefaultLang } }
🤖 Fix all issues with AI agents
In `@i18n/i18n.go`:
- Around line 18-23: The backend currently only defines LangZhCN, LangZhTW and
LangEn (DefaultLang) causing mismatch with the frontend language options and
legacy "zh" values; update the supported locales to match the frontend by either
adding the missing locale YAML files under i18n/locales (fr, ru, ja, vi) so
i18n.go can load them, or remove those options from PreferencesSettings.jsx so
both sides match, and add frontend normalization in PreferencesSettings.jsx when
loading stored preferences (normalize legacy "zh" → "zh-CN" before setting the
Select value) to restore backward compatibility with existing "zh" records; also
consider a one-time DB migration to convert stored "zh" to "zh-CN" for
consistency.
🧹 Nitpick comments (1)
i18n/i18n.go (1)
53-55: Consider adding explicit fallback languages to pre-created localizers for defensive translation coverage.All three locale files (zh-CN.yaml, zh-TW.yaml, en.yaml) currently have identical 203 keys, so missing translations are not an active issue. However, the pre-created localizers only pass a single language to
NewLocalizer(), relying on the bundle's default language (language.Chinese/zhtag). Since nozh.yamlfile is loaded, incomplete translations in any file would return the raw key.For consistency and future-proofing, add explicit fallback languages as done on line 84:
Suggested improvement
- localizers[LangZhCN] = i18n.NewLocalizer(bundle, LangZhCN) - localizers[LangZhTW] = i18n.NewLocalizer(bundle, LangZhTW) + localizers[LangZhCN] = i18n.NewLocalizer(bundle, LangZhCN, LangEn) + localizers[LangZhTW] = i18n.NewLocalizer(bundle, LangZhTW, LangZhCN, LangEn)
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@web/src/components/settings/personal/cards/PreferencesSettings.jsx`:
- Around line 28-36: PreferencesSettings loads a legacy "zh" preference which no
longer matches any option in languageOptions and causes an empty Select;
normalize legacy values before applying them by mapping "zh" → "zh-CN" (and any
other legacy keys) right after reading the saved preference and before calling
i18n.changeLanguage, and/or add the same normalization in the i18n config
language detector so the app-wide resolver maps "zh" to "zh-CN"; update the code
path that reads the saved language (the value passed to i18n.changeLanguage and
the value bound to the Select) to use the normalized value so the dropdown
matches an entry in languageOptions.
|
最近两个提交是出问题了吗?怎么把其他语言给注释了 |
看 @coderabbitai 的留言:
|
|
Tip For best results, initiate chat on the files or code changes.
Yes, commenting out the unsupported languages (fr, ru, ja, vi) in PreferencesSettings.jsx was the correct approach to match the backend's current language support (zh-CN, zh-TW, en). However, the critical issue that Calcium-Ion raised is still outstanding: the migration/normalization of legacy "zh" values. Without this:
To fully address this compatibility concern, you still need to implement: Frontend normalization (quick fix): // In PreferencesSettings.jsx, around line 50
const storedLanguage = userState.user.language || i18n.language || 'zh-CN';
// Normalize legacy 'zh' to 'zh-CN'
const normalizedLanguage = storedLanguage === 'zh' ? 'zh-CN' : storedLanguage;
setCurrentLanguage(normalizedLanguage);Backend migration (proper fix): This will ensure existing users don't experience the language reset issue that Calcium-Ion mentioned (用户如果已选语言偏好zh,你改完会直接变成en). 🧠 Learnings used |
|
这是故意的吗?感觉会有点多余 |
|
一个是语言偏好,设置个人账户语言设定,一个是临时语言切换,不能算是多余 |
了解 |
|
@Calcium-Ion 好了 |
* main: (21 commits) fix: normalize search pagination params to avoid [object Object] fix: ignore header passthrough during channel tests fix(token-search): use TrimPrefix for sk- token normalization fix: rename bulk test action to skip manually disabled channels fix: support numeric status code mapping in ResetStatusCode 优化: 任务日志查询速度并显示用户详情 (QuantumNous#2905) Merge pull request QuantumNous#2916 from worryzyy/feature/add-quota-amount-input feat: Improve backend multilingual support feat: add OpenRouter pricing support to upstream ratio sync feat: refactor request body handling to use BodyStorage for improved efficiency feat(xai): 为xAI渠道添加/v1/responses支持 (QuantumNous#2897) chore: remove deprecated Docker badge from README feat: refactor extra_body handling for improved configuration parsing Update README feat: logs cache field (QuantumNous#2920) feat(localization): added zh_TW (QuantumNous#2913) fix: update README files to improve link formatting and readability feat: add Aion UI link to README files chore(deps): bump axios from 1.12.0 to 1.13.5 in /web simplify language selector display to use text-only labels ... # Conflicts: # web/src/components/layout/headerbar/LanguageSelector.jsx
* feat(localization): added zh_TW * fixed based on @coderabbitai * updated false translation for zh_TW * new workflow * revert * fixed a lot of translations * turned most zh to zh-CN * fallbacklang * bruh * eliminate ALL _ * fix: paths and other miscs thanks @Calcium-Ion * fixed translation and temp fix for preferencessettings.js * fixed translation error * fixed issue about legacy support * reverted stupid coderabbit's suggestion

Added zh_TW in localizations
No breaking changes
Summary by CodeRabbit
New Features
Documentation