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:



46
47
48
# File 'lib/gettext.rb', line 46

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.



65
66
67
# File 'lib/gettext.rb', line 65

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.



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

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



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

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_



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

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.



91
92
93
94
95
96
97
98
99
100
101
# File 'lib/gettext/tools.rb', line 91

def create_mofiles(options = {})
  options = {:po_root => "./po"}.merge(options)

  Dir.glob(File.join(options[:po_root], "*/*.po")) do |po_file|
    mo_file = mo_file_from_po_file(po_file,options)
    $stderr.print %Q[#{po_file} -> #{mo_file} ... ] if options[:verbose]
    FileUtils.mkdir_p(File.dirname(mo_file))
    rmsgfmt(po_file, mo_file)
    $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:



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/gettext/utils.rb', line 18

def create_mofiles(options = {})
  options = {:po_root => "./po"}.merge(options)

  Dir.glob(File.join(options[:po_root], "*/*.po")) do |po_file|
    mo_file = mo_file_from_po_file(po_file,options)
    $stderr.print %Q[#{po_file} -> #{mo_file} ... ] if options[:verbose]
    FileUtils.mkdir_p(File.dirname(mo_file))
    rmsgfmt(po_file, mo_file)
    $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.



129
130
131
# File 'lib/gettext.rb', line 129

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

#localeObject



289
290
291
# File 'lib/gettext.rb', line 289

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



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

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.



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

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.



181
182
183
# File 'lib/gettext.rb', line 181

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.



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

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.



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

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.



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

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.



269
270
271
# File 'lib/gettext.rb', line 269

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



163
164
165
# File 'lib/gettext.rb', line 163

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.



31
32
33
34
35
36
37
# 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)[3..-1]
    File.open(path, "w") {|f| f.write(data)}
  end
end

#rgettext(paths = nil, out = STDOUT) ⇒ 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



242
243
244
245
# File 'lib/gettext/tools/rgettext.rb', line 242

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



79
80
81
# File 'lib/gettext/tools/rmsgfmt.rb', line 79

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

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

Experimental



484
485
486
# File 'lib/gettext/tools/rmsgmerge.rb', line 484

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



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

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)



285
286
287
# File 'lib/gettext.rb', line 285

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.



276
277
278
279
280
# File 'lib/gettext.rb', line 276

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



262
263
264
265
# File 'lib/gettext.rb', line 262

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



146
147
148
# File 'lib/gettext.rb', line 146

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.



94
95
96
# File 'lib/gettext.rb', line 94

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.



103
104
105
106
107
# File 'lib/gettext.rb', line 103

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.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/gettext/tools.rb', line 123

def update_pofiles(textdomain, files, app_version, options = {})
  puts options.inspect if options[:verbose]

  #write found messages to tmp.pot
  temp_pot = "tmp.pot"
  rgettext(files, temp_pot)

  #merge tmp.pot and 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)

  #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)
  else
    Dir.glob("#{po_root}/*/#{textdomain}.po") do |po_file|
      msgmerge(po_file, temp_pot, app_version, options.dup)
    end
  end

  File.delete(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:



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

def update_pofiles(textdomain, files, app_version, options = {})
  puts options.inspect if options[:verbose]

  #write found messages to tmp.pot
  temp_pot = "tmp.pot"
  rgettext(files, temp_pot)

  #merge tmp.pot and 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)

  #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)
  else
    Dir.glob("#{po_root}/*/#{textdomain}.po") do |po_file|
      msgmerge(po_file, temp_pot, app_version, options.dup)
    end
  end

  File.delete(temp_pot)
end