gettext 2.3.3 → 2.3.4

Sign up to get free protection for your applications and to get access to all the features.
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"