gettext 3.3.6 → 3.4.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (207) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/Rakefile +5 -3
  4. data/doc/text/news.md +168 -0
  5. data/gettext.gemspec +7 -4
  6. data/lib/gettext/mo.rb +12 -19
  7. data/lib/gettext/po_entry.rb +31 -21
  8. data/lib/gettext/po_parser.rb +65 -59
  9. data/lib/gettext/text_domain_manager.rb +6 -5
  10. data/lib/gettext/tools/msgcat.rb +9 -2
  11. data/lib/gettext/tools/msginit.rb +221 -50
  12. data/lib/gettext/tools/msgmerge.rb +24 -6
  13. data/lib/gettext/tools/parser/erubi.rb +88 -0
  14. data/lib/gettext/tools/parser/glade.rb +38 -40
  15. data/lib/gettext/tools/parser/gtk_builder_ui_definitions.rb +6 -3
  16. data/lib/gettext/tools/parser/ruby.rb +2 -2
  17. data/lib/gettext/tools/task.rb +3 -5
  18. data/lib/gettext/tools/xgettext.rb +15 -4
  19. data/lib/gettext/version.rb +3 -3
  20. data/locale/bg/LC_MESSAGES/gettext.mo +0 -0
  21. data/locale/bs/LC_MESSAGES/gettext.mo +0 -0
  22. data/locale/ca/LC_MESSAGES/gettext.mo +0 -0
  23. data/locale/cs/LC_MESSAGES/gettext.mo +0 -0
  24. data/locale/de/LC_MESSAGES/gettext.mo +0 -0
  25. data/locale/el/LC_MESSAGES/gettext.mo +0 -0
  26. data/locale/eo/LC_MESSAGES/gettext.mo +0 -0
  27. data/locale/es/LC_MESSAGES/gettext.mo +0 -0
  28. data/locale/et/LC_MESSAGES/gettext.mo +0 -0
  29. data/locale/fr/LC_MESSAGES/gettext.mo +0 -0
  30. data/locale/hr/LC_MESSAGES/gettext.mo +0 -0
  31. data/locale/hu/LC_MESSAGES/gettext.mo +0 -0
  32. data/locale/it/LC_MESSAGES/gettext.mo +0 -0
  33. data/locale/ja/LC_MESSAGES/gettext.mo +0 -0
  34. data/locale/ko/LC_MESSAGES/gettext.mo +0 -0
  35. data/locale/lv/LC_MESSAGES/gettext.mo +0 -0
  36. data/locale/nb/LC_MESSAGES/gettext.mo +0 -0
  37. data/locale/nl/LC_MESSAGES/gettext.mo +0 -0
  38. data/locale/pt_BR/LC_MESSAGES/gettext.mo +0 -0
  39. data/locale/ru/LC_MESSAGES/gettext.mo +0 -0
  40. data/locale/sr/LC_MESSAGES/gettext.mo +0 -0
  41. data/locale/uk/LC_MESSAGES/gettext.mo +0 -0
  42. data/locale/vi/LC_MESSAGES/gettext.mo +0 -0
  43. data/locale/zh/LC_MESSAGES/gettext.mo +0 -0
  44. data/locale/zh_TW/LC_MESSAGES/gettext.mo +0 -0
  45. data/po/bg/gettext.edit.po +80 -593
  46. data/po/bg/gettext.po +6 -423
  47. data/po/bs/gettext.edit.po +80 -593
  48. data/po/bs/gettext.po +6 -423
  49. data/po/ca/gettext.edit.po +80 -593
  50. data/po/ca/gettext.po +6 -423
  51. data/po/cs/gettext.edit.po +80 -593
  52. data/po/cs/gettext.po +6 -423
  53. data/po/de/gettext.edit.po +80 -593
  54. data/po/de/gettext.po +6 -423
  55. data/po/el/gettext.edit.po +80 -593
  56. data/po/el/gettext.po +6 -423
  57. data/po/eo/gettext.edit.po +80 -593
  58. data/po/eo/gettext.po +6 -423
  59. data/po/es/gettext.edit.po +80 -593
  60. data/po/es/gettext.po +6 -423
  61. data/po/et/gettext.edit.po +80 -593
  62. data/po/et/gettext.po +6 -423
  63. data/po/fr/gettext.edit.po +80 -593
  64. data/po/fr/gettext.po +6 -423
  65. data/po/gettext.pot +92 -665
  66. data/po/hr/gettext.edit.po +80 -593
  67. data/po/hr/gettext.po +6 -423
  68. data/po/hu/gettext.edit.po +80 -593
  69. data/po/hu/gettext.po +6 -423
  70. data/po/it/gettext.edit.po +80 -593
  71. data/po/it/gettext.po +6 -423
  72. data/po/ja/gettext.edit.po +81 -594
  73. data/po/ja/gettext.po +7 -424
  74. data/po/ko/gettext.edit.po +80 -593
  75. data/po/ko/gettext.po +6 -423
  76. data/po/lv/gettext.edit.po +80 -593
  77. data/po/lv/gettext.po +6 -423
  78. data/po/nb/gettext.edit.po +80 -593
  79. data/po/nb/gettext.po +6 -423
  80. data/po/nl/gettext.edit.po +80 -593
  81. data/po/nl/gettext.po +6 -423
  82. data/po/pt_BR/gettext.edit.po +80 -593
  83. data/po/pt_BR/gettext.po +6 -423
  84. data/po/ru/gettext.edit.po +80 -593
  85. data/po/ru/gettext.po +6 -423
  86. data/po/sr/gettext.edit.po +80 -593
  87. data/po/sr/gettext.po +6 -423
  88. data/po/sv/gettext.edit.po +80 -593
  89. data/po/sv/gettext.po +6 -423
  90. data/po/uk/gettext.edit.po +80 -593
  91. data/po/uk/gettext.po +6 -423
  92. data/po/vi/gettext.edit.po +80 -593
  93. data/po/vi/gettext.po +6 -423
  94. data/po/zh/gettext.edit.po +80 -593
  95. data/po/zh/gettext.po +6 -423
  96. data/po/zh_TW/gettext.edit.po +80 -593
  97. data/po/zh_TW/gettext.po +6 -423
  98. data/samples/cgi/po/helloerb1.pot +3 -3
  99. data/samples/cgi/po/helloerb2.pot +3 -3
  100. data/samples/cgi/po/hellolib.pot +3 -3
  101. data/samples/cgi/po/main.pot +3 -3
  102. data/samples/po/bg/hello_gtk_builder.edit.po +15 -0
  103. data/samples/po/bg/hello_gtk_builder.po +12 -0
  104. data/samples/po/bs/hello_gtk_builder.edit.po +15 -0
  105. data/samples/po/bs/hello_gtk_builder.po +12 -0
  106. data/samples/po/ca/hello_gtk_builder.edit.po +15 -0
  107. data/samples/po/ca/hello_gtk_builder.po +12 -0
  108. data/samples/po/cs/hello_gtk_builder.edit.po +15 -0
  109. data/samples/po/cs/hello_gtk_builder.po +12 -0
  110. data/samples/po/de/hello_gtk_builder.edit.po +15 -0
  111. data/samples/po/de/hello_gtk_builder.po +12 -0
  112. data/samples/po/el/hello_gtk_builder.edit.po +15 -0
  113. data/samples/po/el/hello_gtk_builder.po +12 -0
  114. data/samples/po/eo/hello_gtk_builder.edit.po +15 -0
  115. data/samples/po/eo/hello_gtk_builder.po +12 -0
  116. data/samples/po/es/hello_gtk_builder.edit.po +15 -0
  117. data/samples/po/es/hello_gtk_builder.po +12 -0
  118. data/samples/po/fr/hello_gtk_builder.edit.po +15 -0
  119. data/samples/po/fr/hello_gtk_builder.po +12 -0
  120. data/samples/po/hello.pot +3 -3
  121. data/samples/po/hello2.pot +4 -4
  122. data/samples/po/hello_glade2.pot +8 -5
  123. data/samples/po/hello_gtk2.pot +4 -4
  124. data/samples/po/hello_gtk_builder.pot +18 -4
  125. data/samples/po/hello_noop.pot +4 -4
  126. data/samples/po/hello_plural.pot +4 -4
  127. data/samples/po/hello_tk.pot +4 -4
  128. data/samples/po/hr/hello_gtk_builder.edit.po +15 -0
  129. data/samples/po/hr/hello_gtk_builder.po +12 -0
  130. data/samples/po/hu/hello_gtk_builder.edit.po +15 -0
  131. data/samples/po/hu/hello_gtk_builder.po +12 -0
  132. data/samples/po/it/hello_gtk_builder.edit.po +15 -0
  133. data/samples/po/it/hello_gtk_builder.po +12 -0
  134. data/samples/po/ja/hello_gtk_builder.edit.po +15 -0
  135. data/samples/po/ja/hello_gtk_builder.po +12 -0
  136. data/samples/po/ko/hello_gtk_builder.edit.po +15 -0
  137. data/samples/po/ko/hello_gtk_builder.po +12 -0
  138. data/samples/po/lv/hello_gtk_builder.edit.po +15 -0
  139. data/samples/po/lv/hello_gtk_builder.po +12 -0
  140. data/samples/po/nb/hello_gtk_builder.edit.po +15 -0
  141. data/samples/po/nb/hello_gtk_builder.po +12 -0
  142. data/samples/po/nl/hello_gtk_builder.edit.po +15 -0
  143. data/samples/po/nl/hello_gtk_builder.po +12 -0
  144. data/samples/po/pt_BR/hello_gtk_builder.edit.po +15 -0
  145. data/samples/po/pt_BR/hello_gtk_builder.po +12 -0
  146. data/samples/po/ru/hello_gtk_builder.edit.po +15 -0
  147. data/samples/po/ru/hello_gtk_builder.po +12 -0
  148. data/samples/po/sr/hello_gtk_builder.edit.po +15 -0
  149. data/samples/po/sr/hello_gtk_builder.po +12 -0
  150. data/samples/po/sv/hello_gtk_builder.edit.po +15 -0
  151. data/samples/po/sv/hello_gtk_builder.po +12 -0
  152. data/samples/po/uk/hello_gtk_builder.edit.po +15 -0
  153. data/samples/po/uk/hello_gtk_builder.po +12 -0
  154. data/samples/po/vi/hello_gtk_builder.edit.po +15 -0
  155. data/samples/po/vi/hello_gtk_builder.po +12 -0
  156. data/samples/po/zh/hello_gtk_builder.edit.po +15 -0
  157. data/samples/po/zh/hello_gtk_builder.po +12 -0
  158. data/samples/po/zh_TW/hello_gtk_builder.edit.po +15 -0
  159. data/samples/po/zh_TW/hello_gtk_builder.po +12 -0
  160. data/src/po_parser.ry +48 -42
  161. data/test/fixtures/_.rb +1 -1
  162. data/test/fixtures/erb/case.rhtml +16 -0
  163. data/test/fixtures/{gtk_builder_ui_definitions.ui~ → glade/3.glade} +12 -17
  164. data/test/fixtures/multi_text_domain.rb +12 -12
  165. data/test/fixtures/np_.rb +1 -1
  166. data/test/fixtures/ns_.rb +1 -1
  167. data/test/fixtures/p_.rb +1 -1
  168. data/test/fixtures/s_.rb +1 -1
  169. data/test/fixtures/simple.rb +5 -1
  170. data/test/fixtures/upper_nn_.rb +77 -0
  171. data/test/locale/fr/LC_MESSAGES/test1.mo +0 -0
  172. data/test/locale/fr_BE/LC_MESSAGES/test1.mo +0 -0
  173. data/test/locale/fr_BE_Foo/LC_MESSAGES/test1.mo +0 -0
  174. data/test/locale/ja/LC_MESSAGES/_.mo +0 -0
  175. data/test/po/_.pot +20 -4
  176. data/test/po/backslash.pot +6 -4
  177. data/test/po/fr/test1.po +7 -0
  178. data/test/po/fr_BE/test1.po +24 -0
  179. data/test/po/fr_BE_Foo/test1.po +20 -0
  180. data/test/po/hello.pot +3 -3
  181. data/test/po/ja/_.edit.po +27 -3
  182. data/test/po/ja/_.po +15 -0
  183. data/test/po/ja/hello.edit.po +0 -1
  184. data/test/po/non_ascii.pot +4 -4
  185. data/test/po/np_.pot +8 -5
  186. data/test/po/ns_.pot +6 -4
  187. data/test/po/p_.pot +3 -3
  188. data/test/po/s_.pot +6 -4
  189. data/test/po/untranslated.pot +4 -4
  190. data/test/test_gettext.rb +23 -0
  191. data/test/test_locale_path.rb +12 -4
  192. data/test/test_parser.rb +97 -17
  193. data/test/test_po_entry.rb +20 -4
  194. data/test/test_po_parser.rb +44 -1
  195. data/test/tools/parser/test_glade.rb +91 -0
  196. data/test/tools/parser/test_gtk_builder_ui_definitions.rb +19 -1
  197. data/test/tools/parser/test_ruby.rb +4 -4
  198. data/test/tools/test_msgcat.rb +21 -1
  199. data/test/tools/test_msginit.rb +82 -3
  200. data/test/tools/test_msgmerge.rb +75 -3
  201. data/test/tools/test_xgettext.rb +100 -3
  202. metadata +70 -19
  203. /data/test/fixtures/{gladeparser.glade → glade/2.glade} +0 -0
  204. /data/test/fixtures/ruby/{percent_i.rb → percent_lower_i.rb} +0 -0
  205. /data/test/fixtures/ruby/{percent_w.rb → percent_lower_w.rb} +0 -0
  206. /data/test/fixtures/ruby/{percent_I.rb → percent_upper_i.rb} +0 -0
  207. /data/test/fixtures/ruby/{percent_W.rb → percent_upper_w.rb} +0 -0
@@ -233,13 +233,15 @@ EOE
233
233
  class TestEscape < self
234
234
  def test_normal
235
235
  entry = GetText::POEntry.new(:normal)
236
- entry.msgid = "He said \"hello.\""
237
- entry.msgstr = "Il a dit \"bonjour.\""
236
+ entry.msgid = "He said \"hello.\"\r\n"
237
+ entry.msgstr = "Il a dit \"bonjour.\"\r\n"
238
238
  entry.references = ["file1:1", "file2:10"]
239
239
  expected_po = <<-EOE
240
240
  #: file1:1 file2:10
241
- msgid "He said \\"hello.\\""
242
- msgstr "Il a dit \\"bonjour.\\""
241
+ msgid ""
242
+ "He said \\"hello.\\"\\r\\n"
243
+ msgstr ""
244
+ "Il a dit \\"bonjour.\\"\\r\\n"
243
245
  EOE
244
246
  assert_equal(expected_po, entry.to_s)
245
247
  end
@@ -342,6 +344,20 @@ EOP
342
344
  assert_equal(expected_po, entry.to_s)
343
345
  end
344
346
 
347
+ def test_multiple_flags
348
+ entry = GetText::POEntry.new(:normal)
349
+ entry.msgid = "msgid"
350
+ entry.msgstr = "msgstr"
351
+ entry.flags = ["It's the flag.", "fuzzy"]
352
+
353
+ expected_po = <<-EOP
354
+ #, It's the flag., fuzzy
355
+ msgid "msgid"
356
+ msgstr "msgstr"
357
+ EOP
358
+ assert_equal(expected_po, entry.to_s)
359
+ end
360
+
345
361
  def test_previous
346
362
  entry = GetText::POEntry.new(:normal)
347
363
  entry.msgid = "msgid"
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2012-2020 Sutou Kouhei <kou@clear-code.com>
1
+ # Copyright (C) 2012-2023 Sutou Kouhei <kou@clear-code.com>
2
2
  # Copyright (C) 2012 Haruka Yoshihara <yoshihara@clear-code.com>
3
3
  #
4
4
  # License: Ruby's or LGPL
@@ -62,6 +62,16 @@ EOP
62
62
  class TestPO < self
63
63
  include Helper::Warning
64
64
 
65
+ def test_msgid_escape
66
+ po_file = create_po_file(<<-'EOP')
67
+ msgid "\\\\r \\r \t \r \n"
68
+ msgstr "\\\\r \\r \t \r \n"
69
+ EOP
70
+ entries = parse_po_file(po_file)
71
+ assert_equal("\\\\r \\r \t \r \n",
72
+ entries["\\\\r \\r \t \r \n"].msgstr)
73
+ end
74
+
65
75
  def test_msgstr
66
76
  po_file = create_po_file(<<-EOP)
67
77
  # This is the comment.
@@ -228,6 +238,39 @@ EOP
228
238
  assert_equal("fuzzy", entries["hello"].flag)
229
239
  end
230
240
 
241
+ def test_fuzzy_ignore
242
+ po_file = create_po_file(<<-PO)
243
+ #, fuzzy
244
+ #: file.rb:10
245
+ msgid "hello"
246
+ msgstr "bonjour"
247
+
248
+ #, c-format, fuzzy , no-sh-format
249
+ #: file.rb:11
250
+ msgid "world"
251
+ msgstr "monde"
252
+
253
+ # This is not fuzzy
254
+ msgid "non-fuzzy"
255
+ msgstr "non-fuzzy string"
256
+ PO
257
+ entries = suppress_warning do
258
+ parse_po_file(po_file)
259
+ end
260
+
261
+ actual = entries.collect do |entry|
262
+ [
263
+ entry.msgid,
264
+ entry.msgstr,
265
+ entry.flags,
266
+ ]
267
+ end
268
+ assert_equal([
269
+ ["non-fuzzy", "non-fuzzy string", []],
270
+ ],
271
+ actual)
272
+ end
273
+
231
274
  private
232
275
  def parse_po_file(po_file, options={:ignore_fuzzy => true})
233
276
  ignore_fuzzy = options[:ignore_fuzzy]
@@ -0,0 +1,91 @@
1
+ # Copyright (C) 2009-2010 Masao Mutoh
2
+ # Copyright (C) 2021 Sutou Kouhei <kou@clear-code.com>
3
+ #
4
+ # License: Ruby's or LGPL
5
+ #
6
+ # This library is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This library is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require "gettext/tools/parser/glade"
20
+
21
+ class TestGladeParser < Test::Unit::TestCase
22
+ include Helper::Parser
23
+
24
+ def parse(file)
25
+ GetText::GladeParser.parse(fixture_path(file))
26
+ end
27
+
28
+ def test_2
29
+ assert_parse([
30
+ {
31
+ msgid: "window1",
32
+ references: ["glade/2.glade:8"],
33
+ },
34
+ {
35
+ msgid: "normal text",
36
+ references: ["glade/2.glade:29"],
37
+ },
38
+ {
39
+ msgid: "1st line\n2nd line\n3rd line",
40
+ references: ["glade/2.glade:50"],
41
+ },
42
+ {
43
+ msgid:
44
+ "<span color=\"red\" " +
45
+ "weight=\"bold\" " +
46
+ "size=\"large\">markup </span>",
47
+ references: ["glade/2.glade:73"],
48
+ },
49
+ {
50
+ msgid:
51
+ "<span color=\"red\">1st line markup </span>\n" +
52
+ "<span color=\"blue\">2nd line markup</span>",
53
+ references: ["glade/2.glade:94"],
54
+ },
55
+ {
56
+ msgid:
57
+ "<span>" +
58
+ "&quot;markup&quot; with &lt;escaped strings&gt;" +
59
+ "</span>",
60
+ references: ["glade/2.glade:116"],
61
+ },
62
+ {
63
+ msgid: "duplicated",
64
+ references: [
65
+ "glade/2.glade:137",
66
+ "glade/2.glade:158",
67
+ ],
68
+ },
69
+ ],
70
+ "glade/2.glade")
71
+ end
72
+
73
+
74
+ class TestDetect < self
75
+ def target?(file)
76
+ GetText::GladeParser.target?(fixture_path(file))
77
+ end
78
+
79
+ def test_2
80
+ assert do
81
+ target?("glade/2.glade")
82
+ end
83
+ end
84
+
85
+ def test_3
86
+ assert do
87
+ not target?("glade/3.glade")
88
+ end
89
+ end
90
+ end
91
+ end
@@ -24,7 +24,7 @@ class TestGtkBuilderUIDefinitionsParser < Test::Unit::TestCase
24
24
  GetText::GtkBuilderUIDefinitionsParser.parse(fixture_path(file))
25
25
  end
26
26
 
27
- def test_all
27
+ def test_ui
28
28
  assert_parse([
29
29
  {
30
30
  :msgid => "label with context",
@@ -42,4 +42,22 @@ class TestGtkBuilderUIDefinitionsParser < Test::Unit::TestCase
42
42
  ],
43
43
  "gtk_builder_ui_definitions.ui")
44
44
  end
45
+
46
+ class TestDetect < self
47
+ def target?(file)
48
+ GetText::GtkBuilderUIDefinitionsParser.target?(fixture_path(file))
49
+ end
50
+
51
+ def test_ui
52
+ assert do
53
+ target?("gtk_builder_ui_definitions.ui")
54
+ end
55
+ end
56
+
57
+ def test_glade_3
58
+ assert do
59
+ target?("glade/3.glade")
60
+ end
61
+ end
62
+ end
45
63
  end
@@ -285,22 +285,22 @@ class TestRubyParser < Test::Unit::TestCase
285
285
  sub_test_case("parse") do
286
286
  def test_percent_w
287
287
  assert_parse([],
288
- "percent_w.rb")
288
+ "percent_lower_w.rb")
289
289
  end
290
290
 
291
291
  def test_percent_W
292
292
  assert_parse([],
293
- "percent_W.rb")
293
+ "percent_upper_w.rb")
294
294
  end
295
295
 
296
296
  def test_percent_i
297
297
  assert_parse([],
298
- "percent_i.rb")
298
+ "percent_lower_i.rb")
299
299
  end
300
300
 
301
301
  def test_percent_I
302
302
  assert_parse([],
303
- "percent_I.rb")
303
+ "percent_upper_i.rb")
304
304
  end
305
305
 
306
306
  private
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2014-2018 Kouhei Sutou <kou@clear-code.com>
1
+ # Copyright (C) 2014-2023 Sutou Kouhei <kou@clear-code.com>
2
2
  #
3
3
  # License: Ruby's or LGPL
4
4
  #
@@ -243,6 +243,7 @@ msgstr ""
243
243
  @po = <<-PO
244
244
  # translator comment
245
245
  #: a.rb:1
246
+ #: a.rb:2
246
247
  msgid "Hello"
247
248
  msgstr ""
248
249
  PO
@@ -252,6 +253,25 @@ msgstr ""
252
253
  assert_equal(<<-PO, run_msgcat([@po], "--no-location"))
253
254
  # translator comment
254
255
  msgid "Hello"
256
+ msgstr ""
257
+ PO
258
+ end
259
+
260
+ def test_wrap
261
+ assert_equal(<<-PO, run_msgcat([@po], "--wrap"))
262
+ # translator comment
263
+ #: a.rb:1 a.rb:2
264
+ msgid "Hello"
265
+ msgstr ""
266
+ PO
267
+ end
268
+
269
+ def test_use_one_line_per_reference
270
+ assert_equal(<<-PO, run_msgcat([@po], "--wrap", "--use-one-line-per-reference"))
271
+ # translator comment
272
+ #: a.rb:1
273
+ #: a.rb:2
274
+ msgid "Hello"
255
275
  msgstr ""
256
276
  PO
257
277
  end
@@ -1,7 +1,5 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
1
  # Copyright (C) 2012 Haruka Yoshihara <yoshihara@clear-code.com>
4
- # Copyright (C) 2012-2017 Kouhei Sutou <kou@clear-code.com>
2
+ # Copyright (C) 2012-2023 Sutou Kouhei <kou@clear-code.com>
5
3
  #
6
4
  # License: Ruby's or LGPL
7
5
  #
@@ -314,6 +312,11 @@ EOF
314
312
  end
315
313
 
316
314
  class TestPluralForms < self
315
+ def setup
316
+ super
317
+ omit("Red Datasets is required") unless defined?(Datasets::CLDRPlurals)
318
+ end
319
+
317
320
  def run_msginit(pot_header_options={})
318
321
  create_pot_file("test.pot", pot_header_options)
319
322
  po_file_path = "output.po"
@@ -327,5 +330,81 @@ EOF
327
330
  run_msginit(:have_plural_forms => false))
328
331
  end
329
332
  end
333
+
334
+ def test_ja
335
+ assert_equal("nplurals=1; plural=0;",
336
+ @msginit.__send__(:plural_forms, "ja"))
337
+ end
338
+
339
+ def test_en
340
+ assert_equal("nplurals=2; plural=n != 1;",
341
+ @msginit.__send__(:plural_forms, "en"))
342
+ end
343
+
344
+ def test_fr
345
+ assert_equal("nplurals=2; plural=n > 1;",
346
+ @msginit.__send__(:plural_forms, "fr"))
347
+ end
348
+
349
+ def test_lv
350
+ assert_equal("nplurals=3; " +
351
+ "plural=((n % 10) == 1) && ((n % 100) != 11) ? 0 : " +
352
+ "((n % 10) == 0) || ((n % 100) >= 11 && (n % 100) <= 19) " +
353
+ "? 1 : 2;",
354
+ @msginit.__send__(:plural_forms, "lv"))
355
+ end
356
+
357
+ def test_ga
358
+ assert_equal("nplurals=5; " +
359
+ "plural=(n == 1) ? 0 : (n == 2) ? 1 : " +
360
+ "(n >= 3 && n <= 6) ? 2 : (n >= 7 && n <= 10) ? 3 : 4;",
361
+ @msginit.__send__(:plural_forms, "ga"))
362
+ end
363
+
364
+ def test_ro
365
+ assert_equal("nplurals=3; " +
366
+ "plural=(n == 1) ? 0 : " +
367
+ "(n == 0) || (n != 1) && ((n % 100) >= 1 && (n % 100) <= 19) ? 1 : 2;",
368
+ @msginit.__send__(:plural_forms, "ro"))
369
+ end
370
+
371
+ def test_lt
372
+ assert_equal("nplurals=3; " +
373
+ "plural=((n % 10) == 1) && " +
374
+ "((n % 100) < 11 || (n % 100) > 19) ? 0 : " +
375
+ "((n % 10) >= 2 && (n % 10) <= 9) && " +
376
+ "((n % 100) < 11 || (n % 100) > 19) ? 1 : 2;",
377
+ @msginit.__send__(:plural_forms, "lt"))
378
+ end
379
+
380
+ def test_ru
381
+ assert_equal("nplurals=3; " +
382
+ "plural=((n % 10) == 1) && ((n % 100) != 11) ? 0 : " +
383
+ "((n % 10) >= 2 && (n % 10) <= 4) && " +
384
+ "((n % 100) < 12 || (n % 100) > 14) ? 1 : 2;",
385
+ @msginit.__send__(:plural_forms, "ru"))
386
+ end
387
+
388
+ def test_cs
389
+ assert_equal("nplurals=3; " +
390
+ "plural=(n == 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2;",
391
+ @msginit.__send__(:plural_forms, "cs"))
392
+ end
393
+
394
+ def test_pl
395
+ assert_equal("nplurals=3; " +
396
+ "plural=(n == 1) ? 0 : " +
397
+ "((n % 10) >= 2 && (n % 10) <= 4) && " +
398
+ "((n % 100) < 12 || (n % 100) > 14) ? 1 : 2;",
399
+ @msginit.__send__(:plural_forms, "pl"))
400
+ end
401
+
402
+ def test_sl
403
+ assert_equal("nplurals=4; " +
404
+ "plural=((n % 100) == 1) ? 0 : " +
405
+ "((n % 100) == 2) ? 1 : " +
406
+ "((n % 100) >= 3 && (n % 100) <= 4) ? 2 : 3;",
407
+ @msginit.__send__(:plural_forms, "sl"))
408
+ end
330
409
  end
331
410
  end
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2012-2020 Sutou Kouhei <kou@clear-code.com>
1
+ # Copyright (C) 2012-2023 Sutou Kouhei <kou@clear-code.com>
4
2
  # Copyright (C) 2010 Eddie Lau <tatonlto@gmail.com>
5
3
  #
6
4
  # License: Ruby's or LGPL
@@ -654,6 +652,46 @@ msgstr ""
654
652
  end
655
653
  end
656
654
 
655
+ class TestUseOneLinePerReference < self
656
+ def pot_content
657
+ super + <<-POT
658
+
659
+ #: hello.rb:10
660
+ #: hello.rb:20
661
+ #: hello.rb:30
662
+ msgid "Good morning"
663
+ msgstr ""
664
+ POT
665
+ end
666
+
667
+ def test_with_wrap
668
+ @msgmerge.run("--update",
669
+ "--wrap",
670
+ "--use-one-line-per-reference",
671
+ @po_file_path, @pot_file_path)
672
+ assert_equal(<<-PO, File.read(@po_file_path))
673
+ #{po_header(@pot_formatted_time, @po_formatted_time)}
674
+ #: hello.rb:1
675
+ msgid "Hello"
676
+ msgstr ""
677
+
678
+ #: hello.rb:2
679
+ msgid "World"
680
+ msgstr "Translated World"
681
+
682
+ #: hello.rb:3
683
+ msgid "Good-bye"
684
+ msgstr ""
685
+
686
+ #: hello.rb:10
687
+ #: hello.rb:20
688
+ #: hello.rb:30
689
+ msgid "Good morning"
690
+ msgstr ""
691
+ PO
692
+ end
693
+ end
694
+
657
695
  class TestWidth < self
658
696
  def pot_content
659
697
  <<-POT
@@ -784,6 +822,40 @@ msgstr ""
784
822
  end
785
823
  end
786
824
 
825
+ class TestWarning < self
826
+ def pot_content
827
+ <<-POT
828
+ msgid "Hello"
829
+ msgstr ""
830
+ POT
831
+ end
832
+
833
+ def po_content
834
+ <<-PO
835
+ #, fuzzy
836
+ msgid "Hello!"
837
+ msgstr "Bonjour!"
838
+ PO
839
+ end
840
+
841
+ def test_default
842
+ _stdout, stderr = capture_output do
843
+ @msgmerge.run(@po_file_path, @pot_file_path)
844
+ end
845
+ assert_equal(<<-STDERR, stderr)
846
+ Warning: fuzzy message was used.
847
+ #{@po_file_path}: msgid 'Hello!'
848
+ STDERR
849
+ end
850
+
851
+ def test_no_report_warning
852
+ _stdout, stderr = capture_output do
853
+ @msgmerge.run("--no-report-warning", @po_file_path, @pot_file_path)
854
+ end
855
+ assert_equal("", stderr)
856
+ end
857
+ end
858
+
787
859
  class TestObsoleteEntries < self
788
860
  def pot_content
789
861
  <<-POT
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2012-2020 Sutou Kouhei <kou@clear-code.com>
1
+ # Copyright (C) 2012-2023 Sutou Kouhei <kou@clear-code.com>
4
2
  # Copyright (C) 2012 Haruka Yoshihara <yoshihara@clear-code.com>
5
3
  #
6
4
  # License: Ruby's or LGPL
@@ -116,6 +114,105 @@ msgid "Hello"
116
114
  msgstr ""
117
115
  EOP
118
116
  end
117
+
118
+ def test_use_one_line_per_reference
119
+ pot_content = generate(<<-RUBY, "--use-one-line-per-reference")
120
+ _("Hello")
121
+ _("Hello")
122
+ RUBY
123
+ assert_equal(<<-POT, pot_content)
124
+ #{header}
125
+ #: ../lib/xgettext.rb:1
126
+ #: ../lib/xgettext.rb:2
127
+ msgid "Hello"
128
+ msgstr ""
129
+ POT
130
+ end
131
+ end
132
+
133
+ class TestParser < self
134
+ # Default ERB parser (don't find anything after "case")
135
+ def test_erb
136
+ rhtml = <<-EOR
137
+ <div>
138
+ <%= _('Hello') %>
139
+ <% case 1 %>
140
+ <% end %>
141
+ <%= _('World') %>
142
+ </div>
143
+ EOR
144
+
145
+ File.open(@rhtml_file_path, "w") do |rhtml_file|
146
+ rhtml_file.puts(rhtml)
147
+ end
148
+
149
+ @xgettext.run(
150
+ "--output", @pot_file_path,
151
+ @rhtml_file_path
152
+ )
153
+
154
+ pot_content = File.read(@pot_file_path)
155
+
156
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.0.0')
157
+ expected_content = <<-EOP
158
+ #{header}
159
+ #: ../templates/xgettext.rhtml:2
160
+ msgid "Hello"
161
+ msgstr ""
162
+
163
+ #: ../templates/xgettext.rhtml:5
164
+ msgid "World"
165
+ msgstr ""
166
+ EOP
167
+ else
168
+ # "World" not detected. see PR #91
169
+ expected_content = <<-EOP
170
+ #{header}
171
+ #: ../templates/xgettext.rhtml:2
172
+ msgid "Hello"
173
+ msgstr ""
174
+ EOP
175
+ end
176
+
177
+ assert_equal(expected_content, pot_content)
178
+ end
179
+
180
+ # Optional Erubi parser (find text after "case")
181
+ def test_erubi
182
+ rhtml = <<-EOR
183
+ <div>
184
+ <%= _('Hello') %>
185
+ <% case 1 %>
186
+ <% end %>
187
+ <%= _('World') %>
188
+ </div>
189
+ EOR
190
+
191
+ File.open(@rhtml_file_path, "w") do |rhtml_file|
192
+ rhtml_file.puts(rhtml)
193
+ end
194
+
195
+ @xgettext.run(
196
+ "--output", @pot_file_path,
197
+ '--require', 'gettext/tools/parser/erubi',
198
+ '--parser', 'GetText::ErubiParser',
199
+ @rhtml_file_path
200
+ )
201
+
202
+ pot_content = File.read(@pot_file_path)
203
+ expected_content = <<-EOP
204
+ #{header}
205
+ #: ../templates/xgettext.rhtml:2
206
+ msgid "Hello"
207
+ msgstr ""
208
+
209
+ #: ../templates/xgettext.rhtml:5
210
+ msgid "World"
211
+ msgstr ""
212
+ EOP
213
+
214
+ assert_equal(expected_content, pot_content)
215
+ end
119
216
  end
120
217
 
121
218
  class TestEncoding < self