Skip to content

chore(i18n): index catalogs instead of branching on locale - #4824

Merged
Astro-Han merged 3 commits into
apache:mainfrom
orangeCatDeveloper:chore/locale-catalog-leftovers
Sep 5, 2026
Merged

chore(i18n): index catalogs instead of branching on locale#4824
Astro-Han merged 3 commits into
apache:mainfrom
orangeCatDeveloper:chore/locale-catalog-leftovers

Conversation

@orangeCatDeveloper

@orangeCatDeveloper orangeCatDeveloper commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Six presentation helpers outside the open locale PRs still chose copy with locale === '…' comparisons, so adding a fourth UiLocale would compile and render the wrong language: the client-settings confirmation dialog, the project picker title, the Astryx message overrides, the retry-delay formatter, and the bypass-required tool error. resolveUiMessageCatalog keeps its en fast path: en is the base every other locale merges over, so that branch is the fallback rule itself rather than a locale leak. Each now indexes a UiCatalog, which the type system enforces per locale.

The bypass-required error is a complete errorMessage in each locale catalog, independent of the banner title and description. This lets future translations choose their own sentence structure rather than fitting a title/separator/description formula; current wording is unchanged.

formatSkillLibraryDescription also decided whether a description was product copy by sniffing it for CJK characters, then guessed which canned line to show from keywords in the text. Only bundled skills carry product copy, and the catalog has exactly one, computer-use, whose description mentions "prefer Browser tools" and so landed on the browser line. Provenance and identity decide instead: a bundled skill renders the localized description filed under its id, a bundled skill the user rewrote keeps the rewritten text, and a skill the user authored renders its own description as written in every locale. The keyword ladder and its 21 unreachable strings are gone. Two user-visible changes: computer-use now describes desktop apps rather than web pages in all three locales, and an English description on a workspace skill shows in English under a Chinese UI rather than a generic canned line.

Refs #2672

Verification

$ node --test packages/ui/dist/__tests__/skill-status.test.js   # against origin/main's skill-status.ts + skills-copy.ts
✖ bundled skills render the product description for their id in every locale
✔ a bundled skill the user edited keeps the edited description
✖ skills the user authored keep their own description in every locale
ℹ pass 1
ℹ fail 2

$ node --test packages/ui/dist/__tests__/skill-status.test.js   # with this change
✔ bundled skills render the product description for their id in every locale
✔ a bundled skill the user edited keeps the edited description
✔ skills the user authored keep their own description in every locale
ℹ pass 3
ℹ fail 0

In the running app (MAKA_E2E fixture; computer-use installed from the built-in tab, the docx-review workspace skill and the bypass tool result seeded into the local fixture for this capture only). computer-use in the skill library and inspector, zh-CN / zh-TW / en, with the English-described workspace skill under the Chinese UI:

skills-computer-use-3-locales

The bypass banner in an expanded tool row, zh-CN / zh-TW / en. The error icon's title tooltip in the same runs reads 需要“绕过”模式。此操作会直接控制本机应用,无法在沙箱模式下执行。 / 需要“繞過”模式。此操作會直接控制本機應用,無法在沙箱模式下執行。 / Bypass mode required. This action controls a local app directly and cannot run inside the sandbox.:

bypass-banner-3-locales

npm run typecheck, core (824) / ui (374) / desktop main (2138) suites, the renderer architecture ratchet, format:check, and knip pass locally. The locale-hygiene scan reports zero locale-branch / cjk-sniff hits in the touched files.

Follow-up verification: core and UI builds, UI typecheck, all 376 UI tests, repository-wide format:check, and lint of the three changed files pass. The bypass rendering test checks the complete error-icon text in every UI_LOCALES entry, including Traditional Chinese, and asserts the tooltip opens with the banner title and ends with the banner description so the two cannot drift.

After review (rebased on main): UI typecheck, all 365 UI tests from a clean dist, format:check, and biome on the changed files pass.

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: Claude Code drafted the catalog conversions, the skill-status test, the review follow-ups (per-id bundled description table, retry units on the copy object, plain Astryx override table, tooltip/banner sync assertion), and this description; the provenance rule was decided by hand. OpenCode replaced sentence concatenation with complete bypass-error catalog messages, extended the rendering test, and updated this description.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

@github-actions github-actions Bot added the effort/M Under 500 readable lines label Sep 5, 2026
@orangeCatDeveloper
orangeCatDeveloper force-pushed the chore/locale-catalog-leftovers branch 3 times, most recently from 6245704 to 0f5f052 Compare September 5, 2026 06:32

@Astro-Han Astro-Han 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.

Reviewed at 0f5f052. The six catalog conversions are exactly what the RFC asks for and I checked each renders byte-identical output to main (including String(true), 小時, and the bypass sentence). The en fast path in resolveUiMessageCatalog is a reference shortcut, not a locale leak, so leaving it with a comment is right. One P2 on the one behavior change, then smaller things.

P2: the provenance rule leaves the keyword ladder with exactly one input, and it maps that input wrong. BUNDLED_SKILL_CATALOG has a single entry, computer-use (bundled-skill-catalog.generated.ts:16). Its description says "prefer Browser tools for web pages", none of the earlier keyword groups match, so skill-status.ts:132 hits browser and renders 打开、检查、操作网页界面 / "Open, inspect, and operate web interfaces" for a skill whose whole point is native desktop apps. main has the same bug, but main at least uses the ladder for every non-CJK skill; after this PR the ladder's other five branches and their 21 localized strings are unreachable, and the premise in the body ("only bundled skills carry product copy") is really "only one skill carries product copy". Two coherent shapes: delete the ladder and give bundled skills a Record<bundledId, localized description> (one row today, no guessing), or keep this PR to the catalog conversions and argue the provenance rule separately. There is also a narrow regression: a bundled skill the user has edited keeps sourceType: 'bundled' (skills-governance.ts:148-160), so a user who rewrote computer-use's description in Chinese sees it today and gets the canned line after this PR.

Smaller:

  • requiresBypass.errorMessage is title + description retyped in three locales (tool-activity/copy.ts:194-197, 299-302, 404-407); the banner reads the parts, the tooltip reads the whole, and nothing keeps them in sync. Make the separator the catalog entry instead, or add one assertion that errorMessage === title + sep + description.
  • astryxMessageOverrides now returns Overrides, so the ?. at astryx-i18n.tsx:68 is dead, and the thunk wrapper around three synchronous values can be a plain satisfies UiCatalog<Overrides> table.
  • RETRY_DELAY_UNITS is a second per-locale table in a file that already has ConversationCopy (compare goalElapsed at conversation-copy.ts:607); put the units on the copy object.
  • The first case in skill-status.test.ts passes on main too ('Create and edit Word documents.' is non-CJK and hits word either way). Only the second case fails without the change.

User-visible, so before this merges someone needs to look at: computer-use's description in the skill library and inspector in zh-CN / zh-TW / en; a workspace skill with an English description under a Chinese UI (the declared behavior change); the bypass tooltip vs banner text in all three locales. CI test was still pending when I read this.

Evidence boundary: static read at 0f5f052 against cbeb1a93c7; the keyword match for computer-use was recomputed on the description string, not observed in the app. No build, no tests.

AI-assisted review: drafted with Maka; I verified the bundled catalog contents and the keyword match myself.

Six presentation helpers still picked copy with locale comparisons,
so a fourth UI locale would compile and silently render the wrong
language. Each now indexes a UiCatalog, and bypass errors are complete
per-locale messages instead of a title-and-description concatenation.
Skill library descriptions stop sniffing the text for CJK: only bundled
skills carry product copy, so a per-id table names what each does and a
bundled skill the user has rewritten keeps the rewritten description.

Generated-by: Claude Code
Claude-Session: https://claude.ai/code/session_01AqdSkg56F2x55wEGRWvzcB
@orangeCatDeveloper
orangeCatDeveloper force-pushed the chore/locale-catalog-leftovers branch from 9a01375 to 127c870 Compare September 5, 2026 11:27
@orangeCatDeveloper
orangeCatDeveloper marked this pull request as ready for review September 5, 2026 12:19
@orangeCatDeveloper
orangeCatDeveloper force-pushed the chore/locale-catalog-leftovers branch from 723138d to 146c7a8 Compare September 5, 2026 12:38

@Astro-Han Astro-Han 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.

Re-reviewed at 146c7a8. The P2 is closed the way I hoped: the keyword ladder and its 21 strings are gone, bundled skills render bundledDescription[skill.id], a user-edited bundled skill keeps its text (skill-status.ts:120), and the three screenshots show computer-use describing desktop apps in every locale. The smaller items are all done too: the tooltip is asserted to open with the banner title and end with its description in every locale, the Astryx overrides are a plain satisfies UiCatalog<Overrides> table with the dead ?. removed, the duration units live on each copy entry, and the first skill-status test now fails on main.

One P3, then approve-worthy:

P3: a bundled skill without a copy entry falls back to its raw English silently. bundledDescription is Partial<Record<string, string>> and ?? raw covers the miss, so the next entry added to BUNDLED_SKILL_CATALOG shows English under a Chinese UI with nothing failing. @maka/ui cannot import the catalog (it lives in @maka/runtime), but apps/desktop can: one test there that walks BUNDLED_SKILL_CATALOG × UI_LOCALES and asserts every id has an entry closes it without changing the type. Fine as a follow-up commit here or on its own.

Ordering: no shared files with the other four locale PRs. CI test was pending when I read this head.

Evidence boundary: static read of the delta since 0f5f052 against 03b5a2cc5a; no build, no suites.

AI-assisted review: drafted with Maka; I verified the ladder removal, the userModified branch and the Partial fallback myself.

@Astro-Han
Astro-Han merged commit afa8a73 into apache:main Sep 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/M Under 500 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants