112 lines
3.1 KiB
Python
112 lines
3.1 KiB
Python
from collections import Counter
|
|
from pathlib import Path
|
|
import re
|
|
|
|
|
|
REPO = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
def read(path: Path) -> str:
|
|
return path.read_text(encoding="utf-8")
|
|
|
|
|
|
def extract_locale_block(src: str, locale_key: str) -> str:
|
|
start_match = re.search(rf"\b{re.escape(locale_key)}\s*:\s*\{{", src)
|
|
assert start_match, f"{locale_key} locale block not found"
|
|
|
|
start = start_match.end() - 1 # "{"
|
|
depth = 0
|
|
in_single = False
|
|
in_double = False
|
|
in_backtick = False
|
|
escape = False
|
|
|
|
for i in range(start, len(src)):
|
|
ch = src[i]
|
|
|
|
if escape:
|
|
escape = False
|
|
continue
|
|
|
|
if in_single:
|
|
if ch == "\\":
|
|
escape = True
|
|
elif ch == "'":
|
|
in_single = False
|
|
continue
|
|
|
|
if in_double:
|
|
if ch == "\\":
|
|
escape = True
|
|
elif ch == '"':
|
|
in_double = False
|
|
continue
|
|
|
|
if in_backtick:
|
|
if ch == "\\":
|
|
escape = True
|
|
elif ch == "`":
|
|
in_backtick = False
|
|
continue
|
|
|
|
if ch == "'":
|
|
in_single = True
|
|
continue
|
|
if ch == '"':
|
|
in_double = True
|
|
continue
|
|
if ch == "`":
|
|
in_backtick = True
|
|
continue
|
|
|
|
if ch == "{":
|
|
depth += 1
|
|
continue
|
|
if ch == "}":
|
|
depth -= 1
|
|
if depth == 0:
|
|
return src[start + 1 : i]
|
|
|
|
raise AssertionError(f"{locale_key} locale block braces are not balanced")
|
|
|
|
|
|
def test_chinese_locale_block_exists():
|
|
src = read(REPO / "static" / "i18n.js")
|
|
assert "\n zh: {" in src
|
|
assert "_lang: 'zh'" in src
|
|
assert "_speech: 'zh-CN'" in src
|
|
|
|
|
|
def test_chinese_locale_includes_representative_translations():
|
|
src = read(REPO / "static" / "i18n.js")
|
|
expected = [
|
|
"settings_title: '\\u8bbe\\u7f6e'",
|
|
"login_title: '\\u767b\\u5f55'",
|
|
"approval_heading: '需要审批'",
|
|
"tab_tasks: '任务'",
|
|
"tab_profiles: '配置'",
|
|
"session_time_just_now: '刚刚'",
|
|
"onboarding_title: '欢迎使用 Hermes Web UI'",
|
|
"onboarding_complete: '引导完成'",
|
|
]
|
|
for entry in expected:
|
|
assert entry in src
|
|
|
|
|
|
def test_chinese_locale_covers_english_keys():
|
|
src = read(REPO / "static" / "i18n.js")
|
|
key_pattern = re.compile(r"^\s{4}([a-zA-Z0-9_]+):", re.MULTILINE)
|
|
en_keys = set(key_pattern.findall(extract_locale_block(src, "en")))
|
|
zh_keys = set(key_pattern.findall(extract_locale_block(src, "zh")))
|
|
|
|
missing = sorted(en_keys - zh_keys)
|
|
assert not missing, f"Chinese locale missing keys: {missing}"
|
|
|
|
|
|
def test_chinese_locale_has_no_duplicate_keys():
|
|
src = read(REPO / "static" / "i18n.js")
|
|
key_pattern = re.compile(r"^\s{4}([a-zA-Z0-9_]+):", re.MULTILINE)
|
|
keys = key_pattern.findall(extract_locale_block(src, "zh"))
|
|
duplicates = sorted(k for k, count in Counter(keys).items() if count > 1)
|
|
assert not duplicates, f"Chinese locale has duplicate keys: {duplicates}"
|