Module: GetText

Included in:
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/poparser.rb,
lib/gettext/class_info.rb,
lib/gettext/parser/erb.rb,
lib/gettext/textdomain.rb,
lib/gettext/parser/ruby.rb,
lib/gettext/parser/glade.rb,
lib/gettext/tools/rmsgfmt.rb,
lib/gettext/tools/rgettext.rb,
lib/gettext/tools/rmsgmerge.rb,
lib/gettext/tools/rmsgmerge.rb,
lib/gettext/tools/rmsgmerge.rb,
lib/gettext/textdomain_manager.rb

Overview

version - version information of Ruby-GetText-Package

Copyright (C) 2005-2009 Masao Mutoh

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

Defined Under Namespace

Modules: ClassInfo, ErbParser, GladeParser, RGetText, RMsgMerge, RMsgfmt, RubyParser Classes: PoParser, TextDomain, TextDomainManager

Constant Summary collapse

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

Class Method Summary collapse

Class Method Details

.bindtextdomain(domainname, *args) ⇒ 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)

    • :supported_language_tags - an Array of the supported language tags for this textdomain.

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



30
31
32
33
34
35
36
37
38
39
40
# File 'lib/gettext.rb', line 30

def bindtextdomain(domainname, *args)
  if args[0].kind_of? Hash
    options = args[0]
  else
    # for backward compatibility.
    options = {}
    options[:path] = args[0] if args[0]
    options[:output_charset] = args[2] if args[2]
  end
  TextDomainManager.bind_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.



46
47
48
49
50
51
52
53
# File 'lib/gettext.rb', line 46

def bindtextdomain_to(klass, domainname, options = {}) 
  ret = nil
  klass.module_eval {
    include GetText
    ret = bindtextdomain(domainname, options)
  }
  ret
end

.cgiObject

Gets the CGI object. If it is nil, returns new CGI object.

  • Returns: the CGI object



37
38
39
# File 'lib/gettext/cgi.rb', line 37

def cgi
  Locale.cgi
end

.cgi=(cgi_) ⇒ Object

Same as GetText.set_cgi.

  • cgi_: CGI object

  • Returns: cgi_



30
31
32
33
# File 'lib/gettext/cgi.rb', line 30

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

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

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

This is a convenience function of GetText.rmsgfmt for plural 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.



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/gettext/tools.rb', line 111

def create_mofiles(options = {})
  opts = {:verbose => false, :po_root => "./po", :mo_root => "./data/locale", 
    :mo_path_rule => "%{lang}/LC_MESSAGES"}
  opts.merge!(options)

  modir = File.join(opts[:mo_root], opts[:mo_path_rule])
  Dir.glob(File.join(opts[:po_root], "*/*.po")) do |file|
    lang, basename = /\/([^\/]+?)\/(.*)\.po/.match(file[opts[:po_root].size..-1]).to_a[1,2]
    outdir = modir % {:lang => lang}
    FileUtils.mkdir_p(outdir) unless File.directory?(outdir)
    $stderr.print %Q[#{file} -> #{File.join(outdir, "#{basename}.mo")} ... ] if opts[:verbose]
    begin
      rmsgfmt(file, File.join(outdir, "#{basename}.mo"))
    rescue Exception => e
      $stderr.puts "Error." if opts[:verbose]
      raise e
    end
    $stderr.puts "Done." if opts[: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 plural 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.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/gettext/utils.rb', line 16

def create_mofiles(options = {})
  opts = {:verbose => false, :po_root => "./po", :mo_root => "./data/locale", 
    :mo_path_rule => "%{lang}/LC_MESSAGES"}
  opts.merge!(options)

  modir = File.join(opts[:mo_root], opts[:mo_path_rule])
  Dir.glob(File.join(opts[:po_root], "*/*.po")) do |file|
    lang, basename = /\/([^\/]+?)\/(.*)\.po/.match(file[opts[:po_root].size..-1]).to_a[1,2]
    outdir = modir % {:lang => lang}
    FileUtils.mkdir_p(outdir) unless File.directory?(outdir)
    $stderr.print %Q[#{file} -> #{File.join(outdir, "#{basename}.mo")} ... ] if opts[:verbose]
    begin
      rmsgfmt(file, File.join(outdir, "#{basename}.mo"))
    rescue Exception => e
      $stderr.puts "Error." if opts[:verbose]
      raise e
    end
    $stderr.puts "Done." if opts[: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.



80
81
82
# File 'lib/gettext.rb', line 80

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

.included(mod) ⇒ Object

:nodoc:



9
10
11
# File 'lib/gettext.rb', line 9

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

.localeObject



225
226
227
# File 'lib/gettext.rb', line 225

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



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

def msgmerge(defpo, refpo, app_version, options)
  verbose = options.delete(:verbose) || false
  puts "msgmerge called" if verbose
  $stderr.print defpo + " "
  cmd = ENV["MSGMERGE_PATH"] || "msgmerge"

  cont = ""
  if FileTest.exist? defpo
    `#{cmd} --help`
    unless $? && $?.success?
      raise _("`%{cmd}' can not be found. \nInstall GNU Gettext then set PATH or MSGMERGE_PATH correctly.") % {:cmd => cmd}
    end
    remove_bom(defpo)

    cmd_params = (options.delete(:msgmerge) || {}).map do |o|
      o.kind_of?(Symbol) ? "--#{o}".gsub('_','-') : o.to_s
    end.join(' ')

    to_run = "#{cmd} #{cmd_params} #{defpo} #{refpo}"
    puts "\nrunning #{to_run}" if verbose
    cont = `#{to_run}`
  else
    File.open(refpo) do |io| 
      cont = io.read
    end
  end
  if cont.empty?
    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
    cont.sub!(/(Project-Id-Version\:).*$/, "\\1 #{app_version}\\n\"")
    File.open(defpo, "w") do |out|
      out.write(cont)
    end
  end
  self
end

.N_(msgid) ⇒ Object

This function does nothing. But it is required in order to recognize the msgid by rgettext.

  • msgid: the message id.

  • Returns: msgid.



193
194
195
# File 'lib/gettext.rb', line 193

def N_(msgid)
  msgid
end

.ngettext(arg1, arg2, arg3 = 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.



131
132
133
# File 'lib/gettext.rb', line 131

def ngettext(arg1, arg2, arg3 = nil)
  TextDomainManager.get(self).translate_plural_message(self, arg1, arg2, arg3)
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.



201
202
203
# File 'lib/gettext.rb', line 201

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

.npgettext(msgctxt, arg1, 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.



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/gettext.rb', line 168

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

.nsgettext(arg1, arg2, arg3 = "|", arg4 = "|") ⇒ Object Also known as: ns_

call-seq:

nsgettext(msgid, msgid_plural, n, div = "|")
nsgettext(msgids, n, div = "|")  # msgids = [msgid, msgid_plural]
n_(msgid, msgid_plural, n, div = "|")
n_(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.



150
151
152
# File 'lib/gettext.rb', line 150

def nsgettext(arg1, arg2, arg3 = "|", arg4 = "|")
  TextDomainManager.get(self).translate_plural_message(self, arg1, arg2, arg3, arg4)
end

.output_charsetObject

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

  • Returns: output_charset.



216
217
218
# File 'lib/gettext.rb', line 216

def output_charset
  TextDomainManager.output_charset
end

.p_Object

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 This is the workaround to conflict p_ methods with the xx(“double x”) library. rubyforge.org/projects/codeforpeople/



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

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

.pgettext(msgctxt, msgid) ⇒ Object

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



113
114
115
# File 'lib/gettext.rb', line 113

def pgettext(msgctxt, msgid)
  TextDomainManager.get(self).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.



31
32
33
34
35
36
37
38
39
# File 'lib/gettext/tools.rb', line 31

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

.rgettext(targetfiles = nil, out = STDOUT) ⇒ Object

Creates a po-file from targetfiles(ruby-script-files, ActiveRecord, .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.

Note for ActiveRecord, you need to run your database server and configure the config/database.yml correctly before execute this function.

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

  • out: output IO or output path.

  • Returns: self



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

def rgettext(targetfiles = nil, out = STDOUT)
  RGetText.run(targetfiles, 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



489
490
491
# File 'lib/gettext/tools/rmsgmerge.rb', line 489

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

.set_cgi(cgi_) ⇒ Object

Sets a CGI object.

  • cgi_: CGI object

  • Returns: self



23
24
25
# File 'lib/gettext/cgi.rb', line 23

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

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



220
221
222
223
# File 'lib/gettext.rb', line 220

def set_locale(lang)
  Locale.clear
  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



209
210
211
212
# File 'lib/gettext.rb', line 209

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

.sgettext(msgid, div = "|") ⇒ 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.

  • 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: www.gnu.org/software/gettext/manual/html_mono/gettext.html#SEC151



96
97
98
# File 'lib/gettext.rb', line 96

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

.textdomain(domainname) ⇒ Object

:nodoc:



55
56
57
58
# File 'lib/gettext.rb', line 55

def textdomain(domainname) #:nodoc:
  warn "GetText.textdomain is deprecated. Call bindtextdomain instead."
  bindtextdomain(domainname)
end

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

Deprecated. Use gettext/tools instead.



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/gettext/tools.rb', line 152

def update_pofiles(textdomain, files, app_version, options = {})
  puts options.inspect
  po_root = options.delete(:po_root) || "po"
  only_one_language = options.delete(:lang)
  refpot = "tmp.pot"
  rgettext(files, refpot)

  FileUtils.mkdir_p(po_root) unless FileTest.exist? po_root
  msgmerge("#{po_root}/#{textdomain}.pot", refpot, app_version, options.dup)

  if only_one_language
    msgmerge("#{po_root}/#{only_one_language}/#{textdomain}.po", refpot, app_version, options.dup)
  else
    Dir.glob("#{po_root}/*/#{textdomain}.po"){ |f|
      lang = /#{po_root}\/(.*)\//.match(f).to_a[1]
      msgmerge("#{po_root}/#{lang}/#{textdomain}.po", refpot, app_version, options.dup)
    }
  end

  File.delete(refpot)
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 or nil (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)



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/gettext/utils.rb', line 17

def update_pofiles(textdomain, files, app_version, options = {})
  puts options.inspect
  po_root = options.delete(:po_root) || "po"
  only_one_language = options.delete(:lang)
  refpot = "tmp.pot"
  rgettext(files, refpot)

  FileUtils.mkdir_p(po_root) unless FileTest.exist? po_root
  msgmerge("#{po_root}/#{textdomain}.pot", refpot, app_version, options.dup)

  if only_one_language
    msgmerge("#{po_root}/#{only_one_language}/#{textdomain}.po", refpot, app_version, options.dup)
  else
    Dir.glob("#{po_root}/*/#{textdomain}.po"){ |f|
      lang = /#{po_root}\/(.*)\//.match(f).to_a[1]
      msgmerge("#{po_root}/#{lang}/#{textdomain}.po", refpot, app_version, options.dup)
    }
  end

  File.delete(refpot)
end