okhp3-i18n-page-sync
OverKill Hill P³ · overkillhill.com · github.com/OKHP3
Keeps a multi-language static site honest about which pages actually have a current translation, the same way a search-index builder already scours a site and catalogs every page: this skill reuses that same generated index as its page inventory rather than inventing a second, competing way to discover content, and adds one persisted ledger to tell "never translated" apart from "translated, but the English source moved on since."
It is deliberately a detector, not a translator. Detection is safe to run
unattended in CI on every push; translation is not, because it produces
prose that needs the voice, dictionary, and register-mediation gates the
language-mediation family's exact-pair skills already enforce. Keeping
these as two skills, run in sequence, is the same non-negotiable boundary
the language-mediation family draws between register mediation and
regional-language translation: detection and translation are two stages,
never one compounded skill.
Scope
| In scope | Out of scope |
|---|---|
| Reading a site's generated search index as the English page inventory | Crawling the filesystem or a live site to discover pages itself |
| Comparing each in-scope page's source hash against a persisted ledger, per configured target locale | Deciding what "in scope" means; that is an explicit, owner-set config field |
A read-only --report/--check mode safe for CI, and an explicit --adopt mode that only ever records a baseline |
Drafting, editing, or publishing any translated page content |
Naming the exact-pair okhp3-translation-en-us-<pair> skill responsible for each flagged route |
Performing that translation itself, or any specialist-register simplification |
Required inputs
- The site's own generated search index (a JSON file the consuming site already builds, commonly at a path like assets/data/search-index.json; the exact path is set by that site's own
search_indexconfig field, not fixed by this package), already current. This skill does not build or refresh it. i18n/sync.config.jsonin the consuming repository (seereferences/config-schema.md). Its absence is a valid, expected state for a site that has not started translating yet: every mode exits 0 and says so.- One
okhp3-translation-en-us-<pair>skill per configured target locale, available to whoever acts on the drift report.
Procedure
- Load
i18n/sync.config.json. If it does not exist, stop here and report "not configured" with exit code 0. This is not an error state. - Load the site's search index and take its
entries[].urlvalues as the candidate page list, excluding any URL containing#(a fragment, not a page) and any URL already under a configured target locale's root. - If
in_scope_routesis set, narrow the candidate list to exactly those routes. A route never listed there can never appear in a drift report, no matter how long its translation has lagged. This is what makes a partial pilot rollout safe to run in CI without failing the build over content nobody has committed to translating. - For each in-scope English page and each configured target locale, compare the target file's presence and the ledger's recorded
synced_source_sha256against the current source-page bytes to classify itmissing,stale,needs_baseline(a translation exists but was never confirmed in the ledger), orin_sync. - Also report
orphan: a ledger entry whose English source page no longer appears in the search index at all. This is a warning, not build-breaking drift; a page can be legitimately retired. - In
--checkmode (the one wired into CI), exit 1 only whenmissingorstaleroutes exist.needs_baselineandorphanare surfaced but never fail the build; they need a one-time--adoptor a human decision, not an emergency. - Never translate. For every
missingorstaleroute, name the exactokhp3-translation-en-us-<pair>skill from the config and stop. Handing that route to the named translation skill is a separate step. A first baseline uses--adopt; replacing a stale baseline requires the deliberate--adopt --refresh-stale --routes "<route>"acknowledgement after review-confirmed content lands.
Format-adapter boundary
This skill assumes a page is exactly the file at <locale-root>/<route-path>/index.html (or index.html at the site root). A site whose routing does not follow that convention needs its own discovery adapter before this skill's route-to-path mapping applies; this package does not attempt to be a general static-site router.
Controlled automation
The GitHub Action built around this skill (see templates/) runs --check on every push and pull request against main, and fails the job on real drift so it shows up the same way any other site-validation failure does. It performs no writes, opens no pull request, and calls no external API: the only remediation path out of a failing check is a human or an agent session running the named translation skill and then --adopt. This keeps the automation boundary the language-mediation family already documents intact: automation may detect and flag, but drafting and publishing stay explicit, reviewed, human-initiated steps.
Quality and review gates
This skill has nothing to say about translation quality; it only proves source-byte freshness for a translated file. Passing --check is not evidence that a translation is accurate, current in tone, reviewed, structurally release-ready, indexed, or published. Those claims belong to separate review and release stages.
Companion release boundary
Once the matching exact-pair skill has a reviewed HTML candidate, hand it to
okhp3-i18n-page-release for static-page release validation. That separate
stage verifies the declared BCP-47 html lang, self-canonical URL, public
alternate cluster, staging state, and optional rendered-language evidence. Do
not add those checks here: this package's source-hash result must remain a
small, deterministic answer to a different question, "has the declared source
changed since this target was confirmed?"
Output contract
Return Configured (yes/no), Missing routes (route, locale, skill to run), Stale routes (route, locale, skill to run), Needs-baseline routes, Orphaned routes, and Check result. Describe in_sync as source-byte freshness. When routes are flagged, name the next action explicitly: which translation skill, then --adopt for a first baseline or --adopt --refresh-stale --routes "<route>" for a reviewed stale refresh.
Resource routing
- Read
references/config-schema.mdbefore writing or editing a consuming site'si18n/sync.config.json. - Copy
templates/i18n-page-sync-workflow.ymlinto a consuming repository's.github/workflows/to wire this into CI. It requires no secrets and calls no external service. - Run
scripts/i18n-page-sync.py --helpbefore using it directly. Use--mode reportto preview drift,--mode checkto verify a repository the way CI does, and--mode adoptonly for a baseline or an explicit--refresh-stale --routesreview-confirmed refresh. - Route a reviewed localized HTML target to
okhp3-i18n-page-releasebefore classifying it as indexable or treating technical metadata as release-ready.
Evaluation and release
evals/evals.json covers missing/stale detection, the never-translates-itself boundary, out-of-scope routes never failing a build, an explicit route-limited stale refresh, and an unconfigured site being a clean no-op. Version 1.2.0 additionally distinguishes source-byte freshness from release readiness and routes reviewed HTML candidates to the distinct release stage. This is a fully deterministic script over structured JSON and file hashes; its ten-test local suite plus the Foundry structural validator are structural evidence only. There is no language-quality dimension here requiring a native-review holdout.
About
Built by Jamie Hill · OverKill Hill P³ Published at github.com/OKHP3 Part of the OKHP3/skillz Agent Skill library. MIT License -- free to use, fork, and adapt. A nod to the source is appreciated.