Skip to content

feat(i18n): complete catalog parity and runtime localization - #973

Open
trac3r00 wants to merge 6 commits into
release/product-value-20260912-03from
release/product-value-20260912-04
Open

trac3r00 wants to merge 6 commits into
release/product-value-20260912-03from
release/product-value-20260912-04

Conversation

@trac3r00

@trac3r00 trac3r00 commented Sep 12, 2026 •

Copy link
Copy Markdown
Owner

Summary

feat(i18n): complete catalog parity and runtime localization. This is logical change 4/11 in the dependency-ordered product-audit release stack.

Refs #969

What changed

  • feat(i18n): complete catalog parity and runtime localization
  • Exact source commit: dd3135661e3d728152724f807d6d8d1c2a2e4f49; validated tree: 9f71693e7667635c7a4eed1d96bf8d8eafa50652.
  • Depends on the preceding release-stack PR. Retarget to main only after its dependency is merged and deployed.

Why

Make related tools, Cron output, Regex explanations, and CIDR messages consistent across ten supported locales.

Verification

  • bun run build passed on this exact candidate tree.
  • npm test -- --maxWorkers=2 passed on this exact candidate tree.
  • Affected behavior manually exercised as described below.
  • Latest GitHub Build, Unit Tests (Vitest), and E2E Tests (Playwright) must all pass before merge.
Tests  758 passed (758)
CANDIDATE_BUILD_UNIT_GREEN
Committed tree equals validated tree: 9f71693e7667635c7a4eed1d96bf8d8eafa50652

Three browser tests traversed all ten locales; 247 backfill keys per locale checked and generators were byte-stable.

Final combined tree additionally passed 801 unit tests and all 293 Playwright tests with retries disabled, plus all 48 primary tool workflows at desktop and mobile. The exploratory Color Converter exact-HEX boundary remains a documented pre-existing defect; its runtime is unchanged by this stack.

Risk & rollback

  • Risk: Dependent commits require earlier stack changes; merge in order.
  • Rollback: revert this PR through a new PR; do not revert dependencies beneath already-merged dependents.
  • Release: require an approving review and latest-SHA CI. Respect the 15-minute soak between deploy-affecting merges and verify the production deployment before continuing.

Summary by cubic

Completes catalog parity across all 10 locales and localizes Cron builder, Regex explanations, CIDR messages, and related-tool cards at runtime so those surfaces no longer fall back to English. Refs #969. This PR is part of a dependency-ordered release stack; merge after its preceding PR.

Runtime localization

  • Passes the route language to the related-tools section on every tool page so cards render translated server-side; related card links now preserve the route language via withLanguageQuery.
  • Replaces hardcoded English in Cron builder, Regex visualizer, CIDR messages, and related-tool cards with catalog lookups; cron field text is inserted literally by the runtime translator.
  • Fixes mismatched tooltip keys in the CSS gradient generator and the cheatsheet id in the markdown editor, plus French and Japanese string defects.
  • Merges the base branch's layout fix (related-tools section inside the content wrapper, oauth-debugger's empty mt-8 div dropped) with the currentLang argument.

Catalog tooling and tests

  • Adds i18n-tool-backfill.mjs and i18n-catalog-additions.mjs with per-locale JSON backfill files to keep the 10 catalogs in sync; pins acorn at 8.16.0 and compares backfill placeholders as an order-independent multiset.
  • Aligns the es/de repos.yml placeholder with the generator so all ten locales deep-equal regenerated output.
  • Adds catalog parity, runtime i18n, and E2E tests covering all locales; the rendered-keys guard now resolves prefixed _t helper call keys, and new tests assert every related-tools section renders, keeps the language on its links, and a concrete ?lang= link contract.

Written for commit fb798fa. Summary will update on new commits.

Review in cubic

Keep related cards, Cron output and Regex explanations localized. Supply missing CIDR runtime keys rather than regress callsites to English literals.

Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 38 files

Confidence score: 5/5

  • src/i18n/catalog-parity.test.js checks locale leaf-key paths but not their values, so English fallbacks or empty translations could go undetected; add assertions that verify translated string values.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/i18n/catalog-parity.test.js">

<violation number="1" location="src/i18n/catalog-parity.test.js:66">
P3: The "keeps exact nested leaf-key parity" test compares only leaf key paths, never the string values beneath them. A locale whose `tools.*`/`nav`/`common` values regressed to English (or to empty strings) would still pass as long as the key structure matches English, so the full catalog can ship untranslated without this test failing. Value-level (untranslated/empty) checking exists only for the four embedded tools in `embedded-tools.test.js`; the 48 active tools get no such coverage. Add a per-locale check that every non-English leaf value differs from the English value (with an allowlist for shared literals like standards names), mirroring the untranslated detection already used for the embedded tools.</violation>
</file>

Shadow auto-approve: would not auto-approve because issues were found.

Re-trigger cubic

Comment thread src/routes/cron-builder.runtime-i18n.test.js Outdated
Comment thread src/utils/content-ui.js
Comment thread src/routes/cron-builder.js Outdated
Comment thread scripts/i18n-tool-backfill.mjs Outdated
Comment thread src/i18n/rendered-keys.test.js
Comment thread scripts/i18n-tool-backfill/fr.json Outdated
Comment thread src/routes/regex-visualizer-i18n.test.js Outdated
@@ -0,0 +1,93 @@
// @vitest-environment node

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The "keeps exact nested leaf-key parity" test compares only leaf key paths, never the string values beneath them. A locale whose tools.*/nav/common values regressed to English (or to empty strings) would still pass as long as the key structure matches English, so the full catalog can ship untranslated without this test failing. Value-level (untranslated/empty) checking exists only for the four embedded tools in embedded-tools.test.js; the 48 active tools get no such coverage. Add a per-locale check that every non-English leaf value differs from the English value (with an allowlist for shared literals like standards names), mirroring the untranslated detection already used for the embedded tools.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/i18n/catalog-parity.test.js, line 66:

<comment>The "keeps exact nested leaf-key parity" test compares only leaf key paths, never the string values beneath them. A locale whose `tools.*`/`nav`/`common` values regressed to English (or to empty strings) would still pass as long as the key structure matches English, so the full catalog can ship untranslated without this test failing. Value-level (untranslated/empty) checking exists only for the four embedded tools in `embedded-tools.test.js`; the 48 active tools get no such coverage. Add a per-locale check that every non-English leaf value differs from the English value (with an allowlist for shared literals like standards names), mirroring the untranslated detection already used for the embedded tools.</comment>

<file context>
@@ -0,0 +1,93 @@
+    expect(englishLeaves.length).toBeGreaterThan(2500);
+
+    for (const [locale, catalog] of Object.entries(CATALOGS)) {
+      expect(leafPaths(catalog).sort(), `${locale} leaf keys`).toEqual(
+        englishLeaves,
+      );
</file context>

Comment thread src/i18n/ja.js Outdated
Comment thread tests/e2e/runtime-i18n.spec.js
- pass the route language to every related-tools section (server render)
- insert cron field text literally in the runtime translator
- compare backfill placeholders as an order-independent multiset
- resolve prefixed _t helper call keys in the rendered-keys guard
- test cron runtime i18n via parsed scripts and a non-English render
- replace not-equal-to-English checks with empty/placeholder parity
- fix fr 1er janvier, ja バイト and ja {{logs}} example
- report locale, pattern, observed and expected on e2e mutation timeout

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 59 files (changes from recent commits).

Confidence score: 5/5

  • In src/i18n/rendered-keys.test.js, the if (related) gate can silently skip the related-tools locale assertion when markup differs from the regex’s expected <section>-to-<h2> adjacency, leaving that label unchecked; make the match robust and ensure the assertion runs.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/i18n/rendered-keys.test.js">

<violation number="1" location="src/i18n/rendered-keys.test.js:126">
P3: The related-tools locale assertion at the bottom of the test is gated by `if (related)` on a regex that requires `<section ... aria-label="Related tools">` to be directly followed by `<h2>`. If the shared section markup ever changes shape (h2 wrapped in a `<header>`/`<div>`, heading element renamed, extra attributes before `aria-label`), the regex stops matching and the check silently no-ops for every tool — the exact route-language regression this fix targets would no longer be detected. Consider asserting on the section's presence for tools that declare related tools (e.g., from the `relatedTools` registry data) rather than only comparing when the regex happens to match.</violation>
</file>

Shadow auto-approve: would not auto-approve because issues were found.

Re-trigger cubic

Comment thread src/routes/json-formatter.js
Comment thread src/i18n/rendered-keys.test.js Outdated
const related = html.match(
/<section[^>]*aria-label="Related tools"[^>]*>\s*<h2[^>]*>([^<]*)<\/h2>/,
);
if (related) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The related-tools locale assertion at the bottom of the test is gated by if (related) on a regex that requires <section ... aria-label="Related tools"> to be directly followed by <h2>. If the shared section markup ever changes shape (h2 wrapped in a <header>/<div>, heading element renamed, extra attributes before aria-label), the regex stops matching and the check silently no-ops for every tool — the exact route-language regression this fix targets would no longer be detected. Consider asserting on the section's presence for tools that declare related tools (e.g., from the relatedTools registry data) rather than only comparing when the regex happens to match.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/i18n/rendered-keys.test.js, line 126:

<comment>The related-tools locale assertion at the bottom of the test is gated by `if (related)` on a regex that requires `<section ... aria-label="Related tools">` to be directly followed by `<h2>`. If the shared section markup ever changes shape (h2 wrapped in a `<header>`/`<div>`, heading element renamed, extra attributes before `aria-label`), the regex stops matching and the check silently no-ops for every tool — the exact route-language regression this fix targets would no longer be detected. Consider asserting on the section's presence for tools that declare related tools (e.g., from the `relatedTools` registry data) rather than only comparing when the regex happens to match.</comment>

<file context>
@@ -92,6 +118,16 @@ describe("rendered translation keys", () => {
+        const related = html.match(
+          /<section[^>]*aria-label="Related tools"[^>]*>\s*<h2[^>]*>([^<]*)<\/h2>/,
+        );
+        if (related) {
+          expect(related[1], `${tool.id} ${locale} related tools heading`).toBe(
+            resolveKey(catalog, "content.relatedTools"),
</file context>

- build related card hrefs with withLanguageQuery(tool.path, lang)
- assert every rendered related section (no silent skip) and its link lang

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files (changes from recent commits).

Shadow auto-approve: would not auto-approve because issues were found.
Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/utils/content-ui.test.js Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Shadow auto-approve: would not auto-approve. Auto-approval blocked by 2 unresolved issues from previous reviews.

Re-trigger cubic

…-value-20260912-04

Resolve conflicts in 7 route files by keeping the base's layout fix (related-tools section inside the content wrapper, oauth-debugger's empty mt-8 div dropped) together with this branch's currentLang argument for createRelatedToolsSection.
tools.public-repos-yml-builder.ui.placeholder2 is a YAML code sample that scripts/i18n-embedded-tools.mjs keeps as 'name: Public repos audit' in every locale. es/de carried a translated literal from the bulk catalog translation, so regenerating the catalogs reverted it and generated-catalog parity was 8/10. Align both to the generator; all ten locales now deep-equal the regenerated output.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 2 files (changes from recent commits).

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Shadow auto-approve: would not auto-approve. Auto-approval blocked by 2 unresolved issues from previous reviews.

Re-trigger cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant