feat(portal-shell): i18n string sweep — mark UI strings + FR translations #93
Reference in New Issue
Block a user
Delete Branch "feat/portal-shell/i18n-string-sweep"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Continue ADR-0019 implementation. Mark every UI string surfaced by the shell with
i18n="@@id"(templates) or$localize(TypeScript), and populatemessages.fr.xlfwith French translations. The production build now ships two genuinely different bundles underdist/.../{en,fr}/.43 trans-units marked, grouped by feature:
app.htmlheader.htmlsidebar.ts+.htmltheme-switcher.ts+.htmlTheme: <mode> (open menu)with named placeholder)footer.htmlhome.htmlapp.routes.tsTooling
"@angular/localize"to thetypesarray in bothtsconfig.app.jsonandtsconfig.spec.jsonso TypeScript resolves the$localizeglobal at compile time. Specs need it too — they evaluate the same component code paths.nx run portal-shell:extract-i18n) reports 44 messages (43 unique IDs).Translation choices worth flagging
/browser tab title. The PWA manifest (site.webmanifest) stays "APF Portal" — manifest values are not bundled, they sit in the static assets and are language-neutral in v1.langattribute (lang="en"andlang="fr"). The dual-link pattern goes away in the upcoming route-fusion PR; until then it's the most honest stopgap.@@route.accessibility.title). In the EN bundle, both display "Accessibility statement · APF Portal"; in the FR bundle, both display "Déclaration d'accessibilité · Portail APF". After route fusion only one route remains.Verification
Welcome to APF Portalin the lazyhomechunk shows "Bienvenue sur Portail APF" in FR.en), so the English assertions still match. No spec edits needed.Out of scope (each its own follow-up PR)
__Host-portal_localecookie + smart/redirect./accessibility+/accessibiliteinto one localised route with locale-translated path segments.nx build --localizetoci:checkand verify it rejects unsealed strings.copy()service rather than i18n-marked templates — restructured during the route fusion.Test plan
pnpm exec nx run-many -t lint test build --projects=portal-shell— green (36 / 36 specs).pnpm exec nx run portal-shell:extract-i18n— clean, 43 unique unit IDs.pnpm exec nx serve portal-shellshows the EN source.pnpm exec nx build portal-shell --configuration=production && pnpm exec nx run portal-shell:serve-static→ openhttp://localhost:4200/fr/for FR,/en/for EN.Continue ADR-0019 implementation. Mark every UI string surfaced by the shell with `i18n="@@id"` (templates) or `$localize` (TypeScript) and populate `messages.fr.xlf` with French translations. 43 trans- units total: skip-link, header, sidebar, theme switcher, footer, home page, route titles. What's marked: - `app.html` skip-link. - `header.html` brand wordmark, search label + placeholder, action buttons (notifications / help / settings), user-menu placeholder. - `sidebar.ts` MENU data (group + item labels) and a computed aria- label for the toggle button (Expand / Collapse). - `sidebar.html` aside / sections / role / collapse strings. - `theme-switcher.ts` MODE_OPTIONS labels + computed trigger aria ("Theme: <mode> (open menu)" with a named placeholder). - `theme-switcher.html` menu aria-label. - `footer.html` aria-labels + copyright. The two accessibility-page link labels stay bilingual on purpose (one per language, each carrying its `lang` attribute) — the dual-link pattern goes away in the upcoming route-fusion PR. - `home.html` welcome heading + intro + status widget labels. - `app.routes.ts` browser tab titles. The `/accessibility` and `/accessibilite` routes share one title key; the route-fusion PR will collapse them to a single localised route. Tooling: - Add `"@angular/localize"` to the `types` array in both `tsconfig.app.json` and `tsconfig.spec.json` so TypeScript resolves the `$localize` global. Translation choices worth flagging: - Wordmark: "APF Portal" → "Portail APF" (consistent with the route title key). - "System" theme mode → "Système". - "Anonymous" role → "Anonyme"; "Role:" → "Rôle :" (French uses a non-breaking-space before the colon — typographic convention, preserved in the XLIFF target). Verification: - Production build emits both locales (`dist/.../{en,fr}/`). Spot-checked the FR bundle: no leftover English source text on any of the swept strings, route titles, or the home page intro. - Initial bundle: 129 kB gzip per locale (vs 122 kB before). +7 kB gzip absorbs the i18n marker metadata + the FR translation data embedded in the FR bundle. Well under the 300 KB budget. - 36 / 36 specs unchanged (they run in the source locale, so the English assertions still match). Out of scope (each its own follow-up PR): - Locale switcher in the footer + `__Host-portal_locale` cookie + smart `/` redirect. - Collapse `/accessibility` + `/accessibilite` into one localised route. - CI gate that fails the build on a missing translation.