plural_test.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package locale // import "miniflux.app/v2/internal/locale"
  4. import "testing"
  5. func TestPluralRules(t *testing.T) {
  6. scenarios := map[string]map[int]int{
  7. // Default rule (covers fr_FR, pt_BR, tr_TR, and other unlisted languages)
  8. "default": {
  9. 0: 0, // n <= 1
  10. 1: 0, // n <= 1
  11. 2: 1, // n > 1
  12. 5: 1, // n > 1
  13. },
  14. // Arabic (ar_SA) - 6 forms
  15. "ar_SA": {
  16. 0: 0, // n == 0
  17. 1: 1, // n == 1
  18. 2: 2, // n == 2
  19. 3: 3, // n%100 >= 3 && n%100 <= 10
  20. 5: 3, // n%100 >= 3 && n%100 <= 10
  21. 10: 3, // n%100 >= 3 && n%100 <= 10
  22. 11: 4, // n%100 >= 11
  23. 15: 4, // n%100 >= 11
  24. 99: 4, // n%100 >= 11
  25. 100: 5, // default case (n%100 == 0, doesn't match any condition)
  26. 101: 5, // default case (n%100 == 1, but n != 1)
  27. 200: 5, // default case
  28. },
  29. // Czech (cs_CZ) - 3 forms
  30. "cs_CZ": {
  31. 1: 0, // n == 1
  32. 2: 1, // n >= 2 && n <= 4
  33. 3: 1, // n >= 2 && n <= 4
  34. 4: 1, // n >= 2 && n <= 4
  35. 5: 2, // default case
  36. },
  37. // French (fr_FR) - uses default rule
  38. "fr_FR": {
  39. 0: 0, // n <= 1
  40. 1: 0, // n <= 1
  41. 2: 1, // n > 1
  42. 5: 1, // n > 1
  43. },
  44. // Galician (gl_ES) - n != 1
  45. "gl_ES": {
  46. 0: 1, // n != 1
  47. 1: 0, // n == 1
  48. 2: 1, // n != 1
  49. 5: 1, // n != 1
  50. },
  51. // Indonesian (id_ID) - always form 0
  52. "id_ID": {
  53. 0: 0,
  54. 1: 0,
  55. 5: 0,
  56. 100: 0,
  57. },
  58. // Japanese (ja_JP) - always form 0
  59. "ja_JP": {
  60. 0: 0,
  61. 1: 0,
  62. 2: 0,
  63. 5: 0,
  64. 100: 0,
  65. },
  66. // Korean (ko_KR) - always form 0
  67. "ko_KR": {
  68. 0: 0,
  69. 1: 0,
  70. 2: 0,
  71. 5: 0,
  72. 100: 0,
  73. },
  74. // Polish (pl_PL) - 3 forms
  75. "pl_PL": {
  76. 1: 0, // n == 1
  77. 2: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  78. 3: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  79. 4: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  80. 5: 2, // default case
  81. 10: 2, // default case (n%100 < 10, but n%10 not in 2-4)
  82. 11: 2, // default case (n%100 >= 10 and < 20)
  83. 12: 2, // default case (n%100 >= 10 and < 20)
  84. 22: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 >= 20)
  85. 24: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 >= 20)
  86. },
  87. // Portuguese Brazilian (pt_BR) - uses default rule
  88. "pt_BR": {
  89. 0: 0, // n <= 1
  90. 1: 0, // n <= 1
  91. 2: 1, // n > 1
  92. 5: 1, // n > 1
  93. },
  94. // Romanian (ro_RO) - 3 forms
  95. "ro_RO": {
  96. 0: 1, // n == 0 || (n%100 > 0 && n%100 < 20)
  97. 1: 0, // n == 1
  98. 2: 1, // n == 0 || (n%100 > 0 && n%100 < 20)
  99. 5: 1, // n == 0 || (n%100 > 0 && n%100 < 20)
  100. 19: 1, // n == 0 || (n%100 > 0 && n%100 < 20)
  101. 20: 2, // default case
  102. 21: 2, // default case
  103. 100: 2, // default case (n%100 == 0, so condition fails)
  104. 101: 1, // n%100 == 1, so n%100 > 0 && n%100 < 20
  105. },
  106. // Russian (ru_RU) - 3 forms
  107. "ru_RU": {
  108. 1: 0, // n%10 == 1 && n%100 != 11
  109. 2: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  110. 3: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  111. 4: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  112. 5: 2, // default case
  113. 11: 2, // n%10 == 1 but n%100 == 11, so default case
  114. 12: 2, // default case
  115. 21: 0, // n%10 == 1 && n%100 != 11
  116. 22: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 >= 20)
  117. },
  118. // Serbian (sr_RS) - same as Russian
  119. "sr_RS": {
  120. 1: 0, // n%10 == 1 && n%100 != 11
  121. 2: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  122. 5: 2, // default case
  123. 11: 2, // n%10 == 1 but n%100 == 11, so default case
  124. 21: 0, // n%10 == 1 && n%100 != 11
  125. },
  126. // Turkish (tr_TR) - uses default rule
  127. "tr_TR": {
  128. 0: 0, // n <= 1
  129. 1: 0, // n <= 1
  130. 2: 1, // n > 1
  131. 5: 1, // n > 1
  132. },
  133. // Ukrainian (uk_UA) - same as Russian
  134. "uk_UA": {
  135. 1: 0, // n%10 == 1 && n%100 != 11
  136. 2: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  137. 5: 2, // default case
  138. 11: 2, // n%10 == 1 but n%100 == 11, so default case
  139. 21: 0, // n%10 == 1 && n%100 != 11
  140. },
  141. // Chinese Simplified (zh_CN) - always form 0
  142. "zh_CN": {
  143. 0: 0,
  144. 1: 0,
  145. 5: 0,
  146. 100: 0,
  147. },
  148. // Chinese Traditional (zh_TW) - always form 0
  149. "zh_TW": {
  150. 0: 0,
  151. 1: 0,
  152. 5: 0,
  153. 100: 0,
  154. },
  155. // Min Nan (nan_Latn_pehoeji) - always form 0
  156. "nan_Latn_pehoeji": {
  157. 0: 0,
  158. 1: 0,
  159. 5: 0,
  160. 100: 0,
  161. },
  162. // Additional languages from AvailableLanguages that use default rule
  163. "de_DE": {
  164. 0: 0, // n <= 1
  165. 1: 0, // n <= 1
  166. 2: 1, // n > 1
  167. },
  168. "el_EL": {
  169. 0: 0, // n <= 1
  170. 1: 0, // n <= 1
  171. 2: 1, // n > 1
  172. },
  173. "en_US": {
  174. 0: 0, // n <= 1
  175. 1: 0, // n <= 1
  176. 2: 1, // n > 1
  177. },
  178. "es_ES": {
  179. 0: 0, // n <= 1
  180. 1: 0, // n <= 1
  181. 2: 1, // n > 1
  182. },
  183. "fi_FI": {
  184. 0: 0, // n <= 1
  185. 1: 0, // n <= 1
  186. 2: 1, // n > 1
  187. },
  188. "hi_IN": {
  189. 0: 0, // n <= 1
  190. 1: 0, // n <= 1
  191. 2: 1, // n > 1
  192. },
  193. "it_IT": {
  194. 0: 0, // n <= 1
  195. 1: 0, // n <= 1
  196. 2: 1, // n > 1
  197. },
  198. "nl_NL": {
  199. 0: 0, // n <= 1
  200. 1: 0, // n <= 1
  201. 2: 1, // n > 1
  202. },
  203. // Test a language not in the switch (should use default rule)
  204. "unknown_language": {
  205. 0: 0, // n <= 1
  206. 1: 0, // n <= 1
  207. 2: 1, // n > 1
  208. },
  209. }
  210. for rule, values := range scenarios {
  211. for input, expected := range values {
  212. result := getPluralForm(rule, input)
  213. if result != expected {
  214. t.Errorf(`Unexpected result for %q rule, got %d instead of %d for %d as input`, rule, result, expected, input)
  215. }
  216. }
  217. }
  218. }