Skip to content

content-lint: warn when a post body links to a different locale than the file it lives in #179

Description

@hotlong

Split out of #142 by seat ruling, and sequenced behind #139 because both want scripts/content-lint.mjs.

Why

#142 fixes the generated side: gen-zh-hant.mjs will rewrite /zh-Hans/ link targets to /zh-Hant/ when it converts a post, so Traditional readers stop being sent to Simplified pages. That fix cannot reach the hand-written locales — index.ja.mdx, .ko, .de, .es, .fr are authored by people and agents, and each can carry the same defect with no generator to blame.

A cross-locale link is invisible to every gate today. #137's validator resolves the target and finds it perfectly real — it just belongs to another locale. The page renders, the link works, and the reader is quietly moved out of the language they were reading in, at which point the language switcher offers to "switch" them to the locale they were already in.

Scope

In resolveInternalLink() (or beside it), compare the locale segment of a body link against the locale of the file the link lives in. Mismatch → a finding.

Severity is the design question and it belongs to whoever picks this up. A deliberate cross-locale link is a real thing — an English-only companion post linked from a translated article is exactly what PR #168 does, on purpose, and #137 already makes the alternative a hard 404. So a blanket error would be wrong. Candidate shapes, decide and record the reasoning on this issue:

  1. Warn always. Simple; every intentional cross-locale link becomes a permanent warning, which trains people to ignore warnings.
  2. Error only when the same-locale target exists. Sharper: if /zh-Hant/blog/x/ is built and the file says /zh-Hans/blog/x/, that is unambiguously a mistake. If the target exists only in English, the link is the author's only option and passes silently. This is the rule the gen-zh-hant.mjs leaves /zh-Hans/ body links intact, so Traditional readers are sent to Simplified pages #142 generator fix already implements on its side.
  3. Warn only when the same-locale target exists, as a softer version of 2 while the corpus is cleaned up.

Option 2 mirrors the generator, which is a point in its favour: one rule, two enforcement points.

Measure first

Count what exists before choosing: how many cross-locale body links are in the hand-written locales today, and how many of those have a same-locale target that is actually built. If the answer is "a handful, all with same-locale targets", option 2 is free.

Acceptance

Rule chosen with the reasoning recorded here; ablation showing a mistake caught and an intentional cross-locale link not falsely flagged; pnpm content:lint, pnpm content:lint --published, pnpm check, pnpm build, pnpm seo:smoke green on the current tree.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions