feat(i18n): translatable Attribute column labels (batch 5)#1156
feat(i18n): translatable Attribute column labels (batch 5)#1156JamieRuderman wants to merge 1 commit into
Conversation
…tter (+ 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: 694eebe795
ℹ️ 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".
| return typeof this._label === 'string' | ||
| ? i18n.t(`columns.${this.id}`, { defaultValue: this._label }) |
There was a problem hiding this comment.
Preserve intentionally empty attribute labels
Skip translation when _label is empty. The enterprise-license actions column constructs an attribute with id: 'actions' and label: '' (AdminEnterpriseLicensesListPage.tsx:84-88), but there is no columns.actions entry and i18n/index.ts configures returnEmptyString: false; consequently i18next rejects the empty default and renders the literal key columns.actions in a header that was intentionally blank.
Useful? React with 👍 / 👎.
| get label(): string | React.ReactNode { | ||
| return typeof this._label === 'string' | ||
| ? i18n.t(`columns.${this.id}`, { defaultValue: this._label }) | ||
| : this._label |
There was a problem hiding this comment.
Subscribe label renderers to catalog loading
Ensure components rendering this getter subscribe to i18next updates. On startup with a saved non-English language, ui.setLanguage starts but does not await the lazy changeLanguage load, so headers can first access this getter while only English is available; GridListHeaderTitle, DataDisplay, and ColumnsDrawer do not use useTranslation, and calling i18n.t() directly does not register a React subscription, leaving the English fallback displayed after the locale chunk finishes until an unrelated rerender or remount occurs.
Useful? React with 👍 / 👎.
| return typeof this._label === 'string' | ||
| ? i18n.t(`columns.${this.id}`, { defaultValue: this._label }) |
There was a problem hiding this comment.
Limit column translations to the intended registries
Avoid applying columns.<id> entries to every Attribute instance. Several admin registries use unprefixed IDs that collide with this catalog—for example, admin users/admins and enterprise licenses define id: 'created' with label Created, while this change resolves it as columns.created (Created date), and admin users' license is similarly translated—so those otherwise untranslated admin tables now acquire unintended, partially translated or renamed headers instead of retaining their supplied defaults.
Useful? React with 👍 / 👎.
Summary
Batch 5 — makes the device/service/connection table column labels translatable. This is the architectural piece deferred from the device-list chrome batch: the
Attributeregistry inAttributes.tsxis a module-level static array (~54 string labels) evaluated once at import, so labels can't use thet()hook.54
columns.*keys, translated to ja/de/es. Stacked oni18n/extract-devicelist(#1155).Approach (the option chosen: label → id-keyed getter)
Attribute.label/Attribute.helpare now getters that resolvei18n.t('columns.<id>')/columns.<id>_helpat access (render) time, keyed by the attribute's existingid, with the original English string asdefaultValue. Backing fields_label/_helphold what the constructor passes.<DeviceGraphColumn />).Attribute-based registries (File/Job/Product/Customer) keep working in English until a later batch, with no code change needed.customer*,job*,product*,script*), so id-keying is unambiguous.Catalog mechanics
columns.${id}), so the i18next-parser can't discover them — they're hand-maintained in the catalogs (same pattern as the cognito dynamic keys). Documented ini18next-parser.config.js;keepRemoved: truemeans an extract run leaves them intact (verified).categoryA–E,statusA–E) are intentionally not keyed — they fall back to English.Deferred (follow-up)
Hardcoded English still lives inside
valuefunctions in this file — connection-type strings ("Peer to Peer", "Inactive", "Local Proxy", …), plus "Yes"/"No", "This system", "since refresh". Those render via inlinei18n.t()(no architecture change) and are a clean separate batch.Verification
i18n:checkpasses;tscclean; production build passes.columns.*keys survive (not pruned).🤖 Generated with Claude Code