gettext 2.3.0 → 2.3.1
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.
- data/.yardopts +6 -0
- data/Rakefile +7 -6
- data/doc/text/news.md +51 -2
- data/gettext.gemspec +1 -0
- data/lib/gettext/runtime/locale_path.rb +0 -1
- data/lib/gettext/runtime/mofile.rb +8 -2
- data/lib/gettext/runtime/textdomain.rb +19 -21
- data/lib/gettext/runtime/textdomain_manager.rb +0 -1
- data/lib/gettext/tools/msginit.rb +19 -9
- data/lib/gettext/tools/msgmerge.rb +28 -15
- data/lib/gettext/tools/parser/erb.rb +25 -5
- data/lib/gettext/tools/parser/glade.rb +4 -3
- data/lib/gettext/tools/parser/ruby.rb +23 -5
- data/lib/gettext/tools/poparser.rb +2 -1
- data/lib/gettext/tools/xgettext.rb +187 -136
- data/lib/gettext/version.rb +1 -1
- data/po/ja/gettext.po +82 -41
- data/samples/cgi/locale/bg/LC_MESSAGES/main.mo +0 -0
- data/samples/cgi/locale/bs/LC_MESSAGES/main.mo +0 -0
- data/samples/cgi/locale/ca/LC_MESSAGES/main.mo +0 -0
- data/samples/cgi/locale/cs/LC_MESSAGES/main.mo +0 -0
- data/samples/cgi/locale/de/LC_MESSAGES/main.mo +0 -0
- data/samples/cgi/locale/el/LC_MESSAGES/main.mo +0 -0
- data/samples/cgi/locale/eo/LC_MESSAGES/main.mo +0 -0
- data/samples/cgi/locale/es/LC_MESSAGES/main.mo +0 -0
- data/samples/po/hello.pot +3 -3
- data/samples/po/hello2.pot +3 -3
- data/samples/po/hello_glade2.pot +3 -3
- data/samples/po/hello_gtk2.pot +3 -3
- data/samples/po/hello_noop.pot +3 -3
- data/samples/po/hello_plural.pot +3 -3
- data/samples/po/hello_tk.pot +3 -3
- data/src/poparser.ry +1 -0
- data/test/fixtures/_.rb +4 -4
- data/test/fixtures/{erb.rhtml → erb/ascii.rhtml} +0 -0
- data/test/fixtures/{erb.rxml → erb/ascii.rxml} +0 -0
- data/test/fixtures/erb/non_ascii.rhtml +13 -0
- data/test/fixtures/untranslated.rb +12 -0
- data/test/gettext-test-utils.rb +23 -0
- data/test/locale/ja/LC_MESSAGES/untranslated.mo +0 -0
- data/test/parser/test_ruby.rb +48 -1
- data/test/po/_.pot +4 -4
- data/test/po/ascii.pot +23 -0
- data/test/po/backslash.pot +3 -3
- data/test/po/ja/untranslated.po +22 -0
- data/test/po/no_exist_msgid.pot +20 -0
- data/test/po/non_ascii.pot +3 -3
- data/test/po/not_existed_msgid.pot +20 -0
- data/test/po/np_.pot +3 -3
- data/test/po/ns_.pot +3 -3
- data/test/po/p_.pot +3 -3
- data/test/po/s_.pot +3 -3
- data/test/po/untranslated.pot +23 -0
- data/test/run-test.rb +1 -1
- data/test/test_gettext.rb +2 -2
- data/test/test_mofile.rb +10 -0
- data/test/test_parser.rb +45 -19
- data/test/test_po_parser.rb +14 -1
- data/test/tools/test_msginit.rb +52 -36
- data/test/tools/test_msgmerge.rb +44 -6
- data/test/tools/test_xgettext.rb +203 -5
- metadata +143 -146
- data/po/de/gettext.po +0 -668
- data/po/de/gettext.po.bak +0 -589
- data/po/el/gettext.po +0 -571
- data/po/fr/gettext.po +0 -589
- data/po/gettext.pot +0 -638
- data/po/gettext.pot~ +0 -638
- data/po/it/gettext.po +0 -589
- data/po/uk/gettext.po +0 -571
- data/test/locale/ja/LC_MESSAGES/npgettext.mo +0 -0
- data/test/locale/ja/LC_MESSAGES/nsgettext.mo +0 -0
- data/test/locale/ja/LC_MESSAGES/pgettext.mo +0 -0
- data/test/locale/ja/LC_MESSAGES/sgettext.mo +0 -0
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
=begin
|
2
3
|
parser/ruby.rb - parser for ruby script
|
3
4
|
|
@@ -118,13 +119,30 @@ module GetText
|
|
118
119
|
# (and ignored here).
|
119
120
|
# And You don't need to keep the pomessages as unique.
|
120
121
|
|
121
|
-
def parse(path
|
122
|
-
|
123
|
-
|
122
|
+
def parse(path) # :nodoc:
|
123
|
+
source = IO.read(path)
|
124
|
+
|
125
|
+
if source.respond_to?(:encode)
|
126
|
+
encoding = detect_encoding(source) || source.encoding
|
127
|
+
|
128
|
+
source.force_encoding(encoding)
|
129
|
+
end
|
130
|
+
|
131
|
+
parse_lines(path, source.each_line.to_a)
|
132
|
+
end
|
133
|
+
|
134
|
+
def detect_encoding(source)
|
135
|
+
return nil unless source.respond_to?(:force_encoding)
|
136
|
+
binary_source = source.dup.force_encoding("ASCII-8BIT")
|
137
|
+
if /\A.*coding\s*[=:]\s*([[:alnum:]\-_]+)/ =~ binary_source
|
138
|
+
$1.gsub(/-(?:unix|mac|dos)\z/, "")
|
139
|
+
else
|
140
|
+
nil
|
141
|
+
end
|
124
142
|
end
|
125
143
|
|
126
|
-
def parse_lines(path, lines
|
127
|
-
pomessages =
|
144
|
+
def parse_lines(path, lines) # :nodoc:
|
145
|
+
pomessages = []
|
128
146
|
file = StringIO.new(lines.join + "\n")
|
129
147
|
rl = RubyLexX.new
|
130
148
|
rl.set_input(file)
|
@@ -123,6 +123,7 @@ module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 119)
|
|
123
123
|
end
|
124
124
|
|
125
125
|
def on_message(msgid, msgstr)
|
126
|
+
msgstr = nil if msgstr.empty?
|
126
127
|
@data[msgid] = msgstr
|
127
128
|
@data.set_comment(msgid, @comments.join("\n"))
|
128
129
|
|
@@ -387,6 +388,6 @@ def _reduce_none(val, _values, result)
|
|
387
388
|
end
|
388
389
|
|
389
390
|
end # class PoParser
|
390
|
-
|
391
|
+
end # module GetText
|
391
392
|
|
392
393
|
|
@@ -22,38 +22,52 @@
|
|
22
22
|
|
23
23
|
require "pathname"
|
24
24
|
require "optparse"
|
25
|
+
require "locale"
|
25
26
|
require "gettext"
|
26
27
|
|
27
28
|
module GetText
|
28
29
|
module Tools
|
29
|
-
class XGetText
|
30
|
+
class XGetText
|
30
31
|
class << self
|
31
32
|
def run(*arguments)
|
32
33
|
new.run(*arguments)
|
33
34
|
end
|
35
|
+
|
36
|
+
# Adds a parser to the default parser list.
|
37
|
+
#
|
38
|
+
# @param (see #add_parser)
|
39
|
+
# @return [void]
|
40
|
+
#
|
41
|
+
# @see #add_parser
|
42
|
+
def add_parser(parser)
|
43
|
+
@@default_parsers.unshift(parser)
|
44
|
+
end
|
34
45
|
end
|
35
46
|
|
36
47
|
include GetText
|
37
48
|
|
38
49
|
bindtextdomain("rgettext")
|
39
50
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
51
|
+
# @api private
|
52
|
+
@@default_parsers = []
|
53
|
+
builtin_parser_info_list = [
|
54
|
+
["glade", "GladeParser"],
|
55
|
+
["erb", "ErbParser"],
|
56
|
+
# ["ripper", "RipperParser"],
|
57
|
+
["ruby", "RubyParser"] # Default parser.
|
58
|
+
]
|
59
|
+
builtin_parser_info_list.each do |f, klass|
|
60
|
+
begin
|
61
|
+
require "gettext/tools/parser/#{f}"
|
62
|
+
@@default_parsers << GetText.const_get(klass)
|
63
|
+
rescue
|
64
|
+
$stderr.puts(_("'%{klass}' is ignored.") % {:klass => klass})
|
65
|
+
$stderr.puts($!) if $DEBUG
|
56
66
|
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def initialize #:nodoc:
|
70
|
+
@parsers = @@default_parsers
|
57
71
|
|
58
72
|
@input_files = nil
|
59
73
|
@output = nil
|
@@ -62,53 +76,58 @@ module GetText
|
|
62
76
|
@package_version = nil
|
63
77
|
@msgid_bugs_address = nil
|
64
78
|
@copyright_holder = nil
|
79
|
+
@output_encoding = nil
|
65
80
|
end
|
66
81
|
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# parser(file, ary) method.
|
82
|
+
# The parser object requires to have target?(path) and
|
83
|
+
# parse(path) method.
|
70
84
|
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
# end
|
85
|
+
# @example How to add your parser
|
86
|
+
# require "gettext/tools/xgettext"
|
87
|
+
# class FooParser
|
88
|
+
# def target?(path)
|
89
|
+
# File.extname(path) == ".foo" # *.foo file only.
|
90
|
+
# end
|
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
|
119
|
+
# end
|
120
|
+
# end
|
108
121
|
#
|
109
|
-
#
|
110
|
-
|
111
|
-
|
122
|
+
# GetText::XGetText.add_parser(FooParser.new)
|
123
|
+
#
|
124
|
+
# @param [#target?, #parse] parser
|
125
|
+
# It parses target file and extracts translate target messages from the
|
126
|
+
# target file. If there are multiple target files, parser.parse is
|
127
|
+
# called multiple times.
|
128
|
+
# @return [void]
|
129
|
+
def add_parser(parser)
|
130
|
+
@parsers.unshift(parser)
|
112
131
|
end
|
113
132
|
|
114
133
|
def generate_pot_header # :nodoc:
|
@@ -131,99 +150,35 @@ msgstr ""
|
|
131
150
|
"Language-Team: LANGUAGE <LL@li.org>\\n"
|
132
151
|
"Language: \\n"
|
133
152
|
"MIME-Version: 1.0\\n"
|
134
|
-
"Content-Type: text/plain; charset
|
153
|
+
"Content-Type: text/plain; charset=#{@output_encoding}\\n"
|
135
154
|
"Content-Transfer-Encoding: 8bit\\n"
|
136
155
|
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n"
|
137
156
|
EOH
|
138
157
|
end
|
139
158
|
|
140
159
|
def generate_pot(paths) # :nodoc:
|
141
|
-
|
160
|
+
po_messages = parse(paths)
|
142
161
|
str = ""
|
143
|
-
|
144
|
-
str << target.to_po_str
|
162
|
+
po_messages.each do |target|
|
163
|
+
str << encode(target.to_po_str)
|
145
164
|
end
|
146
165
|
str
|
147
166
|
end
|
148
167
|
|
149
168
|
def parse(paths) # :nodoc:
|
150
|
-
|
169
|
+
po_messages = []
|
151
170
|
paths = [paths] if paths.kind_of?(String)
|
152
171
|
paths.each do |path|
|
153
172
|
begin
|
154
|
-
|
155
|
-
next unless klass.target?(path)
|
156
|
-
|
157
|
-
if klass.method(:parse).arity == 1
|
158
|
-
targets = klass.parse(path)
|
159
|
-
else
|
160
|
-
# For backward compatibility
|
161
|
-
targets = klass.parse(path, [])
|
162
|
-
end
|
163
|
-
|
164
|
-
targets.each do |pomessage|
|
165
|
-
if pomessage.kind_of?(Array)
|
166
|
-
pomessage = PoMessage.new_from_ary(pomessage)
|
167
|
-
end
|
168
|
-
|
169
|
-
if pomessage.msgid.empty?
|
170
|
-
warn _("Warning: The empty \"\" msgid is reserved by " +
|
171
|
-
"gettext. So gettext(\"\") doesn't returns " +
|
172
|
-
"empty string but the header entry in po file.")
|
173
|
-
# TODO: add pommesage.source to the pot header as below:
|
174
|
-
# # SOME DESCRIPTIVE TITLE.
|
175
|
-
# # Copyright (C) YEAR THE COPYRIGHT HOLDER
|
176
|
-
# # This file is distributed under the same license as the PACKAGE package.
|
177
|
-
# # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
178
|
-
# #
|
179
|
-
# #: test/test_gettext.rb:65
|
180
|
-
# #, fuzzy
|
181
|
-
# "#: test/test_gettext.rb:65" line is added.
|
182
|
-
next
|
183
|
-
end
|
184
|
-
|
185
|
-
if @output.is_a?(String)
|
186
|
-
base_path = Pathname.new(@output).dirname.expand_path
|
187
|
-
pomessage.sources = pomessage.sources.collect do |source|
|
188
|
-
path, line, = source.split(/:(\d+)\z/, 2)
|
189
|
-
absolute_path = Pathname.new(path).expand_path
|
190
|
-
begin
|
191
|
-
path = absolute_path.relative_path_from(base_path).to_s
|
192
|
-
rescue ArgumentError
|
193
|
-
raise # Should we ignore it?
|
194
|
-
end
|
195
|
-
"#{path}:#{line}"
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
# Save the previous target
|
200
|
-
if pomessages.empty?
|
201
|
-
existing = nil
|
202
|
-
else
|
203
|
-
message = pomessages.find {|t| t == pomessage}
|
204
|
-
existing = pomessages.index(message)
|
205
|
-
end
|
206
|
-
|
207
|
-
if existing
|
208
|
-
pomessage = pomessages[existing].merge(pomessage)
|
209
|
-
pomessages[existing] = pomessage
|
210
|
-
else
|
211
|
-
pomessages << pomessage
|
212
|
-
end
|
213
|
-
end
|
214
|
-
break
|
215
|
-
end
|
173
|
+
parse_path(path, po_messages)
|
216
174
|
rescue
|
217
175
|
puts(_("Error parsing %{path}") % {:path => path})
|
218
176
|
raise
|
219
177
|
end
|
220
178
|
end
|
221
|
-
|
179
|
+
po_messages
|
222
180
|
end
|
223
181
|
|
224
|
-
# constant values
|
225
|
-
VERSION = GetText::VERSION
|
226
|
-
|
227
182
|
def check_command_line_options(*options) # :nodoc:
|
228
183
|
input_files, output = parse_arguments(*options)
|
229
184
|
|
@@ -279,6 +234,11 @@ EOH
|
|
279
234
|
@copyright_holder = out
|
280
235
|
end
|
281
236
|
|
237
|
+
parser.on("--output-encoding=ENCODING",
|
238
|
+
_("set encoding for output")) do |encoding|
|
239
|
+
@output_encoding = encoding
|
240
|
+
end
|
241
|
+
|
282
242
|
parser.on("-r", "--require=library",
|
283
243
|
_("require the library before executing xgettext")) do |out|
|
284
244
|
require out
|
@@ -294,7 +254,7 @@ EOH
|
|
294
254
|
end
|
295
255
|
|
296
256
|
parser.on_tail("--version", _("display version information and exit")) do
|
297
|
-
puts(VERSION)
|
257
|
+
puts(GetText::VERSION)
|
298
258
|
exit(true)
|
299
259
|
end
|
300
260
|
|
@@ -306,14 +266,19 @@ EOH
|
|
306
266
|
def run(*options) # :nodoc:
|
307
267
|
check_command_line_options(*options)
|
308
268
|
|
269
|
+
@output_encoding ||= "UTF-8"
|
270
|
+
|
271
|
+
pot_header = generate_pot_header
|
272
|
+
pot_messages = generate_pot(@input_files)
|
273
|
+
|
309
274
|
if @output.is_a?(String)
|
310
275
|
File.open(File.expand_path(@output), "w+") do |file|
|
311
|
-
file.puts(
|
312
|
-
file.puts(
|
276
|
+
file.puts(pot_header)
|
277
|
+
file.puts(pot_messages)
|
313
278
|
end
|
314
279
|
else
|
315
|
-
@output.puts(
|
316
|
-
@output.puts(
|
280
|
+
@output.puts(pot_header)
|
281
|
+
@output.puts(pot_messages)
|
317
282
|
end
|
318
283
|
self
|
319
284
|
end
|
@@ -322,6 +287,92 @@ EOH
|
|
322
287
|
def now
|
323
288
|
Time.now
|
324
289
|
end
|
290
|
+
|
291
|
+
def parse_path(path, po_messages)
|
292
|
+
@parsers.each do |parser|
|
293
|
+
next unless parser.target?(path)
|
294
|
+
|
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)
|
299
|
+
end
|
300
|
+
|
301
|
+
if po_message.msgid.empty?
|
302
|
+
warn _("Warning: The empty \"\" msgid is reserved by " +
|
303
|
+
"gettext. So gettext(\"\") doesn't returns " +
|
304
|
+
"empty string but the header entry in po file.")
|
305
|
+
# TODO: add pommesage.source to the pot header as below:
|
306
|
+
# # SOME DESCRIPTIVE TITLE.
|
307
|
+
# # Copyright (C) YEAR THE COPYRIGHT HOLDER
|
308
|
+
# # This file is distributed under the same license as the PACKAGE package.
|
309
|
+
# # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
310
|
+
# #
|
311
|
+
# #: test/test_gettext.rb:65
|
312
|
+
# #, fuzzy
|
313
|
+
# "#: test/test_gettext.rb:65" line is added.
|
314
|
+
next
|
315
|
+
end
|
316
|
+
|
317
|
+
if @output.is_a?(String)
|
318
|
+
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)
|
321
|
+
absolute_path = Pathname.new(path).expand_path
|
322
|
+
begin
|
323
|
+
path = absolute_path.relative_path_from(base_path).to_s
|
324
|
+
rescue ArgumentError
|
325
|
+
raise # Should we ignore it?
|
326
|
+
end
|
327
|
+
"#{path}:#{line}"
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
# Save the previous target
|
332
|
+
if po_messages.empty?
|
333
|
+
existing = nil
|
334
|
+
else
|
335
|
+
message = po_messages.find {|t| t == po_message}
|
336
|
+
existing = po_messages.index(message)
|
337
|
+
end
|
338
|
+
|
339
|
+
if existing
|
340
|
+
po_message = po_messages[existing].merge(po_message)
|
341
|
+
po_messages[existing] = po_message
|
342
|
+
else
|
343
|
+
po_messages << po_message
|
344
|
+
end
|
345
|
+
end
|
346
|
+
break
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def encode(string)
|
351
|
+
if string.respond_to?(:encode)
|
352
|
+
string.encode(@output_encoding)
|
353
|
+
else
|
354
|
+
string # don't support
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
# This is the module for backward compatibility,
|
362
|
+
# but GetText::Tools::XGetText.run should be used.
|
363
|
+
module GetText
|
364
|
+
module RGetText
|
365
|
+
def run(paths=nil, out=STDOUT)
|
366
|
+
warn("Warning: This method is obsolete. " +
|
367
|
+
"Please use GetText::Tools::XGetText.run.")
|
368
|
+
if paths.nil?
|
369
|
+
GetText::Tools::XGetText.run(*ARGV)
|
370
|
+
elsif out == STDOUT
|
371
|
+
GetText::Tools::XGetText.run(paths)
|
372
|
+
else
|
373
|
+
GetText::Tools::XGetText.run("-o", out, paths)
|
374
|
+
end
|
325
375
|
end
|
376
|
+
module_function :run
|
326
377
|
end
|
327
378
|
end
|