feat(docs): co-locate multilingual docs source#186
Conversation
Restructure the docs half of spec 072: co-locate each page's languages under docs/ as <name>-en.md / <name>-pt.md, with the Docusaurus i18n/<locale>/ trees generated and gitignored. English becomes an equal generated pack, not the implicit default. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Every hand-authored page now lives side by side as docs/<name>-en.md and docs/<name>-pt.md; chrome moves to docs/_i18n/chrome-<lang>.json with en and pt-BR both explicit. A Node sync (apps/docs/scripts/sync-i18n.mjs, run on prebuild/prestart, tested with node --test) generates the i18n/en/ and i18n/pt-BR/ trees Docusaurus consumes and guards language coverage; apps/docs/i18n/ is gitignored and the committed pt-BR tree is removed. docs.path and the search index read the generated en pack; editUrl maps back to the co-located source. The codegen schema import is re-anchored at @site in the generated copies (the committed docs/content/ is unchanged). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 36 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughIntroduces a co-located docs i18n workflow: a new sync-i18n.mjs script generates Docusaurus locale trees from ChangesDocs i18n sync tooling and config
Estimated code review effort: 3 (Moderate) | ~30 minutes Sequence Diagram(s)sequenceDiagram
participant Developer
participant BuildScript as npm build/start
participant SyncI18n as sync-i18n.mjs
participant DocsSource as docs/
participant OutDir as apps/docs/i18n/
participant Docusaurus
Developer->>BuildScript: run start or build
BuildScript->>SyncI18n: node scripts/sync-i18n.mjs
SyncI18n->>DocsSource: scan pages, sidecars, chrome files
SyncI18n->>SyncI18n: assertCoverage (fail if -en/-pt missing)
SyncI18n->>OutDir: write locale trees (pages, assets, chrome json)
SyncI18n-->>BuildScript: exit 0 or exit 1 with error
BuildScript->>Docusaurus: launch with generated docs
Docusaurus->>OutDir: read locale content and chrome strings
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/docs/scripts/sync-i18n.mjs (1)
100-113: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winCoverage key includes the file extension, so mixed
.md/.mdxacross languages false-fails.The grouping key comes from
stripSuffix(rel, m), which retains the extension. If a page is authored asguide-en.mdbut its translation asguide-pt.mdx, the two land in separate groups (guide.md,guide.mdx) and the guard reports both as missing their sibling — even though Docusaurus resolves each locale tree independently and both would produce the same route. Consider keying by the extension-stripped stem so.md/.mdxpairs are treated as one page.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/docs/scripts/sync-i18n.mjs` around lines 100 - 113, The coverage grouping in assertCoverage currently uses stripSuffix(rel, m), which keeps the file extension and can split the same page into separate buckets when locales mix .md and .mdx. Update the grouping key in assertCoverage to use the extension-stripped page stem so variants like guide-en.md and guide-pt.mdx are treated as one page across languages, while keeping the existing LANG_RE and suffix validation flow intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@apps/docs/scripts/sync-i18n.mjs`:
- Around line 100-113: The coverage grouping in assertCoverage currently uses
stripSuffix(rel, m), which keeps the file extension and can split the same page
into separate buckets when locales mix .md and .mdx. Update the grouping key in
assertCoverage to use the extension-stripped page stem so variants like
guide-en.md and guide-pt.mdx are treated as one page across languages, while
keeping the existing LANG_RE and suffix validation flow intact.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 33931912-2ef8-4d69-8342-8697fa207cd3
📒 Files selected for processing (77)
.cspell/ecosystem-terms.txt.gitignoreapps/docs/docusaurus.config.tsapps/docs/i18n/pt-BR/docusaurus-plugin-content-docs/current.jsonapps/docs/i18n/pt-BR/docusaurus-theme-classic/footer.jsonapps/docs/i18n/pt-BR/docusaurus-theme-classic/navbar.jsonapps/docs/package.jsonapps/docs/scripts/sync-i18n.mjsapps/docs/scripts/sync-i18n.test.mjsdocs/00-guides/00-getting-started/index-en.mddocs/00-guides/00-getting-started/index-pt.mddocs/00-guides/01-basic/01-photoshop-en.mddocs/00-guides/01-basic/01-photoshop-pt.mddocs/00-guides/01-basic/02-blender-en.mddocs/00-guides/01-basic/02-blender-pt.mddocs/00-guides/01-basic/03-godot-en.mddocs/00-guides/01-basic/03-godot-pt.mddocs/00-guides/01-basic/index-en.mddocs/00-guides/01-basic/index-pt.mddocs/00-guides/02-advanced/01-photoshop-en.mddocs/00-guides/02-advanced/01-photoshop-pt.mddocs/00-guides/02-advanced/02-blender-en.mddocs/00-guides/02-advanced/02-blender-pt.mddocs/00-guides/02-advanced/03-godot-en.mddocs/00-guides/02-advanced/03-godot-pt.mddocs/00-guides/02-advanced/index-en.mddocs/00-guides/02-advanced/index-pt.mddocs/00-guides/03-iterate-en.mddocs/00-guides/03-iterate-pt.mddocs/00-guides/index-en.mddocs/00-guides/index-pt.mddocs/01-project/01-architecture-en.mddocs/01-project/01-architecture-pt.mddocs/01-project/03-comparison-en.mddocs/01-project/03-comparison-pt.mddocs/01-project/04-deferred-en.mddocs/01-project/04-deferred-pt.mddocs/01-project/index-en.mddocs/01-project/index-pt.mddocs/02-tools/blender-addon/01-outliner-en.mddocs/02-tools/blender-addon/01-outliner-pt.mddocs/02-tools/blender-addon/02-element-en.mddocs/02-tools/blender-addon/02-element-pt.mddocs/02-tools/blender-addon/03-slots-en.mddocs/02-tools/blender-addon/03-slots-pt.mddocs/02-tools/blender-addon/04-skeleton-en.mddocs/02-tools/blender-addon/04-skeleton-pt.mddocs/02-tools/blender-addon/05-mesh-generation-en.mddocs/02-tools/blender-addon/05-mesh-generation-pt.mddocs/02-tools/blender-addon/06-weight-paint-en.mddocs/02-tools/blender-addon/06-weight-paint-pt.mddocs/02-tools/blender-addon/07-animation-en.mddocs/02-tools/blender-addon/07-animation-pt.mddocs/02-tools/blender-addon/08-atlas-en.mddocs/02-tools/blender-addon/08-atlas-pt.mddocs/02-tools/blender-addon/09-manual-mesh-en.mddocs/02-tools/blender-addon/09-manual-mesh-pt.mddocs/02-tools/blender-addon/10-pipeline-en.mddocs/02-tools/blender-addon/10-pipeline-pt.mddocs/02-tools/blender-addon/11-helpers-en.mddocs/02-tools/blender-addon/11-helpers-pt.mddocs/02-tools/blender-addon/index-en.mddocs/02-tools/blender-addon/index-pt.mddocs/02-tools/godot-plugin/index-en.mddocs/02-tools/godot-plugin/index-pt.mddocs/02-tools/index-en.mddocs/02-tools/index-pt.mddocs/02-tools/photoshop-plugin/index-en.mddocs/02-tools/photoshop-plugin/index-pt.mddocs/README-en.mddocs/README-pt.mddocs/_i18n/chrome-en.jsondocs/_i18n/chrome-pt.jsondocs/_i18n/code-pt.jsonspecs/077-colocated-docs-i18n/STUDY.mdspecs/077-colocated-docs-i18n/TODO.mdspecs/index.md
💤 Files with no reviewable changes (3)
- apps/docs/i18n/pt-BR/docusaurus-plugin-content-docs/current.json
- apps/docs/i18n/pt-BR/docusaurus-theme-classic/footer.json
- apps/docs/i18n/pt-BR/docusaurus-theme-classic/navbar.json
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: Analyze (python)
⚠️ CI failures not shown inline (6)
GitHub Actions: SonarCloud / SonarCloud: feat(docs): co-locate multilingual docs source
Conclusion: failure
##[group]Run uv run pytest tests/ --cov=apps/blender --cov=packages --cov=scripts --cov-report=xml:coverage.xml
�[36;1muv run pytest tests/ --cov=apps/blender --cov=packages --cov=scripts --cov-report=xml:coverage.xml�[0m
shell: /usr/bin/bash -e {0}
env:
UV_PYTHON_INSTALL_DIR: /home/runner/work/_temp/uv-python-dir
UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
##[endgroup]
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-9.1.1, pluggy-1.6.0
rootdir: /home/runner/work/proscenio/proscenio
configfile: pyproject.toml
plugins: cov-7.1.0
collected 1002 items
tests/automesh/test_contour.py ...................................... [ 3%]
tests/automesh/test_contour_islands.py ...... [ 4%]
tests/automesh/test_cut_geometry.py ........... [ 5%]
tests/automesh/test_density.py ......................................... [ 9%]
.. [ 9%]
tests/automesh/test_extra_edges_cdt.py ........ [ 10%]
tests/automesh/test_geometry.py ................................. [ 13%]
tests/automesh/test_interior_mode.py ... [ 14%]
tests/automesh/test_open_stroke_pen.py .......... [ 15%]
tests/automesh/test_outer_splice.py ................ [ 16%]
tests/automesh/test_stroke_geometry.py ................................. [ 20%]
... [ 20%]
tests/automesh/test_stroke_pick.py .... [ 20%]
tests/automesh/test_vertex_pen.py .................. [ 22%]
tests/codegen/test_discriminated_union.py ........... [ 23%]
tests/codegen/test_godot_emit.py ..s... [ 24%]
tests/codegen/test_psd_manifest.py ...... ...
GitHub Actions: SonarCloud / 0_SonarCloud.txt: feat(docs): co-locate multilingual docs source
Conclusion: failure
##[group]Run uv run pytest tests/ --cov=apps/blender --cov=packages --cov=scripts --cov-report=xml:coverage.xml
�[36;1muv run pytest tests/ --cov=apps/blender --cov=packages --cov=scripts --cov-report=xml:coverage.xml�[0m
shell: /usr/bin/bash -e {0}
env:
UV_PYTHON_INSTALL_DIR: /home/runner/work/_temp/uv-python-dir
UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
##[endgroup]
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-9.1.1, pluggy-1.6.0
rootdir: /home/runner/work/proscenio/proscenio
configfile: pyproject.toml
plugins: cov-7.1.0
collected 1002 items
tests/automesh/test_contour.py ...................................... [ 3%]
tests/automesh/test_contour_islands.py ...... [ 4%]
tests/automesh/test_cut_geometry.py ........... [ 5%]
tests/automesh/test_density.py ......................................... [ 9%]
.. [ 9%]
tests/automesh/test_extra_edges_cdt.py ........ [ 10%]
tests/automesh/test_geometry.py ................................. [ 13%]
tests/automesh/test_interior_mode.py ... [ 14%]
tests/automesh/test_open_stroke_pen.py .......... [ 15%]
tests/automesh/test_outer_splice.py ................ [ 16%]
tests/automesh/test_stroke_geometry.py ................................. [ 20%]
... [ 20%]
tests/automesh/test_stroke_pick.py .... [ 20%]
tests/automesh/test_vertex_pen.py .................. [ 22%]
tests/codegen/test_discriminated_union.py ........... [ 23%]
tests/codegen/test_godot_emit.py ..s... [ 24%]
tests/codegen/test_psd_manifest.py ...... ...
GitHub Actions: CI / test-blender: feat(docs): co-locate multilingual docs source
Conclusion: failure
##[group]Run ~/blender/blender --background \
�[36;1m~/blender/blender --background \�[0m
�[36;1m --python packages/validator/scripts/validate_automesh.py \�[0m
�[36;1m -- --ci-only�[0m
shell: /usr/bin/bash -e {0}
##[endgroup]
Traceback (most recent call last):
File "/home/runner/work/proscenio/proscenio/packages/validator/scripts/validate_automesh.py", line 50, in <module>
from proscenio_validator.cli import main # noqa: E402
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/proscenio/proscenio/packages/validator/src/proscenio_validator/cli.py", line 16, in <module>
from .measurement import load_fixture, run_validation
File "/home/runner/work/proscenio/proscenio/packages/validator/src/proscenio_validator/measurement.py", line 18, in <module>
from .coverage import measure_coverage
File "/home/runner/work/proscenio/proscenio/packages/validator/src/proscenio_validator/coverage.py", line 17, in <module>
from core.geometry_2d import point_in_triangle_xz
ModuleNotFoundError: No module named 'core.geometry_2d'
Blender 5.1.1 (hash b70da489d7f4 built )
Blender quit
GitHub Actions: CI / lint-python: feat(docs): co-locate multilingual docs source
Conclusion: failure
##[group]Run uv run pytest tests/
�[36;1muv run pytest tests/�[0m
shell: /usr/bin/bash -e {0}
env:
UV_PYTHON_INSTALL_DIR: /home/runner/work/_temp/uv-python-dir
UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
##[endgroup]
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-9.1.1, pluggy-1.6.0
rootdir: /home/runner/work/proscenio/proscenio
configfile: pyproject.toml
plugins: cov-7.1.0
collected 1002 items
tests/automesh/test_contour.py ...................................... [ 3%]
tests/automesh/test_contour_islands.py ...... [ 4%]
tests/automesh/test_cut_geometry.py ........... [ 5%]
tests/automesh/test_density.py ......................................... [ 9%]
.. [ 9%]
tests/automesh/test_extra_edges_cdt.py ........ [ 10%]
tests/automesh/test_geometry.py ................................. [ 13%]
tests/automesh/test_interior_mode.py ... [ 14%]
tests/automesh/test_open_stroke_pen.py .......... [ 15%]
tests/automesh/test_outer_splice.py ................ [ 16%]
tests/automesh/test_stroke_geometry.py ................................. [ 20%]
... [ 20%]
tests/automesh/test_stroke_pick.py .... [ 20%]
tests/automesh/test_vertex_pen.py .................. [ 22%]
tests/codegen/test_discriminated_union.py ........... [ 23%]
tests/codegen/test_godot_emit.py ..s... [ 24%]
tests/codegen/test_psd_manifest.py ...... [ 24%]
tests/codegen/test_schema_roundtrip.py ...................... [ 27%]
tests/codegen/test_ts_emit.py . ...
GitHub Actions: CI / 1_test-blender.txt: feat(docs): co-locate multilingual docs source
Conclusion: failure
Current runner version: '2.335.1'
##[group]Runner Image Provisioner
Hosted Compute Agent
Version: 20260624.560
Commit: 925d229a51159bc391ae97e54a2dd1fe20af789d
Build Date:
Worker ID: {efb36a95-7013-4db4-94d2-e3b190ded529}
Azure Region: eastus
##[endgroup]
##[group]Operating System
Ubuntu
24.04.4
LTS
##[endgroup]
##[group]Runner Image
Image: ubuntu-24.04
Version: 20260628.225.1
Included Software: https://github.com/actions/runner-images/blob/ubuntu24/20260628.225/images/ubuntu/Ubuntu2404-Readme.md
Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu24%2F20260628.225
##[endgroup]
##[group]GITHUB_TOKEN Permissions
Contents: read
Metadata: read
##[endgroup]
Secret source: Actions
Prepare workflow directory
Prepare all required actions
Getting action download info
Download action repository 'actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0' (SHA:9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0)
Download action repository 'actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9' (SHA:55cc8345863c7cc4c66a329aec7e433d2d1c52a9)
Complete job name: test-blender
##[group]Run actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
lfs: true
repository: firebound/proscenio
***REDACTED***
ssh-strict: true
ssh-user: git
persist-credentials: true
clean: true
sparse-checkout-cone-mode: true
fetch-depth: 1
fetch-tags: false
show-progress: true
submodules: false
set-safe-directory: true
allow-unsafe-pr-checkout: false
##[endgroup]
Syncing repository: firebound/proscenio
##[group]Getting Git version info
Working directory is '/home/runner/work/proscenio/proscenio'
[command]/usr/bin/git version
git version 2.54.0
[command]/usr/bin/git lfs version
git-lfs/3.7.1 (GitHub; linux amd64; go 1.24.4)
##[endgroup]
Temporarily overriding HOME='/home/runner/work/_temp/5ec166a6-afc9-4988-a568-ba4f5ab0e808' before making global git config changes
Adding repository directory to the te...
GitHub Actions: CI / 4_lint-python.txt: feat(docs): co-locate multilingual docs source
Conclusion: failure
##[group]Run uv run pytest tests/
�[36;1muv run pytest tests/�[0m
shell: /usr/bin/bash -e {0}
env:
UV_PYTHON_INSTALL_DIR: /home/runner/work/_temp/uv-python-dir
UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
##[endgroup]
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-9.1.1, pluggy-1.6.0
rootdir: /home/runner/work/proscenio/proscenio
configfile: pyproject.toml
plugins: cov-7.1.0
collected 1002 items
tests/automesh/test_contour.py ...................................... [ 3%]
tests/automesh/test_contour_islands.py ...... [ 4%]
tests/automesh/test_cut_geometry.py ........... [ 5%]
tests/automesh/test_density.py ......................................... [ 9%]
.. [ 9%]
tests/automesh/test_extra_edges_cdt.py ........ [ 10%]
tests/automesh/test_geometry.py ................................. [ 13%]
tests/automesh/test_interior_mode.py ... [ 14%]
tests/automesh/test_open_stroke_pen.py .......... [ 15%]
tests/automesh/test_outer_splice.py ................ [ 16%]
tests/automesh/test_stroke_geometry.py ................................. [ 20%]
... [ 20%]
tests/automesh/test_stroke_pick.py .... [ 20%]
tests/automesh/test_vertex_pen.py .................. [ 22%]
tests/codegen/test_discriminated_union.py ........... [ 23%]
tests/codegen/test_godot_emit.py ..s... [ 24%]
tests/codegen/test_psd_manifest.py ...... [ 24%]
tests/codegen/test_schema_roundtrip.py ...................... [ 27%]
tests/codegen/test_ts_emit.py . ...
🧰 Additional context used
🪛 LanguageTool
specs/077-colocated-docs-i18n/TODO.md
[grammar] ~37-~37: Ensure spelling is correct
Context: ...framework theme-UI strings; the sync re-emits it). ### B3. Retire the committed i18n tree - [ ...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[uncategorized] ~58-~58: The official name of this software platform is spelled with a capital “H”.
Context: ...../apps, ../packages, ../specs -> github.com) and relative image paths still res...
(GITHUB)
specs/077-colocated-docs-i18n/STUDY.md
[uncategorized] ~27-~27: The official name of this software platform is spelled with a capital “H”.
Context: ...must survive the migration. - Deploy: [.github/workflows/docs-deploy.yml](../../.githu...
(GITHUB)
[uncategorized] ~27-~27: The official name of this software platform is spelled with a capital “H”.
Context: ...ploy: .github/workflows/docs-deploy.yml is a Node/pn...
(GITHUB)
🔇 Additional comments (14)
apps/docs/scripts/sync-i18n.mjs (3)
48-95: LGTM!
130-182: LGTM!
184-209: LGTM!apps/docs/scripts/sync-i18n.test.mjs (1)
1-201: LGTM!apps/docs/docusaurus.config.ts (2)
11-17: LGTM!Also applies to: 46-46, 96-100
110-119: 🎯 Functional Correctness | ⚡ Quick winConfirm the
editUrlrewrite matches Docusaurus'docPathcontract.This assumes
docPathis always a source-relative.md/.mdxpath; if the callback ever receives a different shape for translated or generated docs, these GitHub links will point at the wrong file.apps/docs/package.json (1)
7-18: LGTM!docs/_i18n/chrome-en.json (1)
1-112: LGTM!docs/_i18n/chrome-pt.json (1)
1-112: LGTM!specs/index.md (1)
165-165: LGTM!.cspell/ecosystem-terms.txt (1)
389-391: LGTM!.gitignore (1)
103-107: LGTM!specs/077-colocated-docs-i18n/STUDY.md (1)
1-60: LGTM!specs/077-colocated-docs-i18n/TODO.md (1)
1-73: LGTM!
… pages The spec-077 co-location renamed docs/02-tools/blender-addon/*.md to <name>-en.md / <name>-pt.md, so the on-disk panel mirror read outliner-en / outliner-pt instead of the bare slug and drifted. Glob the canonical -en pages and strip the -en/-pt language suffix in the slug; the online doc URLs are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The coverage grouping keyed on the page path with its extension, so a page authored as guide-en.md with a guide-pt.mdx translation split into two half-missing groups even though Docusaurus routes both to the same slug. Key by the path minus the -<lang>.<ext> so mixed .md/.mdx pairs group as one page. Surfaced by CodeRabbit on PR #186. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|



What changed
Co-locate each docs page's languages under
docs/as<name>-en.md/<name>-pt.md(31 pairs), with the addon chrome indocs/_i18n/chrome-<lang>.json(en and pt-BR both explicit). A Node sync (apps/docs/scripts/sync-i18n.mjs) fans that source out into the Docusaurusi18n/<locale>/trees for both locales;apps/docs/i18n/is now gitignored and regenerated on prebuild, and the committed pt-BR tree is removed. English is a generated pack like every other language:docs.pathand the search index readi18n/en/, notdocs/directly, andeditUrlmaps each generated page back to its co-located source.Why
The shipped spec-072 layout put the pt-BR translations in a distant
i18n/pt-BR/mirror, far from the English source. Co-location lets a page's languages be edited side by side, and makes adding a third language a matter of-<lang>files plus one row in the sync's language-to-locale map. Spec 077.How to test
pnpm --dir apps/docs test- 8 sync unit tests (node --test): suffix stripping, sidecar + asset copy, chrome split, the codegen@sitere-anchor, and the coverage guard.pnpm --dir apps/docs build- both locales build clean (the sync runs on prebuild); no broken-link or module-not-found warnings.pnpm --dir apps/docs typecheck- green.docs/<path>-<lang>.md.Notes
content/import the JSON schema by a path relative to the olddocs/content/depth; the sync re-anchors that import at@sitein the generated copies only, so the committeddocs/content/stays byte-identical (the codegen committed-match test is untouched). A cleaner follow-on is emitting the@siteanchor from the codegen itself.docs/README.mdbecameREADME-en.md, so the GitHub folder view ofdocs/loses its auto-rendered README (cosmetic).Checklist
tsc)format_versionchanged, migration documented (n/a)Spec:
specs/077-colocated-docs-i18n/Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Documentation