Files
RustProxy/tools/checks/langs_check.py
T
2026-10-07 22:22:54 +02:00

43 lines
2.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""Validate language-pack content and emit the same-shaped bundle used by UI QA.
Rust build.rs performs the actual compile-time discovery and embedding.
"""
from pathlib import Path
import argparse
import json
import re
ROOT = Path(__file__).resolve().parents[2]
def bundle(root=ROOT):
languages=[];locales=set()
for path in sorted((root/'langs').glob('*.json')):
assert re.fullmatch(r'[A-Za-z0-9_-]{1,64}',path.stem),path
assert path.stat().st_size<=262144,path
pack=json.loads(path.read_text(encoding='utf-8'));assert set(pack)=={'meta','translations'},f'unexpected top-level language-pack keys: {set(pack)-{"meta","translations"}} in {path}';meta=pack['meta'];translations=pack['translations']
assert all(isinstance(meta.get(key),str) and 0<len(meta[key].encode())<=128 for key in ['locale','name','native_name','direction']),path
assert meta['direction'] in ('ltr','rtl'),path
assert re.fullmatch(r'[A-Za-z0-9]{1,8}(?:-[A-Za-z0-9]{1,8})*',meta['locale']),path
assert meta['locale'].lower() not in locales, 'duplicate locale'
locales.add(meta['locale'].lower())
assert isinstance(translations,dict) and len(translations)<=4096,path
assert all(isinstance(v,str) and 0<len(k.encode())<=128 and len(v.encode())<=16384 for k,v in translations.items()),path
languages.append({'id':path.stem,**pack})
assert 1<=len(languages)<=128
fallback=next(pack for pack in languages if pack['id']=='en_US')['translations']
html=(root/'src/admin/web/index.html').read_text()
keys=set(re.findall(r'data-i18n(?:-placeholder|-aria)?="([^"]+)"',html))
js='\n'.join(p.read_text() for p in (root/'src/admin/web').glob('**/*.js'))
keys.update(re.findall(r'\bt\("([^"\n]+)"\)',js))
keys.update(re.findall(r'"(vh[A-Z][A-Za-z]+)"',js))
assert keys<=fallback.keys(),f'Missing fallback keys: {keys-fallback.keys()}'
for language in languages:
translations=language['translations']
assert keys<=translations.keys(),f"Missing UI keys in {language['id']}: {keys-translations.keys()}"
result={'default':'en_US','languages':languages}
assert len(json.dumps(result,ensure_ascii=False).encode())<=8388608
return result
if __name__=='__main__':
parser=argparse.ArgumentParser();parser.add_argument('--output',type=Path);args=parser.parse_args()
data=bundle()
if args.output:args.output.write_text(json.dumps(data,ensure_ascii=False)+'\n')
print(f"PASS: {len(data['languages'])} language packs, metadata, fallback UI keys and bounds.")