Skip to content

feat(i18n): Add Korean language support - #3321

Closed
littleduck1219 wants to merge 8 commits into
QuantumNous:mainfrom
littleduck1219:feat/korean-i18n
Closed

feat(i18n): Add Korean language support#3321
littleduck1219 wants to merge 8 commits into
QuantumNous:mainfrom
littleduck1219:feat/korean-i18n

Conversation

@littleduck1219

@littleduck1219 littleduck1219 commented Mar 18, 2026

Copy link
Copy Markdown
  • Add README.kr.md (Korean translation)
  • Add web/src/i18n/locales/kr.json (Korean translation file)
  • Add Korean language link to all README files
  • Add Korean language support to i18n settings (keys.go, i18n.js, language.js)
  • Add Korean option to LanguageSelector component
  • Add Korean support to index.jsx

Summary by CodeRabbit

  • Documentation

    • Added a full Korean README with quick start, features, deployment, env vars, and support links.
  • New Features

    • Korean language option added to the app and language selector; Korean translations included.
  • Localization

    • Localized many user-facing texts across auth, registration, 2FA, settings, modals, toasts, time displays, OAuth messages, and UI placeholders; modal button labels now translated.

@coderabbitai

coderabbitai Bot commented Mar 18, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds Korean documentation and Korean locale support: introduces README.kr.md, registers kr translations, adds Korean to the language selector, and replaces numerous hard-coded UI/helper strings with i18n lookups. No business logic, API contracts, or exported signatures were changed.

Changes

Cohort / File(s) Summary
Documentation
README.kr.md
New full Korean README / project landing page (documentation-only, +475/-0).
i18n Core & Language Normalization
web/src/i18n/i18n.js, web/src/i18n/language.js
Registered kr resource, added kr to supportedLanguages, and added normalization to map ko/ko-XXkr.
Language Selector UI
web/src/components/layout/headerbar/LanguageSelector.jsx
Added Korean dropdown entry (한국어) and updated language-sorting comment/spacing.
Auth UI (Login / Register / 2FA)
web/src/components/auth/LoginForm.jsx, web/src/components/auth/RegisterForm.jsx, web/src/components/auth/TwoFAVerification.jsx
Replaced hard-coded user-facing strings with t(...) for various success/error/info messages across login, OAuth, passkey, Telegram, WeChat, and 2FA flows; no control-flow changes.
Settings & Admin UI
web/src/components/settings/OtherSetting.jsx, web/src/components/settings/SystemSetting.jsx, web/src/pages/Setting/Operation/SettingsChannelAffinity.jsx
Localized placeholders, labels, success/error messages, and modal okText/cancelText via t(...); logic unchanged.
Channel Management
web/src/components/table/channels/modals/EditTagModal.jsx, web/src/hooks/channels/useChannelsData.jsx
Localized tag-update success notifications to use t(...).
Helpers: API / Utils
web/src/helpers/api.js, web/src/helpers/utils.jsx
Imported i18n and localized OAuth/custom-OAuth error strings, Axios toast messages, and relative-time strings; inlined/changed OAuth redirect helper calls to direct window.open / window.location usage; minor formatting/signature reformat in utils.
Misc / Manifest
package.json
Minor manifest/reference tweak surfaced in diff.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • seefs001
  • Calcium-Ion
  • creamlike1024

Poem

🐰 Hopping through keys and strings so bright,
I wrap each word in t() tonight.
한국어 now finds its place,
Small hops bring global interface.
🌸 The rabbit nudges every string to light.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(i18n): Add Korean language support' clearly and concisely summarizes the main objective of the pull request—adding Korean language support to the i18n system across multiple components and files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use your project's `golangci-lint` configuration to improve the quality of Go code reviews.

Add a configuration file to your project to customize how CodeRabbit runs golangci-lint.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/helpers/utils.jsx (1)

125-151: ⚠️ Potential issue | 🟠 Major

Guard error.response with optional chaining before accessing status.

Line 127 directly dereferences error.response.status without checking if response exists. For network errors (CORS failures, timeouts, connection refused), AxiosError has no response property, causing a TypeError that breaks error handling and prevents proper error toasts.

Proposed fix
 export function showError(error) {
   console.error(error);
   if (error.message) {
     if (error.name === 'AxiosError') {
-      switch (error.response.status) {
+      const status = error.response?.status;
+      switch (status) {
         case 401:
           // 清除用户状态
           localStorage.removeItem('user');
           // toast.error('错误:未登录或登录已过期,请重新登录!', showErrorOptions);
           window.location.href = '/login?expired=true';
           break;
         case 429:
           Toast.error(i18n.t('错误:请求次数过多,请稍后再试!'));
           break;
         case 500:
           Toast.error(i18n.t('错误:服务器内部错误,请联系管理员!'));
           break;
         case 405:
           Toast.info(i18n.t('本站仅作演示之用,无服务端!'));
           break;
         default:
           Toast.error(i18n.t('错误:') + error.message);
       }
       return;
     }
     Toast.error(i18n.t('错误:') + error.message);
   } else {
     Toast.error(i18n.t('错误:') + error);
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/helpers/utils.jsx` around lines 125 - 151, The switch on
error.response.status can throw when error.response is undefined
(network/CORS/timeouts); update the AxiosError branch in the error handler to
first check for error.response (e.g., if (!error.response) {
Toast.error(i18n.t('错误:') + (error.message || error)); return; }) or use
optional chaining before accessing status, then only run the switch when
response exists; keep existing cases (401/429/500/405/default) and the redirect
to /login intact for the 401 path.
🧹 Nitpick comments (1)
web/src/i18n/i18n.js (1)

26-26: Consider using ISO 639-1 locale code 'ko' instead of 'kr' for Korean.

The standard ISO 639-1 code for Korean is ko, not kr. While kr is the country code for South Korea, using ko would align with language detection libraries like i18next-browser-languagedetector and browser language settings (e.g., ko-KR). However, if the project intentionally uses kr for consistency with other non-standard codes, this is acceptable.

Also applies to: 45-45

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/i18n/i18n.js` at line 26, The import and locale key use 'kr'
(krTranslation and ./locales/kr.json) should be changed to the ISO 639-1
language code 'ko': rename the file ./locales/kr.json to ./locales/ko.json,
update the import to koTranslation, and replace any resource key or registration
that uses 'kr' (e.g., the i18n resources map where 'kr' is referenced) to 'ko'
so language detection and browser locales (like ko-KR) work correctly; ensure
you update all occurrences (including the other mentioned usage around the
resource registration) so nothing still references 'kr'.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.kr.md`:
- Line 51: The anchor link href currently uses "#-도움말 및-지원" which contains a
space and may not match the generated heading ID; update the href to the
hyphenated ID that matches the heading (e.g., "#-도움말-및-지원") or confirm the
actual generated ID for the heading "## 💬 도움말 및 지원" and adjust the link
accordingly so the anchor navigation works.

In `@web/src/components/auth/TwoFAVerification.jsx`:
- Line 58: The component calls t('登录成功') but never imports or invokes the i18n
hook; import useTranslation from react-i18next at the top and call
useTranslation() inside the TwoFAVerification component to get the t function,
then replace the undefined t usage (e.g., in the showSuccess(t('登录成功')) call)
with the t returned from the hook so the translation function is defined.

In `@web/src/components/layout/headerbar/LanguageSelector.jsx`:
- Around line 61-66: supportedLanguages is missing the Korean code and
normalizeLanguage() doesn't map browser outputs ('ko' / 'ko-KR') to the app's
internal code, so Korean browsers fall back incorrectly; fix by either (A)
adding 'kr' to the supportedLanguages array and extending normalizeLanguage() to
map 'ko' and /^ko(-|$)/ to 'kr' (so detectors produce the app's 'kr'), or (B)
switch all Korean identifiers to the ISO code 'ko' (update supportedLanguages,
i18n resources, normalizeLanguage mappings, and any UI bits like
LanguageSelector's onLanguageChange/currentLang usage) so detection and
resources align; choose one approach and apply the change consistently across
supportedLanguages, normalizeLanguage, i18n resources, and the language selector
logic.

---

Outside diff comments:
In `@web/src/helpers/utils.jsx`:
- Around line 125-151: The switch on error.response.status can throw when
error.response is undefined (network/CORS/timeouts); update the AxiosError
branch in the error handler to first check for error.response (e.g., if
(!error.response) { Toast.error(i18n.t('错误:') + (error.message || error));
return; }) or use optional chaining before accessing status, then only run the
switch when response exists; keep existing cases (401/429/500/405/default) and
the redirect to /login intact for the 401 path.

---

Nitpick comments:
In `@web/src/i18n/i18n.js`:
- Line 26: The import and locale key use 'kr' (krTranslation and
./locales/kr.json) should be changed to the ISO 639-1 language code 'ko': rename
the file ./locales/kr.json to ./locales/ko.json, update the import to
koTranslation, and replace any resource key or registration that uses 'kr'
(e.g., the i18n resources map where 'kr' is referenced) to 'ko' so language
detection and browser locales (like ko-KR) work correctly; ensure you update all
occurrences (including the other mentioned usage around the resource
registration) so nothing still references 'kr'.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 81a9b11d-d69e-4a23-b193-2cc3b7fa2d74

📥 Commits

Reviewing files that changed from the base of the PR and between ede0ad1 and 2d1fa39.

📒 Files selected for processing (14)
  • README.kr.md
  • web/src/components/auth/LoginForm.jsx
  • web/src/components/auth/RegisterForm.jsx
  • web/src/components/auth/TwoFAVerification.jsx
  • web/src/components/layout/headerbar/LanguageSelector.jsx
  • web/src/components/settings/OtherSetting.jsx
  • web/src/components/settings/SystemSetting.jsx
  • web/src/components/table/channels/modals/EditTagModal.jsx
  • web/src/helpers/api.js
  • web/src/helpers/utils.jsx
  • web/src/hooks/channels/useChannelsData.jsx
  • web/src/i18n/i18n.js
  • web/src/i18n/locales/kr.json
  • web/src/pages/Setting/Operation/SettingsChannelAffinity.jsx

Comment thread README.ko.md
Comment thread web/src/components/auth/TwoFAVerification.jsx
Comment thread web/src/components/layout/headerbar/LanguageSelector.jsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
web/src/components/auth/LoginForm.jsx (2)

250-255: ⚠️ Potential issue | 🟡 Minor

Remaining hardcoded Chinese text causes partial localization gaps.

Line 253, Line 254, Line 433, and Line 461 still use raw Chinese strings instead of t(...). In kr locale these remain untranslated.

🌐 Suggested patch
           if (username === 'root' && password === '123456') {
             Modal.error({
-              title: '您正在使用默认密码!',
-              content: '请立刻修改默认密码!',
+              title: t('您正在使用默认密码!'),
+              content: t('请立刻修改默认密码!'),
               centered: true,
             });
           }
@@
       if (!success) {
-        showError(message || '无法发起 Passkey 登录');
+        showError(message || t('无法发起 Passkey 登录'));
         return;
       }
@@
       if (finish.success) {
@@
       } else {
-        showError(finish.message || 'Passkey 登录失败,请重试');
+        showError(finish.message || t('Passkey 登录失败,请重试'));
       }

As per coding guidelines: Frontend i18n must use useTranslation() and call t('中文key') in components.

Also applies to: 433-434, 458-462

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/auth/LoginForm.jsx` around lines 250 - 255, LoginForm
currently contains hardcoded Chinese UI strings (e.g., the success message
passed to showSuccess and the Modal.error title/content) which break i18n;
import and call useTranslation() in the LoginForm component and replace raw
strings with t('...') keys (e.g., t('login.success'),
t('login.defaultPasswordTitle'), t('login.defaultPasswordContent')), ensure all
other occurrences referenced in the review (the other modal/messages in the same
component) are similarly replaced, and keep the original showSuccess and
Modal.error calls but pass translated strings returned by t; add or update
locale keys in your locales files accordingly.

187-208: ⚠️ Potential issue | 🔴 Critical

Add all 41 missing translation keys to web/src/i18n/locales/kr.json.

All keys referenced in LoginForm.jsx are missing from the Korean locale file. This affects the entire login form and will cause Korean users to see Chinese text. The missing keys include UI strings ("登 录", "登录成功!"), error messages ("登录失败,请重试", "Passkey 验证失败,请重试"), authentication method labels ("使用 Discord 继续", "使用 微信 继续"), and API endpoints ("/api/user/passkey/login/begin", "/api/user/passkey/login/finish"), among others (41 total).

List of missing keys (all 41)
  • /api/user/passkey/login/begin
  • /api/user/passkey/login/finish
  • Passkey 登录失败,请重试
  • Passkey 验证失败,请重试
  • aff
  • expired
  • 使用 Discord 继续
  • 使用 LinuxDO 继续
  • 使用 OIDC 继续
  • 使用 Passkey 登录
  • 使用 {{name}} 继续
  • 使用 微信 继续
  • 使用 邮箱或用户名 登录
  • 其他登录选项
  • 密码
  • 已取消 Passkey 登录
  • 当前浏览器不支持 Passkey
  • 当前环境无法使用 Passkey 登录
  • 微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)
  • 微信扫码登录
  • 忘记密码?
  • 我已阅读并同意
  • 未登录或登录已过期,请重新登录
  • 没有账户?
  • 注册
  • 用户协议
  • 用户名或邮箱
  • 登 录
  • 登录
  • 登录失败,请重试
  • 登录成功!
  • 继续
  • 请先阅读并同意用户协议和隐私政策
  • 请稍后几秒重试,Turnstile 正在检查用户环境!
  • 请输入您的密码
  • 请输入您的用户名或邮箱地址
  • 请输入用户名和密码!
  • 隐私政策
  • 验证码
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/auth/LoginForm.jsx` around lines 187 - 208, The Korean
locale is missing 41 translation keys used in LoginForm.jsx (strings passed to
t(...) and messages shown via showSuccess/showError like "登录成功!", "登录失败,请重试",
Turnstile message, UI labels such as "登 录", "使用 微信 继续", API key names like
"/api/user/passkey/login/begin", etc.), so add all listed keys into
web/src/i18n/locales/kr.json with appropriate Korean translations; ensure the
keys exactly match the Chinese keys used in LoginForm.jsx (so t('登录成功!'),
t('请稍后几秒重试,Turnstile 正在检查用户环境!'), etc.) and update any
pluralization/placeholders (e.g., "使用 {{name}} 继续") to preserve interpolation
syntax used in the component.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@web/src/components/auth/LoginForm.jsx`:
- Around line 250-255: LoginForm currently contains hardcoded Chinese UI strings
(e.g., the success message passed to showSuccess and the Modal.error
title/content) which break i18n; import and call useTranslation() in the
LoginForm component and replace raw strings with t('...') keys (e.g.,
t('login.success'), t('login.defaultPasswordTitle'),
t('login.defaultPasswordContent')), ensure all other occurrences referenced in
the review (the other modal/messages in the same component) are similarly
replaced, and keep the original showSuccess and Modal.error calls but pass
translated strings returned by t; add or update locale keys in your locales
files accordingly.
- Around line 187-208: The Korean locale is missing 41 translation keys used in
LoginForm.jsx (strings passed to t(...) and messages shown via
showSuccess/showError like "登录成功!", "登录失败,请重试", Turnstile message, UI labels
such as "登 录", "使用 微信 继续", API key names like "/api/user/passkey/login/begin",
etc.), so add all listed keys into web/src/i18n/locales/kr.json with appropriate
Korean translations; ensure the keys exactly match the Chinese keys used in
LoginForm.jsx (so t('登录成功!'), t('请稍后几秒重试,Turnstile 正在检查用户环境!'), etc.) and update
any pluralization/placeholders (e.g., "使用 {{name}} 继续") to preserve
interpolation syntax used in the component.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1a911359-b178-4c5a-b235-6086bbb51c59

📥 Commits

Reviewing files that changed from the base of the PR and between 2d1fa39 and 9df1489.

📒 Files selected for processing (14)
  • README.kr.md
  • web/src/components/auth/LoginForm.jsx
  • web/src/components/auth/RegisterForm.jsx
  • web/src/components/auth/TwoFAVerification.jsx
  • web/src/components/layout/headerbar/LanguageSelector.jsx
  • web/src/components/settings/OtherSetting.jsx
  • web/src/components/settings/SystemSetting.jsx
  • web/src/components/table/channels/modals/EditTagModal.jsx
  • web/src/helpers/api.js
  • web/src/helpers/utils.jsx
  • web/src/hooks/channels/useChannelsData.jsx
  • web/src/i18n/i18n.js
  • web/src/i18n/locales/kr.json
  • web/src/pages/Setting/Operation/SettingsChannelAffinity.jsx
🚧 Files skipped from review as they are similar to previous changes (11)
  • web/src/components/table/channels/modals/EditTagModal.jsx
  • web/src/components/auth/RegisterForm.jsx
  • web/src/components/auth/TwoFAVerification.jsx
  • web/src/components/settings/OtherSetting.jsx
  • web/src/helpers/utils.jsx
  • web/src/pages/Setting/Operation/SettingsChannelAffinity.jsx
  • web/src/helpers/api.js
  • web/src/i18n/i18n.js
  • web/src/hooks/channels/useChannelsData.jsx
  • web/src/components/layout/headerbar/LanguageSelector.jsx
  • README.kr.md

- Add README.kr.md (Korean translation)
- Add web/src/i18n/locales/kr.json (Korean translation file)
- Add Korean language link to all README files
- Add Korean language support to i18n settings (keys.go, i18n.js, language.js)
- Add Korean option to LanguageSelector component
- Add Korean support to index.jsx
- Fix error.response optional chaining in utils.jsx
- Add useTranslation hook import in TwoFAVerification.jsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/components/auth/LoginForm.jsx (1)

430-462: ⚠️ Potential issue | 🟡 Minor

Wrap the Passkey fallback error messages with t() for i18n consistency.

Lines 433 and 461 contain hardcoded Chinese fallback strings that bypass i18n, causing non-English locales to display Chinese text when backend messages are empty. Line 467 already demonstrates the correct pattern.

Suggested patch
-        showError(message || '无法发起 Passkey 登录');
+        showError(message || t('无法发起 Passkey 登录'));
@@
-        showError(finish.message || 'Passkey 登录失败,请重试');
+        showError(finish.message || t('Passkey 登录失败,请重试'));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/auth/LoginForm.jsx` around lines 430 - 462, The two
hardcoded Chinese fallback messages passed to showError in the Passkey login
flow should be wrapped with the i18n translator t(): replace the literal strings
used after prepareCredentialRequestOptions/buildAssertionResult failure and
after the finish.failure branch with t('...') so they use localization; update
the showError calls around the buildAssertionResult check (where it currently
shows 'Passkey 验证失败,请重试') and the finish.error branch (where it shows 'Passkey
登录失败,请重试') to call t(...) instead, leaving
API.post('/api/user/passkey/login/begin') and
API.post('/api/user/passkey/login/finish') logic unchanged.
🧹 Nitpick comments (1)
web/src/helpers/api.js (1)

333-333: Inconsistent navigation behavior compared to OIDC.

onOIDCClicked has an openInNewTab parameter with explicit control (window.open(..., '_blank') vs window.location.href), but onCustomOAuthClicked always uses window.open() without a target, which typically opens a new tab but behavior varies by browser.

Consider adding the same openInNewTab parameter for consistency, or document this as intentional.

♻️ Suggested change for consistency
-export async function onCustomOAuthClicked(provider, options = {}) {
+export async function onCustomOAuthClicked(provider, openInNewTab = false, options = {}) {
   const state = await prepareOAuthState(options);
   if (!state) return;
   
   try {
     // ... existing code ...
     
-    window.open(authUrl.toString());
+    if (openInNewTab) {
+      window.open(authUrl.toString(), '_blank');
+    } else {
+      window.location.href = authUrl.toString();
+    }
   } catch (error) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/helpers/api.js` at line 333, The navigation in onCustomOAuthClicked
is inconsistent with onOIDCClicked because it always calls
window.open(authUrl.toString()) with no target; update onCustomOAuthClicked to
accept the same openInNewTab boolean parameter used by onOIDCClicked and use it
to decide between window.open(authUrl.toString(), '_blank') when openInNewTab is
true and window.location.href = authUrl.toString() when false (mirroring
onOIDCClicked's behavior), ensuring both functions expose the same navigation
control.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@web/src/components/auth/LoginForm.jsx`:
- Around line 430-462: The two hardcoded Chinese fallback messages passed to
showError in the Passkey login flow should be wrapped with the i18n translator
t(): replace the literal strings used after
prepareCredentialRequestOptions/buildAssertionResult failure and after the
finish.failure branch with t('...') so they use localization; update the
showError calls around the buildAssertionResult check (where it currently shows
'Passkey 验证失败,请重试') and the finish.error branch (where it shows 'Passkey
登录失败,请重试') to call t(...) instead, leaving
API.post('/api/user/passkey/login/begin') and
API.post('/api/user/passkey/login/finish') logic unchanged.

---

Nitpick comments:
In `@web/src/helpers/api.js`:
- Line 333: The navigation in onCustomOAuthClicked is inconsistent with
onOIDCClicked because it always calls window.open(authUrl.toString()) with no
target; update onCustomOAuthClicked to accept the same openInNewTab boolean
parameter used by onOIDCClicked and use it to decide between
window.open(authUrl.toString(), '_blank') when openInNewTab is true and
window.location.href = authUrl.toString() when false (mirroring onOIDCClicked's
behavior), ensuring both functions expose the same navigation control.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d46892f0-5c6e-4ce2-8a84-fad72c27c6db

📥 Commits

Reviewing files that changed from the base of the PR and between 9df1489 and 93c4475.

📒 Files selected for processing (14)
  • README.kr.md
  • web/src/components/auth/LoginForm.jsx
  • web/src/components/auth/RegisterForm.jsx
  • web/src/components/auth/TwoFAVerification.jsx
  • web/src/components/layout/headerbar/LanguageSelector.jsx
  • web/src/components/settings/OtherSetting.jsx
  • web/src/components/settings/SystemSetting.jsx
  • web/src/components/table/channels/modals/EditTagModal.jsx
  • web/src/helpers/api.js
  • web/src/helpers/utils.jsx
  • web/src/hooks/channels/useChannelsData.jsx
  • web/src/i18n/i18n.js
  • web/src/i18n/locales/kr.json
  • web/src/pages/Setting/Operation/SettingsChannelAffinity.jsx
✅ Files skipped from review due to trivial changes (5)
  • web/src/components/auth/TwoFAVerification.jsx
  • web/src/i18n/i18n.js
  • web/src/components/auth/RegisterForm.jsx
  • web/src/components/settings/SystemSetting.jsx
  • README.kr.md
🚧 Files skipped from review as they are similar to previous changes (5)
  • web/src/components/table/channels/modals/EditTagModal.jsx
  • web/src/components/settings/OtherSetting.jsx
  • web/src/pages/Setting/Operation/SettingsChannelAffinity.jsx
  • web/src/hooks/channels/useChannelsData.jsx
  • web/src/helpers/utils.jsx

…omponent

- Wrap all hardcoded Chinese strings in t() function for proper i18n
- Add missing Korean translation keys to kr.json
- Update language.js with Korean language support

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
web/src/i18n/language.js (2)

57-57: Minor: Redundant explicit check.

The condition lower === 'ko' is already covered by the regex /^ko(-|$)/ (which matches 'ko' via the end-of-string anchor $). Simplifying to just the regex would be slightly cleaner.

💡 Optional simplification
-  if (lower === 'ko' || /^ko(-|$)/.test(lower)) {
+  if (/^ko(-|$)/.test(lower)) {
     return 'kr';
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/i18n/language.js` at line 57, The if condition checking language uses
a redundant explicit equality check; replace the compound condition "if (lower
=== 'ko' || /^ko(-|$)/.test(lower))" with just the regex-based test to simplify
logic—locate the if statement referencing the variable "lower" in
web/src/i18n/language.js and remove the "lower === 'ko' ||" part so the
condition is solely "/^ko(-|$)/.test(lower)".

27-27: Consider standardizing to 'ko' for consistency with language codes across the project

The codebase intentionally uses 'kr' (ISO 3166-1 country code for South Korea) instead of the standard ISO 639-1 language code 'ko'. While this is internally consistent—evidenced by the dedicated normalizeLanguage() function that maps 'ko' to 'kr' and the corresponding kr.json translation file—it diverges from the convention used by other languages in the array ('en', 'fr', 'ru', 'ja', 'vi').

The implementation works correctly, with browser language detection properly normalized. However, using the standard 'ko' throughout would improve consistency with language naming conventions and reduce potential confusion for developers and integrations with tools expecting ISO 639-1 codes.

If 'kr' is intentional for project-specific reasons, consider adding a comment explaining the choice for future maintainers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/i18n/language.js` at line 27, Replace the nonstandard 'kr' language
code with the ISO 639-1 'ko' across the project: update the languages array
entry (replace 'kr' with 'ko'), rename the translation file kr.json → ko.json,
and adjust normalizeLanguage() so it maps browser 'ko' to the internal key (or
remove any mapping from 'ko'→'kr'); also update any code that references 'kr' to
use 'ko' (or add a short comment in language.js explaining why 'kr' is
intentionally used if you choose to keep it).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/i18n/language.js`:
- Around line 57-60: The LanguageDetector runs before normalizeLanguage is
applied, causing 'ko'/'ko-KR' to not match supportedLngs ('kr'); add a custom
detector object (e.g., normalizedDetector with type: 'custom', async: false,
init: ()=>{}, detect: ()=>normalizeLanguage(LanguageDetector.detect())) and plug
it into i18n via i18n.use(normalizedDetector) before the rest of initialization
so detected values are normalized to 'kr' before i18next checks supportedLngs;
optionally simplify the normalizeLanguage Korean branch by removing the
redundant lower === 'ko' check since /^ko(-|$)/ already covers it.

---

Nitpick comments:
In `@web/src/i18n/language.js`:
- Line 57: The if condition checking language uses a redundant explicit equality
check; replace the compound condition "if (lower === 'ko' ||
/^ko(-|$)/.test(lower))" with just the regex-based test to simplify logic—locate
the if statement referencing the variable "lower" in web/src/i18n/language.js
and remove the "lower === 'ko' ||" part so the condition is solely
"/^ko(-|$)/.test(lower)".
- Line 27: Replace the nonstandard 'kr' language code with the ISO 639-1 'ko'
across the project: update the languages array entry (replace 'kr' with 'ko'),
rename the translation file kr.json → ko.json, and adjust normalizeLanguage() so
it maps browser 'ko' to the internal key (or remove any mapping from 'ko'→'kr');
also update any code that references 'kr' to use 'ko' (or add a short comment in
language.js explaining why 'kr' is intentionally used if you choose to keep it).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f29a8fff-9872-49c0-9995-cbb7f707e868

📥 Commits

Reviewing files that changed from the base of the PR and between 93c4475 and 3e70ca1.

📒 Files selected for processing (3)
  • web/src/components/auth/TwoFAVerification.jsx
  • web/src/i18n/language.js
  • web/src/i18n/locales/kr.json
✅ Files skipped from review due to trivial changes (1)
  • web/src/components/auth/TwoFAVerification.jsx

Comment thread web/src/i18n/language.js Outdated
…dLngs

- Wrap LanguageDetector.detect() to normalize 'ko'/'ko-KR' to 'kr'
- Simplify Korean regex in normalizeLanguage (remove redundant 'ko' check)
- supportedLanguages 배열에서 'kr' → 'ko' 변경
- language.js에서 한국어 변환 로직 정리
- i18n.js에서 import 및 resources 키 변경
- PreferencesSettings.jsx와 LanguageSelector.jsx의 언어 옵션 업데이트
- kr.json을 ko.json으로 파일명 변경
@Calcium-Ion

Copy link
Copy Markdown
Member

Translation Bugs (ko.json)

  1. Typo: wrong Hangul character for "footer" (line 3367)

"页脚内容更新失败": "푰터 내용 업데이트에 실패했습니다"
푰터 should be 푸터 (correct Korean transliteration of "footer").

  1. Duplicated word 있습니다 (line 3383)

"每个备用码只能使用一次": "백업 코드는 한 번만 사용할 수 있습니다 있습니다"
Remove the duplicated 있습니다 at the end.

  1. Missing number "8" (line 3373)

"备用码必须是8位": "백업 코드는 자리여야 합니다"
Should be 백업 코드는 8자리여야 합니다 — the number 8 is missing from the translation.

  1. Locale key "kr" should be "ko" (line 3318)

"kr": "한국어"
Since the latest commits switched everything to the ISO 639-1 code ko, this key should also be "ko": "한국어" for consistency.

File Naming
README.kr.md should be renamed to README.ko.md to match the ISO 639-1 language code convention used by the locale file (ko.json) and the rest of the codebase.
Scope Concern
This PR includes code changes beyond just adding Korean translations (e.g., wrapping strings with t() in LoginForm.jsx, RegisterForm.jsx, TwoFAVerification.jsx, utils.jsx, api.js, etc.). While these i18n improvements are welcome, they affect all languages and should ideally be in a separate PR, or at minimum need careful review since they touch auth flows and error handling logic.

In particular, the changes in web/src/helpers/api.js appear to modify OAuth redirect behavior (window.open vs window.location.href), which is a functional change beyond i18n scope.

Please fix the 4 translation bugs and the filename, and I'll take another look. Thanks for the effort!

@littleduck1219

Copy link
Copy Markdown
Author

I will proceed smoothly in the new pull request.

@littleduck1219
littleduck1219 deleted the feat/korean-i18n branch March 20, 2026 17:24
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.

2 participants