Korean localization groundwork (staged, nothing live) - #204
Conversation
Groundwork for shipping docs.mixpanel.com in Korean. Everything lands under i18n/ and is deliberately inert: docs.json is untouched, no workflow is installed, and no ko/ tree exists at the repo root. Merging this changes nothing a reader sees. Two findings that reshape the project: - Mintlify sells native AI translations (Pro/Enterprise) that bulk-translate the docs and open a PR per change with a human merge gate — which is M2's bulk run plus all of M3. Every signal says Mixpanel is on Enterprise. Needs one dashboard check before we build a pipeline we may already own. - 3,723 headings in this repo have no explicit anchors, and 710 internal links carry a #fragment. Translating a heading silently changes its anchor, so those links start landing at the top of the page. No error, nothing visible in a diff. Fixed by pinning `## 제목 [#english-anchor]`, but the engine has to do it — this became the disqualifying criterion for engine choice. Contents: 01-plan-and-entitlements.md plan/entitlement findings DF-823 02-scope-and-preservation-spec.md scope + preservation rules DF-826 03-tooling-evaluation.md engine comparison + bake-off DF-827 04-rollout-playbook.md next language + playbook DF-833 glossary/ 121 KO terms, 60 do-not-translate DF-826 nav/ 128 labels, 390 paths, staged DF-824 config/ GT config + CI workflow, staged DF-830/831 pilot/ko/ 3 hand-translated pages DF-828 scripts/ 4 zero-dependency Node tools scripts/validate-mdx-parity.mjs is the load-bearing piece: it verifies JSX components, code fences, imports, image paths, link targets, heading anchors, frontmatter keys, and brace balance against the English source. It is the scoring function for the engine bake-off and the gate for the M3 pipeline, whichever engine wins. All three pilot pages pass it on strictest settings. Also flags that DF-825's "seed ko/ with English fallback" step should be dropped — Mintlify's docs explicitly warn against duplicate page paths across languages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
Confidence Score: 1/5The PR should not merge until the parity gate handles deferred reference links, verifies inline-code contents, and the staged workflow uses immutable dependencies. The mandatory validator currently rejects valid wave-1 links while allowing changed inline identifiers, and the documented workflow activation would expose credentials and write permissions to mutable dependencies. Files Needing Attention: i18n/scripts/validate-mdx-parity.mjs, i18n/config/translate.yml
|
| Filename | Overview |
|---|---|
| i18n/scripts/validate-mdx-parity.mjs | Adds the structural gate, but over-prefixes links to deferred surfaces and does not verify inline-code contents. |
| i18n/config/translate.yml | Stages the translation workflow, but its mutable dependencies would run with secrets and write permissions when activated. |
| i18n/scripts/build-locale-nav.mjs | Deterministically generates localized navigation and checks label completeness. |
| i18n/scripts/build-glossary.mjs | Generates synchronized CSV and do-not-translate artifacts from the human glossary. |
| i18n/config/gt.config.json | Stages wave-1 translation transforms and locale behavior without activating them. |
| i18n/02-scope-and-preservation-spec.md | Defines the wave boundaries and machine-checkable preservation contract used to assess the validator. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[English docs and guides] --> B[Translation engine]
B --> C[Korean tree]
C --> D[MDX parity validator]
D -->|pass| E[Navigation and glossary checks]
E --> F[Translation pull request]
D -->|fail| G[Block pull request]
Reviews (1): Last reviewed commit: "Korean localization groundwork (staged, ..." | Re-trigger Greptile
| const expected = LINK_PREFIX && LOCALE | ||
| ? s.mdLinks.map((l) => (l.startsWith("/") && !l.startsWith(`/${LOCALE}/`) && !l.startsWith("/images/") ? `/${LOCALE}${l}` : l)) | ||
| : s.mdLinks; |
There was a problem hiding this comment.
| /* inline code */ | ||
| if (s.inlineCode.length !== t.inlineCode.length) | ||
| W(`inline code span count ${s.inlineCode.length} → ${t.inlineCode.length}`); |
There was a problem hiding this comment.
When translation changes an identifier inside an inline-code span without changing the span count, this check emits no error, allowing incorrect API identifiers such as distinct_id to pass the preservation gate. Compare inline-code contents rather than only their counts.
Source Used: Linear — [M2] Evaluate & select MDX-aware translation tooling
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: "22" | ||
|
|
||
| # gt-lock.json is what makes this a delta: only content whose hash changed is sent. | ||
| - name: Translate changed content | ||
| env: | ||
| GT_API_KEY: ${{ secrets.GT_API_KEY }} | ||
| GT_PROJECT_ID: ${{ secrets.GT_PROJECT_ID }} | ||
| run: npx gtx-cli translate --config gt.config.json ${{ inputs.full && '--no-cache' || '' }} |
There was a problem hiding this comment.
When this staged workflow is activated, mutable action tags and an unversioned npx gtx-cli execute with translation credentials and repository write permissions, allowing a compromised or retargeted dependency to disclose credentials or modify repository content. Pin actions to commit SHAs and the CLI to an audited version before activation.
How this was verified: The activation instructions move this workflow unchanged, and its floating dependencies run with GT secrets plus contents: write and pull-requests: write.
|
Closing this in favour of a properly scoped stack — one PR per Linear issue, with explicit merge ordering. This PR was 23 files spanning 9 issues, which is not reviewable. Replaced by:
Each is stacked on the one above, and each description carries the full merge order plus the operational One content change while splitting: Otherwise the stack's final state is byte-identical to this PR's, verified by diff. |
Groundwork for shipping
docs.mixpanel.comin Korean — Docs Localization (Mintlify i18n).This is a no-op for readers
Everything lands under
i18n/and is deliberately inert:docs.jsonis untouched — verified, not claimed.github/workflows/ko/tree at the repo rootdocs/,guides/,reference/, orsnippets/is modifiedMerging this changes nothing a reader sees. Per CODEOWNERS this is all
@mixpanel/docs-reviewers— it touches none of the@mixpanel/tofupaths (/scripts/is root-anchored, and these are.mjs, not.jsx).Two findings worth a reviewer's attention
Mintlify already sells the pipeline M2/M3 assumed we'd build. Native AI translations (Pro/Enterprise) bulk-translates the docs and opens a PR in this repo on every change, never publishing without a human merge — that's M2's bulk run plus all of M3. Every signal says Mixpanel is on Enterprise, decisively the README putting the Mintlify web editor behind Okta. One person opening the dashboard → Settings → Translations settles whether we build a pipeline we may already own. (DF-823)
710 internal links will break silently the moment a heading is translated. Anchors derive from English heading text; this repo has 3,723 headings with zero explicit anchors and 710 links carrying a
#fragment. Translate a heading and those links start landing at the top of the page — no error, nothing visible in a diff. Fixed by pinning## 제목 [#english-anchor], but the engine has to do it. This became the disqualifying criterion for engine choice. (DF-826, DF-827)What's in here
scripts/validate-mdx-parity.mjsnav/--checkfails CI if labels drift02-scope-and-preservation-spec.mdglossary/pilot/ko/config/03-tooling-evaluation.md,04-rollout-playbook.md,01-plan-and-entitlements.mdStart at
i18n/README.md.Reviewing this
validate-mdx-parity.mjsis the load-bearing piece — it's the scoring function for the engine bake-off and the gate for the M3 pipeline, whichever engine wins. Zero dependencies, nopackage.jsonneeded:# all three pilot pages, strictest settings — expect 3 clean, 0 warnings node i18n/scripts/build-locale-nav.mjs ko --check node i18n/scripts/build-glossary.mjs ko --check node i18n/scripts/validate-mdx-parity.mjs \ --source docs/data-structure/concepts.mdx \ --target i18n/pilot/ko/docs/data-structure/concepts.mdx \ --locale ko --link-prefix --require-anchors --allow-code-commentsThe Korean itself is the part that most needs a native reader —
pilot/ko/andnav/labels.ko.jsonespecially. Terminology policy and its rationale are inglossary/ko.md; the short version is that Mixpanel's UI is English-only, so feature names stay phonetically recognisable against the button the reader is looking at.Two things to push back on
i18n/status-brief.htmlis the source for a status page linked from the Linear project. It will go stale. Happy to drop it if a one-off status page doesn't belong in the docs repo.ko/with English fallback" step should be dropped. Mintlify's docs explicitly warn: "Do not use the same page path in more than one language. Duplicating paths across languages results in undefined behavior." Flagged on the issue; noted here because it changes that issue's scope.Linear
DF-823, DF-824, DF-825, DF-826, DF-827, DF-828, DF-829, DF-830, DF-831, DF-832, DF-833, DF-834
🤖 Generated with Claude Code