Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 55adc1dbd7 | |||
| 138d8fbb6d |
@@ -0,0 +1,26 @@
|
||||
# I18N-00 baseline audit
|
||||
|
||||
Date: 2026-11-02. Verdict: **IN_PROGRESS; partial research checkpoint, not full I18N-00 acceptance. I18N-01 through 08 BLOCKED. Production NO-GO.**
|
||||
|
||||
Research only, authorised by master prompt and continuous-progress instruction. Branch `feature/i18n-00-audit`, worktree `C:/Users/Connor/.codex/worktrees/i18n-00-audit/Job tracker`, baseline `5cb903b989742b7a96cb22ddf4c0e24993b18980`. Application/API/tests/UI/sidecar diff against `ba04d817` was empty. This is the accepted conditional development handoff, not blanket runtime, language or production acceptance. No controller or approval state was changed. All ten supplied I18N prompts were read. Their implementation requirements are future specifications, not authority to execute them.
|
||||
|
||||
Architecture authority is `docs/architecture/current.md`, which redirects to `overview.md`. Existing React/MUI, ASP.NET/EF/MariaDB, Python sidecar and rendering ownership remain. Graph absent in this baseline: bounded source inspection used; no graph rebuild needed for documentation.
|
||||
|
||||
## Verified source findings
|
||||
|
||||
* `job-tracker-ui/src/i18n/translations.ts`: custom two-language `en | nb` object; it is not an i18next or FormatJS installation.
|
||||
* `I18nProvider.tsx`: local storage accepts `nb`, `nb-NO`, `no`; otherwise English. Auth hydration and cross-tab storage update language. `{word}` substitution handles simple values, not ICU plural/select grammar. Failed preference save offers retry; sequence tracking avoids stale error handling.
|
||||
* `JobTrackerApi/Controllers/AuthController.cs:601`: language endpoint accepts `en` or Bokmål aliases, writes `nb-NO`; unsupported input returns hardcoded English error. Do not rename canonical English to `en-GB` without migration tests.
|
||||
* `CoverLetterDocumentRenderer.cs:36`: labels distinguish `nb-NO` from English; document HTML has its own language. `ThemedCvRenderer.cs:60` derives HTML language from document settings. UI language must not become the output-language owner.
|
||||
* `HumanLanguageCatalog.cs` is CV skill-language recognition, including environment-independent seeds and variant collapsing. It is not an eligible UI-locale registry; reusing it would lose script/region distinctions.
|
||||
* Manifest dependencies: React `^19.2.4`, Next `16.4.1`, MUI `^7.3.9`, TypeScript `^5.9.3`, date-fns `^4.1.0`. These are manifest ranges, not freshly installed/runtime versions. No i18next/FormatJS direct dependency. Lockfile/runtime compatibility must be qualified before implementation.
|
||||
|
||||
## Gate evidence
|
||||
|
||||
`docs/pre-phase10-ux/ACCEPTANCE.md` grants conditional development review, not Phase 10 implementation. `docs/automation/handoffs/pre-phase10/FINAL_DEVELOPMENT_ENTRY.md` separates P10-00 assessment from candidate-specific P10-01 permission. This checkpoint cannot grant either. Product-review and launch-site accepted decisions are absent from this baseline; absence is not permission. Global Jobs planning exists separately at `0ec9f98` in the main workspace (`docs/global-jobs/00/DEPENDENCIES_AND_GATES.md` inspected read-only); it is not integrated here and does not authorise live providers or GJ-01.
|
||||
|
||||
## Honest limits
|
||||
|
||||
The TypeScript AST inventory contains 3,119 existing English catalogue entries and 3,164 syntactically identified static call sites across 134 non-test frontend files. It records 188 dynamic/unknown calls separately as an unresolved count; 853 catalogue entries have no identified static caller. These are not deletion candidates: wrappers, dynamic keys and direct object access remain unresolved. A subsequent partial JSX/accessibility literal inventory now contains 26 source-context-reviewed candidates. CONTEXT_TRIAGE.md records the current 80 unresolved dynamic calls after 108 finite-branch resolutions. This is still not a complete non-catalogue inventory. Every-string attribution, translator context, accessible states and country-specific legal recognition require additional review. Therefore the stage's complete-inventory criterion has not passed. No translations, native approval, screenshots, model results, browser results or locale release are manufactured.
|
||||
|
||||
The country matrix covers an initial 59 territory/market contexts from versioned CLDR 49, with targeted official-record checks for Norway, Switzerland and Serbia. The remaining legal cross-checks are pending. The draft catalogue contains 60 planned locale candidates, not 60 supported languages. Schema, uniqueness, BCP-47 parsing and rejection of a forged released status passed using existing local tools. Node/ICU canonicalises `cnr-ME` to `sr-ME`; retain this unresolved identity issue rather than accepting an automatic product alias. See BASELINE_TESTS.md.
|
||||
@@ -0,0 +1,19 @@
|
||||
# Planning evidence and baseline checks
|
||||
|
||||
2026-11-02. Baseline `5cb903b989742b7a96cb22ddf4c0e24993b18980`, branch `feature/i18n-00-audit`. Documentation only. No runtime code, test code, lockfiles or settings changed.
|
||||
|
||||
| Check | Result | Scope |
|
||||
| --- | --- | --- |
|
||||
| `git diff ba04d817fed26d659bfa2a56b089d6cac851dc34 HEAD --stat -- JobTrackerApi JobTrackerApi.Tests JobTrackerApi.MariaDb.Tests job-tracker-ui tools/summarizer` | PASSED: empty diff, exit 0 | Source identity only; no fresh runtime assertion |
|
||||
| English catalogue AST extraction using existing TypeScript | PASSED: 3,119 unique keys | Property assignments required to be string literals; duplicate/unsupported members throw; 134 non-test TS/TSX files scanned |
|
||||
| Static syntactic `t` call association | 3,164 sites; 188 dynamic/unknown calls; 853 entries without static caller | Partial inventory, not symbol resolution or coverage proof; no dead-code inference |
|
||||
| Existing Ajv draft-07 validation | PASSED: 60 entries | `LOCALE_SCHEMA.json` compiled and validated `LOCALE_CATALOG.json`; no installed dependency changes |
|
||||
| Uniqueness and `Intl.getCanonicalLocales` parsing | PASSED: 60 unique parseable tags | Node v24.19.0, ICU 78.3; syntax acceptance is not runtime translation availability |
|
||||
| Negative publication fixture | PASSED | In-memory copy changed first `surfaces.ui` from `planned` to `released`; validator rejected it |
|
||||
| Montenegrin identity | OPEN | Intl maps `cnr-ME` to `sr-ME`; product semantics require explicit resolution before registry implementation |
|
||||
| Product/unit/browser/MariaDB/Python suites | NOT RUN | No implementation changes; existing accepted evidence remains historical |
|
||||
| Native/legal/AT/device/PDF/hosted/production/provider/model qualification | NOT RUN | No authority or claim conferred by planning checks |
|
||||
|
||||
The inventory records its baseline, parser version, exact source SHA-256 and source line for each English message. Callers retain expressions and file/line, making manual review possible. Extraction covers the `en` object in `translations.ts`, excludes `*.test.*`, and associates literal first arguments of expressions named `t` or ending in `.t`. Dynamic keys, aliases, direct property reads, C#/Python messages and hardcoded JSX are not completely captured. Recompute after source changes; do not extrapolate counts to full application completeness.
|
||||
|
||||
Research sources checked on this date: CLDR 49 territory table, EU official-language list, i18next plural documentation, FormatJS ICU syntax, Norwegian Language Act, Swiss federal multilingualism guidance and Serbian government constitution. Specific links and limitations are in the matrix and implementation plan. No production data or private user text was sent to translation services.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Source-context triage continuation
|
||||
|
||||
2026-11-02, unchanged application baseline `5cb903b989742b7a96cb22ddf4c0e24993b18980`. No translation or runtime implementation.
|
||||
|
||||
## Completed inventory refinement
|
||||
|
||||
- All 188 previously counted dynamic/unknown `t` calls now have source file/line/hash and exact expression in DYNAMIC_MESSAGE_CALLS.json.
|
||||
- 108 calls resolve to finite literal conditional branches, accounting for 240 possible-key references. Each referenced key exists in the English catalogue. Nested ternaries are included. This is key resolution, not translator or runtime acceptance.
|
||||
- 80 calls still need lookup-table, wrapper, template-token or runtime-key review. Type assertions such as `as any` or a single asserted literal must not be treated as proof of actual possible values.
|
||||
- Four direct catalogue reads were located in I18nProvider: save-failure/retry feedback and the evaluator/fallback. These are active consumers missed by a `t("key")`-only search; preserve them during migration.
|
||||
- 26 JSX text/selected accessibility-label candidates were extracted and individually reviewed in source context. The JSON records preservation/extraction decisions and excludes adjacent private runtime values. This scan does not cover every computed JSX expression, object-held label, string-returning helper, backend string or app-shell document text.
|
||||
|
||||
## Findings to carry into approved implementation
|
||||
|
||||
| ID | Source | Finding / required handling |
|
||||
| --- | --- | --- |
|
||||
| I00-13 | `App.tsx:488` | Session-invalidated alert is hardcoded English. Localisation must preserve disposal of the old application tree and must not depend on its discarded session/provider state |
|
||||
| I00-14 | `JobFlowBar.tsx:147` | `Flow` is controlled UI copy outside the catalogue; extract with workflow context |
|
||||
| I00-15 | `Attachments.tsx:361` | Preview iframe title is only `pdf`; use descriptive localised purpose while keeping private filenames out of translator exports |
|
||||
| I00-16 | `AppShell.tsx:692` | `EN`/`NO` with `English`/`Norsk` labels conflates country-like abbreviation and Norwegian variant. Future selector needs native/English names and explicit Bokmal/Nynorsk distinction; preserve existing nb aliases |
|
||||
| I00-17 | `ApplicationAssets.tsx:360` | File-size display uses `toFixed(1)` with KB. Review locale number formatting; filename and underlying byte count remain unchanged |
|
||||
| I00-18 | `I18nProvider.tsx:43` | Save-failure feedback accesses catalogue directly. Migration must preserve same-language retry and stale-save sequencing; static t-call inventory alone misses this contract |
|
||||
| I00-19 | `LandingPage.tsx:133` | Technology-name list is not ordinary translatable prose. Coordinate user-outcome copy with homepage design work; do not translate trademarks or add unverified feature claims |
|
||||
|
||||
Brand/provider names, host examples and technical identifiers were not blindly classified as missing translations. Unit/version fragments require formatting and accessibility context rather than mechanical dictionary substitution. All findings are planning tasks, not permission to edit application files.
|
||||
|
||||
## Verification and remaining work
|
||||
|
||||
The same 134 non-test TS/TSX files were scanned using the installed TypeScript AST parser. Assertions confirmed exactly 188 dynamic calls and that all 240 resolved branch-key references exist. No full application typecheck or browser suite was run. The 26 literal records were reviewed against adjacent source lines; broader semantic census remains IN_PROGRESS.
|
||||
|
||||
Next: resolve the remaining 80 table/template/wrapper calls; cover computed frontend values and app document metadata; inventory backend errors, queued communication text and Python processing messages. Country legal records, reviewer allocation and runtime-library choice remain separate unfinished tasks.
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"baseline": "5cb903b989742b7a96cb22ddf4c0e24993b18980",
|
||||
"method": "TypeScript AST syntactic triage; no symbol resolution or runtime coverage claim",
|
||||
"filesScanned": 134,
|
||||
"entries": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/i18n/I18nProvider.tsx",
|
||||
"line": 43,
|
||||
"sourceSha256": "95a930915cb2240547cc1a91af7cb0a475bc8f46ac75304b3241a401928ed3e4",
|
||||
"kind": "direct-catalogue-access",
|
||||
"text": "translations[l].settingsLanguageSaveFailed",
|
||||
"ownerComponent": "job-tracker-ui/src/i18n/I18nProvider.tsx",
|
||||
"contextStatus": "pending",
|
||||
"sensitivity": "unclassified-template; do-not-export-runtime-values"
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/i18n/I18nProvider.tsx",
|
||||
"line": 44,
|
||||
"sourceSha256": "95a930915cb2240547cc1a91af7cb0a475bc8f46ac75304b3241a401928ed3e4",
|
||||
"kind": "direct-catalogue-access",
|
||||
"text": "translations[l].retry",
|
||||
"ownerComponent": "job-tracker-ui/src/i18n/I18nProvider.tsx",
|
||||
"contextStatus": "pending",
|
||||
"sensitivity": "unclassified-template; do-not-export-runtime-values"
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/i18n/I18nProvider.tsx",
|
||||
"line": 67,
|
||||
"sourceSha256": "95a930915cb2240547cc1a91af7cb0a475bc8f46ac75304b3241a401928ed3e4",
|
||||
"kind": "direct-catalogue-access",
|
||||
"text": "translations[language][key]",
|
||||
"ownerComponent": "job-tracker-ui/src/i18n/I18nProvider.tsx",
|
||||
"contextStatus": "pending",
|
||||
"sensitivity": "unclassified-template; do-not-export-runtime-values"
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/i18n/I18nProvider.tsx",
|
||||
"line": 67,
|
||||
"sourceSha256": "95a930915cb2240547cc1a91af7cb0a475bc8f46ac75304b3241a401928ed3e4",
|
||||
"kind": "direct-catalogue-access",
|
||||
"text": "translations.en[key]",
|
||||
"ownerComponent": "job-tracker-ui/src/i18n/I18nProvider.tsx",
|
||||
"contextStatus": "pending",
|
||||
"sensitivity": "unclassified-template; do-not-export-runtime-values"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,87 @@
|
||||
# Europe country and language research matrix
|
||||
|
||||
Research checkpoint 2026-11-02; not a market-launch list or legal opinion. All entries are candidate scope. CLDR 49 provides an initial language relationship dataset; national/regional official-record cross-checks remain incomplete. Blank CLDR status is not proof of absence or recognition. No tag decides sovereignty, EU membership, provider rights or support. XK is a CLDR user-assigned territory code, not ISO 3166-1; do not silently persist it as an ISO identifier.
|
||||
|
||||
Source: [Unicode CLDR 49 territory-language data](https://www.unicode.org/cldr/charts/49/tsv/territory_language_information.tsv); retrieved SHA-256 `29bcadbb4362e1a7a3685f4bf199152809635acca58fab10a3576a0f7b55868c`. Population percentages are deliberately omitted; they are not product usage evidence.
|
||||
|
||||
| Territory | Code | CLDR official/de-facto | CLDR regional/recognised | Legal cross-check |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Andorra | AD | ca (official) | not recorded; further review required | PENDING |
|
||||
| Albania | AL | sq (official) | not recorded; further review required | PENDING |
|
||||
| Austria | AT | de (official) | hr (official_regional), sl (official_regional), hu (official_regional) | PENDING |
|
||||
| Åland Islands | AX | sv (official) | not recorded; further review required | PENDING |
|
||||
| Bosnia & Herzegovina | BA | bs (official), bs-Cyrl (official), hr (official), sr (official), sr-Latn (official) | not recorded; further review required | PENDING |
|
||||
| Belgium | BE | nl (official), fr (official), de (official) | not recorded; further review required | PENDING |
|
||||
| Bulgaria | BG | bg (official) | not recorded; further review required | PENDING |
|
||||
| Belarus | BY | ru (official), be (official) | not recorded; further review required | PENDING |
|
||||
| Switzerland | CH | de (official), gsw (de_facto_official), fr (official), it (official) | rm (official_regional) | PENDING |
|
||||
| Cyprus | CY | el (official), tr (official) | not recorded; further review required | PENDING |
|
||||
| Czechia | CZ | cs (official) | not recorded; further review required | PENDING |
|
||||
| Germany | DE | de (official) | frr (official_regional) | PENDING |
|
||||
| Denmark | DK | da (official) | de (official_regional), kl (official_regional) | PENDING |
|
||||
| Estonia | EE | et (official) | not recorded; further review required | PENDING |
|
||||
| Spain | ES | es (official) | ca (official_regional), gl (official_regional), eu (official_regional), ast (official_regional), oc (official_regional) | PENDING |
|
||||
| Finland | FI | fi (official), sv (official) | sms (official_regional) | PENDING |
|
||||
| Faroe Islands | FO | fo (official) | not recorded; further review required | PENDING |
|
||||
| France | FR | fr (official) | not recorded; further review required | PENDING |
|
||||
| United Kingdom | GB | en (official) | cy (official_regional), ga (official_regional), gd (official_regional) | PENDING |
|
||||
| Guernsey | GG | en (official) | not recorded; further review required | PENDING |
|
||||
| Gibraltar | GI | en (official) | not recorded; further review required | PENDING |
|
||||
| Greece | GR | el (official) | not recorded; further review required | PENDING |
|
||||
| Croatia | HR | hr (official) | it (official_regional), vec (official_regional) | PENDING |
|
||||
| Hungary | HU | hu (official) | not recorded; further review required | PENDING |
|
||||
| Ireland | IE | en (official), ga (official) | not recorded; further review required | PENDING |
|
||||
| Isle of Man | IM | en (official), gv (official) | not recorded; further review required | PENDING |
|
||||
| Iceland | IS | is (official) | not recorded; further review required | PENDING |
|
||||
| Italy | IT | it (official) | fr (official_regional), vec (official_regional) | PENDING |
|
||||
| Jersey | JE | en (official) | not recorded; further review required | PENDING |
|
||||
| Liechtenstein | LI | de (official), gsw (de_facto_official) | not recorded; further review required | PENDING |
|
||||
| Lithuania | LT | lt (official) | not recorded; further review required | PENDING |
|
||||
| Luxembourg | LU | fr (official), lb (official), de (official) | not recorded; further review required | PENDING |
|
||||
| Latvia | LV | lv (official) | not recorded; further review required | PENDING |
|
||||
| Monaco | MC | fr (official) | not recorded; further review required | PENDING |
|
||||
| Moldova | MD | ro (official) | not recorded; further review required | PENDING |
|
||||
| Montenegro | ME | sr-Latn (official) | not recorded; further review required | PENDING |
|
||||
| North Macedonia | MK | mk (official) | sq (official_regional) | PENDING |
|
||||
| Malta | MT | mt (official), en (official) | not recorded; further review required | PENDING |
|
||||
| Netherlands | NL | nl (official) | fy (official_regional) | PENDING |
|
||||
| Norway | NO | nb (official), no (official), nn (official) | se (official_regional) | PENDING |
|
||||
| Poland | PL | pl (official) | de (official_regional), csb (official_regional), lt (official_regional) | PENDING |
|
||||
| Portugal | PT | pt (official) | not recorded; further review required | PENDING |
|
||||
| Romania | RO | ro (official) | not recorded; further review required | PENDING |
|
||||
| Serbia | RS | sr (official), sr-Latn (official) | hu (official_regional), ro (official_regional), hr (official_regional), sk (official_regional), uk (official_regional) | PENDING |
|
||||
| Russia | RU | ru (official) | tt (official_regional), ce (official_regional), ba (official_regional), av (official_regional), kbd (official_regional), myv (official_regional), kum (official_regional), sah (official_regional), inh (official_regional), bua (official_regional), az-Cyrl (official_regional), lez (official_regional), mdf (official_regional), krc (official_regional), tyv (official_regional), udm (official_regional), ady (official_regional), kv (official_regional), lbe (official_regional), koi (official_regional) | PENDING |
|
||||
| Sweden | SE | sv (official) | fi (official_regional) | PENDING |
|
||||
| Slovenia | SI | sl (official) | vec (official_regional) | PENDING |
|
||||
| Svalbard & Jan Mayen | SJ | nb (official) | not recorded; further review required | PENDING |
|
||||
| Slovakia | SK | sk (official) | not recorded; further review required | PENDING |
|
||||
| San Marino | SM | it (official) | not recorded; further review required | PENDING |
|
||||
| Türkiye | TR | tr (official) | not recorded; further review required | PENDING |
|
||||
| Ukraine | UA | uk (official), ru (de_facto_official) | not recorded; further review required | PENDING |
|
||||
| Vatican City | VA | it (de_facto_official) | not recorded; further review required | PENDING |
|
||||
| Kosovo | XK | sq (official), sr (official), sr-Latn (official) | not recorded; further review required | PENDING |
|
||||
| Armenia | AM | hy (official) | not recorded; further review required | PENDING |
|
||||
| Azerbaijan | AZ | az (official), az-Cyrl (official) | not recorded; further review required | PENDING |
|
||||
| Georgia | GE | ka (official) | ab (official_regional), os (official_regional) | PENDING |
|
||||
| Kazakhstan | KZ | ru (official), kk (official) | not recorded; further review required | PENDING |
|
||||
| Greenland | GL | kl (official) | not recorded; further review required | PENDING |
|
||||
|
||||
## Scope and legal cross-check queue
|
||||
|
||||
Russia, Turkey, Cyprus, Armenia, Azerbaijan, Georgia and Kazakhstan are explicit geographic/market-review cases; inclusion here does not approve a market. Greenland, Faroe Islands, Aland, Crown dependencies, Gibraltar and Svalbard/Jan Mayen are separately considered territory contexts. This is an initial 59-code research envelope, not a claim to have exhausted every dependency or minority language.
|
||||
|
||||
Norway: [Language Act](https://lovdata.no/dokument/NLE/lov/2021-05-21-42) distinguishes Bokmal/Nynorsk and protected Sami/minority languages. Plan distinct nb-NO/nn-NO and investigate Sami/Kven review capacity; do not infer their status from the abbreviated CLDR row.
|
||||
|
||||
Switzerland: [federal multilingualism explanation](https://www.aboutswitzerland.eda.admin.ch/en/multilingualism) distinguishes national languages and official usage. Plan de-CH, fr-CH, it-CH and rm-CH with separate reviewers.
|
||||
|
||||
Serbia: [government constitution](https://www.srbija.gov.rs/tekst/56753/ustav-republike-srbije.php) establishes Serbian/Cyrillic official use. sr-Latn-RS remains an explicit product candidate, separately from sr-Cyrl-RS; not a claim of identical legal status. These source checks inform planning, not exhaustive legal clearance.
|
||||
|
||||
Regional/minority queue includes ca-ES, eu-ES, gl-ES, cy-GB, gd-GB, se-NO, smj-NO, sma-NO and fkv-NO. Country-specific recognition, applicable areas, reviewer capacity, orthography, fonts and locale-data support must be reviewed separately. No automatic mapping of Montenegrin to Serbian; cnr-ME remains a candidate requiring runtime/data validation.
|
||||
|
||||
## EU 24 language baseline
|
||||
|
||||
[EU official language list](https://european-union.europa.eu/principles-countries-history/languages_en), checked 2026-11-02: Bulgarian bg-BG; Croatian hr-HR; Czech cs-CZ; Danish da-DK; Dutch nl-NL; English en (preserve existing canonical ID; en-GB candidate); Estonian et-EE; Finnish fi-FI; French fr-FR; German de-DE; Greek el-GR; Hungarian hu-HU; Irish ga-IE; Italian it-IT; Latvian lv-LV; Lithuanian lt-LT; Maltese mt-MT; Polish pl-PL; Portuguese pt-PT; Romanian ro-RO; Slovak sk-SK; Slovenian sl-SI; Spanish es-ES; Swedish sv-SE. These locale choices are proposals, not mandated by the EU list.
|
||||
|
||||
## Proposed waves
|
||||
|
||||
Foundation candidates: preserve existing en/nb behavior, then nn-NO, sv-SE, da-DK, fi-FI and is-IS if reviewers exist. EU-24 next; broader national/script/region candidates thereafter. Actual usage analytics and reviewer allocation are unavailable, so no evidence-backed commercial ranking or promised dates are asserted. English fallback remains available irrespective of market.
|
||||
@@ -0,0 +1,319 @@
|
||||
{
|
||||
"baseline": "5cb903b989742b7a96cb22ddf4c0e24993b18980",
|
||||
"method": "TypeScript AST syntactic triage; no symbol resolution or runtime coverage claim",
|
||||
"filesScanned": 134,
|
||||
"entries": [
|
||||
{
|
||||
"file": "job-tracker-ui/src/App.tsx",
|
||||
"line": 488,
|
||||
"sourceSha256": "3b5645d12f2c92ed8999d7a072bd7d47fac77023d460a19a9b3bfc2a4191962f",
|
||||
"kind": "jsx-text",
|
||||
"text": "Session changed. Clearing this page…",
|
||||
"ownerComponent": "job-tracker-ui/src/App.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "localise-with-session-boundary-preservation",
|
||||
"translatorContext": "Alert rendered while old application tree is invalidated; preserve unmount/privacy behavior and avoid dependencies on the discarded session/provider tree."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/assets/JobbjaktMark.tsx",
|
||||
"line": 7,
|
||||
"sourceSha256": "5a539514876a66eaf17ec68eb7ce3d28c558384bc24ab76b61f73be8df754473",
|
||||
"kind": "jsx-attribute:aria-label",
|
||||
"text": "Jobbjakt",
|
||||
"ownerComponent": "job-tracker-ui/src/assets/JobbjaktMark.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "preserve-proper-name-or-example",
|
||||
"translatorContext": "Public brand/provider label or synthetic host example; not user content. Retain original spelling; localise surrounding guidance separately."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"line": 198,
|
||||
"sourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"kind": "jsx-text",
|
||||
"text": "· v",
|
||||
"ownerComponent": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "version-or-unit-formatting-review",
|
||||
"translatorContext": "Keep numeric/version identity; review locale number formatting and descriptive accessible labels. Do not translate user file/name data."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"line": 360,
|
||||
"sourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"kind": "jsx-text",
|
||||
"text": "KB",
|
||||
"ownerComponent": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "version-or-unit-formatting-review",
|
||||
"translatorContext": "Keep numeric/version identity; review locale number formatting and descriptive accessible labels. Do not translate user file/name data."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"line": 699,
|
||||
"sourceSha256": "25216c80ef92d519baad9e428a0e77390150605c1a3529a4809819d120661f29",
|
||||
"kind": "jsx-text",
|
||||
"text": "v",
|
||||
"ownerComponent": "job-tracker-ui/src/components/ApplicationAssets.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "version-or-unit-formatting-review",
|
||||
"translatorContext": "Keep numeric/version identity; review locale number formatting and descriptive accessible labels. Do not translate user file/name data."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/Attachments.tsx",
|
||||
"line": 361,
|
||||
"sourceSha256": "fe706526f36d92c10d2a0adfd7abb634d0ebee28f5d7e1794c590179b4fd884c",
|
||||
"kind": "jsx-attribute:title",
|
||||
"text": "pdf",
|
||||
"ownerComponent": "job-tracker-ui/src/components/Attachments.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "descriptive-localised-accessible-title",
|
||||
"translatorContext": "Attachment preview iframe title; describe document preview purpose, without exposing private filename in exported translator context."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/CoverLetterDocument.tsx",
|
||||
"line": 157,
|
||||
"sourceSha256": "17ea0c608db7bc05171fb3c44f378c1acaa78fbdd337f9330002ef6346b92546",
|
||||
"kind": "jsx-text",
|
||||
"text": "pt ·",
|
||||
"ownerComponent": "job-tracker-ui/src/components/CoverLetterDocument.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "version-or-unit-formatting-review",
|
||||
"translatorContext": "Keep numeric/version identity; review locale number formatting and descriptive accessible labels. Do not translate user file/name data."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/CoverLetterDocument.tsx",
|
||||
"line": 157,
|
||||
"sourceSha256": "17ea0c608db7bc05171fb3c44f378c1acaa78fbdd337f9330002ef6346b92546",
|
||||
"kind": "jsx-text",
|
||||
"text": "mm ·",
|
||||
"ownerComponent": "job-tracker-ui/src/components/CoverLetterDocument.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "version-or-unit-formatting-review",
|
||||
"translatorContext": "Keep numeric/version identity; review locale number formatting and descriptive accessible labels. Do not translate user file/name data."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/EmailProviderConnections.tsx",
|
||||
"line": 227,
|
||||
"sourceSha256": "b71228ee28ee73525014c8ece8690364e0f70ddaca3ee7211e9076123d120b1d",
|
||||
"kind": "jsx-attribute:label",
|
||||
"text": "Gmail",
|
||||
"ownerComponent": "job-tracker-ui/src/components/EmailProviderConnections.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "preserve-proper-name-or-example",
|
||||
"translatorContext": "Public brand/provider label or synthetic host example; not user content. Retain original spelling; localise surrounding guidance separately."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/EmailProviderConnections.tsx",
|
||||
"line": 239,
|
||||
"sourceSha256": "b71228ee28ee73525014c8ece8690364e0f70ddaca3ee7211e9076123d120b1d",
|
||||
"kind": "jsx-attribute:label",
|
||||
"text": "Outlook / Microsoft 365",
|
||||
"ownerComponent": "job-tracker-ui/src/components/EmailProviderConnections.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "preserve-proper-name-or-example",
|
||||
"translatorContext": "Public brand/provider label or synthetic host example; not user content. Retain original spelling; localise surrounding guidance separately."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/EmailProviderConnections.tsx",
|
||||
"line": 264,
|
||||
"sourceSha256": "b71228ee28ee73525014c8ece8690364e0f70ddaca3ee7211e9076123d120b1d",
|
||||
"kind": "jsx-attribute:placeholder",
|
||||
"text": "imap.example.com",
|
||||
"ownerComponent": "job-tracker-ui/src/components/EmailProviderConnections.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "preserve-proper-name-or-example",
|
||||
"translatorContext": "Public brand/provider label or synthetic host example; not user content. Retain original spelling; localise surrounding guidance separately."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/JobFlowBar.tsx",
|
||||
"line": 147,
|
||||
"sourceSha256": "643053f6ac883f23ef74c66def7a42678cd7917ed11ca802b11be25ec6df0cb2",
|
||||
"kind": "jsx-text",
|
||||
"text": "Flow",
|
||||
"ownerComponent": "job-tracker-ui/src/components/JobFlowBar.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "extract-controlled-label",
|
||||
"translatorContext": "Workflow overline in JobFlowBar; ordinary user-facing UI label, not a persisted status."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/components/QuickCommandDialog.tsx",
|
||||
"line": 166,
|
||||
"sourceSha256": "27cbbb8b8596fdf4e7474eccfdb6d9a8a219f4baff6a9b8013b825ce5fc2c411",
|
||||
"kind": "jsx-text",
|
||||
"text": "Ctrl/Cmd + K",
|
||||
"ownerComponent": "job-tracker-ui/src/components/QuickCommandDialog.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "version-or-unit-formatting-review",
|
||||
"translatorContext": "Keep numeric/version identity; review locale number formatting and descriptive accessible labels. Do not translate user file/name data."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"line": 312,
|
||||
"sourceSha256": "e75a58f2984bf47d7edc3c2c51439242aba2df32675a30b1f17088095ea1d634",
|
||||
"kind": "jsx-text",
|
||||
"text": "Jobbjakt",
|
||||
"ownerComponent": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "preserve-proper-name-or-example",
|
||||
"translatorContext": "Public brand/provider label or synthetic host example; not user content. Retain original spelling; localise surrounding guidance separately."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"line": 415,
|
||||
"sourceSha256": "e75a58f2984bf47d7edc3c2c51439242aba2df32675a30b1f17088095ea1d634",
|
||||
"kind": "jsx-text",
|
||||
"text": "Jobbjakt",
|
||||
"ownerComponent": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "preserve-proper-name-or-example",
|
||||
"translatorContext": "Public brand/provider label or synthetic host example; not user content. Retain original spelling; localise surrounding guidance separately."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"line": 563,
|
||||
"sourceSha256": "e75a58f2984bf47d7edc3c2c51439242aba2df32675a30b1f17088095ea1d634",
|
||||
"kind": "jsx-text",
|
||||
"text": "commit",
|
||||
"ownerComponent": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "localise-label-preserve-identifier",
|
||||
"translatorContext": "Technical display label may be translated; commit/job identifier remains invariant and must not enter translation resources."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"line": 692,
|
||||
"sourceSha256": "e75a58f2984bf47d7edc3c2c51439242aba2df32675a30b1f17088095ea1d634",
|
||||
"kind": "jsx-attribute:aria-label",
|
||||
"text": "English",
|
||||
"ownerComponent": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "locale-selector-contract",
|
||||
"translatorContext": "Replace ambiguous country-like abbreviation/undifferentiated Norwegian label only within approved locale-selector work; preserve current nb behavior and native labels."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"line": 692,
|
||||
"sourceSha256": "e75a58f2984bf47d7edc3c2c51439242aba2df32675a30b1f17088095ea1d634",
|
||||
"kind": "jsx-text",
|
||||
"text": "EN",
|
||||
"ownerComponent": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "locale-selector-contract",
|
||||
"translatorContext": "Replace ambiguous country-like abbreviation/undifferentiated Norwegian label only within approved locale-selector work; preserve current nb behavior and native labels."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"line": 693,
|
||||
"sourceSha256": "e75a58f2984bf47d7edc3c2c51439242aba2df32675a30b1f17088095ea1d634",
|
||||
"kind": "jsx-attribute:aria-label",
|
||||
"text": "Norsk",
|
||||
"ownerComponent": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "locale-selector-contract",
|
||||
"translatorContext": "Replace ambiguous country-like abbreviation/undifferentiated Norwegian label only within approved locale-selector work; preserve current nb behavior and native labels."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"line": 693,
|
||||
"sourceSha256": "e75a58f2984bf47d7edc3c2c51439242aba2df32675a30b1f17088095ea1d634",
|
||||
"kind": "jsx-text",
|
||||
"text": "NO",
|
||||
"ownerComponent": "job-tracker-ui/src/layout/AppShell.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "locale-selector-contract",
|
||||
"translatorContext": "Replace ambiguous country-like abbreviation/undifferentiated Norwegian label only within approved locale-selector work; preserve current nb behavior and native labels."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/AdminAuditPage.tsx",
|
||||
"line": 146,
|
||||
"sourceSha256": "b78d0c5f6ec86a4ee3d2214e6854e638d9f73a5c69c8d5b01023d8c60b46ac81",
|
||||
"kind": "jsx-text",
|
||||
"text": "jobId=",
|
||||
"ownerComponent": "job-tracker-ui/src/views/AdminAuditPage.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "localise-label-preserve-identifier",
|
||||
"translatorContext": "Technical display label may be translated; commit/job identifier remains invariant and must not enter translation resources."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/AdminUsersPage.tsx",
|
||||
"line": 274,
|
||||
"sourceSha256": "674290a26fc279a25e43176194716dea87f427d1885ecce70dea7c368ab0c6f8",
|
||||
"kind": "jsx-attribute:label",
|
||||
"text": "—",
|
||||
"ownerComponent": "job-tracker-ui/src/views/AdminUsersPage.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "empty-state-accessibility-review",
|
||||
"translatorContext": "No-role placeholder; visual glyph can stay but verify meaningful accessible context."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/LandingPage.tsx",
|
||||
"line": 99,
|
||||
"sourceSha256": "2c550aa126e1db8786ed10b895d2403491ce50bf5073fc95b8a0fcb0cb0e083e",
|
||||
"kind": "jsx-text",
|
||||
"text": "Jobbjakt",
|
||||
"ownerComponent": "job-tracker-ui/src/views/LandingPage.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "preserve-proper-name-or-example",
|
||||
"translatorContext": "Public brand/provider label or synthetic host example; not user content. Retain original spelling; localise surrounding guidance separately."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/LandingPage.tsx",
|
||||
"line": 133,
|
||||
"sourceSha256": "2c550aa126e1db8786ed10b895d2403491ce50bf5073fc95b8a0fcb0cb0e083e",
|
||||
"kind": "jsx-text",
|
||||
"text": "React · TypeScript · ASP.NET Core · EF Core · FastAPI AI · Gmail",
|
||||
"ownerComponent": "job-tracker-ui/src/views/LandingPage.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "launch-copy-review",
|
||||
"translatorContext": "Technology list is public brand names but poor user-value copy; coordinate replacement with Launch Site design approval."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/career/CareerProfileSections.tsx",
|
||||
"line": 100,
|
||||
"sourceSha256": "0c772feb6bde8324676b0884aaf343283465c5cd3b3318128363063df4ea22ab",
|
||||
"kind": "jsx-attribute:label",
|
||||
"text": "GitHub",
|
||||
"ownerComponent": "job-tracker-ui/src/views/career/CareerProfileSections.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "preserve-proper-name-or-example",
|
||||
"translatorContext": "Public brand/provider label or synthetic host example; not user content. Retain original spelling; localise surrounding guidance separately."
|
||||
},
|
||||
{
|
||||
"file": "job-tracker-ui/src/views/career/ProfileCompleteness.tsx",
|
||||
"line": 55,
|
||||
"sourceSha256": "95f017b1495cf9d88a2b69e7c6ae8ef83d55f2b1ad7b6f54895e280b147743b5",
|
||||
"kind": "jsx-text",
|
||||
"text": "v",
|
||||
"ownerComponent": "job-tracker-ui/src/views/career/ProfileCompleteness.tsx",
|
||||
"contextStatus": "source-context-reviewed; implementation-pending",
|
||||
"sensitivity": "public-ui-template; adjacent runtime identifiers excluded",
|
||||
"decision": "version-or-unit-formatting-review",
|
||||
"translatorContext": "Keep numeric/version identity; review locale number formatting and descriptive accessible labels. Do not translate user file/name data."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# Partial I18N-00 research handoff
|
||||
|
||||
Branch `feature/i18n-00-audit`, based on accepted conditional handoff `5cb903b989742b7a96cb22ddf4c0e24993b18980`. Only `docs/i18n/00/` changed. This checkpoint preserves research; I18N-00 acceptance remains IN_PROGRESS and I18N-01 implementation remains BLOCKED.
|
||||
|
||||
Completed: source-owner audit draft; ordered implementation contracts; source-bound English catalogue/static callers; initial 59-territory CLDR matrix; 60 planned locale candidates and schema; planning checks documented in BASELINE_TESTS.md. No locale translated, reviewed or released here.
|
||||
|
||||
Next authorised work, without implementation approval:
|
||||
|
||||
1. Resolve 188 dynamic/unknown calls, direct translation object access and wrappers. Review the 853 entries without static callers without treating them as unused.
|
||||
2. Inventory hardcoded frontend/ARIA/empty/error/export text and backend/Python/email/queue strings. Assign real namespace, translator context, parameter sensitivity and owning component rather than inferring from keys.
|
||||
3. Complete national/regional official-record checks beyond the initial Norway/Switzerland/Serbia checks. Expand territory/minority coverage where the current research envelope omits required contexts.
|
||||
4. Evaluate actual installed/locked library compatibility and Montenegrin canonicalisation before choosing a runtime migration. Do not install packages now.
|
||||
5. Obtain reviewer/market priorities when a concrete rollout proposal is ready. Keep human/native approval separate from planning completeness.
|
||||
|
||||
The delegated researcher was interrupted by a service usage limit; the parent continued, corrected references to nonexistent deliverables and produced the actual inventory/catalogue/matrix. No agent is working in the background. Full stage completion must not be inferred from the presence of the expected filenames.
|
||||
|
||||
Continuation: CONTEXT_TRIAGE.md records all 188 dynamic calls, 108 finite-branch resolutions (240 existing-key references), four direct catalogue reads and 26 source-context-reviewed JSX/accessibility literal candidates. Seven concrete planning findings I00-13 through I00-19 added. Remaining dynamic call queue is 80; prior 188 count is the original inventory total, not the remaining queue. No application changes.
|
||||
|
||||
Product tests NOT RUN; source equality and planning checks PASSED within their documented limits. Preserve existing PDF evidence. No application models, production services, orchestrator configuration or signing/approval material accessed.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Ordered implementation specification — not execution authority
|
||||
|
||||
## Proposed architecture decision
|
||||
|
||||
Keep existing `useI18n` call sites and React/MUI owners. Replace only its message evaluation/storage behind that contract after entry approval. Compare: current substitution is smallest but cannot meet plural/select requirements; i18next offers namespace loading and CLDR plural suffixes but changes interpolation/catalogue shape; FormatJS ICU supports complete sentence plural/select messages behind the current helper with less caller churn. **Proposed preference: ICU message evaluation behind the existing API plus platform Intl formatting**, subject to actual lockfile/runtime compatibility, bundle and extraction prototype after approval. Do not install either now. Do not implement two competing message engines. .NET renders server communications from its own typed templates with shared IDs/parameter contracts; do not assume identical ICU parser support in .NET/Python.
|
||||
|
||||
Sources checked 2026-11-02: https://www.i18next.com/translation-function/plurals and https://formatjs.github.io/docs/core-concepts/icu-syntax/. These establish syntax capabilities, not repository compatibility.
|
||||
|
||||
## Independent preference contract
|
||||
|
||||
Residence `countryId`, `searchCountryIds`, typed location IDs, `uiLocale`, `adLanguageFilters`, document `outputLocale`, optional `communicationLocale` and `timeZone` are distinct. Country changes only suggestion ordering. Manual saved preference wins over URL/app choice, onboarding, browser negotiation and English fallback. Explicitly distinguish signed-out local storage from account hydration. Persist provenance and revision semantics without weakening tenant ownership. Existing `en` stays canonical until an approved compatibility migration; `en-GB` is a candidate variant, not a silent rewrite. `nb/no/nb-NO` legacy aliases preserve existing Bokmål behavior. `nn-NO` must never silently map to Bokmål. `sr-Latn` and `sr-Cyrl` retain script identity. Unsupported locale resolves to reliable English chrome; user content unchanged.
|
||||
|
||||
## Stage sequence and evidence
|
||||
|
||||
| Stage | Bounded change after prerequisites | Required exit evidence |
|
||||
|---|---|---|
|
||||
| 00 | Finish contextual census, country legal cross-check, reviewer ownership | Complete source-bound inventory; independent schema validation; planning review |
|
||||
| 01 | Registry, aliases, separate preferences, migration, formatting | Legacy roundtrip, invalid IDs, tenant/multi-device conflicts, MariaDB migration/reversal; new locales hidden |
|
||||
| 02 | Extract full UI and accessible strings into existing owners | Required-key completeness, placeholder parser, dirty-form language switch, pseudo/long-label responsive tests |
|
||||
| 03 | Stable backend codes; queued communication templates | Event-time locale snapshot proposed, retry determinism, isolated Mailpit/plain/HTML tests, legal approvals |
|
||||
| 04 | Per-document headings/fonts, import boundaries | RD21/history invariance; script/PDF extraction and layout; native/physical review distinct |
|
||||
| 05 | GJ-owned geography/provider/search integration | All-industry synthetic fixtures, explicit alias suggestions, source language and rights/retention evidence |
|
||||
| 06 | Translation supply chain and glossary | Licensed source, translator context, independent proficient review, source-change invalidation |
|
||||
| 07 | Launch Site localisation/SEO contract | Approved visual design; published-only alternates/sitemaps; truthful feature/provider claims |
|
||||
| 08 | Cross-surface/native/device/security acceptance | Locale × surface × market × profession × device matrix; exact commit and disjoint counts |
|
||||
|
||||
Phase 10 completion/appropriate accepted handoff, PRODUCT-REVIEW-01, accepted I18N-00 and explicit stage authority precede I18N-01. Sequential accepted stage integration is mandatory. Separate development commits, no main merge/deploy.
|
||||
|
||||
GJ owns source fetch, rights, stable geography/occupation IDs and search mechanics; I18N owns display labels, ad-language semantics and translated-summary labels. ESCO concept identity cannot be replaced by translated free text. Original advertisement always remains distinguishable. Provider rights are checked before requests, not inferred from locale availability. Launch Site owns visual design/routing architecture; I18N supplies market+content-locale+publication schema and claims binding to deployed capability. Future fixtures may be designed now but no dependent runtime is invented.
|
||||
|
||||
Terminology queue: Career Profile (canonical facts), CV (document variant), cover letter, application (pursuit), job (opportunity), apprenticeship, shift, seasonal work, salary, qualification, nursing/teaching licence. Define each English concept before translation; profession label never establishes accreditation. Planned fixtures include teacher, cook, nurse, electrician, construction worker, driver, cleaner, retail, office administrator and developer.
|
||||
@@ -0,0 +1,846 @@
|
||||
{
|
||||
"baseline": "5cb903b989742b7a96cb22ddf4c0e24993b18980",
|
||||
"status": "research-draft",
|
||||
"locales": [
|
||||
{
|
||||
"tag": "en",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "en-GB",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "nb-NO",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "nn-NO",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "sv-SE",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "da-DK",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "fi-FI",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "is-IS",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "bg-BG",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "hr-HR",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "cs-CZ",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "nl-NL",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "et-EE",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "fr-FR",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "de-DE",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "el-GR",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "hu-HU",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "ga-IE",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "it-IT",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "lv-LV",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "lt-LT",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "mt-MT",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "pl-PL",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "pt-PT",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "ro-RO",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "sk-SK",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "sl-SI",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "es-ES",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "uk-UA",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "sq-AL",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "sr-Latn-RS",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "sr-Cyrl-RS",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "bs-BA",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "cnr-ME",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "mk-MK",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "tr-TR",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "lb-LU",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "cy-GB",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "rm-CH",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "fo-FO",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "be-BY",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "ka-GE",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "hy-AM",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "az-Latn-AZ",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "ru-RU",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "fr-CH",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "de-CH",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "it-CH",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "nl-BE",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "fr-BE",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "de-BE",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "en-IE",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "ca-ES",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "eu-ES",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "gl-ES",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "gd-GB",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "se-NO",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "smj-NO",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "sma-NO",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
},
|
||||
{
|
||||
"tag": "fkv-NO",
|
||||
"ownerRole": "localisation-product-owner",
|
||||
"reviewer": null,
|
||||
"status": "planned",
|
||||
"surfaces": {
|
||||
"ui": "planned",
|
||||
"backend": "planned",
|
||||
"communications": "planned",
|
||||
"documents": "planned",
|
||||
"jobDiscovery": "planned",
|
||||
"marketing": "planned"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Research-only locale catalogue; no release authority",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"baseline",
|
||||
"status",
|
||||
"locales"
|
||||
],
|
||||
"properties": {
|
||||
"baseline": {
|
||||
"const": "5cb903b989742b7a96cb22ddf4c0e24993b18980"
|
||||
},
|
||||
"status": {
|
||||
"const": "research-draft"
|
||||
},
|
||||
"locales": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"tag",
|
||||
"ownerRole",
|
||||
"reviewer",
|
||||
"status",
|
||||
"surfaces"
|
||||
],
|
||||
"properties": {
|
||||
"tag": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$"
|
||||
},
|
||||
"ownerRole": {
|
||||
"const": "localisation-product-owner"
|
||||
},
|
||||
"reviewer": {
|
||||
"type": "null"
|
||||
},
|
||||
"status": {
|
||||
"const": "planned"
|
||||
},
|
||||
"surfaces": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"ui",
|
||||
"backend",
|
||||
"communications",
|
||||
"documents",
|
||||
"jobDiscovery",
|
||||
"marketing"
|
||||
],
|
||||
"properties": {
|
||||
"ui": {
|
||||
"const": "planned"
|
||||
},
|
||||
"backend": {
|
||||
"const": "planned"
|
||||
},
|
||||
"communications": {
|
||||
"const": "planned"
|
||||
},
|
||||
"documents": {
|
||||
"const": "planned"
|
||||
},
|
||||
"jobDiscovery": {
|
||||
"const": "planned"
|
||||
},
|
||||
"marketing": {
|
||||
"const": "planned"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
||||
# Risks, blockers and independent approval
|
||||
|
||||
| ID | Risk / unresolved item | Owner and closure evidence |
|
||||
|---|---|---|
|
||||
| I00-01 | Catalogue scan is not every-string contextual inventory | UI/backend owners triage literals, all callers, runtime/ARIA/export states; no unknown required surface |
|
||||
| I00-02 | CLDR is not complete national/regional legal authority | Product research owner checks official country records, political/territory scope and versioned licence before activating suggestions |
|
||||
| I00-03 | No allocated translators/native reviewers | Product owner assigns named reviewers per locale/surface; critical legal/billing/security needs qualified review |
|
||||
| I00-04 | Implementation predecessor gates unresolved | Owner records Phase10/product review and explicit I18N entry against accepted baseline; this document cannot approve them |
|
||||
| I00-05 | Plurals, gender, inflection, word order | ICU whole-sentence contexts, Slavic/Irish/Welsh fixtures, native review; no fragment concatenation |
|
||||
| I00-06 | Turkish casing, Greek accents, Serbian script, names | Locale-aware search/display separate from invariant IDs; preserve original names and qualification titles |
|
||||
| I00-07 | Dates/timezones/DST, salary/currency | UTC storage, partial-date precision, explicit timezone; formatting never FX conversion |
|
||||
| I00-08 | Fonts/glyphs, RTL readiness, long labels | Licensed extended Latin/Greek/Cyrillic font tests, logical layout and focus; RTL activation only when approved |
|
||||
| I00-09 | Career fact loss, frozen PDF drift, stale writes | UI switch never mutates facts/history/undo; ApplicationAssetsService and revision contracts retained |
|
||||
| I00-10 | Private content external translation | No PII export; separately approved consent/contracts/data controls before external translation; no live-model calls |
|
||||
| I00-11 | Draft locale exposed as supported | Per-surface publication gate, English fallback; no selector/SEO claims from catalogue presence |
|
||||
| I00-12 | Backend literal errors and queue drift | Stable error codes, typed escaped params, deterministic event-time locale and retry tests |
|
||||
|
||||
Public release requires required-key completeness, syntax/placeholders/plurals and escaping checks, whole critical journeys, native/proficient review, accessibility/device/PDF tests, country/provider truthfulness, owner release decision and actual deployed identity. Status advances separately per surface: planned → draft/machine_draft → review_required → reviewed → qa_passed → release_approved → released. No generated JSON grants review or approval. Approval evidence must be externally controlled and source-bound. All catalogue entries here are `planned`; existing en/nb code presence is independently recorded, not relabelled as newly qualified release.
|
||||
|
||||
Human/native/legal/device/physical-print review: pending, not executed. Provider and live-model tests: not run. Implementation/release: not authorised. Independent planning can continue on I00-01/02 without waiting for runtime gates.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Surface inventory and message accounting
|
||||
|
||||
All rows need a source-bound contextual census before I18N-00 acceptance. Existing-catalogue inventory is in `MESSAGE_INVENTORY.json`; partial JSX/accessibility literals are now recorded in `FRONTEND_LITERAL_CANDIDATES.json`, with direct reads and dynamic calls in separate inventories. This is not a 100% coverage claim. Namespace assignments remain provisional until caller review; translator context cannot be inferred safely from key names alone. The AST inventory identifies syntactically named `t` calls, not symbol-resolved calls. See CONTEXT_TRIAGE.md for reviewed literal context and the 108 resolved conditional calls; 80 table/template/wrapper calls remain.
|
||||
|
||||
| Surface / proposed namespace | Source owner / inspection target | Content boundary and required evidence |
|
||||
|---|---|---|
|
||||
| Account, onboarding, recovery / auth | views LoginPage, ForgotPasswordPage, ResetPasswordPage, VerifyEmailPage; AuthController | Forms, ARIA, errors, consent, email templates, multi-device hydration; preserve token URLs |
|
||||
| Dashboard, navigation, mobile / app | App routing, dashboard components | Hidden/empty/loading/error states, keyboard labels, tooltips and layout expansion |
|
||||
| Jobs, discovery, applications / jobs | JobDiscoveryPage, ApplicationWorkspacePage; JobPipeline | Translate controlled status labels, never stored identity/status codes or original advertisements |
|
||||
| Career facts, imports / career | CareerProfilePage, career/CvImportReview, CvImportMappingEditor; CareerProfileService; Python app.py | Original facts and uncertainty remain; parser/script quality separate from UI coverage |
|
||||
| CV editor, templates, letters / documents | CvBuilderEditor, DocumentsPage; ThemedCvRenderer, CoverLetterDocumentRenderer, ApplicationAssetsService | Output locale independent; headings, dates, filename labels; preserve null-as-inherit and JobApplication.Version |
|
||||
| PDF, public CV / exports | PublicCvPage, PlaywrightCvPdfExporter, CvDocumentFonts | Font licence/glyph matrix, selectable text, physical print, frozen snapshots and public access |
|
||||
| Email, inbox, reminders / communications | CorrespondenceInboxPage, GmailReviewPage, SmtpEmailSender, FollowUpReminderHostedService | User correspondence is private content; subject/preheader/plain/HTML copy and queued locale policy |
|
||||
| Settings, linked accounts / settings | ConnectedAccountsPage, EmailProviderConnections | Provider names stay proper nouns; OAuth errors and cancellation need usable fallback |
|
||||
| Billing, subscriptions / billing | StripeBillingGateway, entitlement UI | Amount and currency invariant; legal/tax wording needs qualified approval |
|
||||
| Admin and operations / admin | AdminUsersPage, AdminSystemPage, AdminProcessingPage, AdminAuditPage, OperationsPage; OperationEventLog | Stable diagnostic codes; localized presentation without multilingual log parsing or PII leaks |
|
||||
| Analytics, comparisons / analytics | AnalyticsPage, OfferComparisonPage | Plurals, dates, currency and accessible chart/table labels |
|
||||
| Marketing, SEO, legal / public | LandingPage, RouteErrorPage, NotFoundPage; future Launch Site | No locale claims, hreflang or indexing for draft pages; owner mockup gate untouched |
|
||||
| Backend/API/queues / errors | Controllers, UserNotificationStore, AiOperationQueue, CvProcessingQueue | Stable code plus typed parameters; UTC storage; deterministic queue-recipient locale |
|
||||
| Python/AI / processing | tools/summarizer/app.py | Machine codes vs user text, validation and document-language metadata; no live-model qualification |
|
||||
|
||||
For each required message record: stable ID, namespace, exact source, source hash/line, all callers, English text, context/screenshot, typed placeholders, plural/select variants, sensitivity, owner, translator and independent review state. Sensitive values are runtime parameters, never translation exports. Static public UI text is eligible; names, CV facts, messages, tokens, job ads and employer claims are not automatically translated. Existing flat keys remain stable through migration; do not bulk rename for aesthetics.
|
||||
Reference in New Issue
Block a user