Fix unnatural Japanese (ja) localization wording (#5589)

* Fix unnatural Japanese localization wording

- "Open in" submenu: bare で開く → アプリで開く
- "Assigned to me" filter: 私に割り当てられました → 私に割り当てられた Issue
- Use Latin "Issue" instead of katakana イシュー throughout (JP engineering convention)
- Terminal/theme cursor settings: render the screen cursor as カーソル, not the
  Cursor product. The brand-protection revert (Cursor→カーソル→Cursor) now exempts
  these keys/values so カーソル survives while the Cursor product stays Latin.
- GraphQL: グラフQL → GraphQL
- Assignee picker aria-label: {{value0}} に割り当てられました → {{value0}} に割り当て済み

Fixes are made in the locale repair policy (overrides / phrase fixes) and applied via
repair:ja-catalog so they persist across future catalog regeneration.

* Extract screen-cursor exemption into a focused module

Move the Cursor screen-vs-product discrimination (SCREEN_CURSOR_ENVALUES /
SCREEN_CURSOR_KEYS / isScreenCursorContext) out of locale-translation-policy.mjs
into locale-screen-cursor-exemptions.mjs to keep the policy file under the
max-lines limit. No behavior change.

* Fix PR/issue state badge wording in Japanese

"State: Closed" was 状態: 閉店 (a shop closing) — change to 状態: クローズ to match
how the Closed state is rendered elsewhere. Also align "State: Merged" (状態: 結合済み)
with the standard マージ済み used for git merges.

---------

Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
This commit is contained in:
Mantaroh Yoshinaga 2026-06-18 07:14:35 +09:00 committed by GitHub
parent abc3037b6a
commit 5ff6bc9778
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 580 additions and 525 deletions

View File

@ -11,6 +11,7 @@ export const JA_PHRASE_FIXES = [
{ pattern: /端末/g, replacement: 'ターミナル', whenEnIncludes: 'erminal' },
{ pattern: /シャチ:\/\//g, replacement: 'orca://', whenEnIncludes: 'orca://' },
{ pattern: /線形/g, replacement: 'Linear', whenEnIncludes: 'Linear' },
{ pattern: /グラフQL/g, replacement: 'GraphQL', whenEnIncludes: 'GraphQL' },
{ pattern: /不和/g, replacement: 'Discord', whenEnIncludes: 'Discord' },
{ pattern: /爽やか/g, replacement: '更新中', whenEnIncludes: 'Refreshing' },
{ pattern: /殺害/g, replacement: '終了中', whenEnIncludes: 'Killing' },
@ -238,5 +239,7 @@ export const JA_PHRASE_FIXES = [
{ pattern: /を選択してください/g, replacement: 'を選択', whenEnIncludes: 'Choose' },
{ pattern: /入力してください/g, replacement: '入力', whenEnIncludes: 'Enter' },
{ pattern: /追加してください/g, replacement: '追加', whenEnIncludes: 'Add' },
{ pattern: /試してください/g, replacement: '試す', whenEnIncludes: 'Try' }
{ pattern: /試してください/g, replacement: '試す', whenEnIncludes: 'Try' },
// Why: JP engineers use "Issue" in Latin, not katakana. Runs last so all *→イシュー fixes above normalize to Issue.
{ pattern: /イシュー/g, replacement: 'Issue', whenEnIncludes: 'issue' }
]

View File

@ -51,9 +51,9 @@ export const JA_VALUE_OVERRIDES = {
'No Linear issues found': 'Linear イシューが見つかりません',
'Unable to load Linear issues': 'Linear イシューを読み込めません',
'No Jira issues found': 'Jira イシューが見つかりません',
issue: 'イシュー',
issues: 'イシュー',
Issues: 'イシュー',
issue: 'Issue',
issues: 'Issue',
Issues: 'Issue',
'Common emulator commands': 'よく使うエミュレータコマンド',
'Pull request': 'PR',
'pull request': 'PR',
@ -223,5 +223,15 @@ export const JA_VALUE_OVERRIDES = {
'Open job in GitLab': 'GitLab でジョブを開く',
'Showing first 100 jobs': '最初の 100 件のジョブを表示しています',
'Imported from Ghostty.': 'Ghostty からインポートしました。',
'Claude Accounts': 'Claude アカウント'
'Claude Accounts': 'Claude アカウント',
// PR/issue state badges: "Closed" is クローズ (not 閉店 = a shop closing); align "Merged" with マージ済み.
'State: Closed': '状態: クローズ',
'State: Merged': '状態: マージ済み',
// Terminal/theme cursor settings = the on-screen カーソル, not the Cursor product.
'Cursor Text': 'カーソル文字',
'Cursor color': 'カーソル色',
'Cursor Opacity': 'カーソルの不透明度',
'Cursor Shape': 'カーソル形状',
'Blinking Cursor': 'カーソルの点滅',
'Terminal Cursor': 'Terminal カーソル'
}

View File

@ -3,6 +3,15 @@ import { KO_KEY_OVERRIDES } from './locale-ko-key-overrides.mjs'
// Key-specific overrides from high-visibility UI audit (P0/P1/P2).
// Why: some fixes depend on full key context, not English value alone.
export const LOCALE_KEY_OVERRIDES = {
// "Open in" is a submenu header for "open in <app>"; bare で開く reads as broken JP.
'auto.components.sidebar.WorktreeOpenInMenu.8009ab69a6': { ja: 'アプリで開く' },
// "Assigned to me" filter; the MT past-passive 割り当てられました reads as a sentence, not a filter label.
'auto.components.TaskPage.94f0339621': { ja: '私に割り当てられた Issue' },
// aria-label describing the assignee picker state; the past-passive sentence reads oddly for a static label.
'auto.components.TaskPage.bb63046423': { ja: '{{value0}} に割り当て済み' },
// Bare "Cursor" terminal/theme settings = on-screen カーソル, not the Cursor product.
'auto.components.settings.TerminalWindowSection.c9e1fdf42f': { ja: 'カーソル' },
'auto.components.onboarding.ThemeStep.ab2a583a97': { ja: 'カーソル' },
'menu.reportCrash': { ko: '크래시 신고...', zh: '报告崩溃...', ja: 'クラッシュを報告...' },
'menu.showMobileButton': {
ko: 'Orca 모바일 버튼 표시',
@ -25,7 +34,7 @@ export const LOCALE_KEY_OVERRIDES = {
ja: 'ワークツリーパレットを開く'
},
'menu.exploreOrca': { ko: 'Orca 둘러보기', zh: '探索 Orca', ja: 'Orca を探索' },
'worktreeJumpPalette.matchLabel.issue': { ko: '이슈', zh: '议题', ja: 'イシュー' },
'worktreeJumpPalette.matchLabel.issue': { ko: '이슈', zh: '议题', ja: 'Issue' },
'worktreeJumpPalette.matchLabel.comment': { ko: '댓글', zh: '评论', ja: 'コメント' },
'auto.hooks.useSettingsNavigationMetadata.13241992bd': {
ko: '일반',

View File

@ -0,0 +1,25 @@
// Distinguishes the on-screen cursor (カーソル) from the "Cursor" product so the brand
// revert in the translation policy doesn't force terminal/theme cursor settings back to Latin.
// Multi-word "Cursor …" labels always mean the screen cursor, never the Cursor product.
const SCREEN_CURSOR_ENVALUES = new Set([
'Cursor Text',
'Cursor color',
'Cursor Opacity',
'Cursor Shape',
'Blinking Cursor',
'Terminal Cursor'
])
// Bare "Cursor" is ambiguous; these keys are the terminal/theme cursor settings (screen cursor).
const SCREEN_CURSOR_KEYS = new Set([
'auto.components.settings.TerminalWindowSection.c9e1fdf42f',
'auto.components.onboarding.ThemeStep.ab2a583a97'
])
export function isScreenCursorContext(brand, enValue, key) {
if (brand !== 'Cursor') {
return false
}
return SCREEN_CURSOR_ENVALUES.has(enValue) || SCREEN_CURSOR_KEYS.has(key)
}

View File

@ -234,8 +234,8 @@ export const SEARCH_KEYWORD_OVERRIDES = {
glab: 'glab',
mr: 'MR',
'azure devops': 'Azure DevOps',
issue: 'イシュー',
issues: 'イシュー',
issue: 'Issue',
issues: 'Issue',
pr: 'PR',
'pull request': 'PR',
phone: 'スマートフォン',

View File

@ -75,7 +75,7 @@ describe('locale-translation-policy ja round 5', () => {
localeValue: 'リクエスト、イシュー、ToDo、パイプラインをマージします。',
locale: 'ja'
})
).toBe('MR、イシュー、ToDo、パイプラインは')
).toBe('MR、Issue、ToDo、パイプラインは')
expect(
repairTranslatedValue({
key: 'auto.components.GitLabItemDialog.98718490e4',

View File

@ -1,3 +1,4 @@
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'
import { SEARCH_KEYWORD_OVERRIDES } from './locale-search-keyword-overrides.mjs'
@ -331,6 +332,8 @@ export const NATIVE_PICKER_LABELS = {
}
const CJK_LATIN_SPACED_TERMS = [
'Issues',
'Issue',
'Terminal',
'Terminals',
'terminal',
@ -407,7 +410,7 @@ function includesPreservedLatinTerm(value, term) {
return new RegExp(`(^|[^A-Za-z_])${escapeRegExp(term)}($|[^A-Za-z_])`).test(value)
}
function applyBrandMistranslationFixes(enValue, localeValue, locale) {
function applyBrandMistranslationFixes(enValue, localeValue, locale, key = '') {
let result = localeValue
const mistranslations = BRAND_MISTRANSLATIONS[locale] ?? {}
@ -417,6 +420,11 @@ function applyBrandMistranslationFixes(enValue, localeValue, locale) {
if (!enValue.includes(brand)) {
continue
}
// Why: terminal/theme "Cursor" labels name the on-screen カーソル, not the Cursor product —
// skip the revert so カーソル survives for these settings.
if (isScreenCursorContext(brand, enValue, key)) {
continue
}
if (includesPreservedLatinTerm(result, brand)) {
continue
}
@ -483,7 +491,7 @@ export function repairTranslatedValue({ key, enValue, localeValue, locale }) {
const keyOverride = LOCALE_KEY_OVERRIDES[key]?.[locale]
if (keyOverride) {
// Why: exact key overrides can still carry stale MT output, so glossary repairs remain the final gate.
let result = applyBrandMistranslationFixes(enValue, keyOverride, locale)
let result = applyBrandMistranslationFixes(enValue, keyOverride, locale, key)
result = applyPhraseFixes(enValue, result, locale)
if (['zh', 'ja', 'ko'].includes(locale)) {
result = applyCjkLatinTermSpacing(result, locale)
@ -493,7 +501,7 @@ export function repairTranslatedValue({ key, enValue, localeValue, locale }) {
const valueOverride = LOCALE_VALUE_OVERRIDES[locale]?.[enValue]
if (valueOverride) {
let result = applyBrandMistranslationFixes(enValue, valueOverride, locale)
let result = applyBrandMistranslationFixes(enValue, valueOverride, locale, key)
result = applyPhraseFixes(enValue, result, locale)
if (['zh', 'ja', 'ko'].includes(locale)) {
result = applyCjkLatinTermSpacing(result, locale)
@ -514,7 +522,7 @@ export function repairTranslatedValue({ key, enValue, localeValue, locale }) {
}
}
result = applyBrandMistranslationFixes(enValue, result, locale)
result = applyBrandMistranslationFixes(enValue, result, locale, key)
result = applyPhraseFixes(enValue, result, locale)
if (['zh', 'ja', 'ko'].includes(locale)) {
result = applyCjkLatinTermSpacing(result, locale)

View File

@ -390,7 +390,7 @@ describe('locale-translation-policy', () => {
localeValue: 'Jira の問題',
locale: 'ja'
})
).toBe('Jira イシュー')
).toBe('Jira Issue')
expect(
repairTranslatedValue({
key: 'auto.components.mobile.MobileHero.668016be7a',
@ -406,7 +406,7 @@ describe('locale-translation-policy', () => {
localeValue: '選択した GitHub の課題またはプル リクエストをプレビューおよび編集します。',
locale: 'ja'
})
).toBe('選択した GitHub イシューまたは PR をプレビュー・編集します。')
).toBe('選択した GitHub Issue または PR をプレビュー・編集します。')
expect(
repairTranslatedValue({
key: 'auto.components.GitHubItemDialog.a2495e4784',
@ -422,7 +422,7 @@ describe('locale-translation-policy', () => {
localeValue: '問題を表示する',
locale: 'ja'
})
).toBe('イシューを表示')
).toBe('Issue を表示')
expect(
repairTranslatedValue({
key: 'auto.components.editor.EditorContent.e4b074749d',
@ -439,7 +439,7 @@ describe('locale-translation-policy', () => {
'GitHub CLI をインストールして、プル リクエスト、発行、チェックを有効にします。',
locale: 'ja'
})
).toBe('GitHub CLI をインストールして PR、イシュー、チェックを有効にします。')
).toBe('GitHub CLI をインストールして PR、Issue、チェックを有効にします。')
expect(
repairTranslatedValue({
key: 'auto.components.mobile.MobilePage.e17393c6a3',

View File

@ -456,7 +456,7 @@ export const LOCALE_VALUE_OVERRIDES = {
string: '文字列',
Refreshing: '更新中',
'Refreshing…': '更新中…',
Issue: 'イシュー',
Issue: 'Issue',
'Privacy & Telemetry': 'プライバシーとテレメトリ',
Experimental: '実験的機能',
Advanced: '詳細設定',

File diff suppressed because it is too large Load Diff