gettext 3.0.2 → 3.0.3
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.
- checksums.yaml +7 -0
- data/doc/text/news.md +30 -0
- data/lib/gettext/class_info.rb +0 -6
- data/lib/gettext/locale_path.rb +0 -7
- data/lib/gettext/po_entry.rb +21 -7
- data/lib/gettext/text_domain_manager.rb +2 -2
- data/lib/gettext/tools/msgmerge.rb +123 -107
- data/lib/gettext/tools/task.rb +11 -0
- data/lib/gettext/tools/xgettext.rb +31 -24
- data/lib/gettext/version.rb +1 -1
- data/po/gettext.pot +50 -38
- data/test/test_locale_path.rb +0 -4
- data/test/test_po_entry.rb +101 -15
- data/test/tools/test_msgmerge.rb +133 -30
- data/test/tools/test_xgettext.rb +11 -2
- metadata +27 -50
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5dd7b69714925629b741151ac292ea6cdd610594
|
4
|
+
data.tar.gz: d46007fce3f43d56375c311bcf13c0edbc493adb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e902eb611d9e036c68aafcd6b2f0cb462c43344b683ee841a5792e2a5061dc587f351ddf172e0234eebad4a0f0d87aa7c9ef3c563a04b129ecba94dec35e0399
|
7
|
+
data.tar.gz: 57ab4f506008399e3b5b0c52a2ecdb09cbc2f1f401abdfd8005a238228b9fcbe4e90f182dfb5db4d57b7a8c14f5f9b532d74b1dd5c4d479873936311f5d63e78
|
data/doc/text/news.md
CHANGED
@@ -1,5 +1,35 @@
|
|
1
1
|
# News
|
2
2
|
|
3
|
+
## <a id="3-0-3">3.0.3</a>: 2013-12-15
|
4
|
+
|
5
|
+
### Improvements
|
6
|
+
|
7
|
+
* Documented {GetText::Tools::Task#namespace_prefix}.
|
8
|
+
* Added `--copyright-year` option to {GetText::Tools::XGetText}.
|
9
|
+
[GitHub#25] [Debian #726941] [Reported by Francesco Poli]
|
10
|
+
[Reported by 375gnu]
|
11
|
+
* {GetText::Tools::XGetText} respects new lines in translate target
|
12
|
+
message.
|
13
|
+
* Added {GetText::POEntry#header?}.
|
14
|
+
* Added {GetText::POEntry#obsolete?}.
|
15
|
+
* Added `--no-fuzzy-matching` option to {GetText::Tools::MsgMerge}.
|
16
|
+
[GitHub#28] [Reported by Sam Lown]
|
17
|
+
|
18
|
+
### Fixes
|
19
|
+
|
20
|
+
* Fixed cache key hash conflict on armv7hl. Memoization feature is
|
21
|
+
removed for this fix. If you get performance issue. Please report
|
22
|
+
it. We will solve the issue. See also locale gem's GitHub issue #3.
|
23
|
+
[GitHub#22] [Reported by mtasaka]
|
24
|
+
* Fixed a bug that obsolete comment misses the last new line.
|
25
|
+
|
26
|
+
### Thanks
|
27
|
+
|
28
|
+
* Francesco Poli
|
29
|
+
* 375gnu
|
30
|
+
* Sam Lown
|
31
|
+
* mtasaka
|
32
|
+
|
3
33
|
## <a id="3-0-2">3.0.2</a>: 2013-09-29
|
4
34
|
|
5
35
|
### Improvements
|
data/lib/gettext/class_info.rb
CHANGED
@@ -1,15 +1,11 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
-
require 'locale/util/memoizable'
|
4
|
-
|
5
3
|
module GetText
|
6
4
|
# For normalize/finding the related classes/modules.
|
7
5
|
# This is used for realizing the scope of TextDomain.
|
8
6
|
# (see: http://www.yotabanana.com/hiki/ruby-gettext-scope.html)
|
9
7
|
module ClassInfo
|
10
8
|
extend self
|
11
|
-
include Locale::Util::Memoizable
|
12
|
-
|
13
9
|
# normalize the class name
|
14
10
|
# klass should kind of the class, not object.
|
15
11
|
def normalize_class(klass)
|
@@ -23,7 +19,6 @@ module GetText
|
|
23
19
|
def root_ancestors # :nodoc:
|
24
20
|
Object.ancestors
|
25
21
|
end
|
26
|
-
memoize :root_ancestors
|
27
22
|
|
28
23
|
# Internal method for related_classes.
|
29
24
|
def related_classes_internal(klass, all_classes = [], analyzed_classes = [] )
|
@@ -64,6 +59,5 @@ module GetText
|
|
64
59
|
end
|
65
60
|
ret
|
66
61
|
end
|
67
|
-
memoize :related_classes
|
68
62
|
end
|
69
63
|
end
|
data/lib/gettext/locale_path.rb
CHANGED
@@ -15,8 +15,6 @@ require 'rbconfig'
|
|
15
15
|
module GetText
|
16
16
|
# Treats locale-path for mo-files.
|
17
17
|
class LocalePath
|
18
|
-
include Locale::Util::Memoizable
|
19
|
-
|
20
18
|
# The default locale paths.
|
21
19
|
CONFIG_PREFIX = RbConfig::CONFIG['prefix'].gsub(/\/local/, "")
|
22
20
|
DEFAULT_RULES = [
|
@@ -29,8 +27,6 @@ module GetText
|
|
29
27
|
].uniq
|
30
28
|
|
31
29
|
class << self
|
32
|
-
include Locale::Util::Memoizable
|
33
|
-
|
34
30
|
# Add default locale path. Usually you should use GetText.add_default_locale_path instead.
|
35
31
|
# * path: a new locale path. (e.g.) "/usr/share/locale/%{lang}/LC_MESSAGES/%{name}.mo"
|
36
32
|
# ('locale' => "ja_JP", 'name' => "textdomain")
|
@@ -66,7 +62,6 @@ module GetText
|
|
66
62
|
Dir.glob(path % {:lang => "*", :name => "*"}).size > 0}.uniq
|
67
63
|
default_path_rules
|
68
64
|
end
|
69
|
-
memoize_dup :default_path_rules
|
70
65
|
end
|
71
66
|
|
72
67
|
attr_reader :locale_paths, :supported_locales
|
@@ -114,7 +109,5 @@ module GetText
|
|
114
109
|
end
|
115
110
|
nil
|
116
111
|
end
|
117
|
-
memoize :current_path
|
118
|
-
|
119
112
|
end
|
120
113
|
end
|
data/lib/gettext/po_entry.rb
CHANGED
@@ -165,6 +165,18 @@ module GetText
|
|
165
165
|
[:plural, :msgctxt_plural].include?(@type)
|
166
166
|
end
|
167
167
|
|
168
|
+
# @return true if the entry is header entry, false otherwise.
|
169
|
+
# Header entry is normal type and has empty msgid.
|
170
|
+
def header?
|
171
|
+
@type == :normal and @msgid == ""
|
172
|
+
end
|
173
|
+
|
174
|
+
# @return true if the entry is obsolete entry, false otherwise.
|
175
|
+
# Obsolete entry is normal type and has :last msgid.
|
176
|
+
def obsolete?
|
177
|
+
@type == :normal and @msgid == :last
|
178
|
+
end
|
179
|
+
|
168
180
|
def [](number)
|
169
181
|
param = @param_type[number]
|
170
182
|
raise ParseError, 'no more string parameters expected' unless param
|
@@ -220,8 +232,7 @@ module GetText
|
|
220
232
|
end
|
221
233
|
|
222
234
|
def format
|
223
|
-
|
224
|
-
if @entry.msgid == :last
|
235
|
+
if @entry.obsolete?
|
225
236
|
return format_obsolete_comment(@entry.comment)
|
226
237
|
end
|
227
238
|
|
@@ -343,7 +354,7 @@ module GetText
|
|
343
354
|
formatted_comment = ""
|
344
355
|
comment.each_line do |comment_line|
|
345
356
|
if /\A#[^~]/ =~ comment_line or comment_line.start_with?(mark)
|
346
|
-
formatted_comment << comment_line
|
357
|
+
formatted_comment << "#{comment_line.chomp}\n"
|
347
358
|
elsif comment_line == "\n"
|
348
359
|
formatted_comment << "\n"
|
349
360
|
else
|
@@ -373,13 +384,16 @@ module GetText
|
|
373
384
|
return [message] if message.empty?
|
374
385
|
|
375
386
|
max_line_width = @options[:max_line_width]
|
376
|
-
return [message] if max_line_width <= 0
|
377
387
|
|
378
388
|
chunks = []
|
379
389
|
message.each_line do |line|
|
380
|
-
|
381
|
-
|
382
|
-
|
390
|
+
if max_line_width <= 0
|
391
|
+
chunks << line
|
392
|
+
else
|
393
|
+
# TODO: use character width instead of the number of characters
|
394
|
+
line.scan(/.{1,#{max_line_width}}/m) do |chunk|
|
395
|
+
chunks << chunk
|
396
|
+
end
|
383
397
|
end
|
384
398
|
end
|
385
399
|
chunks
|
@@ -96,7 +96,7 @@ module GetText
|
|
96
96
|
# it returns a last part of msgid separeted "div".
|
97
97
|
def translate_singular_message(klass, msgid, div = nil)
|
98
98
|
klass = ClassInfo.normalize_class(klass)
|
99
|
-
key = [Locale.current, klass, msgid, div]
|
99
|
+
key = [Locale.current, klass, msgid, div]
|
100
100
|
msg = @@singular_message_cache[key]
|
101
101
|
return msg if msg and @@cached
|
102
102
|
# Find messages from related classes.
|
@@ -156,7 +156,7 @@ module GetText
|
|
156
156
|
div = arg4
|
157
157
|
end
|
158
158
|
|
159
|
-
key = [Locale.current, klass, msgid, msgid_plural, div]
|
159
|
+
key = [Locale.current, klass, msgid, msgid_plural, div]
|
160
160
|
msgs = @@plural_message_cache[key]
|
161
161
|
unless (msgs and @@cached)
|
162
162
|
# Find messages from related classes.
|
@@ -29,7 +29,49 @@ require "gettext/po"
|
|
29
29
|
module GetText
|
30
30
|
module Tools
|
31
31
|
class MsgMerge
|
32
|
-
class
|
32
|
+
class << self
|
33
|
+
# (see #run)
|
34
|
+
#
|
35
|
+
# This method is provided just for convenience. It equals to
|
36
|
+
# `new.run(*command_line)`.
|
37
|
+
def run(*command_line)
|
38
|
+
new.run(*command_line)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Merge a po-file inluding translated messages and a new pot-file.
|
43
|
+
#
|
44
|
+
# @param [Array<String>] command_line
|
45
|
+
# command line arguments for rmsgmerge.
|
46
|
+
# @return [void]
|
47
|
+
def run(*command_line)
|
48
|
+
config = Config.new
|
49
|
+
config.parse(command_line)
|
50
|
+
|
51
|
+
parser = POParser.new
|
52
|
+
parser.ignore_fuzzy = false
|
53
|
+
definition_po = PO.new
|
54
|
+
reference_pot = PO.new
|
55
|
+
parser.parse_file(config.definition_po, definition_po)
|
56
|
+
parser.parse_file(config.reference_pot, reference_pot)
|
57
|
+
|
58
|
+
merger = Merger.new(reference_pot, definition_po, config)
|
59
|
+
result = merger.merge
|
60
|
+
result.order = config.order
|
61
|
+
p result if $DEBUG
|
62
|
+
print result.generate_po if $DEBUG
|
63
|
+
|
64
|
+
if config.output.is_a?(String)
|
65
|
+
File.open(File.expand_path(config.output), "w+") do |file|
|
66
|
+
file.write(result.to_s(config.po_format_options))
|
67
|
+
end
|
68
|
+
else
|
69
|
+
puts(result.to_s(config.po_format_options))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# @private
|
74
|
+
class Merger
|
33
75
|
# Merge the reference with the definition: take the #. and
|
34
76
|
# #: comments from the reference, take the # comments from
|
35
77
|
# the definition, take the msgstr from the definition. Add
|
@@ -38,55 +80,60 @@ module GetText
|
|
38
80
|
POT_DATE_EXTRACT_RE = /POT-Creation-Date:\s*(.*)?\s*$/
|
39
81
|
POT_DATE_RE = /POT-Creation-Date:.*?$/
|
40
82
|
|
41
|
-
def
|
83
|
+
def initialize(reference, definition, config)
|
84
|
+
@reference = reference
|
85
|
+
@definition = definition
|
86
|
+
@translated_entries = @definition.reject do |entry|
|
87
|
+
entry.msgstr.nil?
|
88
|
+
end
|
89
|
+
@config = config
|
90
|
+
end
|
91
|
+
|
92
|
+
def merge
|
42
93
|
result = GetText::PO.new
|
43
94
|
|
44
|
-
|
45
|
-
entry.
|
95
|
+
@reference.each do |entry|
|
96
|
+
id = [entry.msgctxt, entry.msgid]
|
97
|
+
result[*id] = merge_definition(entry)
|
46
98
|
end
|
47
99
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
id = [msgctxt, msgid]
|
100
|
+
add_obsolete_entry(result)
|
101
|
+
result
|
102
|
+
end
|
52
103
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
104
|
+
private
|
105
|
+
def merge_definition(entry)
|
106
|
+
msgid = entry.msgid
|
107
|
+
msgctxt = entry.msgctxt
|
108
|
+
id = [msgctxt, msgid]
|
57
109
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
result[nil, msgid] = merge_fuzzy_entry(same_msgid_entry, entry)
|
62
|
-
next
|
63
|
-
end
|
64
|
-
end
|
110
|
+
if @definition.has_key?(*id)
|
111
|
+
return merge_entry(entry, @definition[*id])
|
112
|
+
end
|
65
113
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
114
|
+
return entry unless @config.enable_fuzzy_matching?
|
115
|
+
|
116
|
+
if msgctxt.nil?
|
117
|
+
same_msgid_entry = find_by_msgid(@translated_entries, msgid)
|
118
|
+
if same_msgid_entry and same_msgid_entry.msgctxt
|
119
|
+
return merge_fuzzy_entry(entry, same_msgid_entry)
|
70
120
|
end
|
121
|
+
end
|
71
122
|
|
72
|
-
|
123
|
+
fuzzy_entry = find_fuzzy_entry(@translated_entries, msgid, msgctxt)
|
124
|
+
if fuzzy_entry
|
125
|
+
return merge_fuzzy_entry(entry, fuzzy_entry)
|
73
126
|
end
|
74
127
|
|
75
|
-
|
76
|
-
result
|
128
|
+
entry
|
77
129
|
end
|
78
130
|
|
79
|
-
def merge_entry(
|
80
|
-
if definition_entry.
|
81
|
-
|
82
|
-
return new_header
|
131
|
+
def merge_entry(reference_entry, definition_entry)
|
132
|
+
if definition_entry.header?
|
133
|
+
return merge_header(reference_entry, definition_entry)
|
83
134
|
end
|
84
135
|
|
85
|
-
if definition_entry.flag == "fuzzy"
|
86
|
-
entry = definition_entry
|
87
|
-
entry.flag = "fuzzy"
|
88
|
-
return entry
|
89
|
-
end
|
136
|
+
return definition_entry if definition_entry.flag == "fuzzy"
|
90
137
|
|
91
138
|
entry = reference_entry
|
92
139
|
entry.translator_comment = definition_entry.translator_comment
|
@@ -100,7 +147,7 @@ module GetText
|
|
100
147
|
entry
|
101
148
|
end
|
102
149
|
|
103
|
-
def merge_header(
|
150
|
+
def merge_header(new_header, old_header)
|
104
151
|
header = old_header
|
105
152
|
if POT_DATE_EXTRACT_RE =~ new_header.msgstr
|
106
153
|
create_date = $1
|
@@ -121,8 +168,8 @@ module GetText
|
|
121
168
|
same_msgid_entries.first
|
122
169
|
end
|
123
170
|
|
124
|
-
def merge_fuzzy_entry(
|
125
|
-
merged_entry = merge_entry(
|
171
|
+
def merge_fuzzy_entry(entry, fuzzy_entry)
|
172
|
+
merged_entry = merge_entry(entry, fuzzy_entry)
|
126
173
|
merged_entry.flag = "fuzzy"
|
127
174
|
merged_entry
|
128
175
|
end
|
@@ -155,40 +202,38 @@ module GetText
|
|
155
202
|
Text::Levenshtein.distance(source, destination) / max_size.to_f
|
156
203
|
end
|
157
204
|
|
158
|
-
def add_obsolete_entry(result
|
159
|
-
obsolete_entry = generate_obsolete_entry(result
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
result
|
205
|
+
def add_obsolete_entry(result)
|
206
|
+
obsolete_entry = generate_obsolete_entry(result)
|
207
|
+
return if obsolete_entry.nil?
|
208
|
+
|
209
|
+
result[:last] = obsolete_entry
|
164
210
|
end
|
165
211
|
|
166
|
-
def generate_obsolete_entry(result
|
167
|
-
|
212
|
+
def generate_obsolete_entry(result)
|
213
|
+
obsolete_entries = extract_obsolete_entries(result)
|
214
|
+
obsolete_comments = obsolete_entries.collect do |entry|
|
215
|
+
entry.to_s
|
216
|
+
end
|
168
217
|
|
169
|
-
|
170
|
-
unless obsolete_entries.empty?
|
171
|
-
obsolete_comment = []
|
218
|
+
return nil if obsolete_comments.empty?
|
172
219
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
obsolete_entry = POEntry.new(:normal)
|
177
|
-
obsolete_entry.msgid = :last
|
178
|
-
obsolete_entry.comment = obsolete_comment.join("\n")
|
179
|
-
end
|
220
|
+
obsolete_entry = POEntry.new(:normal)
|
221
|
+
obsolete_entry.msgid = :last
|
222
|
+
obsolete_entry.comment = obsolete_comments.join("\n")
|
180
223
|
obsolete_entry
|
181
224
|
end
|
182
225
|
|
183
|
-
def extract_obsolete_entries(result
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
226
|
+
def extract_obsolete_entries(result)
|
227
|
+
@definition.find_all do |entry|
|
228
|
+
if entry.obsolete?
|
229
|
+
true
|
230
|
+
elsif entry.msgstr.nil?
|
231
|
+
false
|
232
|
+
else
|
233
|
+
id = [entry.msgctxt, entry.msgid]
|
234
|
+
not result.has_key?(*id)
|
189
235
|
end
|
190
236
|
end
|
191
|
-
obsolete_entries
|
192
237
|
end
|
193
238
|
end
|
194
239
|
|
@@ -199,13 +244,16 @@ module GetText
|
|
199
244
|
bindtextdomain("gettext")
|
200
245
|
|
201
246
|
attr_accessor :definition_po, :reference_pot
|
202
|
-
attr_accessor :output, :
|
247
|
+
attr_accessor :output, :update
|
203
248
|
attr_accessor :order
|
204
249
|
attr_accessor :po_format_options
|
205
250
|
|
206
251
|
# update mode options
|
207
252
|
attr_accessor :backup, :suffix
|
208
253
|
|
254
|
+
# (#see #enable_fuzzy_matching?)
|
255
|
+
attr_writer :enable_fuzzy_matching
|
256
|
+
|
209
257
|
# The result is written back to def.po.
|
210
258
|
# --backup=CONTROL make a backup of def.po
|
211
259
|
# --suffix=SUFFIX override the usual backup suffix
|
@@ -228,7 +276,7 @@ module GetText
|
|
228
276
|
@po_format_options = {
|
229
277
|
:max_line_width => POEntry::Formatter::DEFAULT_MAX_LINE_WIDTH,
|
230
278
|
}
|
231
|
-
@
|
279
|
+
@enable_fuzzy_matching = true
|
232
280
|
@update = nil
|
233
281
|
@backup = ENV["VERSION_CONTROL"]
|
234
282
|
@suffix = ENV["SIMPLE_BACKUP_SUFFIX"] || "~"
|
@@ -248,6 +296,11 @@ module GetText
|
|
248
296
|
@output = @definition_po if @update
|
249
297
|
end
|
250
298
|
|
299
|
+
# @return [Bool] true if fuzzy matching is enabled, false otherwise.
|
300
|
+
def enable_fuzzy_matching?
|
301
|
+
@enable_fuzzy_matching
|
302
|
+
end
|
303
|
+
|
251
304
|
private
|
252
305
|
def create_option_parser
|
253
306
|
parser = OptionParser.new
|
@@ -312,7 +365,11 @@ module GetText
|
|
312
365
|
@po_format_options[:max_line_width] = max_line_width
|
313
366
|
end
|
314
367
|
|
315
|
-
|
368
|
+
parser.on("--[no-]fuzzy-matching",
|
369
|
+
_("Disable fuzzy matching"),
|
370
|
+
_("(enable)")) do |boolean|
|
371
|
+
@enable_fuzzy_matching = boolean
|
372
|
+
end
|
316
373
|
|
317
374
|
parser.on("-h", "--help", _("Display this help and exit")) do
|
318
375
|
puts(parser.help)
|
@@ -328,47 +385,6 @@ module GetText
|
|
328
385
|
parser
|
329
386
|
end
|
330
387
|
end
|
331
|
-
|
332
|
-
class << self
|
333
|
-
# (see #run)
|
334
|
-
#
|
335
|
-
# This method is provided just for convenience. It equals to
|
336
|
-
# `new.run(*command_line)`.
|
337
|
-
def run(*command_line)
|
338
|
-
new.run(*command_line)
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
# Merge a po-file inluding translated messages and a new pot-file.
|
343
|
-
#
|
344
|
-
# @param [Array<String>] command_line
|
345
|
-
# command line arguments for rmsgmerge.
|
346
|
-
# @return [void]
|
347
|
-
def run(*command_line)
|
348
|
-
config = Config.new
|
349
|
-
config.parse(command_line)
|
350
|
-
|
351
|
-
parser = POParser.new
|
352
|
-
parser.ignore_fuzzy = false
|
353
|
-
definition_po = PO.new
|
354
|
-
reference_pot = PO.new
|
355
|
-
parser.parse_file(config.definition_po, definition_po)
|
356
|
-
parser.parse_file(config.reference_pot, reference_pot)
|
357
|
-
|
358
|
-
merger = Merger.new
|
359
|
-
result = merger.merge(definition_po, reference_pot)
|
360
|
-
result.order = config.order
|
361
|
-
p result if $DEBUG
|
362
|
-
print result.generate_po if $DEBUG
|
363
|
-
|
364
|
-
if config.output.is_a?(String)
|
365
|
-
File.open(File.expand_path(config.output), "w+") do |file|
|
366
|
-
file.write(result.to_s(config.po_format_options))
|
367
|
-
end
|
368
|
-
else
|
369
|
-
puts(result.to_s(config.po_format_options))
|
370
|
-
end
|
371
|
-
end
|
372
388
|
end
|
373
389
|
end
|
374
390
|
end
|