forked from ChelseaKR/fare-policy-assistant
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_i18n.py
More file actions
154 lines (123 loc) · 5.88 KB
/
Copy pathtest_i18n.py
File metadata and controls
154 lines (123 loc) · 5.88 KB
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
"""The gettext seam: catalog loading, rider-facing message helpers, negotiation.
These guard the migration from the bespoke EN/ES dict/branch to gettext catalogs
(INTERNATIONALIZATION-STANDARD §3): a loaded catalog returns real Spanish, an
unknown tag falls back to English text, the refusal/no-support helpers render the
same text the old dict did, and ``negotiate_lang`` implements the
``<requested> → <primary subtag> → en`` fallback chain (§6). The refusal *control
flow* is asserted separately in test_guards.py; this file asserts the *text*.
"""
from __future__ import annotations
import pytest
from assistant.i18n import (
DEFAULT_LANGUAGE,
SUPPORTED_LANGUAGES,
get_translation,
negotiate_lang,
no_support_message,
refusal_message,
)
def test_get_translation_loads_spanish_catalog() -> None:
assert (
refusal_message(get_translation("es"), "injection")
== "Solo puedo responder preguntas sobre las políticas de tarifas "
"publicadas. Si necesita otra ayuda, comuníquese con el servicio al "
"cliente de la agencia de tránsito."
)
def test_get_translation_loads_tagalog_catalog() -> None:
assert (
refusal_message(get_translation("tl"), "injection")
== "Maaari lamang akong sumagot sa mga tanong tungkol sa mga inilathalang "
"patakaran sa pamasahe. Kung kailangan mo ng ibang tulong, makipag-ugnayan "
"sa customer service ng transit agency."
)
def test_get_translation_english_is_source_text() -> None:
msg = refusal_message(get_translation("en"), "injection")
assert msg.startswith("I can only answer questions about published transit fare policies.")
def test_get_translation_unknown_tag_falls_back_to_source() -> None:
# fallback=True → NullTranslations returns the English msgid unchanged.
en = refusal_message(get_translation("en"), "pii")
xx = refusal_message(get_translation("xx"), "pii")
assert xx == en
@pytest.mark.parametrize(
("lang", "kind", "needle"),
[
("es", "pii", "datos personales"),
("es", "scope", "asuntos médicos"),
("es", "injection", "tarifas publicadas"),
("tl", "pii", "personal na detalye"),
("tl", "scope", "usaping medikal"),
("tl", "injection", "inilathalang patakaran"),
("en", "pii", "personal details"),
("en", "scope", "medical, immigration, or legal"),
("en", "injection", "published transit fare policies"),
],
)
def test_refusal_message(lang: str, kind: str, needle: str) -> None:
assert needle in refusal_message(get_translation(lang), kind)
def test_no_support_message_english_agency_and_statewide() -> None:
en = get_translation("en")
with_agency = no_support_message(en, agency_hint="MST", statewide_info="STATEWIDE")
without = no_support_message(en, agency_hint=None, statewide_info="STATEWIDE")
assert with_agency == (
"I don't have a published policy document that answers that, and I "
"won't guess about fares or eligibility. Please check the agency's "
"website or customer service for current information."
)
# No-agency branch renders the statewide pointer via the {statewide} field.
assert "your transit agency directly, or STATEWIDE for current" in without
def test_no_support_message_spanish_preserves_no_determination_stance() -> None:
es = get_translation("es")
msg = no_support_message(es, agency_hint=None, statewide_info="INFO")
# The refusal-to-guess stance must survive translation (safety, not just text).
assert "no voy a adivinar sobre tarifas o elegibilidad" in msg
assert "su agencia de tránsito directamente, o INFO" in msg
@pytest.mark.parametrize(
("header", "expected"),
[
(None, "en"),
("", "en"),
(" ", "en"),
("es", "es"),
("ES", "es"),
("es-MX", "es"), # primary-subtag fallback
("tl", "tl"),
("tl-PH", "tl"),
("fr", "en"), # unsupported → default
("*", "en"), # wildcard → default
("en-US,es;q=0.9", "en"), # highest-q primary matches en
("fr;q=0.2, es;q=0.8", "es"), # q-weighted selection
("de-DE, es", "es"), # first unsupported, tie broken by order to es
("es;q=0", "en"), # q=0 means "not acceptable"
("es;q=notanumber", "en"), # malformed q → dropped
(";q=0.5, es", "es"), # empty tag skipped
],
)
def test_negotiate_lang(header: str | None, expected: str) -> None:
assert negotiate_lang(header) == expected
def test_default_language_is_supported() -> None:
assert DEFAULT_LANGUAGE in SUPPORTED_LANGUAGES
def test_catalog_parity_gate_refuses_an_empty_template(tmp_path, monkeypatch, capsys):
"""The gate's own denominator.
Every G5/G6 check iterates over the template's msgid set, so an empty
template makes all of them vacuous: the gate prints "catalog parity OK: 0
msgids" and exits 0 while nothing rider-facing is translated. G2-lite
catches a template that drifts from the sources, but a commit that empties
the sources and the template together drifts from nothing.
"""
from babel.messages.catalog import Catalog
from babel.messages.pofile import write_po
from tools import check_catalog_parity as gate
locales = tmp_path / "locales"
for name in gate.CATALOGS:
(locales / name / "LC_MESSAGES").mkdir(parents=True)
with (locales / name / "LC_MESSAGES" / "messages.po").open("wb") as fh:
write_po(fh, Catalog(locale=name))
with (locales / "messages.pot").open("wb") as fh:
write_po(fh, Catalog())
monkeypatch.setattr(gate, "LOCALES", locales)
monkeypatch.setattr(gate, "POT", locales / "messages.pot")
assert gate.main() == 1
assert "no msgids" in capsys.readouterr().err
def test_the_committed_template_is_not_empty():
from tools import check_catalog_parity as gate
assert len(gate._ids(gate._load(gate.POT, None))) >= 6