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

1import pytest 

2 

3from couchers.i18n.i18next import I18Next, LocalizationError 

4from couchers.i18n.plurals import PluralRules 

5 

6 

7def test_lookup(): 

8 i18next = I18Next() 

9 i18next.add_language("en", PluralRules.en).add_string("greeting", "hello") 

10 assert i18next.localize("greeting", "en") == "hello" 

11 

12 

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!" 

17 

18 

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!" 

23 

24 

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" 

33 

34 

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" 

42 

43 

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" 

54 

55 

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" 

63 

64 

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" 

72 

73 

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" 

81 

82 

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" 

88 

89 

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" 

95 

96 

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" 

103 

104 

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" 

111 

112 

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" 

120 

121 

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" 

131 

132 

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"}) 

137 

138 

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" 

146 

147 

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"