gettext 2.3.3 → 2.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. data/doc/text/news.md +37 -0
  2. data/gettext.gemspec +1 -0
  3. data/lib/gettext/runtime/mo.rb +382 -0
  4. data/lib/gettext/runtime/mofile.rb +24 -366
  5. data/lib/gettext/runtime/textdomain.rb +17 -17
  6. data/lib/gettext/tools.rb +1 -1
  7. data/lib/gettext/tools/msgfmt.rb +2 -2
  8. data/lib/gettext/tools/msginit.rb +16 -15
  9. data/lib/gettext/tools/msgmerge.rb +258 -255
  10. data/lib/gettext/tools/parser/ruby.rb +24 -24
  11. data/lib/gettext/tools/po.rb +256 -0
  12. data/lib/gettext/tools/po_entry.rb +355 -0
  13. data/lib/gettext/tools/poparser.rb +118 -16
  14. data/lib/gettext/tools/xgettext.rb +56 -58
  15. data/lib/gettext/version.rb +1 -1
  16. data/samples/po/hello.pot +3 -3
  17. data/samples/po/hello2.pot +3 -3
  18. data/samples/po/hello_glade2.pot +3 -3
  19. data/samples/po/hello_gtk2.pot +3 -3
  20. data/samples/po/hello_noop.pot +3 -3
  21. data/samples/po/hello_plural.pot +3 -3
  22. data/samples/po/hello_tk.pot +3 -3
  23. data/src/poparser.ry +111 -9
  24. data/test/parser/test_ruby.rb +17 -13
  25. data/test/po/_.pot +3 -3
  26. data/test/po/backslash.pot +3 -3
  27. data/test/po/non_ascii.pot +3 -3
  28. data/test/po/np_.pot +5 -4
  29. data/test/po/ns_.pot +3 -3
  30. data/test/po/p_.pot +3 -3
  31. data/test/po/s_.pot +3 -3
  32. data/test/po/untranslated.pot +3 -3
  33. data/test/{test_mofile.rb → test_mo.rb} +3 -3
  34. data/test/test_parser.rb +13 -12
  35. data/test/test_po_entry.rb +329 -0
  36. data/test/test_po_parser.rb +209 -8
  37. data/test/tools/test_msginit.rb +0 -2
  38. data/test/tools/test_msgmerge.rb +427 -50
  39. data/test/tools/test_po.rb +487 -0
  40. data/test/tools/test_xgettext.rb +1 -1
  41. metadata +28 -45
  42. data/data/locale/de/LC_MESSAGES/gettext.mo +0 -0
  43. data/data/locale/de/LC_MESSAGES/rgettext.mo +0 -0
  44. data/data/locale/el/LC_MESSAGES/gettext.mo +0 -0
  45. data/data/locale/el/LC_MESSAGES/rgettext.mo +0 -0
  46. data/data/locale/sr/LC_MESSAGES/gettext.mo +0 -0
  47. data/data/locale/sr/LC_MESSAGES/rgettext.mo +0 -0
  48. data/data/locale/uk/LC_MESSAGES/gettext.mo +0 -0
  49. data/data/locale/uk/LC_MESSAGES/rgettext.mo +0 -0
  50. data/lib/gettext/tools/pomessage.rb +0 -232
  51. data/samples/locale/bg/LC_MESSAGES/hello_gtk.mo +0 -0
  52. data/samples/locale/bs/LC_MESSAGES/hello_gtk.mo +0 -0
  53. data/samples/locale/ca/LC_MESSAGES/hello_gtk.mo +0 -0
  54. data/samples/locale/cs/LC_MESSAGES/hello_gtk.mo +0 -0
  55. data/samples/locale/de/LC_MESSAGES/hello_gtk.mo +0 -0
  56. data/samples/locale/el/LC_MESSAGES/hello_gtk.mo +0 -0
  57. data/samples/locale/eo/LC_MESSAGES/hello_gtk.mo +0 -0
  58. data/samples/locale/es/LC_MESSAGES/hello_gtk.mo +0 -0
  59. data/samples/locale/fr/LC_MESSAGES/hello_gtk.mo +0 -0
  60. data/samples/locale/hr/LC_MESSAGES/hello_gtk.mo +0 -0
  61. data/samples/locale/hu/LC_MESSAGES/hello_gtk.mo +0 -0
  62. data/samples/locale/it/LC_MESSAGES/hello_gtk.mo +0 -0
  63. data/samples/locale/ja/LC_MESSAGES/hello_gtk.mo +0 -0
  64. data/samples/locale/ko/LC_MESSAGES/hello_gtk.mo +0 -0
  65. data/samples/locale/lv/LC_MESSAGES/hello_gtk.mo +0 -0
  66. data/samples/locale/nb/LC_MESSAGES/hello_gtk.mo +0 -0
  67. data/samples/locale/nl/LC_MESSAGES/hello_gtk.mo +0 -0
  68. data/samples/locale/pt_BR/LC_MESSAGES/hello_gtk.mo +0 -0
  69. data/samples/locale/ru/LC_MESSAGES/hello_gtk.mo +0 -0
  70. data/samples/locale/sr/LC_MESSAGES/hello_gtk.mo +0 -0
  71. data/samples/locale/sv/LC_MESSAGES/hello_gtk.mo +0 -0
  72. data/samples/locale/uk/LC_MESSAGES/hello_gtk.mo +0 -0
  73. data/samples/locale/vi/LC_MESSAGES/hello_gtk.mo +0 -0
  74. data/samples/locale/zh/LC_MESSAGES/hello_gtk.mo +0 -0
  75. data/samples/locale/zh_TW/LC_MESSAGES/hello_gtk.mo +0 -0
  76. data/test/po/ascii.pot +0 -23
  77. data/test/po/no_exist_msgid.pot +0 -20
  78. data/test/po/not_existed_msgid.pot +0 -20
  79. data/test/test_po_message.rb +0 -118
@@ -15,10 +15,16 @@
15
15
  #
16
16
 
17
17
  require 'racc/parser.rb'
18
+
19
+ require "gettext/tools/po"
20
+ require "gettext/tools/msgmerge"
18
21
  module GetText
19
- class PoParser < Racc::Parser
22
+ class POParser < Racc::Parser
23
+
24
+ module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 123)
25
+ # for backward compatibility.
26
+ PoParser = POParser
20
27
 
21
- module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 119)
22
28
  if GetText.respond_to?(:bindtextdomain)
23
29
  include GetText
24
30
  GetText.bindtextdomain("gettext")
@@ -58,10 +64,16 @@ module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 119)
58
64
  private :unescape_string
59
65
 
60
66
  def parse(str, data)
67
+ @translator_comments = []
68
+ @extracted_comments = []
69
+ @references = []
70
+ @flag = []
71
+ @previous = []
61
72
  @comments = []
62
73
  @data = data
63
74
  @fuzzy = false
64
- @msgctxt = ""
75
+ @msgctxt = nil
76
+ @msgid_plural = nil
65
77
 
66
78
  str.strip!
67
79
  @q = []
@@ -124,16 +136,89 @@ module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 119)
124
136
 
125
137
  def on_message(msgid, msgstr)
126
138
  msgstr = nil if msgstr.empty?
127
- @data[msgid] = msgstr
128
- @data.set_comment(msgid, @comments.join("\n"))
129
139
 
140
+ if @data.instance_of?(PO) or
141
+ @data.instance_of?(GetText::Tools::MsgMerge::PoData)
142
+ type = detect_entry_type
143
+ entry = POEntry.new(type)
144
+ entry.translator_comment = format_comment(@translator_comments)
145
+ entry.extracted_comment = format_comment(@extracted_comments)
146
+ entry.flag = format_comment(@flag)
147
+ entry.previous = format_comment(@previous)
148
+ entry.references = @references
149
+ entry.msgctxt = @msgctxt
150
+ entry.msgid = msgid
151
+ entry.msgid_plural = @msgid_plural
152
+ entry.msgstr = msgstr
153
+
154
+ if @data.instance_of?(PO)
155
+ @data[@msgctxt, msgid] = entry
156
+ elsif @data.instance_of?(GetText::Tools::MsgMerge::PoData)
157
+ id = ""
158
+ id << "#{@msgctxt}\004" unless @msgctxt.nil?
159
+ id << msgid
160
+ id << "\000#{@msgid_plural}" unless @msgid_plural.nil?
161
+ @data[id] = entry
162
+ end
163
+ else
164
+ options = {}
165
+ options[:msgctxt] = @msgctxt
166
+ options[:msgid_plural] = @msgid_plural
167
+ @data.store(msgid, msgstr, options)
168
+ @data.set_comment(msgid, format_comment(@comments))
169
+ end
170
+
171
+ @translator_comments = []
172
+ @extracted_comments = []
173
+ @references = []
174
+ @flag = []
175
+ @previous = []
176
+ @references = []
130
177
  @comments.clear
131
- @msgctxt = ""
178
+ @msgctxt = nil
179
+ @msgid_plural = nil
132
180
  end
133
181
 
182
+ def format_comment(comments)
183
+ return "" if comments.empty?
184
+
185
+ comment = comments.join("\n")
186
+ comment << "\n" if comments.last.empty?
187
+ comment
188
+ end
189
+
190
+ TRANSLATOR_COMMENT_MARK = "# "
191
+ EXTRACTED_COMMENT_MARK = "#."
192
+ FLAG_MARK = "#,"
193
+ PREVIOUS_MSGID_COMMENT_MARK = "#|"
194
+ REFERENCE_COMMENT_MARK = "#:"
134
195
  def on_comment(comment)
135
196
  @fuzzy = true if (/fuzzy/ =~ comment)
136
- @comments << comment
197
+ if @data.instance_of?(PO) or
198
+ @data.instance_of?(GetText::Tools::MsgMerge::PoData)
199
+ if comment == "#"
200
+ @translator_comments << ""
201
+ elsif /\A(#.)\s*(.*)\z/ =~ comment
202
+ mark = $1
203
+ content = $2
204
+ case mark
205
+ when TRANSLATOR_COMMENT_MARK
206
+ @translator_comments << content
207
+ when EXTRACTED_COMMENT_MARK
208
+ @extracted_comments << content
209
+ when REFERENCE_COMMENT_MARK
210
+ @references << content
211
+ when FLAG_MARK
212
+ @flag << content
213
+ when PREVIOUS_MSGID_COMMENT_MARK
214
+ @previous << content
215
+ else
216
+ @comments << comment
217
+ end
218
+ end
219
+ else
220
+ @comments << comment
221
+ end
137
222
  end
138
223
 
139
224
  def parse_file(po_file, data)
@@ -155,6 +240,22 @@ module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 119)
155
240
  end
156
241
  Encoding.default_external
157
242
  end
243
+
244
+ def detect_entry_type
245
+ if @msgctxt.nil?
246
+ if @msgid_plural.nil?
247
+ :normal
248
+ else
249
+ :plural
250
+ end
251
+ else
252
+ if @msgid_plural.nil?
253
+ :msgctxt
254
+ else
255
+ :msgctxt_plural
256
+ end
257
+ end
258
+ end
158
259
  private :detect_file_encoding
159
260
  ...end poparser.ry/module_eval...
160
261
  ##### State transition tables begin ###
@@ -281,7 +382,7 @@ Racc_debug_parser = true
281
382
 
282
383
  module_eval(<<'.,.,', 'poparser.ry', 26)
283
384
  def _reduce_5(val, _values, result)
284
- @msgctxt = unescape(val[1]) + "\004"
385
+ @msgctxt = unescape(val[1])
285
386
 
286
387
  result
287
388
  end
@@ -309,7 +410,7 @@ module_eval(<<'.,.,', 'poparser.ry', 38)
309
410
  end
310
411
  end
311
412
  @fuzzy = false
312
- on_message(@msgctxt + msgid, msgstr) if use_message_p
413
+ on_message(msgid, msgstr) if use_message_p
313
414
  result = ""
314
415
 
315
416
  result
@@ -329,7 +430,8 @@ module_eval(<<'.,.,', 'poparser.ry', 61)
329
430
  end
330
431
  @fuzzy = false
331
432
  else
332
- on_message(@msgctxt + unescape(val[1]) + "\000" + unescape(val[3]), unescape(val[4]))
433
+ @msgid_plural = unescape(val[3])
434
+ on_message(unescape(val[1]), unescape(val[4]))
333
435
  end
334
436
  result = ""
335
437
 
@@ -337,7 +439,7 @@ module_eval(<<'.,.,', 'poparser.ry', 61)
337
439
  end
338
440
  .,.,
339
441
 
340
- module_eval(<<'.,.,', 'poparser.ry', 81)
442
+ module_eval(<<'.,.,', 'poparser.ry', 82)
341
443
  def _reduce_10(val, _values, result)
342
444
  if val[0].size > 0
343
445
  result = val[0] + "\000" + val[1]
@@ -351,7 +453,7 @@ module_eval(<<'.,.,', 'poparser.ry', 81)
351
453
 
352
454
  # reduce 11 omitted
353
455
 
354
- module_eval(<<'.,.,', 'poparser.ry', 93)
456
+ module_eval(<<'.,.,', 'poparser.ry', 94)
355
457
  def _reduce_12(val, _values, result)
356
458
  result = val[2]
357
459
 
@@ -359,7 +461,7 @@ module_eval(<<'.,.,', 'poparser.ry', 93)
359
461
  end
360
462
  .,.,
361
463
 
362
- module_eval(<<'.,.,', 'poparser.ry', 100)
464
+ module_eval(<<'.,.,', 'poparser.ry', 101)
363
465
  def _reduce_13(val, _values, result)
364
466
  on_comment(val[0])
365
467
 
@@ -367,7 +469,7 @@ module_eval(<<'.,.,', 'poparser.ry', 100)
367
469
  end
368
470
  .,.,
369
471
 
370
- module_eval(<<'.,.,', 'poparser.ry', 108)
472
+ module_eval(<<'.,.,', 'poparser.ry', 109)
371
473
  def _reduce_14(val, _values, result)
372
474
  result = val.delete_if{|item| item == ""}.join
373
475
 
@@ -375,7 +477,7 @@ module_eval(<<'.,.,', 'poparser.ry', 108)
375
477
  end
376
478
  .,.,
377
479
 
378
- module_eval(<<'.,.,', 'poparser.ry', 112)
480
+ module_eval(<<'.,.,', 'poparser.ry', 113)
379
481
  def _reduce_15(val, _values, result)
380
482
  result = val[0]
381
483
 
@@ -387,7 +489,7 @@ def _reduce_none(val, _values, result)
387
489
  val[0]
388
490
  end
389
491
 
390
- end # class PoParser
492
+ end # class POParser
391
493
  end # module GetText
392
494
 
393
495
 
@@ -89,40 +89,40 @@ module GetText
89
89
  # File.extname(path) == ".foo" # *.foo file only.
90
90
  # end
91
91
  # def parse(path)
92
- # po_messages = []
93
- # # Simple message
94
- # message = PoMessage.new(:normal)
95
- # message.msgid = "hello"
96
- # message.sources = ["foo.rb:200", "bar.rb:300"]
97
- # message.add_comment("Comment for the message")
98
- # po_messages << message
99
- # # Plural message
100
- # message = PoMessage.new(:plural)
101
- # message.msgid = "An apple"
102
- # message.msgid_plural = "Apples"
103
- # message.sources = ["foo.rb:200", "bar.rb:300"]
104
- # po_messages << message
105
- # # Simple message with the message context
106
- # message = PoMessage.new(:msgctxt)
107
- # message.msgctxt = "context"
108
- # message.msgid = "hello"
109
- # message.sources = ["foo.rb:200", "bar.rb:300"]
110
- # po_messages << message
111
- # # Plural message with the message context.
112
- # message = PoMessage.new(:msgctxt_plural)
113
- # message.msgctxt = "context"
114
- # message.msgid = "An apple"
115
- # message.msgid_plural = "Apples"
116
- # message.sources = ["foo.rb:200", "bar.rb:300"]
117
- # po_messages << message
118
- # return po_messages
92
+ # po = []
93
+ # # Simple entry
94
+ # entry = POEntry.new(:normal)
95
+ # entry.msgid = "hello"
96
+ # entry.references = ["foo.rb:200", "bar.rb:300"]
97
+ # entry.add_comment("Comment for the entry")
98
+ # po << entry
99
+ # # Plural entry
100
+ # entry = POEntry.new(:plural)
101
+ # entry.msgid = "An apple"
102
+ # entry.msgid_plural = "Apples"
103
+ # entry.references = ["foo.rb:200", "bar.rb:300"]
104
+ # po << entry
105
+ # # Simple entry with the entry context
106
+ # entry = POEntry.new(:msgctxt)
107
+ # entry.msgctxt = "context"
108
+ # entry.msgid = "hello"
109
+ # entry.references = ["foo.rb:200", "bar.rb:300"]
110
+ # po << entry
111
+ # # Plural entry with the message context.
112
+ # entry = POEntry.new(:msgctxt_plural)
113
+ # entry.msgctxt = "context"
114
+ # entry.msgid = "An apple"
115
+ # entry.msgid_plural = "Apples"
116
+ # entry.references = ["foo.rb:200", "bar.rb:300"]
117
+ # po << entry
118
+ # return po
119
119
  # end
120
120
  # end
121
121
  #
122
122
  # GetText::XGetText.add_parser(FooParser.new)
123
123
  #
124
124
  # @param [#target?, #parse] parser
125
- # It parses target file and extracts translate target messages from the
125
+ # It parses target file and extracts translate target entries from the
126
126
  # target file. If there are multiple target files, parser.parse is
127
127
  # called multiple times.
128
128
  # @return [void]
@@ -157,26 +157,26 @@ EOH
157
157
  end
158
158
 
159
159
  def generate_pot(paths) # :nodoc:
160
- po_messages = parse(paths)
161
- str = ""
162
- po_messages.each do |target|
163
- str << encode(target.to_po_str)
160
+ po = parse(paths)
161
+ entries = []
162
+ po.each do |target|
163
+ entries << encode(target.to_s)
164
164
  end
165
- str
165
+ entries.join("\n")
166
166
  end
167
167
 
168
168
  def parse(paths) # :nodoc:
169
- po_messages = []
169
+ po = []
170
170
  paths = [paths] if paths.kind_of?(String)
171
171
  paths.each do |path|
172
172
  begin
173
- parse_path(path, po_messages)
173
+ parse_path(path, po)
174
174
  rescue
175
175
  puts(_("Error parsing %{path}") % {:path => path})
176
176
  raise
177
177
  end
178
178
  end
179
- po_messages
179
+ po
180
180
  end
181
181
 
182
182
  def check_command_line_options(*options) # :nodoc:
@@ -267,18 +267,16 @@ EOH
267
267
  check_command_line_options(*options)
268
268
 
269
269
  @output_encoding ||= "UTF-8"
270
-
271
- pot_header = generate_pot_header
272
- pot_messages = generate_pot(@input_files)
270
+ pot = generate_pot_header
271
+ pot << "\n"
272
+ pot << generate_pot(@input_files)
273
273
 
274
274
  if @output.is_a?(String)
275
275
  File.open(File.expand_path(@output), "w+") do |file|
276
- file.puts(pot_header)
277
- file.puts(pot_messages)
276
+ file.puts(pot)
278
277
  end
279
278
  else
280
- @output.puts(pot_header)
281
- @output.puts(pot_messages)
279
+ @output.puts(pot)
282
280
  end
283
281
  self
284
282
  end
@@ -288,21 +286,21 @@ EOH
288
286
  Time.now
289
287
  end
290
288
 
291
- def parse_path(path, po_messages)
289
+ def parse_path(path, po)
292
290
  @parsers.each do |parser|
293
291
  next unless parser.target?(path)
294
292
 
295
- extracted_po_messages = parser.parse(path)
296
- extracted_po_messages.each do |po_message|
297
- if po_message.kind_of?(Array)
298
- po_message = PoMessage.new_from_ary(po_message)
293
+ extracted_po = parser.parse(path)
294
+ extracted_po.each do |po_entry|
295
+ if po_entry.kind_of?(Array)
296
+ po_entry = POEntry.new_from_ary(po_entry)
299
297
  end
300
298
 
301
- if po_message.msgid.empty?
299
+ if po_entry.msgid.empty?
302
300
  warn _("Warning: The empty \"\" msgid is reserved by " +
303
301
  "gettext. So gettext(\"\") doesn't returns " +
304
302
  "empty string but the header entry in po file.")
305
- # TODO: add pommesage.source to the pot header as below:
303
+ # TODO: add pommesage.reference to the pot header as below:
306
304
  # # SOME DESCRIPTIVE TITLE.
307
305
  # # Copyright (C) YEAR THE COPYRIGHT HOLDER
308
306
  # # This file is distributed under the same license as the PACKAGE package.
@@ -316,8 +314,8 @@ EOH
316
314
 
317
315
  if @output.is_a?(String)
318
316
  base_path = Pathname.new(@output).dirname.expand_path
319
- po_message.sources = po_message.sources.collect do |source|
320
- path, line, = source.split(/:(\d+)\z/, 2)
317
+ po_entry.references = po_entry.references.collect do |reference|
318
+ path, line, = reference.split(/:(\d+)\z/, 2)
321
319
  absolute_path = Pathname.new(path).expand_path
322
320
  begin
323
321
  path = absolute_path.relative_path_from(base_path).to_s
@@ -329,18 +327,18 @@ EOH
329
327
  end
330
328
 
331
329
  # Save the previous target
332
- if po_messages.empty?
330
+ if po.empty?
333
331
  existing = nil
334
332
  else
335
- message = po_messages.find {|t| t == po_message}
336
- existing = po_messages.index(message)
333
+ entry = po.find {|t| t.mergeable?(po_entry)}
334
+ existing = po.index(entry)
337
335
  end
338
336
 
339
337
  if existing
340
- po_message = po_messages[existing].merge(po_message)
341
- po_messages[existing] = po_message
338
+ po_entry = po[existing].merge(po_entry)
339
+ po[existing] = po_entry
342
340
  else
343
- po_messages << po_message
341
+ po << po_entry
344
342
  end
345
343
  end
346
344
  break
@@ -9,5 +9,5 @@
9
9
  =end
10
10
 
11
11
  module GetText
12
- VERSION = "2.3.3"
12
+ VERSION = "2.3.4"
13
13
  end
data/samples/po/hello.pot CHANGED
@@ -6,10 +6,10 @@
6
6
  #, fuzzy
7
7
  msgid ""
8
8
  msgstr ""
9
- "Project-Id-Version: gettext 2.3.3\n"
9
+ "Project-Id-Version: gettext 2.3.4\n"
10
10
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2012-10-17 10:26+0900\n"
12
- "PO-Revision-Date: 2012-10-17 10:26+0900\n"
11
+ "POT-Creation-Date: 2012-11-15 10:50+0900\n"
12
+ "PO-Revision-Date: 2012-11-15 10:50+0900\n"
13
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
15
  "Language: \n"
@@ -6,10 +6,10 @@
6
6
  #, fuzzy
7
7
  msgid ""
8
8
  msgstr ""
9
- "Project-Id-Version: gettext 2.3.3\n"
9
+ "Project-Id-Version: gettext 2.3.4\n"
10
10
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2012-10-17 10:26+0900\n"
12
- "PO-Revision-Date: 2012-10-17 10:26+0900\n"
11
+ "POT-Creation-Date: 2012-11-15 10:50+0900\n"
12
+ "PO-Revision-Date: 2012-11-15 10:50+0900\n"
13
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
15
  "Language: \n"