plural_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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. // Polish (pl_PL) - 3 forms
  67. "pl_PL": {
  68. 1: 0, // n == 1
  69. 2: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  70. 3: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  71. 4: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  72. 5: 2, // default case
  73. 10: 2, // default case (n%100 < 10, but n%10 not in 2-4)
  74. 11: 2, // default case (n%100 >= 10 and < 20)
  75. 12: 2, // default case (n%100 >= 10 and < 20)
  76. 22: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 >= 20)
  77. 24: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 >= 20)
  78. },
  79. // Portuguese Brazilian (pt_BR) - uses default rule
  80. "pt_BR": {
  81. 0: 0, // n <= 1
  82. 1: 0, // n <= 1
  83. 2: 1, // n > 1
  84. 5: 1, // n > 1
  85. },
  86. // Romanian (ro_RO) - 3 forms
  87. "ro_RO": {
  88. 0: 1, // n == 0 || (n%100 > 0 && n%100 < 20)
  89. 1: 0, // n == 1
  90. 2: 1, // n == 0 || (n%100 > 0 && n%100 < 20)
  91. 5: 1, // n == 0 || (n%100 > 0 && n%100 < 20)
  92. 19: 1, // n == 0 || (n%100 > 0 && n%100 < 20)
  93. 20: 2, // default case
  94. 21: 2, // default case
  95. 100: 2, // default case (n%100 == 0, so condition fails)
  96. 101: 1, // n%100 == 1, so n%100 > 0 && n%100 < 20
  97. },
  98. // Russian (ru_RU) - 3 forms
  99. "ru_RU": {
  100. 1: 0, // n%10 == 1 && n%100 != 11
  101. 2: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  102. 3: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  103. 4: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  104. 5: 2, // default case
  105. 11: 2, // n%10 == 1 but n%100 == 11, so default case
  106. 12: 2, // default case
  107. 21: 0, // n%10 == 1 && n%100 != 11
  108. 22: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 >= 20)
  109. },
  110. // Serbian (sr_RS) - same as Russian
  111. "sr_RS": {
  112. 1: 0, // n%10 == 1 && n%100 != 11
  113. 2: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  114. 5: 2, // default case
  115. 11: 2, // n%10 == 1 but n%100 == 11, so default case
  116. 21: 0, // n%10 == 1 && n%100 != 11
  117. },
  118. // Turkish (tr_TR) - uses default rule
  119. "tr_TR": {
  120. 0: 0, // n <= 1
  121. 1: 0, // n <= 1
  122. 2: 1, // n > 1
  123. 5: 1, // n > 1
  124. },
  125. // Ukrainian (uk_UA) - same as Russian
  126. "uk_UA": {
  127. 1: 0, // n%10 == 1 && n%100 != 11
  128. 2: 1, // n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20)
  129. 5: 2, // default case
  130. 11: 2, // n%10 == 1 but n%100 == 11, so default case
  131. 21: 0, // n%10 == 1 && n%100 != 11
  132. },
  133. // Chinese Simplified (zh_CN) - always form 0
  134. "zh_CN": {
  135. 0: 0,
  136. 1: 0,
  137. 5: 0,
  138. 100: 0,
  139. },
  140. // Chinese Traditional (zh_TW) - always form 0
  141. "zh_TW": {
  142. 0: 0,
  143. 1: 0,
  144. 5: 0,
  145. 100: 0,
  146. },
  147. // Min Nan (nan_Latn_pehoeji) - always form 0
  148. "nan_Latn_pehoeji": {
  149. 0: 0,
  150. 1: 0,
  151. 5: 0,
  152. 100: 0,
  153. },
  154. // Additional languages from AvailableLanguages that use default rule
  155. "de_DE": {
  156. 0: 0, // n <= 1
  157. 1: 0, // n <= 1
  158. 2: 1, // n > 1
  159. },
  160. "el_EL": {
  161. 0: 0, // n <= 1
  162. 1: 0, // n <= 1
  163. 2: 1, // n > 1
  164. },
  165. "en_US": {
  166. 0: 0, // n <= 1
  167. 1: 0, // n <= 1
  168. 2: 1, // n > 1
  169. },
  170. "es_ES": {
  171. 0: 0, // n <= 1
  172. 1: 0, // n <= 1
  173. 2: 1, // n > 1
  174. },
  175. "fi_FI": {
  176. 0: 0, // n <= 1
  177. 1: 0, // n <= 1
  178. 2: 1, // n > 1
  179. },
  180. "hi_IN": {
  181. 0: 0, // n <= 1
  182. 1: 0, // n <= 1
  183. 2: 1, // n > 1
  184. },
  185. "it_IT": {
  186. 0: 0, // n <= 1
  187. 1: 0, // n <= 1
  188. 2: 1, // n > 1
  189. },
  190. "nl_NL": {
  191. 0: 0, // n <= 1
  192. 1: 0, // n <= 1
  193. 2: 1, // n > 1
  194. },
  195. // Test a language not in the switch (should use default rule)
  196. "unknown_language": {
  197. 0: 0, // n <= 1
  198. 1: 0, // n <= 1
  199. 2: 1, // n > 1
  200. },
  201. }
  202. for rule, values := range scenarios {
  203. for input, expected := range values {
  204. result := getPluralForm(rule, input)
  205. if result != expected {
  206. t.Errorf(`Unexpected result for %q rule, got %d instead of %d for %d as input`, rule, result, expected, input)
  207. }
  208. }
  209. }
  210. }