fix(i18n): correct Korean mistranslations and particle spacing (#5761)

This commit is contained in:
Goo 2026-06-19 13:26:12 +09:00 committed by GitHub
parent bbacb694cd
commit 4c5c2f4df3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 455 additions and 355 deletions

View File

@ -0,0 +1,50 @@
// Latin workflow/brand terms that get a space inserted around them when CJK machine
// translation glues them to native text (see applyCjkLatinTermSpacing).
export const CJK_LATIN_SPACED_TERMS = [
'Issues',
'Issue',
'Terminal',
'Terminals',
'terminal',
'terminals',
'Agents',
'Agent',
'agents',
'agent',
'Markdown',
'markdown',
'Repos',
'Repo',
'repos',
'repo',
'Commits',
'Commit',
'commits',
'commit',
'Linear',
'GitHub',
'GitLab',
'Jira',
'Claude',
'Claude Code',
'Codex',
'Gemini',
'Kimi',
'OpenCode',
'Orca',
'Cursor',
'Bitbucket',
'Tailscale',
'Kagi',
'SSH',
'WSL',
'PR',
'MR',
'REST',
'HEAD',
'Bash',
'PowerShell',
'Git AI Author',
'Token',
'token'
]

View File

@ -87,6 +87,10 @@ export const KO_VALUE_OVERRIDES = {
Start: '시작',
Work: '작업',
Show: '표시',
Hide: '숨기기',
Import: '가져오기',
import: '가져오기',
'Import…': '가져오기…',
Pass: '통과',
Maintain: '유지',
Approve: '승인',

View File

@ -134,4 +134,53 @@ describe('locale-translation-policy ko round 5', () => {
})
).toBe('로컬 프로젝트, Git repo 또는 repos가 많은 폴더')
})
it('re-glues Korean particles after Latin terms without gluing content words', () => {
// A wrong space before the 에 particle is re-glued onto the Latin term.
expect(
repairTranslatedValue({
key: 'auto.components.StarNagCard.cf82170065',
enValue: 'Could not star the repo. Make sure',
localeValue: 'repo 에 스타를 표시할 수 없습니다. 다음을 확인하세요',
locale: 'ko'
})
).toBe('repo에 스타를 표시할 수 없습니다. 다음을 확인하세요')
expect(
repairTranslatedValue({
key: 'auto.components.github.project.ProjectCell.4b5b871da8',
enValue: 'No labels in this repo.',
localeValue: '이 repo 에는 라벨이 없습니다.',
locale: 'ko'
})
).toBe('이 repo에는 라벨이 없습니다.')
expect(
repairTranslatedValue({
key: 'auto.components.terminal.pane.CloseTerminalDialog.6b9a6975f8',
enValue:
'The terminal still has a running process. If you close the terminal, the process will be killed.',
localeValue:
'terminal 에는 여전히 실행 중인 프로세스가 있습니다. terminal을 닫으면 프로세스가 종료됩니다.',
locale: 'ko'
})
).toBe(
'terminal에는 여전히 실행 중인 프로세스가 있습니다. terminal을 닫으면 프로세스가 종료됩니다.'
)
// A correct space before a content word that merely starts with a particle syllable is kept.
expect(
repairTranslatedValue({
key: 'auto.components.JiraIssueWorkspace.76513c7898',
enValue: 'Close Jira issue preview',
localeValue: 'Jira 이슈 미리보기 닫기',
locale: 'ko'
})
).toBe('Jira 이슈 미리보기 닫기')
expect(
repairTranslatedValue({
key: 'auto.components.GitHubItemDialog.3ab6ac0fc8',
enValue: 'Preview and edit the selected GitHub issue or pull request.',
localeValue: '선택한 GitHub 이슈 또는 PR을 미리보기하고 편집합니다.',
locale: 'ko'
})
).toBe('선택한 GitHub 이슈 또는 PR을 미리보기하고 편집합니다.')
})
})

View File

@ -1,3 +1,4 @@
import { CJK_LATIN_SPACED_TERMS } from './locale-cjk-latin-spaced-terms.mjs'
import { isScreenCursorContext } from './locale-screen-cursor-exemptions.mjs'
import { LOCALE_KEY_OVERRIDES } from './locale-key-overrides.mjs'
import { LOCALE_PHRASE_FIXES } from './locale-phrase-fixes.mjs'
@ -20,6 +21,7 @@ export const NEVER_TRANSLATE_VALUES = new Set([
'Agents',
'Aider',
'Amp',
'Android',
'Antigravity',
'Auggie',
'Autohand Code',
@ -35,6 +37,8 @@ export const NEVER_TRANSLATE_VALUES = new Set([
'Droid',
'Devin',
'Gemini',
'Git',
'Git Bash',
'GitHub Copilot',
'GitLab',
'Goose',
@ -68,6 +72,7 @@ export const NEVER_TRANSLATE_VALUES = new Set([
'Zed',
'agent',
'agents',
'android',
'codex',
'commit',
'commits',
@ -188,6 +193,7 @@ export const BRAND_MISTRANSLATIONS = {
Goose: ['거위'],
Pi: ['파이'],
'GitHub Copilot': ['GitHub 코파일럿', '코파일럿'],
Git: ['힘내'],
Discord: ['디스코드'],
Linear: ['선형'],
Agent: ['에이전트'],
@ -331,55 +337,6 @@ export const NATIVE_PICKER_LABELS = {
es: { chinese: '中文(简体)', korean: '한국어', japanese: '日本語', spanish: 'Español' }
}
const CJK_LATIN_SPACED_TERMS = [
'Issues',
'Issue',
'Terminal',
'Terminals',
'terminal',
'terminals',
'Agents',
'Agent',
'agents',
'agent',
'Markdown',
'markdown',
'Repos',
'Repo',
'repos',
'repo',
'Commits',
'Commit',
'commits',
'commit',
'Linear',
'GitHub',
'GitLab',
'Jira',
'Claude',
'Claude Code',
'Codex',
'Gemini',
'Kimi',
'OpenCode',
'Orca',
'Cursor',
'Bitbucket',
'Tailscale',
'Kagi',
'SSH',
'WSL',
'PR',
'MR',
'REST',
'HEAD',
'Bash',
'PowerShell',
'Git AI Author',
'Token',
'token'
]
const CJK_LATIN_SPACED_TERM_PATTERN = CJK_LATIN_SPACED_TERMS.join('|')
export function isEnglishOnlyKey(key) {
@ -465,9 +422,11 @@ function applyCjkLatinTermSpacing(localeValue, locale) {
'$1 $2'
)
if (locale === 'ko') {
// Korean particles attach to the noun (no space) only when the particle is a complete token at a
// boundary — re-glue "Orca 에"/"PR 을"/"에서는" but keep "Jira 이슈"/"Orca 로고"/"agent 에뮬레이터".
result = result.replace(
new RegExp(
`(${CJK_LATIN_SPACED_TERM_PATTERN}) (가|이|은|는|을|를|와|과|의|로|으로|에서|에게|도|만|부터|까지)`,
`(${CJK_LATIN_SPACED_TERM_PATTERN}) ((?:에서|에게|에는|에선|으로|로서|로써|부터|까지|보다|처럼|은|는|이|가|을|를|와|과|의|에|로|도|만)+)(?=$|[\\s.,!?…·:;)\\]}"'」』])`,
'g'
),
'$1$2'

View File

@ -3668,7 +3668,6 @@
"1a0eec0d35": "Status",
"b5536d5a88": "Tasks",
"8d62c68b35": "Notes",
"automation": "Automation",
"2d74665a56": "Ports",
"65a9820bd1": "Agent statuses",
"219ebf1961": "Branch name"
@ -11391,7 +11390,15 @@
"openReviewExternally": "Open {{value0}} externally",
"summary": "{{value0}} attached · {{value1}} with PR/MR · {{value2}} attention · {{value3}} pending · {{value4}} passing · {{value5}} no PR · {{value6}} unknown",
"showDetails": "Show {{value0}} PR check details",
"hideDetails": "Hide {{value0}} PR check details"
"hideDetails": "Hide {{value0}} PR check details",
"reviewChecks": "Review checks",
"allChecksPassing": "all checks passing",
"oneWorktree": "1 worktree",
"worktreeCount": "{{value0}} worktrees",
"oneFailing": "1 failing",
"failingCount": "{{value0}} failing",
"onePending": "1 pending",
"pendingCount": "{{value0}} pending"
},
"parentPrChecks": {
"rowSummary": {

View File

@ -3656,8 +3656,7 @@
"automation": "Automation",
"2d74665a56": "Puertos",
"65a9820bd1": "Estados del agente",
"219ebf1961": "Nombre de rama",
"automation": "Automation"
"219ebf1961": "Nombre de rama"
},
"SshDisconnectedDialog": {
"ca4a7892af": "Conectando...",
@ -11391,7 +11390,15 @@
"openReviewExternally": "Abrir {{value0}} externamente",
"summary": "{{value0}} adjuntos · {{value1}} con PR/MR · {{value2}} requieren atención · {{value3}} pendientes · {{value4}} correctos · {{value5}} sin PR · {{value6}} desconocidos",
"showDetails": "Mostrar detalles de comprobaciones de PR de {{value0}}",
"hideDetails": "Ocultar detalles de comprobaciones de PR de {{value0}}"
"hideDetails": "Ocultar detalles de comprobaciones de PR de {{value0}}",
"reviewChecks": "Review checks",
"allChecksPassing": "all checks passing",
"oneWorktree": "1 worktree",
"worktreeCount": "{{value0}} worktrees",
"oneFailing": "1 failing",
"failingCount": "{{value0}} failing",
"onePending": "1 pending",
"pendingCount": "{{value0}} pending"
},
"parentPrChecks": {
"rowSummary": {

View File

@ -11390,7 +11390,15 @@
"openReviewExternally": "{{value0}} を外部で開く",
"summary": "{{value0}} 件添付 · PR/MR あり {{value1}} 件 · 要対応 {{value2}} 件 · 保留中 {{value3}} 件 · 成功 {{value4}} 件 · PR なし {{value5}} 件 · 不明 {{value6}} 件",
"showDetails": "{{value0}} の PR チェック詳細を表示",
"hideDetails": "{{value0}} の PR チェック詳細を非表示"
"hideDetails": "{{value0}} の PR チェック詳細を非表示",
"reviewChecks": "Review checks",
"allChecksPassing": "all checks passing",
"oneWorktree": "1 worktree",
"worktreeCount": "{{value0}} worktrees",
"oneFailing": "1 failing",
"failingCount": "{{value0}} failing",
"onePending": "1 pending",
"pendingCount": "{{value0}} pending"
},
"parentPrChecks": {
"rowSummary": {

File diff suppressed because it is too large Load Diff

View File

@ -11390,7 +11390,15 @@
"openReviewExternally": "在外部打开 {{value0}}",
"summary": "已附加 {{value0}} 个 · 有 PR/MR {{value1}} 个 · 需注意 {{value2}} 个 · 等待中 {{value3}} 个 · 通过 {{value4}} 个 · 无 PR {{value5}} 个 · 未知 {{value6}} 个",
"showDetails": "显示 {{value0}} 的 PR 检查详情",
"hideDetails": "隐藏 {{value0}} 的 PR 检查详情"
"hideDetails": "隐藏 {{value0}} 的 PR 检查详情",
"reviewChecks": "Review checks",
"allChecksPassing": "all checks passing",
"oneWorktree": "1 worktree",
"worktreeCount": "{{value0}} worktrees",
"oneFailing": "1 failing",
"failingCount": "{{value0}} failing",
"onePending": "1 pending",
"pendingCount": "{{value0}} pending"
},
"parentPrChecks": {
"rowSummary": {