Files
Auto-Trader/wiki/scripts/check_i18n.py
T
Haozhe Wu a7f645f368 wiki: one header on every page, English by default, one switch for 中文
Each section carried its own copy of the header: Home's nav had no Home,
the docs' nav had no Docs, the research post had no star or theme button,
and the generated Alpha Library pages had no header at all. Only the docs
could switch language, and they guessed Chinese from the browser while
every other page stayed English.

- partials/ holds one head block, header and footer; sync_site_chrome.py
  writes them into every page between markers and, with --check in CI,
  also requires <body data-section> (the current section is highlighted by
  CSS), the language attributes and a single ?v= token site-wide. The
  Alpha Library generator inserts the same partials.
- site.js is the shared shell (theme, stars, language, footer traffic on
  home only). English is the HTML; Chinese comes from locales/zh.json via
  data-i18n hooks, and check_i18n.py fails on a key with no Chinese or a
  Chinese string nothing uses. A URL that names a language (/docs/zh/,
  the two articles) shows it and remembers it; everything else follows the
  stored choice, English by default. theme-init.js keeps a page hidden until
  its Chinese text is in, so it never flashes English.
- English tutorial and Chinese research post added. The Chinese tutorial
  gets the corrections its translation surfaced: 462 alphas in five zoos,
  AAPL.US, the mandate caps trades per day (it has no daily loss limit),
  Shadow Account extracts up to five rules, the web UI needs Docker or a
  checkout.
- Alpha Library: the zoo pages were never deployed — content/ is
  gitignored and nothing built it, so every zoo link served the root
  redirect. The deploy now exports the manifest and renders the pages (and
  redeploys when agent/src/factors changes); the fifth zoo, fundamental, is
  listed; generated pages allow same-origin scripts only.
- Phones keep the nav as a scrollable row instead of hiding it.
2026-09-29 17:53:13 +08:00

119 lines
4.7 KiB
Python

#!/usr/bin/env python3
"""Every translatable string on the wiki has a Chinese version, and no more.
English is the HTML itself; Chinese lives in ``wiki/locales/zh.json`` and is
applied by ``site.js`` through ``data-i18n``, ``data-i18n-html``,
``data-i18n-attr`` and ``data-href-zh``. This fails when:
* a key used on a page (hand-written, a partial, or a page the Alpha Library
generator renders) has no Chinese value — the reader would see English in
the middle of a Chinese page;
* ``zh.json`` holds a key nothing uses — a translation that silently stopped
applying after someone renamed its key;
* a ``data-href-zh`` link points at a file that does not exist;
* a generated Alpha Library page is not marked language-neutral or not in
the ``alpha`` section — it would stay English for a Chinese reader and
highlight no header item (``sync_site_chrome.py`` checks the hand-written
pages the same way).
The generator's templates are rendered from a one-alpha-per-zoo manifest, so
their keys are checked the way they ship (zoo ids are substituted into keys).
The docs are checked separately by ``check_docs_parity.mjs``.
Usage:
python wiki/scripts/check_i18n.py
"""
from __future__ import annotations
import json
import re
import sys
from pathlib import Path
SCRIPTS = Path(__file__).resolve().parent
WIKI = SCRIPTS.parent
sys.path.insert(0, str(SCRIPTS))
import build_alpha_library as alpha # noqa: E402
from sync_site_chrome import pages # noqa: E402
KEY_ATTR_RE = re.compile(r'data-i18n(?:-html)?="([^"]+)"')
ATTR_LIST_RE = re.compile(r'data-i18n-attr="([^"]+)"')
HREF_ZH_RE = re.compile(r'data-href-zh="([^"]+)"')
def generated_pages() -> list[str]:
"""Render one zoo page and one alpha page for every known zoo.
Returns:
The rendered HTML strings.
"""
env = alpha._build_env()
rendered = []
for zoo_id in alpha._ZOO_DISPLAY:
sample = {
"id": f"{zoo_id}_001",
"module_path": f"src.factors.zoo.{zoo_id}.alpha_001",
"meta": {"theme": ["momentum"], "universe": ["equity_cn"], "frequency": ["1d"],
"formula_latex": "rank(x)", "notes": "note", "decay_horizon": 1,
"min_warmup_bars": 1, "requires_sector": False, "columns_required": ["close"]},
}
zoo = {"zoo_id": zoo_id, "alphas": [sample]}
rendered.append(alpha.render_zoo_page(env, zoo))
rendered.append(alpha.render_alpha_page(env, sample, zoo))
return rendered
def main() -> int:
"""Compare the keys the pages use with the keys zh.json defines.
Returns:
Process exit code.
"""
zh = json.loads((WIKI / "locales" / "zh.json").read_text(encoding="utf-8"))
sources = {path.relative_to(WIKI).as_posix(): path.read_text(encoding="utf-8") for path in pages()}
sources.update({f"partials/{p.name}": p.read_text(encoding="utf-8") for p in (WIKI / "partials").glob("*.html")})
generated = {f"<generated #{i}>": html for i, html in enumerate(generated_pages())}
sources.update(generated)
used: dict[str, str] = {}
problems = []
for name, html in generated.items():
html_tag = re.search(r"<html\b[^>]*>", html)
body_tag = re.search(r"<body\b[^>]*>", html)
if not html_tag or "data-lang-neutral" not in html_tag.group(0):
problems.append(f"{name}: generated page lacks <html data-lang-neutral>")
if not body_tag or 'data-section="alpha"' not in body_tag.group(0):
problems.append(f'{name}: generated page lacks <body data-section="alpha">')
for name, text in sources.items():
for key in KEY_ATTR_RE.findall(text):
used.setdefault(key, name)
for spec in ATTR_LIST_RE.findall(text):
for pair in spec.split(","):
attr, _, key = pair.partition("=")
if not attr.strip() or not key.strip():
problems.append(f"{name}: malformed data-i18n-attr {spec!r}")
continue
used.setdefault(key.strip(), name)
for href in HREF_ZH_RE.findall(text):
if not (WIKI / href.lstrip("/")).is_file():
problems.append(f"{name}: data-href-zh points at missing {href}")
for key, where in sorted(used.items()):
value = zh.get(key)
if not isinstance(value, str) or not value.strip():
problems.append(f"{where}: no Chinese for {key!r}")
for key in sorted(set(zh) - set(used)):
problems.append(f"locales/zh.json: {key!r} is used by no page")
if problems:
print("\n".join(problems), file=sys.stderr)
return 1
print(f"i18n ok: {len(used)} keys, {len(sources)} sources")
return 0
if __name__ == "__main__":
sys.exit(main())