gettext 2.3.9 → 3.0.0

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 (106) hide show
  1. data/.yardopts +1 -0
  2. data/README.rdoc +28 -23
  3. data/Rakefile +29 -21
  4. data/doc/text/news.md +57 -0
  5. data/gettext.gemspec +1 -1
  6. data/lib/gettext.rb +13 -29
  7. data/lib/gettext/cgi.rb +1 -1
  8. data/lib/gettext/{runtime/class_info.rb → class_info.rb} +1 -1
  9. data/lib/gettext/{runtime/locale_path.rb → locale_path.rb} +1 -2
  10. data/lib/gettext/{runtime/mo.rb → mo.rb} +18 -33
  11. data/lib/gettext/{tools/po.rb → po.rb} +1 -1
  12. data/lib/gettext/{tools/po_entry.rb → po_entry.rb} +8 -4
  13. data/lib/gettext/{tools/poparser.rb → po_parser.rb} +41 -44
  14. data/lib/gettext/{runtime/textdomain.rb → text_domain.rb} +6 -16
  15. data/lib/gettext/text_domain_group.rb +26 -0
  16. data/lib/gettext/{runtime/textdomain_manager.rb → text_domain_manager.rb} +40 -40
  17. data/lib/gettext/tools.rb +1 -182
  18. data/lib/gettext/tools/msgfmt.rb +1 -1
  19. data/lib/gettext/tools/msginit.rb +1 -1
  20. data/lib/gettext/tools/msgmerge.rb +2 -221
  21. data/lib/gettext/tools/parser/erb.rb +49 -30
  22. data/lib/gettext/tools/parser/glade.rb +44 -36
  23. data/lib/gettext/tools/parser/ruby.rb +126 -37
  24. data/lib/gettext/tools/task.rb +225 -0
  25. data/lib/gettext/tools/xgettext.rb +25 -28
  26. data/lib/gettext/version.rb +1 -1
  27. data/locale/bg/LC_MESSAGES/gettext.mo +0 -0
  28. data/locale/bs/LC_MESSAGES/gettext.mo +0 -0
  29. data/locale/ca/LC_MESSAGES/gettext.mo +0 -0
  30. data/locale/cs/LC_MESSAGES/gettext.mo +0 -0
  31. data/locale/de/LC_MESSAGES/gettext.mo +0 -0
  32. data/locale/el/LC_MESSAGES/gettext.mo +0 -0
  33. data/locale/eo/LC_MESSAGES/gettext.mo +0 -0
  34. data/locale/es/LC_MESSAGES/gettext.mo +0 -0
  35. data/locale/et/LC_MESSAGES/gettext.mo +0 -0
  36. data/locale/fr/LC_MESSAGES/gettext.mo +0 -0
  37. data/locale/hr/LC_MESSAGES/gettext.mo +0 -0
  38. data/locale/hu/LC_MESSAGES/gettext.mo +0 -0
  39. data/locale/it/LC_MESSAGES/gettext.mo +0 -0
  40. data/locale/ja/LC_MESSAGES/gettext.mo +0 -0
  41. data/locale/ko/LC_MESSAGES/gettext.mo +0 -0
  42. data/locale/lv/LC_MESSAGES/gettext.mo +0 -0
  43. data/locale/nb/LC_MESSAGES/gettext.mo +0 -0
  44. data/locale/nl/LC_MESSAGES/gettext.mo +0 -0
  45. data/locale/pt_BR/LC_MESSAGES/gettext.mo +0 -0
  46. data/locale/ru/LC_MESSAGES/gettext.mo +0 -0
  47. data/locale/sr/LC_MESSAGES/gettext.mo +0 -0
  48. data/locale/sv/LC_MESSAGES/gettext.mo +0 -0
  49. data/locale/uk/LC_MESSAGES/gettext.mo +0 -0
  50. data/locale/vi/LC_MESSAGES/gettext.mo +0 -0
  51. data/locale/zh/LC_MESSAGES/gettext.mo +0 -0
  52. data/locale/zh_TW/LC_MESSAGES/gettext.mo +0 -0
  53. data/po/gettext.pot +171 -97
  54. data/samples/hello.rb +3 -2
  55. data/samples/hello2.rb +2 -1
  56. data/samples/hello_gtk2.rb +4 -1
  57. data/samples/hello_gtk_builder.rb +32 -0
  58. data/samples/hello_gtk_builder.ui +46 -0
  59. data/samples/hello_noop.rb +2 -1
  60. data/samples/hello_plural.rb +2 -1
  61. data/samples/hello_tk.rb +2 -1
  62. data/src/{poparser.ry → po_parser.ry} +31 -35
  63. data/test/fixtures/N_.rb +1 -1
  64. data/test/fixtures/_/double_quote_in_double_quote.rb +32 -0
  65. data/test/fixtures/_/double_quote_in_single_quote.rb +32 -0
  66. data/test/fixtures/_/literal_concatenation_with_continuation_line.rb +36 -0
  67. data/test/fixtures/_/middle_new_line.rb +32 -0
  68. data/test/fixtures/_/multiple_lines_literal.rb +35 -0
  69. data/test/fixtures/_/multiple_messages_in_same_line.rb +32 -0
  70. data/test/fixtures/_/multiple_same_messages.rb +36 -0
  71. data/{lib/gettext/runtime/mofile.rb → test/fixtures/_/one_new_line.rb} +12 -6
  72. data/test/fixtures/{multi_textdomain.rb → multi_text_domain.rb} +1 -1
  73. data/test/fixtures/non_ascii.rb +1 -1
  74. data/test/fixtures/simple.rb +1 -1
  75. data/test/fixtures/untranslated.rb +1 -1
  76. data/test/gettext-test-utils.rb +1 -24
  77. data/test/po/ja/_.po +63 -13
  78. data/test/po/ja/non_ascii.po +2 -3
  79. data/test/po/ja/untranslated.po +1 -1
  80. data/test/test_class_info.rb +2 -2
  81. data/test/test_gettext.rb +11 -11
  82. data/test/test_mo.rb +2 -2
  83. data/test/test_parser.rb +93 -96
  84. data/test/test_po_entry.rb +237 -146
  85. data/test/test_po_parser.rb +107 -98
  86. data/test/test_string.rb +1 -1
  87. data/test/{test_textdomain_bind.rb → test_text_domain_bind.rb} +6 -6
  88. data/test/{test_textdomain_multi.rb → test_text_domain_multi.rb} +5 -5
  89. data/test/{test_textdomain_toplevel.rb → test_text_domain_toplevel.rb} +1 -1
  90. data/test/test_thread.rb +1 -1
  91. data/test/tools/files/simple_translation.rb +1 -1
  92. data/test/{parser → tools/parser}/test_ruby.rb +110 -14
  93. data/test/tools/test_msgmerge.rb +17 -276
  94. data/test/tools/test_po.rb +1 -1
  95. data/test/tools/test_xgettext.rb +175 -144
  96. metadata +59 -33
  97. data/lib/gettext/core_ext/iconv.rb +0 -110
  98. data/lib/gettext/core_ext/string.rb +0 -91
  99. data/lib/gettext/parser/erb.rb +0 -5
  100. data/lib/gettext/parser/glade.rb +0 -5
  101. data/lib/gettext/parser/ruby.rb +0 -172
  102. data/lib/gettext/runtime/textdomain_group.rb +0 -26
  103. data/lib/gettext/task.rb +0 -203
  104. data/lib/gettext/utils.rb +0 -39
  105. data/test/test_po_generation.rb +0 -45
  106. data/test/tools/test_tools.rb +0 -61
@@ -1,8 +1,9 @@
1
- # encoding: utf-8
1
+ # -*- coding: utf-8 -*-
2
2
 
3
3
  =begin
4
4
  parser/glade.rb - parser for Glade-2
5
5
 
6
+ Copyright (C) 2013 Kouhei Sutou <kou@clear-code.com>
6
7
  Copyright (C) 2004,2005 Masao Mutoh
7
8
 
8
9
  You may redistribute it and/or modify it under the same
@@ -13,47 +14,69 @@ require 'cgi'
13
14
  require 'gettext'
14
15
 
15
16
  module GetText
16
- module GladeParser
17
+ class GladeParser
17
18
  extend GetText
18
- extend self
19
19
 
20
20
  bindtextdomain("gettext")
21
21
 
22
+ class << self
23
+ XML_RE = /<\?xml/
24
+ GLADE_RE = /glade-2.0.dtd/
25
+
26
+ def target?(file) # :nodoc:
27
+ data = IO.readlines(file)
28
+ if XML_RE =~ data[0] and GLADE_RE =~ data[1]
29
+ true
30
+ else
31
+ if File.extname(file) == '.glade'
32
+ raise _("`%{file}' is not glade-2.0 format.") % {:file => file}
33
+ end
34
+ false
35
+ end
36
+ end
37
+
38
+ def parse(path, options={})
39
+ parser = new(path, options)
40
+ parser.parse
41
+ end
42
+ end
43
+
22
44
  TARGET1 = /<property.*translatable="yes">(.*)/
23
45
  TARGET2 = /(.*)<\/property>/
24
46
 
25
- def parse(file) # :nodoc:
26
- lines = IO.readlines(file)
27
- parse_lines(file, lines)
47
+ def initialize(path, options={})
48
+ @path = path
49
+ @options = options
50
+ end
51
+
52
+ def parse # :nodoc:
53
+ File.open(@path) do |file|
54
+ parse_source(file)
55
+ end
28
56
  end
29
57
 
30
- #from ary of lines.
31
- def parse_lines(file, lines) # :nodoc:
58
+ private
59
+ def parse_source(input) # :nodoc:
32
60
  targets = []
33
- cnt = 0
34
61
  target = false
35
- line_no = 0
62
+ start_line_no = nil
36
63
  val = nil
37
64
 
38
- loop do
39
- line = lines.shift
40
- break unless line
41
-
42
- cnt += 1
65
+ input.each_line.with_index do |line, i|
43
66
  if TARGET1 =~ line
44
- line_no = cnt
67
+ start_line_no = i + 1
45
68
  val = $1 + "\n"
46
69
  target = true
47
70
  if TARGET2 =~ $1
48
71
  val = $1
49
- add_target(val, file, line_no, targets)
72
+ add_target(val, start_line_no, targets)
50
73
  val = nil
51
74
  target = false
52
75
  end
53
76
  elsif target
54
77
  if TARGET2 =~ line
55
78
  val << $1
56
- add_target(val, file, line_no, targets)
79
+ add_target(val, start_line_no, targets)
57
80
  val = nil
58
81
  target = false
59
82
  else
@@ -64,29 +87,14 @@ module GetText
64
87
  targets
65
88
  end
66
89
 
67
- XML_RE = /<\?xml/
68
- GLADE_RE = /glade-2.0.dtd/
69
-
70
- def target?(file) # :nodoc:
71
- data = IO.readlines(file)
72
- if XML_RE =~ data[0] and GLADE_RE =~ data[1]
73
- true
74
- else
75
- if File.extname(file) == '.glade'
76
- raise _("`%{file}' is not glade-2.0 format.") % {:file => file}
77
- end
78
- false
79
- end
80
- end
81
-
82
- def add_target(val, file, line_no, targets) # :nodoc:
90
+ def add_target(val, line_no, targets) # :nodoc:
83
91
  return unless val.size > 0
84
92
  assoc_data = targets.assoc(val)
85
93
  val = CGI.unescapeHTML(val)
86
94
  if assoc_data
87
- targets[targets.index(assoc_data)] = assoc_data << "#{file}:#{line_no}"
95
+ targets[targets.index(assoc_data)] = assoc_data << "#{@path}:#{line_no}"
88
96
  else
89
- targets << [val.gsub(/\n/, '\n'), "#{file}:#{line_no}"]
97
+ targets << [val.gsub(/\n/, '\n'), "#{@path}:#{line_no}"]
90
98
  end
91
99
  targets
92
100
  end
@@ -2,6 +2,7 @@
2
2
  =begin
3
3
  parser/ruby.rb - parser for ruby script
4
4
 
5
+ Copyright (C) 2013 Kouhei Sutou <kou@clear-code.com>
5
6
  Copyright (C) 2003-2009 Masao Mutoh
6
7
  Copyright (C) 2005 speakillof
7
8
  Copyright (C) 2001,2002 Yasushi Shoji, Masao Mutoh
@@ -11,9 +12,9 @@
11
12
 
12
13
  =end
13
14
 
14
- require 'irb/ruby-lex.rb'
15
- require 'stringio'
16
- require 'gettext/tools/po_entry'
15
+ require "irb/ruby-lex"
16
+ require "stringio"
17
+ require "gettext/po_entry"
17
18
 
18
19
  module GetText
19
20
  class RubyLexX < RubyLex # :nodoc: all
@@ -31,7 +32,7 @@ module GetText
31
32
  end
32
33
 
33
34
  if @here_header
34
- s = s.sub(/\A.*?\n/, '').sub(/^.*\n\Z/, '')
35
+ s = s.sub(/\A.*?\n/, "").sub(/^.*\n\Z/, "")
35
36
  else
36
37
  begin
37
38
  s = eval(s)
@@ -85,7 +86,7 @@ module GetText
85
86
  # Supports parsing by setting attributes by and by.
86
87
  def set_current_attribute(str)
87
88
  param = @param_type[@param_number]
88
- raise ParseError, 'no more string parameters expected' unless param
89
+ raise ParseError, "no more string parameters expected" unless param
89
90
  set_value(param, str)
90
91
  end
91
92
 
@@ -107,32 +108,116 @@ module GetText
107
108
  end
108
109
  end
109
110
 
110
- module RubyParser
111
- extend self
111
+ class RubyParser
112
+ ID = ["gettext", "_", "N_", "sgettext", "s_"]
113
+ PLURAL_ID = ["ngettext", "n_", "Nn_", "ns_", "nsgettext"]
114
+ MSGCTXT_ID = ["pgettext", "p_"]
115
+ MSGCTXT_PLURAL_ID = ["npgettext", "np_"]
112
116
 
113
- ID = ['gettext', '_', 'N_', 'sgettext', 's_']
114
- PLURAL_ID = ['ngettext', 'n_', 'Nn_', 'ns_', 'nsgettext']
115
- MSGCTXT_ID = ['pgettext', 'p_']
116
- MSGCTXT_PLURAL_ID = ['npgettext', 'np_']
117
+ class << self
118
+ def target?(file) # :nodoc:
119
+ true # always true, as the default parser.
120
+ end
117
121
 
118
- # (Since 2.1.0) the 2nd parameter is deprecated
119
- # (and ignored here).
120
- # And You don't need to keep the poentries as unique.
122
+ # Parses Ruby script located at `path`.
123
+ #
124
+ # This is a short cut method. It equals to `new(path,
125
+ # options).parse`.
126
+ #
127
+ # @param (see #initialize)
128
+ # @option (see #initialize)
129
+ # @return (see #parse)
130
+ # @see #initialize
131
+ # @see #parse
132
+ def parse(path, options={})
133
+ parser = new(path, options)
134
+ parser.parse
135
+ end
136
+ end
121
137
 
122
- def parse(path) # :nodoc:
123
- source = IO.read(path)
138
+ #
139
+ # @example `:comment_tag` option: String tag
140
+ # path = "hello.rb"
141
+ # # content:
142
+ # # # TRANSLATORS: This is a comment to translators.
143
+ # # _("Hello")
144
+ # #
145
+ # # # This is a comment for programmers.
146
+ # # # TRANSLATORS: This is a comment to translators.
147
+ # # # This is also a comment to translators.
148
+ # # _("World")
149
+ # #
150
+ # # # This is a comment for programmers.
151
+ # # # This is also a comment for programmers
152
+ # # # because all lines don't start with "TRANSRATORS:".
153
+ # # _("Bye")
154
+ # options = {:comment_tag => "TRANSLATORS:"}
155
+ # parser = GetText::RubyParser.new(path, options)
156
+ # parser.parse
157
+ # # => [
158
+ # # POEntry<
159
+ # # :msgid => "Hello",
160
+ # # :extracted_comment =>
161
+ # # "TRANSLATORS: This is a comment to translators.",
162
+ # # >,
163
+ # # POEntry<
164
+ # # :msgid => "World",
165
+ # # :extracted_comment =>
166
+ # # "TRANSLATORS: This is a comment to translators.\n" +
167
+ # # "This is also a comment to translators.",
168
+ # # >,
169
+ # # POEntry<
170
+ # # :msgid => "Bye",
171
+ # # :extracted_comment => nil,
172
+ # # >,
173
+ # # ]
174
+ #
175
+ # @example `:comment_tag` option: nil tag
176
+ # path = "hello.rb"
177
+ # # content:
178
+ # # # This is a comment to translators.
179
+ # # # This is also a comment for translators.
180
+ # # _("Hello")
181
+ # options = {:comment_tag => nil}
182
+ # parser = GetText::RubyParser.new(path, options)
183
+ # parser.parse
184
+ # # => [
185
+ # # POEntry<
186
+ # # :msgid => "Hello",
187
+ # # :extracted_comment =>
188
+ # # "This is a comment to translators.\n" +
189
+ # # " This is also a comment for translators.",
190
+ # # >,
191
+ # # ]
192
+ #
193
+ # @param path [String] Ruby script path to be parsed
194
+ # @param options [Hash] Options
195
+ # @option options [String, nil] :comment_tag The tag to
196
+ # detect comments to be extracted. The extracted comments are
197
+ # used to deliver messages to translators from programmers.
198
+ #
199
+ # If the tag is String and a line in a comment start with the
200
+ # tag, the line and the following lines are extracted.
201
+ #
202
+ # If the tag is nil, all comments are extracted.
203
+ def initialize(path, options={})
204
+ @path = path
205
+ @options = options
206
+ end
124
207
 
125
- if source.respond_to?(:encode)
126
- encoding = detect_encoding(source) || source.encoding
208
+ # Extracts messages from @path.
209
+ #
210
+ # @return [Array<POEntry>] Extracted messages
211
+ def parse
212
+ source = IO.read(@path)
127
213
 
128
- source.force_encoding(encoding)
129
- end
214
+ encoding = detect_encoding(source) || source.encoding
215
+ source.force_encoding(encoding)
130
216
 
131
- parse_lines(path, source.each_line.to_a)
217
+ parse_source(source)
132
218
  end
133
219
 
134
220
  def detect_encoding(source)
135
- return nil unless source.respond_to?(:force_encoding)
136
221
  binary_source = source.dup.force_encoding("ASCII-8BIT")
137
222
  if /\A.*coding\s*[=:]\s*([[:alnum:]\-_]+)/ =~ binary_source
138
223
  $1.gsub(/-(?:unix|mac|dos)\z/, "")
@@ -141,9 +226,9 @@ module GetText
141
226
  end
142
227
  end
143
228
 
144
- def parse_lines(path, lines) # :nodoc:
229
+ def parse_source(source)
145
230
  po = []
146
- file = StringIO.new(lines.join + "\n")
231
+ file = StringIO.new(source)
147
232
  rl = RubyLexX.new
148
233
  rl.set_input(file)
149
234
  rl.skip_space = true
@@ -151,7 +236,7 @@ module GetText
151
236
 
152
237
  po_entry = nil
153
238
  line_no = nil
154
- last_comment = ''
239
+ last_comment = ""
155
240
  reset_comment = false
156
241
  ignore_next_comma = false
157
242
  rl.parse do |tk|
@@ -160,7 +245,7 @@ module GetText
160
245
  ignore_next_comma = false
161
246
  case tk
162
247
  when RubyToken::TkIDENTIFIER, RubyToken::TkCONSTANT
163
- if store_po_entry(po, po_entry, path, line_no, last_comment)
248
+ if store_po_entry(po, po_entry, line_no, last_comment)
164
249
  last_comment = ""
165
250
  end
166
251
  if ID.include?(tk.name)
@@ -186,14 +271,14 @@ module GetText
186
271
  po_entry.advance_to_next_attribute if po_entry
187
272
  end
188
273
  else
189
- if store_po_entry(po, po_entry, path, line_no, last_comment)
274
+ if store_po_entry(po, po_entry, line_no, last_comment)
190
275
  po_entry = nil
191
276
  last_comment = ""
192
277
  end
193
278
  end
194
279
  rescue
195
280
  $stderr.print "\n\nError"
196
- $stderr.print " parsing #{path}:#{tk.line_no}\n\t #{lines[tk.line_no - 1]}" if tk
281
+ $stderr.print " parsing #{@path}:#{tk.line_no}\n\t #{source.lines.to_a[tk.line_no - 1]}" if tk
197
282
  $stderr.print "\n #{$!.inspect} in\n"
198
283
  $stderr.print $!.backtrace.join("\n")
199
284
  $stderr.print "\n"
@@ -204,10 +289,9 @@ module GetText
204
289
  when RubyToken::TkCOMMENT_WITH_CONTENT
205
290
  last_comment = "" if reset_comment
206
291
  if last_comment.empty?
207
- # new comment from programmer to translator?
208
292
  comment1 = tk.value.lstrip
209
- if comment1 =~ /^TRANSLATORS\:/
210
- last_comment = $'
293
+ if comment_to_be_extracted?(comment1)
294
+ last_comment << comment1
211
295
  end
212
296
  else
213
297
  last_comment += "\n"
@@ -222,14 +306,10 @@ module GetText
222
306
  po
223
307
  end
224
308
 
225
- def target?(file) # :nodoc:
226
- true # always true, as the default parser.
227
- end
228
-
229
309
  private
230
- def store_po_entry(po, po_entry, file_name, line_no, last_comment) #:nodoc:
310
+ def store_po_entry(po, po_entry, line_no, last_comment) #:nodoc:
231
311
  if po_entry && po_entry.msgid
232
- po_entry.references << file_name + ":" + line_no
312
+ po_entry.references << @path + ":" + line_no
233
313
  po_entry.add_comment(last_comment) unless last_comment.empty?
234
314
  po << po_entry
235
315
  true
@@ -237,5 +317,14 @@ module GetText
237
317
  false
238
318
  end
239
319
  end
320
+
321
+ def comment_to_be_extracted?(comment)
322
+ return false unless @options.has_key?(:comment_tag)
323
+
324
+ tag = @options[:comment_tag]
325
+ return true if tag.nil?
326
+
327
+ /\A#{Regexp.escape(tag)}/ === comment
328
+ end
240
329
  end
241
330
  end
@@ -0,0 +1,225 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2012-2013 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # License: Ruby's or LGPL
6
+ #
7
+ # This library is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # This library is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ require "rake"
21
+ require "gettext/tools"
22
+
23
+ module GetText
24
+ module Tools
25
+ class Task
26
+ include GetText
27
+ include Rake::DSL
28
+
29
+ attr_accessor :locales, :po_base_directory, :mo_base_directory, :domain
30
+ attr_accessor :namespace_prefix, :files
31
+ # @return [Array<String>] Command line options for extracting messages
32
+ # from sources.
33
+ # @see GetText::Tools::XGetText
34
+ # @see `rxgettext --help`
35
+ attr_reader :xgettext_options
36
+ def initialize(spec)
37
+ @spec = spec
38
+ @locales = []
39
+ @po_base_directory = "po"
40
+ @mo_base_directory = "."
41
+ @files = target_files
42
+ @domain = @spec.name
43
+ @namespace_prefix = nil
44
+ @xgettext_options = []
45
+ yield(self) if block_given?
46
+ @locales = detect_locales if @locales.empty?
47
+ raise("must set locales: #{inspect}") if @locales.empty?
48
+ define
49
+ end
50
+
51
+ private
52
+ def define
53
+ define_file_tasks
54
+ if namespace_prefix
55
+ namespace_recursive namespace_prefix do
56
+ define_named_tasks
57
+ end
58
+ else
59
+ define_named_tasks
60
+ end
61
+ end
62
+
63
+ def define_file_tasks
64
+ unless files.empty?
65
+ pot_dependencies = files.dup
66
+ unless File.exist?(po_base_directory)
67
+ directory po_base_directory
68
+ pot_dependencies << po_base_directory
69
+ end
70
+ file pot_file => pot_dependencies do
71
+ command_line = [
72
+ "--package-name", @spec.name,
73
+ "--package-version", @spec.version.to_s,
74
+ "--output", pot_file,
75
+ ]
76
+ command_line.concat(@xgettext_options)
77
+ command_line.concat(files)
78
+ GetText::Tools::XGetText.run(*command_line)
79
+ end
80
+ end
81
+
82
+ locales.each do |locale|
83
+ _po_file = po_file(locale)
84
+ unless files.empty?
85
+ po_dependencies = [pot_file]
86
+ _po_directory = po_directory(locale)
87
+ unless File.exist?(_po_directory)
88
+ directory _po_directory
89
+ po_dependencies << _po_directory
90
+ end
91
+ file _po_file => po_dependencies do
92
+ if File.exist?(_po_file)
93
+ GetText::Tools::MsgMerge.run(po_file(locale), pot_file,
94
+ "--output", _po_file)
95
+ else
96
+ GetText::Tools::MsgInit.run("--input", pot_file,
97
+ "--output", _po_file,
98
+ "--locale", locale.to_s)
99
+ end
100
+ end
101
+ end
102
+
103
+ mo_dependencies = [_po_file]
104
+ _mo_directory = mo_directory(locale)
105
+ unless File.exist?(_mo_directory)
106
+ directory _mo_directory
107
+ mo_dependencies << _mo_directory
108
+ end
109
+ _mo_file = mo_file(locale)
110
+ file _mo_file => mo_dependencies do
111
+ GetText::Tools::MsgFmt.run(_po_file, "--output", _mo_file)
112
+ end
113
+ end
114
+ end
115
+
116
+ def define_named_tasks
117
+ namespace :gettext do
118
+ namespace :pot do
119
+ desc "Create #{pot_file}"
120
+ task :create => pot_file
121
+ end
122
+
123
+ namespace :po do
124
+ update_tasks = []
125
+ @locales.each do |locale|
126
+ namespace locale do
127
+ desc "Update #{po_file(locale)}"
128
+ task :update => po_file(locale)
129
+ update_tasks << (current_scope + ["update"]).join(":")
130
+ end
131
+ end
132
+
133
+ desc "Update *.po"
134
+ task :update => update_tasks
135
+ end
136
+
137
+ namespace :mo do
138
+ update_tasks = []
139
+ @locales.each do |locale|
140
+ namespace locale do
141
+ desc "Update #{mo_file(locale)}"
142
+ task :update => mo_file(locale)
143
+ update_tasks << (current_scope + ["update"]).join(":")
144
+ end
145
+ end
146
+
147
+ desc "Update *.mo"
148
+ task :update => update_tasks
149
+ end
150
+ end
151
+
152
+ desc "Update *.mo"
153
+ task :gettext => (current_scope + ["gettext", "mo", "update"]).join(":")
154
+ end
155
+
156
+ def pot_file
157
+ File.join(po_base_directory, "#{domain}.pot")
158
+ end
159
+
160
+ def po_directory(locale)
161
+ File.join(po_base_directory, locale.to_s)
162
+ end
163
+
164
+ def po_file(locale)
165
+ File.join(po_directory(locale), "#{domain}.po")
166
+ end
167
+
168
+ def mo_directory(locale)
169
+ File.join(mo_base_directory, "locale", locale.to_s, "LC_MESSAGES")
170
+ end
171
+
172
+ def mo_file(locale)
173
+ File.join(mo_directory(locale), "#{domain}.mo")
174
+ end
175
+
176
+ def target_files
177
+ files = @spec.files.find_all do |file|
178
+ /\A\.(?:rb|erb|glade)\z/i =~ File.extname(file)
179
+ end
180
+ files += @spec.executables.collect do |executable|
181
+ "bin/#{executable}"
182
+ end
183
+ files
184
+ end
185
+
186
+ def detect_locales
187
+ locales = []
188
+ return locales unless File.exist?(po_base_directory)
189
+
190
+ Dir.open(po_base_directory) do |dir|
191
+ dir.each do |entry|
192
+ next unless /\A[a-z]{2}(?:_[A-Z]{2})?\z/ =~ entry
193
+ next unless File.directory?(File.join(dir.path, entry))
194
+ locales << entry
195
+ end
196
+ end
197
+ locales
198
+ end
199
+
200
+ def current_scope
201
+ scope = Rake.application.current_scope
202
+ if scope.is_a?(Array)
203
+ scope
204
+ else
205
+ if scope.empty?
206
+ []
207
+ else
208
+ [scope.path]
209
+ end
210
+ end
211
+ end
212
+
213
+ def namespace_recursive(namespace_spec, &block)
214
+ first, rest = namespace_spec.split(/:/, 2)
215
+ namespace first do
216
+ if rest.nil?
217
+ block.call
218
+ else
219
+ namespace_recursive(rest, &block)
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
225
+ end