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