mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 03:38:32 +02:00
The previous fix (#3446) for the i18next/no-literal-string CI failure took the lazy route — added a file-level eslint-disable comment with the rationale that the test page is slated for deletion when the real billing UI ships, so investing in a translation namespace was wasted churn. That argument is weak in practice: * The test page has been around since #3442 and there is no concrete date for when the real billing UI lands. "Throwaway" surfaces tend to outlive their stated half-life. * File-level disables hide future violations of the same rule from review — anyone touching this file later inherits an opt-out they didn't ask for. * The translation namespace is genuinely cheap. The page has ~50 distinct strings, all of which now have a single en.json/zh.json home that the locale-parity test guards. This commit replaces the silencer with a real `billing` namespace: * packages/views/locales/en/billing.json + zh-Hans/billing.json — every literal English label from the page, plus interpolated sentences with i18next `{{var}}` placeholders. The zh-Hans bundle is a basic translation; not perfect prose, but the parity test passes and a Chinese reviewer testing the page won't see raw English mixed with native UI chrome. * packages/views/i18n/resources-types.ts — adds the namespace to `I18nResources` so `t($ => $.billing.x.y)` is type-checked. * packages/views/locales/index.ts — registers both bundles in `RESOURCES` so the parity test sees them. * packages/views/billing/billing-test-page.tsx — every JSX literal rewritten as `t(($) => $.path)`, including aria-label, interpolated sentences (balance meta line, transactions row meta, paging footer), and conditional branches (with-bonus vs without-bonus rendering goes through two distinct keys rather than two literals). The file-level eslint-disable is removed along with its multi-paragraph rationale comment. * formatDate now takes `t` as an argument so the en/zh "—" dash placeholder is itself translated; calling useT inside the util would have violated the rule of hooks (the function is called from conditional render branches). Verification: * pnpm --filter @multica/views lint — 0 errors (15 unrelated warnings, all pre-existing on main) * pnpm --filter @multica/views typecheck — clean * pnpm --filter @multica/views test — 883/883 passing, including the locale-parity test (which fails the build if en and zh-Hans diverge) When the real billing UI ships and this file is deleted, the `billing` namespace JSONs and the `resources-types.ts` / `locales/index.ts` entries get deleted with it — same blast radius as the eslint-disable would have had, but with proper i18n along the way.