feat(i18n): long-tail extraction — finish app-wide i18n (batch 6)#1157
feat(i18n): long-tail extraction — finish app-wide i18n (batch 6)#1157JamieRuderman wants to merge 7 commits into
Conversation
…ssions, graph/status lookups, column labels, license limits)
…n common/applications.ts
…ve, Cloud Proxy, Personal)
…, and split-string grammar (ja/de/es)
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e5d05c81bf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| setDefaults() { | ||
| this.type = 'COMMAND' | ||
| this.icon = 'code-simple' | ||
| this.name = 'Command' | ||
| this.name = t('appType.launch.command', 'Command') |
There was a problem hiding this comment.
Resolve launch labels after language changes
When the user changes the app language while viewing the same service or connection, these translated names remain in the previous language. LaunchMethod.name is stored when the Application is constructed, while selectApplication memoizes that object using only defaults, service, and connection as inputs, so the language update does not reconstruct it; launch-method menus and derived titles stay stale until one of those inputs changes. Resolve the label at display time or include the resolved language in the selector inputs.
Useful? React with 👍 / 👎.
| name: i18n.t('routeSetting.adaptiveName', 'Adaptive'), | ||
| description: i18n.t( | ||
| 'routeSetting.adaptiveDescription', | ||
| 'Will pick the best route available, prioritizing a direct connection to this service.' | ||
| ), |
There was a problem hiding this comment.
Build translated route options reactively
For any non-English startup or in-app language change, the route names and descriptions remain English. ROUTES is evaluated at module import while i18n boots with lng: 'en', and useTranslation() later only rerenders RouteSetting; it does not recompute this module-level array. Construct these translated fields inside the component or through a language-aware factory.
Useful? React with 👍 / 👎.
| export const networkName = (name?: string): string => | ||
| (name && SYSTEM_NETWORK_KEYS[name] ? i18n.t(SYSTEM_NETWORK_KEYS[name], { defaultValue: name }) : name) || '' |
There was a problem hiding this comment.
Distinguish system networks by ID before translating
When a user creates or renames a network to Active, Recent, Local, Personal, or Cloud Proxy, NetworkListTitle now displays the localized system label instead of the user-provided name. The creation and rename forms allow these names, and this helper classifies solely by name, so ordinary cloud networks collide with the built-ins. Determine whether the network is synthetic from its ID/type and translate only those instances.
Useful? React with 👍 / 👎.
Summary
The final long-tail batch — internationalizes the remaining ~200 components and pages, completing the app-wide string extraction. ~1560 new keys, translated to ja/de/es. Also finishes
Attributes.tsx(the connection-type value strings deferred from batch 5).Stacked on
i18n/extract-columns(#1156). With this merged (up the stack intofeature/i18n), the app is fully internationalized.What's covered
All previously-untouched surfaces: device detail / connection / network pages, organization + billing + plans + reseller + customer, admin pages, MFA/security, access keys, scripting/products/files, onboarding, notifications, and the shared components across all of them. Plus
Attributes.tsxconnection-type values ("Peer to Peer", "Inactive", "Local Proxy"…), Yes/No, "This system", "since refresh".How it was done
To cover this volume, conversion was fanned out across 8 parallel agents (25 files each), each keying strings under the file's component/page name (so keys never collide across files) with inline English defaults, then translation was fanned out across 8 more agents + a dedicated plural pass. Every string uses
t()/i18n.t(); interpolation via{{placeholders}}; manual plural ternaries converted to i18nextcountplurals; sentences with embedded<Link>split rather than concatenated; brand/technical terms (remote.it, AWS, Docker, SAML, TOTP…) left verbatim.Notable structural fixes agents made where a hook couldn't be used: module-level
Attributearrays converted togetX(t)factories ori18n.t(), default-prop strings moved into component bodies, andt-shadowing lambda params renamed.Verification
tsc --noEmit: 0 errors across the whole project (all 200 files compile together).i18n:checkpasses — 4 locales × 3 namespaces, no missing/dead keys, no empty English, plural-aware (the check caught and I fixed an over-generation of Japanese_oneforms — ja correctly carries only_other; de/es carry_one/_other, es also_many).Caveats (important)
🤖 Generated with Claude Code