Module: GetText

Extended by:
GetText
Included in:
GetText, GladeParser, RGetText, RMsgMerge, RMsgfmt
Defined in:
lib/gettext/version.rb,
lib/gettext.rb,
lib/gettext/cgi.rb,
lib/gettext/tools.rb,
lib/gettext/utils.rb,
lib/gettext/parser/ruby.rb,
lib/gettext/tools/rmsgfmt.rb,
lib/gettext/runtime/mofile.rb,
lib/gettext/tools/poparser.rb,
lib/gettext/tools/rgettext.rb,
lib/gettext/tools/pomessage.rb,
lib/gettext/tools/rmsgmerge.rb,
lib/gettext/tools/rmsgmerge.rb,
lib/gettext/tools/rmsgmerge.rb,
lib/gettext/tools/parser/erb.rb,
lib/gettext/tools/parser/ruby.rb,
lib/gettext/runtime/class_info.rb,
lib/gettext/runtime/textdomain.rb,
lib/gettext/tools/parser/glade.rb,
lib/gettext/runtime/locale_path.rb,
lib/gettext/runtime/textdomain_group.rb,
lib/gettext/runtime/textdomain_manager.rb

Overview

gettext/textdomain_group - GetText::TextDomainGroup class

Copyright (C) 2009  Masao Mutoh

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

Defined Under Namespace

Modules: ClassInfo, ErbParser, GladeParser, PoMessageForRubyParser, RGetText, RMsgMerge, RMsgfmt, RubyParser, TextDomainManager Classes: LocalePath, MOFile, NoboundTextDomainError, ParseError, PoMessage, PoParser, RubyLexX, TextDomain, TextDomainGroup

Constant Summary collapse

BOM_UTF8 =
[0xef, 0xbb, 0xbf].pack("c3")
VERSION =
"2.1.0"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(mod) ⇒ Object

:nodoc:



44
45
46
# File 'lib/gettext.rb', line 44

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

Instance Method Details

#bindtextdomain(domainname, *options) ⇒ Object

bindtextdomain(domainname, options = {})

Bind a textdomain(%path/%#locale/LC_MESSAGES/%domainname.mo) to your program. Normally, the texdomain scope becomes the class/module(and parent classes/included modules).

  • 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)

    • :output_charset - The output charset. Same with GetText.set_output_charset. Usually, L10n library doesn’t use this option. Application may use this once.

  • Returns: the GetText::TextDomainManager.



63
64
65
# File 'lib/gettext.rb', line 63

def bindtextdomain(domainname, *options)
  bindtextdomain_to(self, domainname, *options)
end

#bindtextdomain_to(klass, domainname, *options) ⇒ Object

Includes GetText module and bind a textdomain to a class.

  • klass: the target ruby class.

  • domainname: the textdomain name.

  • options: options as an Hash. See GetText.bindtextdomain.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/gettext.rb', line 71

def bindtextdomain_to(klass, domainname, *options) 
  if options[0].kind_of? Hash
    opts = options[0]
  else
    # for backward compatibility.
    opts = {}
    opts[:path] = options[0] if options[0]
    opts[:output_charset] = options[2] if options[2]
  end
  unless (klass.kind_of? GetText or klass.include? GetText)
    klass.__send__(:include, GetText)
  end
  TextDomainManager.bind_to(klass, domainname, opts)
end

#cgiObject

Gets the CGI object. If it is nil, returns new CGI object. This methods is appeared when requiring “gettext/cgi”.

  • Returns: the CGI object



34
35
36
# File 'lib/gettext/cgi.rb', line 34

def cgi
  Locale.cgi
end

#cgi=(cgi_) ⇒ Object

Same as GetText.set_cgi. This methods is appeared when requiring “gettext/cgi”.

  • cgi_: CGI object

  • Returns: cgi_



27
28
29
30
# File 'lib/gettext/cgi.rb', line 27

def cgi=(cgi_)
  set_cgi(cgi_)
  cgi_
end

#create_mofiles(verbose = false, podir = "./po", targetdir = "./data/locale", targetpath_rule = "%s/LC_MESSAGES") ⇒ Object

Deprecated. Use gettext/tools instead.



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
# File 'lib/gettext/tools.rb', line 89

def create_mofiles(options = {})
  options = {:po_root => "./po"}.merge(options)
  
  po_text = ''
  mo_file = ''
  pofile = ''
  
  Dir.glob(File.join(options[:po_root], "*/")) do |dir|
    Dir.glob(File.join(dir, "*.po")).each do |po_file|
      po_text = File.read(po_file) + po_text
      pofile = po_file unless po_file.include?("private")
      mo_file = mo_file_from_po_file(pofile,options)
    end
    $stderr.print %Q[#{pofile} -> #{mo_file} ... ] if options[:verbose]
    
    en_tmp = dir + 'en_tmp.po'
    file = File.new(en_tmp,  "w+")
    file << po_text
    FileUtils.mkdir_p(File.dirname(mo_file))
    rmsgfmt(file, mo_file)
    File.delete(en_tmp)
    po_text = ''
    $stderr.puts "Done." if options[:verbose]
  end
end

#create_mofiles_orgObject

Creates mo-files using #po_root/#lang/*.po an put them to #targetdir/#targetdir_rule/.

This is a convenience function of GetText.rmsgfmt for multiple target files.

  • options: options as a Hash.

    • verbose: true if verbose mode, otherwise false

    • po_root: the root directory of po-files.

    • mo_root: the target root directory where the mo-files are stored.

    • mo_path_rule: the target directory for each mo-files.

:nodoc:



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
# File 'lib/gettext/utils.rb', line 16

def create_mofiles(options = {})
  options = {:po_root => "./po"}.merge(options)
  
  po_text = ''
  mo_file = ''
  pofile = ''
  
  Dir.glob(File.join(options[:po_root], "*/")) do |dir|
    Dir.glob(File.join(dir, "*.po")).each do |po_file|
      po_text = File.read(po_file) + po_text
      pofile = po_file unless po_file.include?("private")
      mo_file = mo_file_from_po_file(pofile,options)
    end
    $stderr.print %Q[#{pofile} -> #{mo_file} ... ] if options[:verbose]
    
    en_tmp = dir + 'en_tmp.po'
    file = File.new(en_tmp,  "w+")
    file << po_text
    FileUtils.mkdir_p(File.dirname(mo_file))
    rmsgfmt(file, mo_file)
    File.delete(en_tmp)
    po_text = ''
    $stderr.puts "Done." if options[:verbose]
  end
end

#gettext(msgid) ⇒ Object Also known as: _

call-seq:

gettext(msgid)
_(msgid)

Translates msgid and return the message. This doesn’t make a copy of the message.

You need to use String#dup if you want to modify the return value with destructive functions.

(e.g.1) _(“Hello ”).dup << “world”

But e.g.1 should be rewrite to:

(e.g.2) _(“Hello %val”) % => “world”

Because the translator may want to change the position of “world”.

  • msgid: the message id.

  • Returns: localized text by msgid. If there are not binded mo-file, it will return msgid.



127
128
129
# File 'lib/gettext.rb', line 127

def gettext(msgid)
  TextDomainManager.translate_singluar_message(self, msgid)
end

#localeObject



287
288
289
# File 'lib/gettext.rb', line 287

def locale
  Locale.current[0]
end

#msgmerge(defpo, refpo, app_version, options = {}) ⇒ Object

Merges two Uniforum style .po files together.

Note This function requires “msgmerge” tool included in GNU GetText. So you need to install GNU GetText.

The def.po file is an existing PO file with translations which will be taken over to the newly created file as long as they still match; comments will be preserved, but extracted comments and file positions will be discarded.

The ref.pot file is the last created PO file with up-to-date source references but old translations, or a PO Template file (generally created by rgettext); any translations or comments in the file will be discarded, however dot comments and file positions will be preserved. Where an exact match cannot be found, fuzzy matching is used to produce better results.

Usually you don’t need to call this function directly. Use GetText.update_pofiles instead.

  • defpo: a po-file. translations referring to old sources

  • refpo: a po-file. references to new sources

  • app_version: the application information which appears “Project-Id-Version: #app_version” in the pot/po-files.

  • Returns: self



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/gettext/tools.rb', line 57

def msgmerge(defpo, refpo, app_version, options={})
  verbose = options.delete(:verbose)
  puts "msgmerge called" if verbose
  $stderr.print defpo + " "
 
  content = merge_po_files(defpo,refpo,options.delete(:msgmerge),verbose)
  
  if content.empty?
    # report failure
    failed_filename = refpo + "~"
    FileUtils.cp(refpo, failed_filename)
    $stderr.puts _("Failed to merge with %{defpo}") % {:defpo => defpo}
    $stderr.puts _("New .pot was copied to %{failed_filename}") %{:failed_filename => failed_filename}
    raise _("Check these po/pot-files. It may have syntax errors or something wrong.")
  else
    # update version and save merged data
    content.sub!(/(Project-Id-Version\:).*$/, "\\1 #{app_version}\\n\"")
    File.open(defpo, "w") {|f|f.write(content)}
  end
  
  self
end

#N_(msgid) ⇒ Object

makes dynamic translation messages readable for the gettext parser. _(fruit) cannot be understood by the gettext parser. To help the parser find all your translations, you can add fruit = N_("Apple") which does not translate, but tells the parser: “Apple” needs translation.

  • msgid: the message id.

  • Returns: msgid.



244
245
246
# File 'lib/gettext.rb', line 244

def N_(msgid)
  msgid
end

#ngettext(msgid, msgid_plural, n = nil) ⇒ Object Also known as: n_

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.



179
180
181
# File 'lib/gettext.rb', line 179

def ngettext(msgid, msgid_plural, n = nil)
  TextDomainManager.translate_plural_message(self, msgid, msgid_plural, n)
end

#Nn_(msgid, msgid_plural) ⇒ Object

This is same function as N_ but for ngettext.

  • msgid: the message id.

  • msgid_plural: the plural message id.

  • Returns: msgid.



252
253
254
# File 'lib/gettext.rb', line 252

def Nn_(msgid, msgid_plural)
  [msgid, msgid_plural]
end

#npgettext(msgctxt, msgids, arg2 = nil, arg3 = nil) ⇒ Object Also known as: np_

call-seq:

npgettext(msgctxt, msgid, msgid_plural, n)
npgettext(msgctxt, msgids, n)  # msgids = [msgid, msgid_plural]
np_(msgctxt, msgid, msgid_plural, n)
np_(msgctxt, msgids, n)  # msgids = [msgid, msgid_plural]

The npgettext is similar to the nsgettext function.

e.g.) np_("Special", "An apple", "%{num} Apples", num) == ns_("Special|An apple", "%{num} Apples", num)
  • msgctxt: the message context.

  • 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.



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/gettext.rb', line 216

def npgettext(msgctxt, msgids, arg2 = nil, arg3 = nil)
  if msgids.kind_of?(Array)
    msgid = msgids[0]
    msgid_ctxt = "#{msgctxt}\004#{msgid}"
    msgid_plural = msgids[1]
    opt1 = arg2
    opt2 = arg3
  else
    msgid = msgids
    msgid_ctxt = "#{msgctxt}\004#{msgid}"
    msgid_plural = arg2
    opt1 = arg3
    opt2 = nil
  end
  
  msgstr = TextDomainManager.translate_plural_message(self, msgid_ctxt, msgid_plural, opt1, opt2)
  if msgstr == msgid_ctxt
    msgid
  else
    msgstr
  end
end

#nsgettext(msgid, msgid_plural, n = "|", seperator = "|") ⇒ Object Also known as: ns_

call-seq:

nsgettext(msgid, msgid_plural, n, div = "|")
nsgettext(msgids, n, div = "|")  # msgids = [msgid, msgid_plural]
ns_(msgid, msgid_plural, n, div = "|")
ns_(msgids, n, div = "|")  # msgids = [msgid, msgid_plural]

The nsgettext is similar to the ngettext. But if there are no localized text, it returns a last part of msgid separeted “div”.

  • msgid: the singular form with “div”. (e.g. “Special|An apple”)

  • msgid_plural: the plural form. (e.g. “%num Apples”)

  • 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.



198
199
200
# File 'lib/gettext.rb', line 198

def nsgettext(msgid, msgid_plural, n="|", seperator = "|")
  TextDomainManager.translate_plural_message(self, msgid, msgid_plural, n, seperator)
end

#output_charsetObject

Gets the current output_charset which is set using GetText.set_output_charset.

  • Returns: output_charset.



267
268
269
# File 'lib/gettext.rb', line 267

def output_charset
  TextDomainManager.output_charset
end

#pgettext(msgctxt, msgid) ⇒ Object Also known as: p_

call-seq:

pgettext(msgctxt, msgid)
p_(msgctxt, msgid)

Translates msgid with msgctxt. This methods is similer with s_().

e.g.) p_("File", "New")   == s_("File|New")
      p_("File", "Open")  == s_("File|Open")
  • msgctxt: the message context.

  • msgid: the message id.

  • Returns: the localized text by msgid. If there are no localized text, it returns msgid.

See: www.gnu.org/software/autoconf/manual/gettext/Contexts.html



161
162
163
# File 'lib/gettext.rb', line 161

def pgettext(msgctxt, msgid)
  TextDomainManager.translate_singluar_message(self, "#{msgctxt}\004#{msgid}", "\004")
end

#remove_bom(path) ⇒ Object

Currently, GNU msgmerge doesn’t accept BOM. This mesthod remove the UTF-8 BOM from the po-file.



29
30
31
32
33
34
35
# File 'lib/gettext/tools.rb', line 29

def remove_bom(path)  #:nodoc:
  bom = IO.read(path, 3)
  if bom == BOM_UTF8
    data = IO.read(path)[3..-1]
    File.open(path, "w") {|f| f.write(data)}
  end
end

#rgettext(paths = nil, out = STDOUT, private_out) ⇒ Object

Creates a po-file from targetfiles(ruby-script-files, .rhtml files, glade-2 XML files), then output the result to out. If no parameter is set, it behaves same as command line tools(rgettet).

This function is a part of GetText.create_pofiles. Usually you don’t need to call this function directly.

  • paths: An Array of po-file paths or nil.

  • out: output IO or output path.

  • Returns: self



245
246
247
248
# File 'lib/gettext/tools/rgettext.rb', line 245

def rgettext(paths = nil, out = STDOUT, private_out)
  RGetText.run(paths, out, private_out)
  self
end

#rmsgfmt(targetfile = nil, output_path = nil) ⇒ Object

Creates a mo-file from a targetfile(po-file), then output the result to out. If no parameter is set, it behaves same as command line tools(rmsgfmt).

  • targetfile: An Array of po-files or nil.

  • output_path: output path.

  • Returns: the MOFile object.



77
78
79
# File 'lib/gettext/tools/rmsgfmt.rb', line 77

def rmsgfmt(targetfile = nil, output_path = nil)
  RMsgfmt.run(targetfile, output_path)
end

#rmsgmerge(reference = nil, definition = nil, out = STDOUT) ⇒ Object

Experimental



482
483
484
# File 'lib/gettext/tools/rmsgmerge.rb', line 482

def rmsgmerge(reference = nil, definition = nil, out = STDOUT)
  RMsgMerge.run(reference, definition, out)
end

#set_cgi(cgi_) ⇒ Object

Sets a CGI object. This methods is appeared when requiring “gettext/cgi”.

  • cgi_: CGI object

  • Returns: self



20
21
22
# File 'lib/gettext/cgi.rb', line 20

def set_cgi(cgi_)
  Locale.set_cgi(cgi_)
end

#set_current_locale(lang) ⇒ Object Also known as: current_locale=

Set the locale to the current thread. Note that if #set_locale is set, this value is ignored. If you need, set_locale(nil); set_current_locale(lang)



283
284
285
# File 'lib/gettext.rb', line 283

def set_current_locale(lang)
  Locale.current = lang
end

#set_locale(lang) ⇒ Object Also known as: locale=, set_locale_all, setlocale

Set the locale. This value forces the locale whole the programs. This method calls Locale.set_app_language_tags, Locale.default, Locale.current. Use Locale methods if you need to handle locales more flexible.



274
275
276
277
278
# File 'lib/gettext.rb', line 274

def set_locale(lang)
  Locale.set_app_language_tags(lang)
  Locale.default = lang
  Locale.current = lang
end

#set_output_charset(charset) ⇒ Object Also known as: output_charset=

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: self



260
261
262
263
# File 'lib/gettext.rb', line 260

def set_output_charset(charset)
  TextDomainManager.output_charset = charset
  self
end

#sgettext(msgid, seperator = "|") ⇒ Object Also known as: s_

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.

  • separator: separator or nil for no seperation.

  • Returns: the localized text by msgid. If there are no localized text, it returns a last part of the msgid separeted by “seperator”. Movie|Location -> Location

See: www.gnu.org/software/gettext/manual/html_mono/gettext.html#SEC151



144
145
146
# File 'lib/gettext.rb', line 144

def sgettext(msgid, seperator = "|")
  TextDomainManager.translate_singluar_message(self, msgid, seperator)
end

#textdomain(domainname) ⇒ Object

Binds a existed textdomain to your program. This is the same function with GetText.bindtextdomain but simpler(and faster) than bindtextdomain. Note 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::TextDomainManager.



92
93
94
# File 'lib/gettext.rb', line 92

def textdomain(domainname) #:nodoc:
  textdomain_to(self, domainname)
end

#textdomain_to(klass, domainname) ⇒ Object

Includes GetText module and bind an exsited textdomain to a class. See textdomain for more detail.

  • klass: the target ruby class.

  • domainname: the textdomain name.



101
102
103
104
105
# File 'lib/gettext.rb', line 101

def textdomain_to(klass, domainname)  #:nodoc:
  domain = TextDomainManager.textdomain_pool(domainname)
  raise NoboundTextDomainError.new(domainname) unless domain
  bindtextdomain_to(klass, domainname)
end

#update_pofiles(textdomain, files, app_version, po_root = "po", refpot = "tmp.pot") ⇒ Object

Deprecated. Use gettext/tools instead.



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
# File 'lib/gettext/tools.rb', line 134

def update_pofiles(textdomain, files, app_version, options = {})
  puts options.inspect if options[:verbose]
 
  #write found messages to tmp.pot and private_tmp.pot
  temp_pot = "tmp.pot"
  private_temp_pot = "private_tmp.pot"
  rgettext(files, temp_pot, private_temp_pot)
  
  #merge tmp.pot and private_tmp.pot with existing pot
  po_root = options.delete(:po_root) || "po"
  FileUtils.mkdir_p(po_root)
  msgmerge("#{po_root}/#{textdomain}.pot", temp_pot, app_version, options.dup)
  msgmerge("#{po_root}/private_#{textdomain}.pot", private_temp_pot, app_version, options.dup)
 
  #update local po-files
  only_one_language = options.delete(:lang)
  if only_one_language
    msgmerge("#{po_root}/#{only_one_language}/#{textdomain}.po", temp_pot, app_version, options.dup)
    msgmerge("#{po_root}/#{only_one_language}/private_#{textdomain}.po", private_temp_pot, app_version, options.dup)
  else
    Dir.glob("#{po_root}/*/#{textdomain}.po") do |po_file|
      msgmerge(po_file, temp_pot, app_version, options.dup)
    end
    Dir.glob("#{po_root}/*/private_#{textdomain}.po") do |po_file|
      msgmerge(po_file, private_temp_pot, app_version, options.dup)
    end
  end
 
  File.delete(temp_pot)
  File.delete(private_temp_pot)
end

#update_pofiles_orgObject

At first, this creates the #po_root/#domainname.pot file using GetText.rgettext. In the second step, this updates(merges) the #po_root/#domainname.pot and all of the #po_root/#lang/#domainname.po files under “po_root” using “msgmerge”.

Note “msgmerge” tool is included in GNU GetText. So you need to install GNU GetText.

See <HOWTO maintain po/mo files(www.yotabanana.com/hiki/ruby-gettext-howto-manage.html)> for more detals.

  • domainname: the textdomain name.

  • targetfiles: An Array of target files, that should be parsed for messages (See GetText.rgettext for more details).

  • app_version: the application information which appears “Project-Id-Version: #app_version” in the pot/po-files.

  • options: a hash with following possible settings

    :lang    - update files only for one language - the language specified by this option
    :po_root - the root directory of po-files
    :msgmerge - an array with the options, passed through to the gnu msgmerge tool
                symbols are automatically translated to options with dashes,
                example: [:no_wrap, :no_fuzzy_matching, :sort_output] translated to '--no-fuzzy-matching --sort-output'
    :verbose - true to show verbose messages. default is false.
    

Example: GetText.update_pofiles(“myapp”, Dir.glob(“lib/*.rb”), “myapp 1.0.0”, :verbose => true) :nodoc:



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
# File 'lib/gettext/utils.rb', line 17

def update_pofiles(textdomain, files, app_version, options = {})
  puts options.inspect if options[:verbose]
 
  #write found messages to tmp.pot and private_tmp.pot
  temp_pot = "tmp.pot"
  private_temp_pot = "private_tmp.pot"
  rgettext(files, temp_pot, private_temp_pot)
  
  #merge tmp.pot and private_tmp.pot with existing pot
  po_root = options.delete(:po_root) || "po"
  FileUtils.mkdir_p(po_root)
  msgmerge("#{po_root}/#{textdomain}.pot", temp_pot, app_version, options.dup)
  msgmerge("#{po_root}/private_#{textdomain}.pot", private_temp_pot, app_version, options.dup)
 
  #update local po-files
  only_one_language = options.delete(:lang)
  if only_one_language
    msgmerge("#{po_root}/#{only_one_language}/#{textdomain}.po", temp_pot, app_version, options.dup)
    msgmerge("#{po_root}/#{only_one_language}/private_#{textdomain}.po", private_temp_pot, app_version, options.dup)
  else
    Dir.glob("#{po_root}/*/#{textdomain}.po") do |po_file|
      msgmerge(po_file, temp_pot, app_version, options.dup)
    end
    Dir.glob("#{po_root}/*/private_#{textdomain}.po") do |po_file|
      msgmerge(po_file, private_temp_pot, app_version, options.dup)
    end
  end
 
  File.delete(temp_pot)
  File.delete(private_temp_pot)
end