1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
"""Tests that i18n keys referenced in code and templates exist in JSON files."""
from __future__ import annotations
import json
import re
from pathlib import Path
import pytest
from ollama_web import i18n, prompts
_SRC = Path(__file__).resolve().parent.parent / "src" / "ollama_web"
def _json_keys(data: dict, prefix: str = "") -> set[str]:
"""Return all dot-separated keys in a nested dict."""
keys: set[str] = set()
for key, value in data.items():
full = f"{prefix}.{key}" if prefix else key
keys.add(full)
if isinstance(value, dict):
keys.update(_json_keys(value, full))
return keys
def _extract_template_keys(path: Path) -> set[str]:
"""Find t('...') calls in Jinja2 templates."""
text = path.read_text(encoding="utf-8")
return set(re.findall(r"{{\s*t\(['\"]([^'\"]+)['\"]", text))
def _extract_js_keys(path: Path) -> set[str]:
"""Find t("...") / t('...') calls in JavaScript files."""
text = path.read_text(encoding="utf-8")
return set(re.findall(r"\bt\(['\"]([^'\"]+)['\"]", text))
def _extract_python_t_keys(path: Path) -> set[str]:
"""Find t(...) calls in Python source."""
text = path.read_text(encoding="utf-8")
return set(re.findall(r"\bt\(['\"]([^'\"]+)['\"]", text))
def _extract_python_prompt_keys(path: Path) -> set[str]:
"""Find get_prompt(...) calls in Python source."""
text = path.read_text(encoding="utf-8")
return set(re.findall(r"\bget_prompt\(['\"]([^'\"]+)['\"]", text))
def _referenced_message_keys() -> set[str]:
"""Collect every message key referenced from templates, JS and Python."""
referenced: set[str] = set()
for path in _SRC.rglob("*.html"):
referenced.update(_extract_template_keys(path))
for path in _SRC.rglob("*.js"):
referenced.update(_extract_js_keys(path))
for path in _SRC.rglob("*.py"):
referenced.update(_extract_python_t_keys(path))
return referenced
def _referenced_prompt_keys() -> set[str]:
"""Collect every prompt key referenced from Python."""
referenced: set[str] = set()
for path in _SRC.rglob("*.py"):
referenced.update(_extract_python_prompt_keys(path))
return referenced
@pytest.mark.parametrize("lang", ["ja", "en"])
def test_all_message_keys_exist(lang: str):
"""Every referenced message key must exist for each supported language."""
messages = i18n.get_messages(lang)
available = _json_keys(messages)
missing = _referenced_message_keys() - available
assert not missing, f"Missing keys in i18n/messages/{lang}.json: {sorted(missing)}"
@pytest.mark.parametrize("lang", ["ja", "en"])
def test_all_prompt_keys_exist(lang: str):
"""Every referenced prompt key must exist for each supported language."""
prompt_data = prompts.get_prompts(lang)
available = _json_keys(prompt_data)
missing = _referenced_prompt_keys() - available
assert not missing, f"Missing keys in prompts/{lang}.json: {sorted(missing)}"
@pytest.mark.parametrize("lang", ["ja", "en"])
def test_json_files_are_valid(lang: str):
"""Both localization JSON files must be valid and parseable."""
assert isinstance(i18n.get_messages(lang), dict)
assert isinstance(prompts.get_prompts(lang), dict)
def test_t_returns_expected_strings():
"""Basic sanity checks for the t() helper."""
assert i18n.t("common.send") == "送信"
assert i18n.t("common.send", lang="en") == "Send"
assert i18n.t("missing.key", fallback="fallback") == "fallback"
assert i18n.t("missing.key") == "missing.key"
def test_get_prompt_returns_expected_strings():
"""Basic sanity checks for the get_prompt() helper."""
assert prompts.get_prompt("tool_system") == prompts.get_prompts("ja")["tool_system"]
assert prompts.get_prompt("tool_system", lang="en") == prompts.get_prompts("en")["tool_system"]
assert prompts.get_prompt("missing.prompt", fallback="fallback") == "fallback"
assert prompts.get_prompt("missing.prompt") == "missing.prompt"
|