Skip to content
Open
Show file tree
Hide file tree
Changes from 189 commits
Commits
Show all changes
195 commits
Select commit Hold shift + click to select a range
f78fe06
Create locale switcher component
finnar-bin Jun 8, 2026
72a792f
Set default html lang to 'en-US'
finnar-bin Jun 8, 2026
835931c
Localization: Set up i18next infrastructure (Phase 1)
finnar-bin Jun 8, 2026
b721565
Update implementation plan
finnar-bin Jun 8, 2026
3fe16c4
Localization: Wire locale switcher to i18n and persist user preferenc…
finnar-bin Jun 8, 2026
d93ca1e
Updated implementation plan and defaultValue
finnar-bin Jun 9, 2026
f0777b5
Localization: Add common namespace t() calls and fix locale file gene…
finnar-bin Jun 9, 2026
966b6cb
Fix TypeScript 5 compile errors
finnar-bin Jun 9, 2026
99a8637
Added empty shell.json files
finnar-bin Jun 9, 2026
a982369
Resolve UI flicker caused by Suspense when loading the locale files
finnar-bin Jun 9, 2026
9c2877e
Added translations to non-English common namespaces
finnar-bin Jun 9, 2026
c0d70f4
Remove cache expiration time override
finnar-bin Jun 9, 2026
da8cabc
Localization: Remove defaultValue props from common t() calls and upd…
finnar-bin Jun 9, 2026
677a296
Add zed editor settings to gitignore
finnar-bin Jun 9, 2026
7b92ad9
Localization: Complete shell Tier 1 components and expand common name…
finnar-bin Jun 9, 2026
364861d
Localization: Remove defaultValue from Tier 1 shell t() calls and upd…
finnar-bin Jun 9, 2026
02f6a20
Localization: Translate global menu labels, tooltips, and sidebar com…
finnar-bin Jun 9, 2026
8fe5fca
Added translation for tier 1 additional components
finnar-bin Jun 10, 2026
4accc3d
Localization: Apply logged-in user's locale on account switch
finnar-bin Jun 10, 2026
bef46f2
Localization: Complete shell Tier 2 components and RoleAccessInfo
finnar-bin Jun 10, 2026
d2f8ce5
Fixed global topbar overlapping locale switcher
finnar-bin Jun 11, 2026
63c1e8b
Translate locale switcher tooltip
finnar-bin Jun 11, 2026
863ea0f
Translate shell tier 3
finnar-bin Jun 11, 2026
2c18b44
Localize shell search empty states
finnar-bin Jun 11, 2026
d02b41d
Update LOCALIZATION_PLAN.md
finnar-bin Jun 11, 2026
4d03276
Localize missed shell phase 3 items
finnar-bin Jun 11, 2026
86ff508
Localize date display strings
finnar-bin Jun 11, 2026
b22dfa0
Add repository contributor guide
finnar-bin Jun 11, 2026
76f3c94
Update LOCALIZATION_PLAN.md
finnar-bin Jun 11, 2026
a46730f
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jun 11, 2026
1c037ef
Dashboard: localize home sub-app and consolidate shared nouns into co…
finnar-bin Jun 16, 2026
f40b5dc
Shell: group i18n modules under shell/i18n and localize Data Grid chrome
finnar-bin Jun 16, 2026
2bcda96
Shell: surface missing translation keys (i18n Phase 6)
finnar-bin Jun 16, 2026
c34f99b
Docs: add Phase 5 third-party component localization plan
finnar-bin Jun 16, 2026
7a81f34
Docs: add Phase 4/5 execution order and MUI X version-bump guardrail
finnar-bin Jun 16, 2026
1a14d79
Shell: reactive MUI locale theme (localization Phase 5 step 1)
finnar-bin Jun 16, 2026
364d161
Media: localize media namespace + consolidate shared strings to common
finnar-bin Jun 17, 2026
f699dc0
Docs: add content namespace sub-pass breakdown + slice 1 pre-audit
finnar-bin Jun 17, 2026
e1f7383
[Settings] - Localize Bynder compact view
finnar-bin Jun 17, 2026
9e23cbb
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jun 17, 2026
028b68f
Content: localize Editor + Field shell (content namespace sub-pass 1)
finnar-bin Jun 17, 2026
08febac
Docs: add content sub-pass 8 + tab-to-sub-pass mapping
finnar-bin Jun 17, 2026
4526357
Shell: localize field-type widgets
finnar-bin Jun 17, 2026
4f38243
localized relational field base
finnar-bin Jun 17, 2026
3ed32c6
[Localization] - Field integration widgets
finnar-bin Jun 17, 2026
f24457a
[Localization] - Improve dev translation loading
finnar-bin Jun 17, 2026
12ec022
Update LOCALIZATION_PLAN.md
finnar-bin Jun 17, 2026
70da793
[Localization] - Field type widget copy
finnar-bin Jun 17, 2026
46bdb34
[Localization] - FieldTypeEditor / ProseMirror widget copy
finnar-bin Jun 17, 2026
fbbe2aa
[Localization] - FieldTypeRepeater widget copy
finnar-bin Jun 17, 2026
e2ad37d
[Localization] - Phase 3 shell audit backfill
finnar-bin Jun 18, 2026
8a86657
Translate ItemList
finnar-bin Jun 18, 2026
e1c050b
[Content] - Localize ItemEdit chrome and action widgets
finnar-bin Jun 18, 2026
2131d5c
[Content] - Localize ItemEdit SEO/meta panel
finnar-bin Jun 18, 2026
f4d067a
Content: Localize ItemCreate, Link create/edit, and NotFound views
finnar-bin Jun 18, 2026
673861b
Content: Localize Analytics, CSVImport, and Redirects views
finnar-bin Jun 18, 2026
f76b11f
Update LOCALIZATION_PLAN.md
finnar-bin Jun 18, 2026
7004fbf
Updated and refined the plan and tasks board
finnar-bin Jun 19, 2026
6cd779b
[Content] - Localize content nav, Studio, and FieldTypeMedia (sub-passes
finnar-bin Jun 19, 2026
3fafd2d
Localize schema app
finnar-bin Jun 22, 2026
5883cf3
Fixed ts errors
finnar-bin Jun 22, 2026
99fc7db
localize redirects app
finnar-bin Jun 22, 2026
590c123
localize subapp workflow
finnar-bin Jun 22, 2026
e932377
Localize leads app
finnar-bin Jun 22, 2026
a7f54df
optimize orchestrator
finnar-bin Jun 22, 2026
0219307
Localize reports app
finnar-bin Jun 23, 2026
6e8057c
Localize settings app
finnar-bin Jun 23, 2026
9fa3036
update localize subapp
finnar-bin Jun 24, 2026
ebd6e55
localize code app
finnar-bin Jun 24, 2026
2b8148d
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jun 24, 2026
b49a3fd
Added new translations
finnar-bin Jun 24, 2026
94e51a4
localize release app
finnar-bin Jun 24, 2026
d77f354
localize active-preview
finnar-bin Jun 24, 2026
c438d61
translate blocks app
finnar-bin Jun 24, 2026
75d6dca
localize starter blocks
finnar-bin Jun 24, 2026
2cff4f0
localize marketplace
finnar-bin Jun 25, 2026
3e351f6
Wrap up subapps
finnar-bin Jun 25, 2026
82bad72
upstream mui-related localization to @zesty-io/material
finnar-bin Jun 25, 2026
2ffdeda
Add subappskeleton loader as suspense fallback when loading translation
finnar-bin Jun 25, 2026
8da2b59
Update LOCALIZATION_TASKS.md
finnar-bin Jun 25, 2026
d3493e4
Update translation values to ensure we're following the discussed do's
finnar-bin Jun 25, 2026
2cbe7ac
Resolve text transform
finnar-bin Jun 25, 2026
787faf2
[Localization] - Enforce translation value formatting rules across all
finnar-bin Jun 25, 2026
453b3c4
Resolve app crash when hovering field tooltip
finnar-bin Jun 26, 2026
e5a3f02
Dashboard and shell css fixes
finnar-bin Jun 26, 2026
78dc0cc
ensure memoized data get translated when changing languages
finnar-bin Jun 26, 2026
6db8c83
item edit
finnar-bin Jun 26, 2026
d608f9d
Refine error handling for missing namespaces
finnar-bin Jun 29, 2026
5af20d0
Resolve css issues
finnar-bin Jun 29, 2026
439bc00
Prevent browser cache from serving stale locale json files
finnar-bin Jun 29, 2026
af086b2
Schema css fixes
finnar-bin Jun 29, 2026
37a6b6e
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jun 29, 2026
5a549d4
Update configs.ts
finnar-bin Jun 29, 2026
464d471
Code app css fixes
finnar-bin Jun 30, 2026
cca10b1
Settings app css fixes
finnar-bin Jun 30, 2026
3880714
releases css fix
finnar-bin Jun 30, 2026
3104162
Further head css fixes
finnar-bin Jun 30, 2026
ffa34c4
translate redux notifications
finnar-bin Jul 1, 2026
f489dbe
Preload all namespaces on boot by default
finnar-bin Jul 1, 2026
4302462
active-preview css fixes
finnar-bin Jul 1, 2026
a435eaf
Add navigator.language to fallback chain
finnar-bin Jul 1, 2026
5f899b3
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 1, 2026
d498b48
Translate new studio changes
finnar-bin Jul 1, 2026
d5f59de
Resolve gaps in translation
finnar-bin Jul 1, 2026
9784520
Updated localize workflow and added details on readme
finnar-bin Jul 1, 2026
0a9378b
Translate used blocks
finnar-bin Jul 1, 2026
f35aa4a
Update content.json
finnar-bin Jul 1, 2026
3ee9beb
Update README.md
finnar-bin Jul 1, 2026
9273e5f
Translate tab names
finnar-bin Jul 1, 2026
e9fec3a
wire i18next-parser and resolved translation gaps
finnar-bin Jul 1, 2026
f6c5478
updated claude and readme
finnar-bin Jul 1, 2026
7209d4f
Remove old unused files
finnar-bin Jul 1, 2026
3aa1926
Extend auto reviewer to also perform i18n-related review
finnar-bin Jul 1, 2026
0ee2c0e
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 2, 2026
ab624c3
Fix failing test
finnar-bin Jul 2, 2026
95d2923
Resolve incorrect plural grammar
finnar-bin Jul 3, 2026
0e977b5
Fixed failing tests
finnar-bin Jul 3, 2026
c33860a
Create sub-app-translations.spec.js
finnar-bin Jul 3, 2026
628f3cc
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 3, 2026
4bc19fc
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 7, 2026
258cc24
Translated settings fields
finnar-bin Jul 7, 2026
ba75d60
Translate style categories
finnar-bin Jul 7, 2026
63b0441
Translate sso button
finnar-bin Jul 7, 2026
3b2d3eb
add spacing and center items
finnar-bin Jul 7, 2026
6e33abd
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 8, 2026
5b430d0
Remove Locale Switcher
finnar-bin Jul 8, 2026
d514f19
Increase auto reviewer turns to 50
finnar-bin Jul 8, 2026
4f14dca
Resolve autoreviewer comments
finnar-bin Jul 8, 2026
06bc41f
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 9, 2026
9c97f77
Make sure that locale string stored in database is actually a supported
finnar-bin Jul 9, 2026
8627234
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 9, 2026
b9e2321
Delete AGENTS.md
finnar-bin Jul 13, 2026
fa80270
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 13, 2026
ff5010e
Track selected locale in sentry amplitude
finnar-bin Jul 13, 2026
ca1efc9
Update src/shell/i18n/index.ts
finnar-bin Jul 14, 2026
663a8ff
Add mui theme translation helper
finnar-bin Jul 14, 2026
ded09e9
Delete Translation_Rules.md
finnar-bin Jul 14, 2026
274f941
Shell - Address PR review nits (caps, colons, mistranslation, redunda…
finnar-bin Jul 14, 2026
e1d58a6
Shell - Fix i18n init syntax error, dead key, stale comment
finnar-bin Jul 14, 2026
b136b10
Shell - Simplify locale-switcher comment in i18n spec
finnar-bin Jul 14, 2026
dc32447
Fix mui-locale wildcard imports blocking tree-shaking
finnar-bin Jul 14, 2026
2bb9cfa
Shell - Skip webpack filesystem cache in CI
finnar-bin Jul 14, 2026
15928d9
Shell - Address remaining i18n PR review comments
finnar-bin Jul 15, 2026
3491d06
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 15, 2026
8a39824
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 20, 2026
552f944
Bump @zesty-io/material
finnar-bin Jul 20, 2026
7d0efbc
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 21, 2026
1f4a478
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 22, 2026
2fff458
Update CLAUDE.md
finnar-bin Jul 22, 2026
00ddcc3
Added tests to address cypress gaps
finnar-bin Jul 22, 2026
a5267a3
Added claude i18n verifier workflow
finnar-bin Jul 22, 2026
6470109
Add 200kb limit to gh diff check
finnar-bin Jul 22, 2026
5e96389
Change order of priority on how to check gh diff
finnar-bin Jul 22, 2026
50afeba
Deterministic inline comments, fixed false-positive broken-key checks,
finnar-bin Jul 22, 2026
04066e6
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 23, 2026
59e9f6a
Merge branch 'feat/4148-product-localization' into test/i18n-verifier…
finnar-bin Jul 23, 2026
bd59bbe
Keep the bullet point succint
finnar-bin Jul 23, 2026
1517a86
Test hardcoded string capture
finnar-bin Jul 23, 2026
5e0aec2
Revert test change
finnar-bin Jul 23, 2026
e833c9e
renamed workflow to localization instead of i18n
finnar-bin Jul 23, 2026
01f8065
Clean up comments and revert diff file back to 200kb cap
finnar-bin Jul 23, 2026
66bbd8c
Translate missed out strings
finnar-bin Jul 23, 2026
ed71bfb
Remove (TEST) tag
finnar-bin Jul 23, 2026
7a32e8c
Resolve pr review comments
finnar-bin Jul 23, 2026
17a7934
Fixed bug with html lang not being set properly
finnar-bin Jul 23, 2026
df32adb
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 24, 2026
914aa79
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 27, 2026
92c0241
Localization - Fix hardcoded date connectors and untranslated strings…
finnar-bin Jul 28, 2026
66dab7b
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Jul 31, 2026
24f7ef4
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 3, 2026
3898bde
Fixed missed file from being translated
finnar-bin Aug 3, 2026
ad48d38
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 3, 2026
ae364cd
Update blocks.json
finnar-bin Aug 3, 2026
25bd1a6
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 4, 2026
66370c2
Update RoleAccessInfo.tsx
finnar-bin Aug 4, 2026
878528d
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 5, 2026
82501b3
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 5, 2026
94b4a5e
Resolve review comments
finnar-bin Aug 6, 2026
e9aceaa
Update workflow so it posts a new comment every time it performs a
finnar-bin Aug 6, 2026
eec07d2
Pin model to sonnet 5
finnar-bin Aug 6, 2026
0099812
Fixed incorrect file location in docs
finnar-bin Aug 6, 2026
d0b716a
Update workflow so comment format is kind of similar to the auto
finnar-bin Aug 6, 2026
2fdb7af
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 10, 2026
78eddcc
Studio - Localize the Save All / Save & Publish All toast messages
finnar-bin Aug 11, 2026
4949368
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 11, 2026
afd83ac
Code Editor - Fix Instant JSON preview link reusing the webpage-previ…
finnar-bin Aug 11, 2026
8187133
CI - Change Verifier reads the PR description, not just the linked issue
finnar-bin Aug 11, 2026
ea6c13c
Revert "CI - Change Verifier reads the PR description, not just the l…
finnar-bin Aug 11, 2026
67eb674
Shell - Resolve remaining localization reviewer findings
finnar-bin Aug 12, 2026
bd46f07
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 12, 2026
92078c8
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 19, 2026
2cbdba5
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 24, 2026
4cb5726
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 24, 2026
d87aa24
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Aug 31, 2026
b8c27dc
Merge branch 'dev' into feat/4148-product-localization
finnar-bin Sep 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
920 changes: 920 additions & 0 deletions .claude/workflows/localize.js

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions .github/workflows/claude-auto-reviewer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ jobs:
PR_NUMBER = ${{ github.event.pull_request.number }}
REPORT_FILE = ${{ github.workspace }}/review-comment.md

Note: The PR branch is already checked out in the current working directory.
Localization compliance is reviewed separately by the "Claude Localization Reviewer"
workflow — don't duplicate that review here.

Read the diff (gh pr diff <PR_NUMBER> --repo <REPO>) and the checked-out source, and
look only for, in priority order:
1. Bugs — logic errors, crashes, broken edge cases, regressions.
Expand Down
242 changes: 242 additions & 0 deletions .github/workflows/claude-localization-reviewer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
name: Claude Localization Reviewer

# Dedicated localization gap check for PRs into dev that touch source or locale files.
# 1. ci/scripts/check_localization_objective.js: deterministic checks — TypeScript
# errors, locale JSON validity, cross-locale key parity, broken t()/i18n.t() refs.
# 2. Claude reviews the diff for what only language/intent can catch: missed t()
# wiring, value-formatting violations, and translation quality.
# Posts inline PR comments plus a summary comment; fails on any finding. Each run posts a
# fresh summary comment (deliberately NOT updated in place) so the PR timeline shows the
# review history: "FAIL" → fix commits → "PASS" — mirrors claude-auto-reviewer.yml.

on:
pull_request:
branches: [dev]
types: [opened, synchronize, reopened, ready_for_review]

jobs:
verify:
# Fork PRs don't get ANTHROPIC_API_KEY; this uses pull_request (not pull_request_target).
if: >-
github.event.pull_request.draft == false &&
github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
timeout-minutes: 15
concurrency:
group: claude-localization-reviewer-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 1

# Skip everything below on PRs that don't touch translatable source or locale files.
- name: Detect relevant changes
id: changed
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail
# `gh pr diff` hits GitHub's 300-file diff cap on large PRs; the paginated Files
# API doesn't. Cache the result — "Extract relevant diff" reuses this file.
gh api "repos/$REPO/pulls/$PR/files" --paginate > pr_files.json
jq -r '.[].filename' pr_files.json > changed_files.txt
if grep -qE '^src/.*\.(js|jsx|ts|tsx)$|^public/locales/' changed_files.txt; then
echo "relevant=true" >> "$GITHUB_OUTPUT"
else
echo "relevant=false" >> "$GITHUB_OUTPUT"
echo "No i18n-relevant files changed — skipping."
fi

- name: Set up Node
if: steps.changed.outputs.relevant == 'true'
uses: actions/setup-node@v4.1.0
with:
node-version: "22.19.0"
cache: "npm"
cache-dependency-path: package-lock.json

- name: Install Dependencies
if: steps.changed.outputs.relevant == 'true'
run: npm install --legacy-peer-deps

- name: Run TypeScript check
if: steps.changed.outputs.relevant == 'true'
run: npx tsc --noEmit --pretty false > tsc-output.txt 2>&1 || true

- name: Run objective i18n checks
if: steps.changed.outputs.relevant == 'true'
run: node ci/scripts/check_localization_objective.js --changed-files changed_files.txt --tsc-output tsc-output.txt

# Plain-text, pre-filtered diff capped so a huge PR can't blow context/cost. Source
# files claim the budget first (missed-string check), then locale files get what's
# left, round-robined across sub-apps/locales — see ci/scripts/build_localization_diff.js.
- name: Extract relevant diff
id: diff
if: steps.changed.outputs.relevant == 'true'
run: |
set -euo pipefail
node ci/scripts/build_localization_diff.js pr_files.json 200000 > i18n-relevant.diff 2> diff-stderr.txt
cat diff-stderr.txt
if grep -q "TRUNCATED" diff-stderr.txt; then
echo "::warning::i18n-relevant.diff was truncated to fit the review budget."
printf '\n\n[... diff truncated: this PR is too large to review in full — findings above are non-exhaustive ...]\n' >> i18n-relevant.diff
echo "truncated=true" >> "$GITHUB_OUTPUT"
else
echo "truncated=false" >> "$GITHUB_OUTPUT"
fi

- uses: anthropics/claude-code-action@1dc994ee7a008f0ecc866d9ac23ef036b7229f84 # v1.0.127
if: steps.changed.outputs.relevant == 'true'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: |
--max-turns 50
--allowedTools "Bash(gh pr view:*),Read,Write,Grep,Glob"
--model claude-sonnet-5
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
REPORT_FILE: ${{ github.workspace }}/i18n-comment.md
DIFF_TRUNCATED: ${{ steps.diff.outputs.truncated }}

The PR branch is already checked out. i18n-objective-results.json (in the workspace
root) holds deterministic findings already computed by a script — read it first;
never re-judge or second-guess those, just report them.

Read CLAUDE.md's "Localization (i18next)" section for the full rules, then read
i18n-relevant.diff with the Read tool — it's the PR's diff, already pre-filtered to
only files under src/**/*.{js,jsx,ts,tsx} and public/locales/**, formatted as plain
`=== <filename> ===` sections. Never run `gh pr diff` or `gh api` to fetch the diff
yourself; this file is the full and only diff context you get. Some entries may say
"(no patch available — file too large for GitHub to diff)" — treat those as
un-reviewable, don't guess at their contents. If DIFF_TRUNCATED is "true", the PR was
too large to include in full — note this once in the report rather than silently
reviewing a partial diff as if it were complete.

Review the diff for two things a script can't check:

1. Missed strings: new hardcoded user-facing copy (JSX text, string props, notify()/
dispatch() messages, module-level string maps, class components) that should be
wired through t()/i18n.t() instead, per the "Where strings hide" and "What to SKIP"
rules. Also check value-formatting-rule violations in any changed
public/locales/*.json value (no decorative characters, no ALL CAPS, no HTML, no
hardcoded URLs).
2. Translation quality: for every changed value in a non-English locale file
(public/locales/{es-ES,hi-IN,zh-CN,ru-RU,nl-NL}/*.json), confirm it reads as
grammatically correct in that language, and that it's an actual translation — not
the English string copied verbatim (ignoring {{var}} interpolations) or a stale
English placeholder.

If something is genuinely ambiguous (can't tell if a string is UI copy vs. a
skippable data value, or a translation choice that's debatable rather than clearly
wrong), put it under Advisory, not Blocking — a later deterministic step turns every
Blocking bullet into an inline PR comment automatically, so Blocking is reserved for
confident, file/line-anchored findings only.

Keep every bullet to one short sentence: what's wrong and the fix, nothing else. Avoid
long explanations — no rationale, no background, no multi-clause justification. This is
a PR comment, not an essay.

Write the report to REPORT_FILE with the Write tool, in exactly this shape (keep both
HTML markers verbatim):

<!-- localization-reviewer -->
## Localization Reviewer — <verdict line>
<If DIFF_TRUNCATED is "true": "⚠️ This PR's diff was too large to review in full — findings below are non-exhaustive." Otherwise omit this line.>

### 🔴 Blocking
<one bullet per objective finding (verbatim from i18n-objective-results.json) plus
every confident missed-string / formatting / translation-quality finding — or "None".
Every bullet MUST be shaped exactly `- \`path:line\` — message` (backtick-quoted
path:line, then an em dash, then the message) — a later step parses this exact shape
to post inline PR comments automatically, so a bullet that doesn't match it will
silently never get one.>

### 🟡 Advisory
<ambiguous observations that aren't blocking — or "None">

<!-- localization-verdict: <PASS_OR_FAIL> -->

<verdict line> mirrors the Claude Auto Review workflow's terse verdict phrasing —
counts, not prose, and never a zero count segment:
✅ No blockers
✅ No blockers · 🟡 M advisory note(s)
🔴 N blocker(s) · 🟡 M advisory note(s) — see inline comments
N is the number of Blocking bullets (0 if "None"), M the number of Advisory bullets.
Say "see inline comments" only when N > 0, since only Blocking bullets get posted as
inline comments — Advisory ones live only in this comment's body.

FAIL if i18n-objective-results.json has "passed": false, OR you added anything under
Blocking. Otherwise PASS. This PASS/FAIL is the `<!-- localization-verdict: ... -->`
marker used by the merge gate — independent of the human-readable verdict line above,
which reports counts rather than pass/fail. Write the marker exactly once, as the final
line — never quote it or the `<!-- localization-reviewer -->` marker anywhere else in
the report. Do not post the summary comment yourself, and do not create any inline PR
comments yourself — later steps handle both from REPORT_FILE.

# Always post a NEW summary comment (never update in place): each push's verdict lands
# in the PR timeline between the commits it reviewed, preserving the review history.
- name: Post Localization Reviewer comment
id: i18n
if: always() && steps.changed.outputs.relevant == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail
FILE="$GITHUB_WORKSPACE/i18n-comment.md"
if [ ! -s "$FILE" ] || ! grep -q '<!-- localization-reviewer -->' "$FILE"; then
echo "::warning::report file missing or malformed; the Localization Reviewer gate will fail."
echo "no_report=true" >> "$GITHUB_OUTPUT"
exit 0
fi
BODY=$(cat "$FILE")
VERDICT=$(printf '%s' "$BODY" | grep -oiE '<!-- localization-verdict:[[:space:]]*(PASS|FAIL)[[:space:]]*-->' \
| grep -oiE '(PASS|FAIL)' | tail -n1 | tr '[:lower:]' '[:upper:]' || true)
if [ -z "$VERDICT" ]; then
echo "::warning::report has no usable localization-verdict marker; the gate will fail."
echo "no_report=true" >> "$GITHUB_OUTPUT"
exit 0
fi
PAYLOAD=$(BODY="$BODY" python3 -c 'import os,json,sys; sys.stdout.write(json.dumps({"body": os.environ["BODY"]}))')
printf '%s' "$PAYLOAD" | gh api -X POST "repos/$REPO/issues/$PR/comments" --input - --silent
echo "Posted Localization Reviewer comment."
echo "verdict=${VERDICT:-}" >> "$GITHUB_OUTPUT"

# Deterministic instead of relying on Claude to reliably call an inline-comment tool
# itself. Reusable: see ci/scripts/post_inline_comments.js.
- name: Post inline comments for Blocking findings
if: always() && steps.changed.outputs.relevant == 'true' && steps.i18n.outputs.no_report != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
node ci/scripts/post_inline_comments.js \
--report i18n-comment.md \
--section "### 🔴 Blocking" \
--pr-files pr_files.json \
--repo "${{ github.repository }}" \
--pr "${{ github.event.pull_request.number }}" \
--commit "${{ github.event.pull_request.head.sha }}" \
--label "Localization Reviewer"

- name: Localization Reviewer gate
if: always() && steps.changed.outputs.relevant == 'true'
run: |
V="${{ steps.i18n.outputs.verdict }}"
echo "Localization Reviewer verdict: ${V:-<none>} (no_report=${{ steps.i18n.outputs.no_report || 'false' }})"
if [ "${{ steps.i18n.outputs.no_report }}" = "true" ]; then
echo "::error::No Localization Reviewer report was produced — check the workflow logs."
exit 1
fi
if [ "$V" = "FAIL" ]; then
echo "::error::Localization Reviewer found a blocking issue — see its comment."
exit 1
fi
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ skills-lock.json
.agents
.playwright-mcp
.claude/worktrees
.zed

# negative-QA workflow runtime output (auth-state.json holds a session token)
auth-state.json
Expand Down
Loading
Loading