Coverage for app / backend / src / tests / test_i18next.py: 100%
118 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 06:18 +0000
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 06:18 +0000
1import pytest
3from couchers.i18n.i18next import I18Next, LocalizationError
4from couchers.i18n.plurals import PluralRules
7def test_lookup():
8 i18next = I18Next()
9 i18next.add_language("en", PluralRules.en).add_string("greeting", "hello")
10 assert i18next.localize("greeting", "en") == "hello"
13def test_substitution():
14 i18next = I18Next()
15 i18next.add_language("en", PluralRules.en).add_string("greeting", "hello {{name}}!")
16 assert i18next.localize("greeting", "en", {"name": "world"}) == "hello world!"
19def test_placeholder_with_spacing():
20 i18next = I18Next()
21 i18next.add_language("en", PluralRules.en).add_string("greeting", "hello {{ name }}!")
22 assert i18next.localize("greeting", "en", {"name": "world"}) == "hello world!"
25def test_localized():
26 i18next = I18Next()
27 en = i18next.add_language("en", PluralRules.en)
28 en.add_string("greeting", "hello")
29 fr = i18next.add_language("fr", PluralRules.en)
30 fr.add_string("greeting", "bonjour")
31 fr.fallbacks.append(en)
32 assert i18next.localize("greeting", "fr") == "bonjour"
35def test_fallback():
36 i18next = I18Next()
37 en = i18next.add_language("en", PluralRules.en)
38 en.add_string("greeting", "hello")
39 fr = i18next.add_language("fr", PluralRules.en)
40 fr.fallbacks.append(en)
41 assert i18next.localize("greeting", "fr") == "hello"
44def test_mutual_fallback():
45 i18next = I18Next()
46 pt_pt = i18next.add_language("pt-PT", PluralRules.en)
47 pt_pt.add_string("greeting", "olá")
48 pt_br = i18next.add_language("pt-BR", PluralRules.en)
49 pt_br.add_string("farewell", "tchau")
50 pt_pt.fallbacks.append(pt_br)
51 pt_br.fallbacks.append(pt_pt)
52 assert i18next.localize("greeting", "pt-BR") == "olá"
53 assert i18next.localize("farewell", "pt-PT") == "tchau"
56def test_plural_suffixes():
57 i18next = I18Next()
58 en = i18next.add_language("en", PluralRules.en)
59 en.add_string("apples_one", "{{count}} apple")
60 en.add_string("apples_other", "{{count}} apples")
61 assert i18next.localize("apples", "en", {"count": 1}) == "1 apple"
62 assert i18next.localize("apples", "en", {"count": 2}) == "2 apples"
65def test_plural_suffix_fallback():
66 i18next = I18Next()
67 en = i18next.add_language("en", PluralRules.en)
68 en.add_string("apples", "{{count}} apples")
69 en.add_string("apples_one", "{{count}} apple")
70 assert i18next.localize("apples", "en", {"count": 1}) == "1 apple"
71 assert i18next.localize("apples", "en", {"count": 2}) == "2 apples"
74def test_plural_no_count():
75 i18next = I18Next()
76 en = i18next.add_language("en", PluralRules.en)
77 en.add_string("apples_one", "apple")
78 en.add_string("apples_other", "apples")
79 assert i18next.localize("apples", "en", {"count": 1}) == "apple"
80 assert i18next.localize("apples", "en", {"count": 2}) == "apples"
83def test_load_simple_json():
84 i18next = I18Next()
85 en = i18next.add_language("en", PluralRules.en)
86 en.load_json_dict({"greeting": "hello"})
87 assert i18next.localize("greeting", "en") == "hello"
90def test_load_nested_json():
91 i18next = I18Next()
92 en = i18next.add_language("en", PluralRules.en)
93 en.load_json_dict({"greeting": {"short": "hi"}})
94 assert i18next.localize("greeting.short", "en") == "hi"
97def test_fallback_locale():
98 i18next = I18Next()
99 en = i18next.add_language("en", PluralRules.en)
100 en.add_string("greeting", "hello")
101 i18next.default_language = en
102 assert i18next.localize("greeting", "fr") == "hello"
105def test_missing_locale():
106 i18next = I18Next()
107 with pytest.raises(LocalizationError) as raised:
108 i18next.localize("greeting", "en")
109 assert raised.value.language_code == "en"
110 assert raised.value.string_key == "greeting"
113def test_missing_string():
114 i18next = I18Next()
115 i18next.add_language("en", PluralRules.en)
116 with pytest.raises(LocalizationError) as raised:
117 i18next.localize("greeting", "en")
118 assert raised.value.language_code == "en"
119 assert raised.value.string_key == "greeting"
122def test_missing_plural_form():
123 i18next = I18Next()
124 en = i18next.add_language("en", PluralRules.en)
125 en.add_string("apples_one", "{{count}} apple")
126 assert i18next.localize("apples", "en", {"count": 1}) == "1 apple"
127 with pytest.raises(LocalizationError) as raised:
128 i18next.localize("apples", "en", {"count": 2})
129 assert raised.value.language_code == "en"
130 assert raised.value.string_key == "apples"
133def test_extra_substitution():
134 i18next = I18Next()
135 i18next.add_language("en", PluralRules.en).add_string("greeting", "hello")
136 assert i18next.localize("greeting", "en", substitutions={"e": "mc2"})
139def test_missing_substitution():
140 i18next = I18Next()
141 i18next.add_language("en", PluralRules.en).add_string("greeting", "hello {{name}}")
142 with pytest.raises(LocalizationError) as raised:
143 i18next.localize("greeting", "en")
144 assert raised.value.language_code == "en"
145 assert raised.value.string_key == "greeting"
148def test_missing_substitution_fallback():
149 i18next = I18Next()
150 en = i18next.add_language("en", PluralRules.en)
151 en.add_string("greeting", "hello {{name}}")
152 fr = i18next.add_language("fr", PluralRules.fr)
153 fr.add_string("greeting", "bonjour {{nom}}")
154 fr.fallbacks.append(en)
155 assert i18next.localize("greeting", "fr", substitutions={"name": "world"}) == "hello world"