File: gettext.rb

package info (click to toggle)
libgettext-ruby 1.7.0-1
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 3,892 kB
  • ctags: 1,198
  • sloc: ruby: 6,738; ansic: 67; makefile: 38; sql: 14; sh: 6
file content (369 lines) | stat: -rw-r--r-- 11,677 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
=begin
  gettext.rb - GetText module

  Copyright (C) 2001-2006  Masao Mutoh
  Copyright (C) 2001-2003  Masahiro Sakai

      Masao Mutoh       <mutoh@highway.ne.jp>
      Masahiro Sakai    <s01397ms@sfc.keio.ac.jp>

  You may redistribute it and/or modify it under the same
  license terms as Ruby.

  $Id: gettext.rb,v 1.15 2006/06/11 15:36:20 mutoh Exp $
=end

require 'rbconfig'
require 'gettext/version'
require 'gettext/mo'
require 'gettext/locale'
require 'gettext/textdomainmanager'
require 'gettext/string'

module GetText
  # If the textdomain isn't bound when calling GetText.textdomain, this error is raised.
  class NoboundTextDomainError < RuntimeError
  end

  def self.included(mod)  #:nodoc:
    mod.extend self
  end

  @@__textdomainmanagers = Hash.new

  # call-seq:
  # bindtextdomain(domainname, options = {})
  #
  # Bind a textdomain(%{path}/%{locale}/LC_MESSAGES/%{domainname}.mo) to your program.
  # Normally, the texdomain scope becomes a ruby-script-file. 
  # So you need to call this function each ruby-script-files. 
  # On the other hand, if you call this function under GetText::Container 
  # (gettext/container, gettext/erb, gettext/rails), the textdomain scope becomes a Class/Module.
  # * domainname: the textdomain name.
  # * options: options as an Hash.
  #   * :path - the path to the mo-files. When the value is nil, it will search default paths such as 
  #     /usr/share/locale, /usr/local/share/locale)
  #   * :locale - the locale string such as "ja_JP.UTF-8".  Generally, you should use GetText.set_locale instead.
  #     The value is searched order by:
  #     the value of this value > System default language.
  #   * :charset - output charset.  This affect the current textdomain only. Generally, you should use GetText.set_output_charset instead.
  #     The value is searched order by:
  #     the value of Locale.set_output_charset > ENV["OUTPUT_CHARSET"] > this value > System default charset.
  # * Returns: the GetText::TextDomain.
  # Note: Don't use locale_, charset argument(not in options). 
  # They are remained for backward compatibility. 
  #
  def bindtextdomain(domainname, options = {}, locale_ = nil, charset = nil)
    opt = {}
    if options.kind_of? String
      # For backward compatibility
      opt = {:path => options, :locale => locale_, :charset => charset}
    elsif options
      opt = options
    end
    opt[:locale] = opt[:locale] ? Locale::Object.new(opt[:locale]) : Locale.get
    opt[:charset] = output_charset if output_charset
    locale.charset = opt[:charset] if opt[:charset]
    Locale.set_current(opt[:locale])
    manager = @@__textdomainmanagers[bound_target]
    if manager
      manager.set_locale(opt[:locale]) 
    else
      manager = TextDomainManager.new(bound_target, opt[:locale])
      @@__textdomainmanagers[bound_target] = manager
    end
    manager.add_textdomain(domainname, opt)
    manager
  end

  # Binds a existed textdomain to your program. 
  # This is the same function with GetText.bindtextdomain but simpler than bindtextdomain.
  # Notice that you need to call GetText.bindtextdomain first. If the domainname hasn't bound yet, 
  # raises GetText::NoboundTextDomainError.
  # * domainname: a textdomain name.
  # * Returns: the GetText::TextDomain.
  def textdomain(domainname)
    domain = TextDomainManager.textdomain(domainname)
    raise NoboundTextDomainError, "#{domainname} is not bound." unless domain
    manager = @@__textdomainmanagers[bound_target]
    unless manager
      manager = TextDomainManager.new(bound_target, Locale.get)
      @@__textdomainmanagers[bound_target] = manager
    end
    manager.add_textdomain(domainname)
    manager.set_locale(Locale.get)
  end

  TARGET_REGEXP = /\:\:/  # :nodoc:

  # Iterates bound textdomains.
  # * klass: a class/module to find. Default is the class of self.
  # * ignore_targets: Ignore tragets.
  # * Returns: a bound GetText::TextDomain or nil.
  def each_textdomain(klass = bound_target, ignore_targets = []) #:nodoc:
    (klass.ancestors + [GetText]).each do |target|
      unless ignore_targets.include? target
	ignore_targets << target
	manager = @@__textdomainmanagers[target]
	if manager
	  manager.each{ |textdomain|
	    yield textdomain
	  }
	end
	if target.to_s =~ TARGET_REGEXP
	  each_textdomain(Module.const_get($`), ignore_targets){|domain|
	    yield domain
	  }
	end
      end
    end
    self
  end

  def bound_target # :nodoc:
    if self.kind_of? Class or self.kind_of? Module
      self
    else
      self.class
    end
  end

  # call-seq:
  #   gettext(msgid)
  #   _(msgid)
  #
  # Translates msgid and return the message.
  # * msgid: the message id.
  # * Returns: localized text by msgid. If there are not binded mo-file, it will return msgid.
  def gettext(msgid)
    ret = nil
    each_textdomain {|textdomain|
      ret = textdomain.gettext(msgid)
      break if ret
    }
    ret ? ret : msgid
  end

  # call-seq:
  #   ngettext(msgid, msgid_plural, n)
  #   ngettext(msgids, n)  # msgids = [msgid, msgid_plural]
  #   n_(msgid, msgid_plural, n)
  #   n_(msgids, n)  # msgids = [msgid, msgid_plural]
  #
  # The ngettext is similar to the gettext function as it finds the message catalogs in the same way. 
  # But it takes two extra arguments for plural form.
  #
  # * msgid: the singular form.
  # * msgid_plural: the plural form.
  # * n: a number used to determine the plural form.
  # * Returns: the localized text which key is msgid_plural if n is plural(follow plural-rule) or msgid.
  #   "plural-rule" is defined in po-file.
  def ngettext(arg1, arg2, arg3 = nil)
    if arg1.kind_of?(Array)
      msgid = arg1[0]
      msgid_plural = arg1[1]
      n = arg2
    else
      msgid = arg1
      msgid_plural = arg2
      n = arg3
    end
    ret = nil
    each_textdomain {|textdomain|
      ret = textdomain.ngettext(msgid, msgid_plural, n)
      break if ret
    }
    ret ? ret : (n == 1 ? msgid : msgid_plural)
  end

  # This function does nothing. But it is required in order to recognize the msgid by rgettext.
  # * msgid: the message id.
  # * Returns: msgid.
  def N_(msgid)
    msgid
  end

  # This is same function as N_ but for ngettext. 
  # * msgid: the message id.
  # * msgid_plural: the plural message id.
  # * Returns: msgid.
  def Nn_(msgid, msgid_plural)
    [msgid, msgid_plural]
  end

  # call-seq:
  #   sgettext(msgid, div = '|')
  #   s_(msgid, div = '|')
  #
  # Translates msgid, but if there are no localized text, 
  # it returns a last part of msgid separeted "div".
  #
  # * msgid: the message id.
  # * div: separator or nil.
  # * Returns: the localized text by msgid. If there are no localized text, 
  #   it returns a last part of msgid separeted "div".
  # See: http://www.gnu.org/software/gettext/manual/html_mono/gettext.html#SEC151
  def sgettext(msgid, div = '|')
    msg = gettext(msgid)
    if msg == msgid
      if index = msg.rindex(div)
	msg = msg[(index + 1)..-1]
      end
    end
    msg
  end

  # Sets locale to the current class/module
  #
  # Notice that you shouldn't use this for your own Libraries.
  # * locale: a locale string or Locale::Object.
  # * this_target_only: true if you want to change the current class/module only.
  # Otherwise, this changes the locale of the current class/module and its ancestors.
  # Default is false.
  # * Returns: self
  def set_locale(locale, this_target_only = false)
    ret = nil
    if locale
      if locale.kind_of? Locale::Object
	ret = locale
      else
	ret = Locale::Object.new(locale.to_s)
      end
      ret.charset = output_charset if output_charset
      Locale.set(ret)
    else
      Locale.clear
      ret = Locale.get
    end
    if this_target_only
      manager = @@__textdomainmanagers[bound_target]
      if manager
	manager.set_locale(ret)
      end
    else
      each_textdomain {|textdomain|
	textdomain.set_locale(ret)
      }
    end
    self
  end

  # Sets locale to the all textdomains.
  #
  # Notice that you shouldn't use this for your own Libraries.
  # * locale: a locale string or Locale::Object.
  # * Returns: self
  def set_locale_all(locale)
    ret = nil
    if locale
      if locale.kind_of? Locale::Object
	ret = locale
      else
	ret = Locale::Object.new(locale.to_s)
      end
      ret.charset = output_charset if output_charset
      Locale.set(ret)
    else
      Locale.set(nil)
      ret = Locale.get
    end
    TextDomainManager.each_all {|textdomain|
      textdomain.set_locale(ret)
    }
    self
  end

  # Same as GetText.set_locale.
  # * locale: a locale string
  # * src: internal usage only. You shouldn't use this.
  # * Returns: a locale string
  def locale=(locale)
    set_locale(locale)
    locale
  end

  # Sets charset(String) such as "euc-jp", "sjis", "CP932", "utf-8", ... 
  # You shouldn't use this in your own Libraries.
  # * charset: an output_charset
  # * Returns: charset
  def set_output_charset(charset)
    TextDomainManager.output_charset = charset
    self
  end

  # Same as GetText.set_output_charset
  # * charset: an output_charset
  # * Returns: charset
  def output_charset=(charset)
    TextDomainManager.output_charset = charset
  end

  # Gets the current output_charset which is set using GetText.set_output_charset.
  # * Returns: output_charset.
  def output_charset
    TextDomainManager.output_charset
  end

  # Gets the current locale.
  # * Returns: a current Locale::Object
  def locale
    Locale.current
  end

  # Deprecated. Now this function do nothing. Use GetText.output_charset= instead.
  def set_charset(cs) #:nodoc:
    $stderr.puts "Deprecated. Now this function do nothing. Use GetText.output_charset= instead." if $DEBUG
    self
  end

  def charset=(cs) #:nodoc:
    set_charset(cs)
    cs
  end
  
  # Add default locale path.
  # * path: a new locale path. (e.g.) "/usr/share/locale/%{locale}/LC_MESSAGES/%{name}.mo"
  #   ('locale' => "ja_JP", 'name' => "textdomain")
  # * Returns: the new DEFAULT_LOCALE_PATHS
  def add_default_locale_path(path)
    TextDomain.add_default_locale_path(path)
  end

  # Show the current textdomain information. This function is for debugging.
  # * options: options as a Hash.
  #   * :with_messages - show informations with messages of the current mo file. Default is false.
  #   * :out - An output target. Default is STDOUT.
  #   * :with_paths - show the load paths for mo-files.
  # * Returns: localized text by msgid. If there are not binded mo-file, it will return msgid.
  def current_textdomain_info(options = {})
    opts = {:with_messages => false, :with_paths => false, :out => STDOUT}.merge(options)
    ret = nil
    each_textdomain {|textdomain|
      opts[:out].puts "TextDomain name: \"#{textdomain.name}\""
      opts[:out].puts "TextDomain current locale: \"#{textdomain.current_locale}\""
      opts[:out].puts "TextDomain current mo filename: \"#{textdomain.current_mo.filename}\""
      if opts[:with_paths]
	opts[:out].puts "TextDomain locale file paths:"
	textdomain.locale_paths.each do |v|
	  opts[:out].puts "  #{v}"
	end
      end
      if opts[:with_messages]
	opts[:out].puts "The messages in the mo file:"
	textdomain.current_mo.each{|k, v|
	  opts[:out].puts "  \"#{k}\": \"#{v}\""
	}
      end
    }
  end

  alias :setlocale :locale= #:nodoc:
  alias :_ :gettext   #:nodoc:
  alias :n_ :ngettext #:nodoc:
  alias :s_ :sgettext #:nodoc:

  module_function :bindtextdomain, :textdomain, :each_textdomain,
    :N_, :gettext, :_, :ngettext, :n_, :sgettext, :s_, :bound_target,
    :setlocale, :set_locale, :locale=, :set_locale_all, :locale, :charset=, :set_charset,
    :set_output_charset, :output_charset=, :output_charset, :current_textdomain_info
end