aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/gems/gettext-2.1.0/lib/gettext
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gems/gettext-2.1.0/lib/gettext')
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/cgi.rb37
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/core_ext/iconv.rb110
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/core_ext/string.rb84
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/parser/erb.rb3
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/parser/glade.rb3
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/parser/ruby.rb172
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/runtime/class_info.rb67
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/runtime/locale_path.rb122
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/runtime/mofile.rb330
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain.rb177
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain_group.rb24
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain_manager.rb211
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/tools.rb195
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/erb.rb52
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/glade.rb98
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/ruby.rb226
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/tools/pomessage.rb197
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/tools/poparser.rb356
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/tools/rgettext.rb226
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/tools/rmsgfmt.rb84
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/tools/rmsgmerge.rb498
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/utils.rb37
-rw-r--r--vendor/gems/gettext-2.1.0/lib/gettext/version.rb12
23 files changed, 3321 insertions, 0 deletions
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/cgi.rb b/vendor/gems/gettext-2.1.0/lib/gettext/cgi.rb
new file mode 100644
index 000000000..78868fc10
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/cgi.rb
@@ -0,0 +1,37 @@
+=begin
+ gettext/cgi.rb - GetText for CGI
+
+ Copyright (C) 2005-2009 Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+=end
+
+require 'cgi'
+require 'gettext'
+
+Locale.init(:driver => :cgi)
+
+module GetText
+
+ # Sets a CGI object. This methods is appeared when requiring "gettext/cgi".
+ # * cgi_: CGI object
+ # * Returns: self
+ def set_cgi(cgi_)
+ Locale.set_cgi(cgi_)
+ end
+
+ # Same as GetText.set_cgi. This methods is appeared when requiring "gettext/cgi".
+ # * cgi_: CGI object
+ # * Returns: cgi_
+ def cgi=(cgi_)
+ set_cgi(cgi_)
+ cgi_
+ end
+
+ # Gets the CGI object. If it is nil, returns new CGI object. This methods is appeared when requiring "gettext/cgi".
+ # * Returns: the CGI object
+ def cgi
+ Locale.cgi
+ end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/core_ext/iconv.rb b/vendor/gems/gettext-2.1.0/lib/gettext/core_ext/iconv.rb
new file mode 100644
index 000000000..bc3aab0eb
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/core_ext/iconv.rb
@@ -0,0 +1,110 @@
+# encoding: utf-8
+=begin
+ iconv.rb - Pseudo Iconv class. Supports Iconv.iconv, Iconv.conv.
+
+ For Matz Ruby:
+ If you don't have iconv but glib2, this library uses glib2 iconv functions.
+
+ For JRuby:
+ Use Java String class to convert strings.
+
+ Copyright (C) 2004-2009 Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+=end
+
+begin
+ require 'iconv.so'
+rescue LoadError
+ # Pseudo Iconv class
+ #
+ # ==== For Matz Ruby:
+ # If you don't have iconv but Ruby/GLib2, this library uses Ruby/GLib2's
+ # iconv functions.
+ #
+ # Ruby/GLib is a module which is provided from Ruby-GNOME2 Project.
+ # You can get binaries for Win32(One-Click Ruby Installer).
+ # <URL: http://ruby-gnome2.sourceforge.jp/>
+ # ==== For JRuby:
+ # Use Java String class to convert strings.
+ class Iconv
+ module Failure; end
+ class InvalidEncoding < ArgumentError; include Failure; end
+ class IllegalSequence < ArgumentError; include Failure; end
+ class InvalidCharacter < ArgumentError; include Failure; end
+
+ if RUBY_PLATFORM =~ /java/
+ def self.conv(to, from, str)
+ raise InvalidCharacter, "the 3rd argument is nil" unless str
+ begin
+ str = java.lang.String.new(str.unpack("C*").to_java(:byte), from)
+ str.getBytes(to).to_ary.pack("C*")
+ rescue java.io.UnsupportedEncodingException
+ raise InvalidEncoding
+ end
+ end
+ else
+ begin
+ require 'glib2'
+
+ def self.check_glib_version?(major, minor, micro) # :nodoc:
+ (GLib::BINDING_VERSION[0] > major ||
+ (GLib::BINDING_VERSION[0] == major &&
+ GLib::BINDING_VERSION[1] > minor) ||
+ (GLib::BINDING_VERSION[0] == major &&
+ GLib::BINDING_VERSION[1] == minor &&
+ GLib::BINDING_VERSION[2] >= micro))
+ end
+
+ if check_glib_version?(0, 11, 0)
+ # This is a function equivalent of Iconv.iconv.
+ # * to: encoding name for destination
+ # * from: encoding name for source
+ # * str: strings to be converted
+ # * Returns: Returns an Array of converted strings.
+ def self.conv(to, from, str)
+ begin
+ GLib.convert(str, to, from)
+ rescue GLib::ConvertError => e
+ case e.code
+ when GLib::ConvertError::NO_CONVERSION
+ raise InvalidEncoding.new(str)
+ when GLib::ConvertError::ILLEGAL_SEQUENCE
+ raise IllegalSequence.new(str)
+ else
+ raise InvalidCharacter.new(str)
+ end
+ end
+ end
+ else
+ def self.conv(to, from, str) # :nodoc:
+ begin
+ GLib.convert(str, to, from)
+ rescue
+ raise IllegalSequence.new(str)
+ end
+ end
+ end
+ rescue LoadError
+ def self.conv(to, from, str) # :nodoc:
+ warn "Iconv was not found." if $DEBUG
+ str
+ end
+ end
+ end
+ def self.iconv(to, from, str)
+ conv(to, from, str).split(//)
+ end
+ end
+end
+
+if __FILE__ == $0
+ puts Iconv.iconv("EUC-JP", "UTF-8", "ほげ").join
+ begin
+ puts Iconv.iconv("EUC-JP", "EUC-JP", "ほげ").join
+ rescue Iconv::Failure
+ puts $!
+ puts $!.class
+ end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/core_ext/string.rb b/vendor/gems/gettext-2.1.0/lib/gettext/core_ext/string.rb
new file mode 100644
index 000000000..1cbd91567
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/core_ext/string.rb
@@ -0,0 +1,84 @@
+=begin
+ string.rb - Extension for String.
+
+ Copyright (C) 2005-2009 Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+=end
+
+# Extension for String class. This feature is included in Ruby 1.9 or later but not occur TypeError.
+#
+# String#% method which accept "named argument". The translator can know
+# the meaning of the msgids using "named argument" instead of %s/%d style.
+class String
+
+ unless instance_methods.find {|m| m.to_s == 'bytesize'}
+ # For older ruby (such as ruby-1.8.5)
+ alias :bytesize :size
+ end
+
+ alias :_old_format_m :% # :nodoc:
+
+ PERCENT_MATCH_RE = Regexp.union(
+ /%%/,
+ /%\{(.+?)\}/,
+ /%<(.+?)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/
+ )
+
+ # call-seq:
+ # %(arg)
+ # %(hash)
+ #
+ # Format - Uses str as a format specification, and returns the result of applying it to arg.
+ # If the format specification contains more than one substitution, then arg must be
+ # an Array containing the values to be substituted. See Kernel::sprintf for details of the
+ # format string. This is the default behavior of the String class.
+ # * arg: an Array or other class except Hash.
+ # * Returns: formatted String
+ #
+ # (e.g.) "%s, %s" % ["Masao", "Mutoh"]
+ #
+ # Also you can use a Hash as the "named argument". This is recommanded way for Ruby-GetText
+ # because the translators can understand the meanings of the msgids easily.
+ # * hash: {:key1 => value1, :key2 => value2, ... }
+ # * Returns: formatted String
+ #
+ # (e.g.)
+ # For strings.
+ # "%{firstname}, %{familyname}" % {:firstname => "Masao", :familyname => "Mutoh"}
+ #
+ # With field type to specify format such as d(decimal), f(float),...
+ # "%<age>d, %<weight>.1f" % {:age => 10, :weight => 43.4}
+ def %(args)
+ if args.kind_of?(Hash)
+ ret = dup
+ ret.gsub!(PERCENT_MATCH_RE) {|match|
+ if match == '%%'
+ '%'
+ elsif $1
+ key = $1.to_sym
+ args.has_key?(key) ? args[key] : match
+ elsif $2
+ key = $2.to_sym
+ args.has_key?(key) ? sprintf("%#{$3}", args[key]) : match
+ end
+ }
+ ret
+ else
+ ret = gsub(/%([{<])/, '%%\1')
+ begin
+ ret._old_format_m(args)
+ rescue ArgumentError => e
+ if $DEBUG
+ $stderr.puts " The string:#{ret}"
+ $stderr.puts " args:#{args.inspect}"
+ puts e.backtrace
+ else
+ raise ArgumentError, e.message
+ end
+ end
+ end
+ end
+end
+
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/parser/erb.rb b/vendor/gems/gettext-2.1.0/lib/gettext/parser/erb.rb
new file mode 100644
index 000000000..eea0ea828
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/parser/erb.rb
@@ -0,0 +1,3 @@
+warn "DEPRECATED: Use 'gettext/tools/parser/erb' instead."
+
+require 'gettext/tools/parser/erb'
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/parser/glade.rb b/vendor/gems/gettext-2.1.0/lib/gettext/parser/glade.rb
new file mode 100644
index 000000000..7b61fedad
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/parser/glade.rb
@@ -0,0 +1,3 @@
+warn "DEPRECATED: Use 'gettext/tools/parser/glade' instead."
+
+require 'gettext/tools/parser/glade'
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/parser/ruby.rb b/vendor/gems/gettext-2.1.0/lib/gettext/parser/ruby.rb
new file mode 100644
index 000000000..cf8fae47a
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/parser/ruby.rb
@@ -0,0 +1,172 @@
+#!/usr/bin/ruby
+=begin
+ parser/ruby.rb - parser for ruby script
+
+ Copyright (C) 2003-2005 Masao Mutoh
+ Copyright (C) 2005 speakillof
+ Copyright (C) 2001,2002 Yasushi Shoji, Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby.
+
+=end
+
+require 'irb/ruby-lex.rb'
+require 'stringio'
+warn "DEPRECATED: Use 'gettext/tools/parser/ruby' instead."
+
+class RubyLexX < RubyLex # :nodoc: all
+ # Parser#parse resemlbes RubyLex#lex
+ def parse
+ until ( (tk = token).kind_of?(RubyToken::TkEND_OF_SCRIPT) && !@continue or tk.nil? )
+ s = get_readed
+ if RubyToken::TkSTRING === tk
+ def tk.value
+ @value
+ end
+
+ def tk.value=(s)
+ @value = s
+ end
+
+ if @here_header
+ s = s.sub(/\A.*?\n/, '').sub(/^.*\n\Z/, '')
+ else
+ begin
+ s = eval(s)
+ rescue Exception
+ # Do nothing.
+ end
+ end
+
+ tk.value = s
+ end
+
+ if $DEBUG
+ if tk.is_a? TkSTRING
+ $stderr.puts("#{tk}: #{tk.value}")
+ elsif tk.is_a? TkIDENTIFIER
+ $stderr.puts("#{tk}: #{tk.name}")
+ else
+ $stderr.puts(tk)
+ end
+ end
+
+ yield tk
+ end
+ return nil
+ end
+
+end
+
+module GetText
+ module RubyParser
+ extend self
+
+ unless defined? ID
+ ID = ['gettext', '_', 'N_', 'sgettext', 's_']
+ PLURAL_ID = ['ngettext', 'n_', 'Nn_', 'ns_', 'nsgettext']
+ MSGCTXT_ID = ['pgettext', 'p_']
+ MSGCTXT_PLURAL_ID = ['npgettext', 'np_']
+ end
+
+ def parse(file, targets = []) # :nodoc:
+ lines = IO.readlines(file)
+ parse_lines(file, lines, targets)
+ end
+
+ def parse_lines(file_name, lines, targets) # :nodoc:
+ file = StringIO.new(lines.join + "\n")
+ rl = RubyLexX.new
+ rl.set_input(file)
+ rl.skip_space = true
+ #rl.readed_auto_clean_up = true
+
+ target = nil
+ msgid = nil
+ line_no = nil
+ rl.parse do |tk|
+ begin
+ case tk
+ when RubyToken::TkIDENTIFIER, RubyToken::TkCONSTANT
+ if ID.include?(tk.name)
+ target = :normal
+ elsif PLURAL_ID.include?(tk.name)
+ target = :plural
+ elsif MSGCTXT_ID.include?(tk.name)
+ target = :msgctxt
+ elsif MSGCTXT_PLURAL_ID.include?(tk.name)
+ target = :msgctxt_plural
+ else
+ target = nil
+ end
+ line_no = tk.line_no.to_s
+ when RubyToken::TkSTRING
+ if target
+ if msgid
+ msgid += tk.value
+ else
+ msgid = tk.value
+ end
+ end
+ when RubyToken::TkPLUS, RubyToken::TkNL
+ #do nothing
+ when RubyToken::TkCOMMA
+ if msgid
+ case target
+ when :plural
+ msgid += "\000"
+ target = :normal
+ when :msgctxt
+ msgid += "\004"
+ target = :normal
+ when :msgctxt_plural
+ msgid += "\004"
+ target = :plural
+ else
+ target = :normal
+ end
+ end
+ else
+ if msgid
+ key_existed = targets.assoc(msgid.gsub(/\n/, '\n'))
+ if key_existed
+ targets[targets.index(key_existed)] = key_existed <<
+ file_name + ":" + line_no
+ else
+ targets << [msgid.gsub(/\n/, '\n'), file_name + ":" + line_no]
+ end
+ msgid = nil
+ target = nil
+ end
+ end
+ targets
+ rescue
+ $stderr.print "\n\nError: #{$!.inspect} "
+ $stderr.print " in #{file_name}:#{tk.line_no}\n\t #{lines[tk.line_no - 1]}" if tk
+ $stderr.print "\n"
+ exit 1
+ end
+ end
+ targets
+ end
+
+ def target?(file) # :nodoc:
+ true # always true, as default parser.
+ end
+ end
+end
+
+
+
+if __FILE__ == $0
+ require 'pp'
+ ARGV.each do |file|
+ pp GetText::RubyParser.parse(file)
+ end
+
+ #rl = RubyLexX.new; rl.set_input(ARGF)
+ #rl.parse do |tk|
+ #p tk
+ #end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/runtime/class_info.rb b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/class_info.rb
new file mode 100644
index 000000000..c7acca267
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/class_info.rb
@@ -0,0 +1,67 @@
+require 'locale/util/memoizable'
+
+module GetText
+ # For normalize/finding the related classes/modules.
+ # This is used for realizing the scope of TextDomain.
+ # (see: http://www.yotabanana.com/hiki/ruby-gettext-scope.html)
+ module ClassInfo
+ extend self
+ include Locale::Util::Memoizable
+
+ # normalize the class name
+ # klass should kind of the class, not object.
+ def normalize_class(klass)
+ ret = (klass.kind_of? Module) ? klass : klass.class
+ if ret.name =~ /^\#<|^$/ or ret == GetText
+ ret = Object
+ end
+ ret
+ end
+
+ def root_ancestors # :nodoc:
+ Object.ancestors
+ end
+ memoize :root_ancestors
+
+ # Internal method for related_classes.
+ def related_classes_internal(klass, all_classes = [], analyzed_classes = [] )
+ ret = []
+ klass = normalize_class(klass)
+
+ return [Object] if root_ancestors.include? klass
+
+ ary = klass.name.split(/::/)
+ while(v = ary.shift)
+ ret.unshift(((ret.size == 0) ? Object.const_get(v) : ret[0].const_get(v)))
+ end
+ ret -= analyzed_classes
+ if ret.size > 1
+ ret += related_classes_internal(ret[1], all_classes, analyzed_classes)
+ ret.uniq!
+ end
+ analyzed_classes << klass unless analyzed_classes.include? klass
+
+ klass.ancestors[1..-1].each do |a|
+ ret += related_classes_internal(a, all_classes, analyzed_classes)
+ ret.uniq!
+ end
+
+ if all_classes.size > 0
+ (ret & all_classes).uniq
+ else
+ ret.uniq
+ end
+ end
+
+ # Returns the classes which related to klass
+ # (klass's ancestors, included modules and nested modules)
+ def related_classes(klass, all_classes = [])
+ ret = related_classes_internal(klass, all_classes)
+ unless ret.include? Object
+ ret += [Object]
+ end
+ ret
+ end
+ memoize :related_classes
+ end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/runtime/locale_path.rb b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/locale_path.rb
new file mode 100644
index 000000000..5500bca20
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/locale_path.rb
@@ -0,0 +1,122 @@
+=begin
+ locale_path.rb - GetText::LocalePath
+
+ Copyright (C) 2001-2009 Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+
+=end
+
+require 'rbconfig'
+require 'gettext/core_ext/string'
+
+module GetText
+ # Treats locale-path for mo-files.
+ class LocalePath
+ include Locale::Util::Memoizable
+
+ # The default locale paths.
+ CONFIG_PREFIX = Config::CONFIG['prefix'].gsub(/\/local/, "")
+ DEFAULT_RULES = [
+ "./locale/%{lang}/LC_MESSAGES/%{name}.mo",
+ "./locale/%{lang}/%{name}.mo",
+ "#{Config::CONFIG['datadir']}/locale/%{lang}/LC_MESSAGES/%{name}.mo",
+ "#{Config::CONFIG['datadir'].gsub(/\/local/, "")}/locale/%{lang}/LC_MESSAGES/%{name}.mo",
+ "#{CONFIG_PREFIX}/share/locale/%{lang}/LC_MESSAGES/%{name}.mo",
+ "#{CONFIG_PREFIX}/local/share/locale/%{lang}/LC_MESSAGES/%{name}.mo"
+ ].uniq
+
+ class << self
+ include Locale::Util::Memoizable
+
+ # Add default locale path. Usually you should use GetText.add_default_locale_path instead.
+ # * path: a new locale path. (e.g.) "/usr/share/locale/%{lang}/LC_MESSAGES/%{name}.mo"
+ # ('locale' => "ja_JP", 'name' => "textdomain")
+ # * Returns: the new DEFAULT_LOCALE_PATHS
+ def add_default_rule(path)
+ DEFAULT_RULES.unshift(path)
+ end
+
+ # Returns path rules as an Array.
+ # (e.g.) ["/usr/share/locale/%{lang}/LC_MESSAGES/%{name}.mo", ...]
+ def default_path_rules
+ default_path_rules = []
+
+ if ENV["GETTEXT_PATH"]
+ ENV["GETTEXT_PATH"].split(/,/).each {|i|
+ default_path_rules = ["#{i}/%{lang}/LC_MESSAGES/%{name}.mo", "#{i}/%{lang}/%{name}.mo"]
+ }
+ end
+
+ default_path_rules += DEFAULT_RULES
+
+ load_path = $LOAD_PATH
+ if defined? ::Gem
+ load_path += Gem.all_load_paths
+ end
+ load_path.map!{|v| v.match(/(.*?)(\/lib)*?$/); $1}
+ load_path.each {|path|
+ default_path_rules += [
+ "#{path}/data/locale/%{lang}/LC_MESSAGES/%{name}.mo",
+ "#{path}/data/locale/%{lang}/%{name}.mo",
+ "#{path}/locale/%{lang}/%{name}.mo"]
+ }
+ # paths existed only.
+ default_path_rules = default_path_rules.select{|path|
+ Dir.glob(path % {:lang => "*", :name => "*"}).size > 0}.uniq
+ default_path_rules
+ end
+ memoize_dup :default_path_rules
+ end
+
+ attr_reader :locale_paths, :supported_locales
+
+ # Creates a new GetText::TextDomain.
+ # * name: the textdomain name.
+ # * topdir: the locale path ("%{topdir}/%{lang}/LC_MESSAGES/%{name}.mo") or nil.
+ def initialize(name, topdir = nil)
+ @name = name
+
+ if topdir
+ path_rules = ["#{topdir}/%{lang}/LC_MESSAGES/%{name}.mo", "#{topdir}/%{lang}/%{name}.mo"]
+ else
+ path_rules = self.class.default_path_rules
+ end
+
+ @locale_paths = {}
+ path_rules.each do |rule|
+ this_path_rules = rule % {:lang => "([^\/]+)", :name => name}
+ Dir.glob(rule %{:lang => "*", :name => name}).each do |path|
+ if /#{this_path_rules}/ =~ path
+ @locale_paths[$1] = path unless @locale_paths[$1]
+ end
+ end
+ end
+ @supported_locales = @locale_paths.keys.sort
+ end
+
+ # Gets the current path.
+ # * lang: a Locale::Tag.
+ def current_path(lang)
+ lang_candidates = lang.to_posix.candidates
+ search_files = []
+
+ lang_candidates.each do |tag|
+ path = @locale_paths[tag.to_s]
+ warn "GetText::TextDomain#load_mo: mo-file is #{path}" if $DEBUG
+ return path if path
+ end
+
+ if $DEBUG
+ warn "MO file is not found in"
+ @locale_paths.each do |path|
+ warn " #{path[1]}"
+ end
+ end
+ nil
+ end
+ memoize :current_path
+
+ end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/runtime/mofile.rb b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/mofile.rb
new file mode 100644
index 000000000..dd8158d01
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/mofile.rb
@@ -0,0 +1,330 @@
+=begin
+ mofile.rb - A simple class for operating GNU MO file.
+
+ Copyright (C) 2003-2009 Masao Mutoh
+ Copyright (C) 2002 Masahiro Sakai, Masao Mutoh
+ Copyright (C) 2001 Masahiro Sakai
+
+ Masahiro Sakai <s01397ms at sfc.keio.ac.jp>
+ Masao Mutoh <mutomasa at gmail.com>
+
+ You can redistribute this file and/or modify it under the same term
+ of Ruby. License of Ruby is included with Ruby distribution in
+ the file "README".
+
+=end
+
+require 'gettext/core_ext/iconv'
+require 'stringio'
+
+module GetText
+ class MOFile < Hash
+ class InvalidFormat < RuntimeError; end;
+
+ attr_reader :filename
+
+ Header = Struct.new(:magic,
+ :revision,
+ :nstrings,
+ :orig_table_offset,
+ :translated_table_offset,
+ :hash_table_size,
+ :hash_table_offset)
+
+ # The following are only used in .mo files
+ # with minor revision >= 1.
+ class HeaderRev1 < Header
+ attr_accessor :n_sysdep_segments,
+ :sysdep_segments_offset,
+ :n_sysdep_strings,
+ :orig_sysdep_tab_offset,
+ :trans_sysdep_tab_offset
+ end
+
+ MAGIC_BIG_ENDIAN = "\x95\x04\x12\xde"
+ MAGIC_LITTLE_ENDIAN = "\xde\x12\x04\x95"
+
+ def self.open(arg = nil, output_charset = nil)
+ result = self.new(output_charset)
+ result.load(arg)
+ end
+
+ def initialize(output_charset = nil)
+ @filename = nil
+ @last_modified = nil
+ @little_endian = true
+ @output_charset = output_charset
+ @plural_proc = nil
+ super()
+ end
+
+ def update!
+ if FileTest.exist?(@filename)
+ st = File.stat(@filename)
+ load(@filename) unless (@last_modified == [st.ctime, st.mtime])
+ else
+ warn "#{@filename} was lost." if $DEBUG
+ clear
+ end
+ self
+ end
+
+ def load(arg)
+ if arg.kind_of? String
+ begin
+ st = File.stat(arg)
+ @last_modified = [st.ctime, st.mtime]
+ rescue Exception
+ end
+ load_from_file(arg)
+ else
+ load_from_stream(arg)
+ end
+ @filename = arg
+ self
+ end
+
+ def load_from_stream(io)
+ magic = io.read(4)
+ case magic
+ when MAGIC_BIG_ENDIAN
+ @little_endian = false
+ when MAGIC_LITTLE_ENDIAN
+ @little_endian = true
+ else
+ raise InvalidFormat.new(sprintf("Unknown signature %s", magic.dump))
+ end
+
+ endian_type6 = @little_endian ? 'V6' : 'N6'
+ endian_type_astr = @little_endian ? 'V*' : 'N*'
+
+ header = HeaderRev1.new(magic, *(io.read(4 * 6).unpack(endian_type6)))
+
+ if header.revision == 1
+ # FIXME: It doesn't support sysdep correctly.
+ header.n_sysdep_segments = io.read(4).unpack(endian_type6)
+ header.sysdep_segments_offset = io.read(4).unpack(endian_type6)
+ header.n_sysdep_strings = io.read(4).unpack(endian_type6)
+ header.orig_sysdep_tab_offset = io.read(4).unpack(endian_type6)
+ header.trans_sysdep_tab_offset = io.read(4).unpack(endian_type6)
+ elsif header.revision > 1
+ raise InvalidFormat.new(sprintf("file format revision %d isn't supported", header.revision))
+ end
+ io.pos = header.orig_table_offset
+ orig_table_data = io.read((4 * 2) * header.nstrings).unpack(endian_type_astr)
+
+ io.pos = header.translated_table_offset
+ trans_table_data = io.read((4 * 2) * header.nstrings).unpack(endian_type_astr)
+
+ original_strings = Array.new(header.nstrings)
+ for i in 0...header.nstrings
+ io.pos = orig_table_data[i * 2 + 1]
+ original_strings[i] = io.read(orig_table_data[i * 2 + 0])
+ end
+
+ clear
+ for i in 0...header.nstrings
+ io.pos = trans_table_data[i * 2 + 1]
+ str = io.read(trans_table_data[i * 2 + 0])
+
+ if (! original_strings[i]) || original_strings[i] == ""
+ if str
+ @charset = nil
+ @nplurals = nil
+ @plural = nil
+ str.each_line{|line|
+ if /^Content-Type:/i =~ line and /charset=((?:\w|-)+)/i =~ line
+ @charset = $1
+ elsif /^Plural-Forms:\s*nplurals\s*\=\s*(\d*);\s*plural\s*\=\s*([^;]*)\n?/ =~ line
+ @nplurals = $1
+ @plural = $2
+ end
+ break if @charset and @nplurals
+ }
+ @nplurals = "1" unless @nplurals
+ @plural = "0" unless @plural
+ end
+ else
+ if @output_charset
+ begin
+ str = Iconv.conv(@output_charset, @charset, str) if @charset
+ rescue Iconv::Failure
+ if $DEBUG
+ warn "@charset = ", @charset
+ warn"@output_charset = ", @output_charset
+ warn "msgid = ", original_strings[i]
+ warn "msgstr = ", str
+ end
+ end
+ end
+ end
+ self[original_strings[i]] = str.freeze
+ end
+ self
+ end
+
+ def prime?(number)
+ ('1' * number) !~ /^1?$|^(11+?)\1+$/
+ end
+
+ begin
+ require 'prime'
+ def next_prime(seed)
+ Prime.instance.find{|x| x > seed }
+ end
+ rescue LoadError
+ def next_prime(seed)
+ require 'mathn'
+ prime = Prime.new
+ while current = prime.succ
+ return current if current > seed
+ end
+ end
+ end
+
+ HASHWORDBITS = 32
+ # From gettext-0.12.1/gettext-runtime/intl/hash-string.h
+ # Defines the so called `hashpjw' function by P.J. Weinberger
+ # [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
+ # 1986, 1987 Bell Telephone Laboratories, Inc.]
+ def hash_string(str)
+ hval = 0
+ i = 0
+ str.each_byte do |b|
+ break if b == '\0'
+ hval <<= 4
+ hval += b.to_i
+ g = hval & (0xf << (HASHWORDBITS - 4))
+ if (g != 0)
+ hval ^= g >> (HASHWORDBITS - 8)
+ hval ^= g
+ end
+ end
+ hval
+ end
+
+ #Save data as little endian format.
+ def save_to_stream(io)
+ header_size = 4 * 7
+ table_size = 4 * 2 * size
+
+ hash_table_size = next_prime((size * 4) / 3)
+ hash_table_size = 3 if hash_table_size <= 2
+ header = Header.new(
+ MAGIC_LITTLE_ENDIAN, # magic
+ 0, # revision
+ size, # nstrings
+ header_size, # orig_table_offset
+ header_size + table_size, # translated_table_offset
+ hash_table_size, # hash_table_size
+ header_size + table_size * 2 # hash_table_offset
+ )
+ io.write(header.to_a.pack('a4V*'))
+
+ ary = to_a
+ ary.sort!{|a, b| a[0] <=> b[0]} # sort by original string
+
+ pos = header.hash_table_size * 4 + header.hash_table_offset
+
+ orig_table_data = Array.new()
+ ary.each{|item, _|
+ orig_table_data.push(item.bytesize)
+ orig_table_data.push(pos)
+ pos += item.bytesize + 1 # +1 is <NUL>
+ }
+ io.write(orig_table_data.pack('V*'))
+
+ trans_table_data = Array.new()
+ ary.each{|_, item|
+ trans_table_data.push(item.bytesize)
+ trans_table_data.push(pos)
+ pos += item.bytesize + 1 # +1 is <NUL>
+ }
+ io.write(trans_table_data.pack('V*'))
+
+ hash_tab = Array.new(hash_table_size)
+ j = 0
+ ary[0...size].each {|key, _|
+ hash_val = hash_string(key)
+ idx = hash_val % hash_table_size
+ if hash_tab[idx] != nil
+ incr = 1 + (hash_val % (hash_table_size - 2))
+ begin
+ if (idx >= hash_table_size - incr)
+ idx -= hash_table_size - incr
+ else
+ idx += incr
+ end
+ end until (hash_tab[idx] == nil)
+ end
+ hash_tab[idx] = j + 1
+ j += 1
+ }
+ hash_tab.collect!{|i| i ? i : 0}
+
+ io.write(hash_tab.pack('V*'))
+
+ ary.each{|item, _| io.write(item); io.write("\0") }
+ ary.each{|_, item| io.write(item); io.write("\0") }
+
+ self
+ end
+
+ def load_from_file(filename)
+ @filename = filename
+ begin
+ File.open(filename, 'rb'){|f| load_from_stream(f)}
+ rescue => e
+ e.set_backtrace("File: #{@filename}")
+ raise e
+ end
+ end
+
+ def save_to_file(filename)
+ File.open(filename, 'wb'){|f| save_to_stream(f)}
+ end
+
+ def set_comment(msgid_or_sym, comment)
+ #Do nothing
+ end
+
+ def plural_as_proc
+ unless @plural_proc
+ @plural_proc = Proc.new{|n| eval(@plural)}
+ begin
+ @plural_proc.call(1)
+ rescue
+ @plural_proc = Proc.new{|n| 0}
+ end
+ end
+ @plural_proc
+ end
+
+ attr_accessor :little_endian, :path, :last_modified
+ attr_reader :charset, :nplurals, :plural
+ end
+
+end
+
+# Test
+
+if $0 == __FILE__
+ if (ARGV.include? "-h") or (ARGV.include? "--help")
+ STDERR.puts("mo.rb [filename.mo ...]")
+ exit
+ end
+
+ ARGV.each{ |item|
+ mo = GetText::MOFile.open(item)
+ puts "------------------------------------------------------------------"
+ puts "charset = \"#{mo.charset}\""
+ puts "nplurals = \"#{mo.nplurals}\""
+ puts "plural = \"#{mo.plural}\""
+ puts "------------------------------------------------------------------"
+ mo.each do |key, value|
+ puts "original message = #{key.inspect}"
+ puts "translated message = #{value.inspect}"
+ puts "--------------------------------------------------------------------"
+ end
+ }
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain.rb b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain.rb
new file mode 100644
index 000000000..ce52fab3a
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain.rb
@@ -0,0 +1,177 @@
+=begin
+ textdomain.rb - GetText::Textdomain
+
+ Copyright (C) 2001-2009 Masao Mutoh
+ Copyright (C) 2001-2003 Masahiro Sakai
+
+ Masahiro Sakai <s01397ms@sfc.keio.ac.jp>
+ Masao Mutoh <mutomasa at gmail.com>
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+=end
+
+require 'gettext/core_ext/string'
+require 'gettext/runtime/mofile'
+require 'gettext/runtime/locale_path'
+
+module GetText
+ # GetText::TextDomain class manages mo-files of a textdomain.
+ #
+ # Usually, you don't need to use this class directly.
+ #
+ # Notice: This class is unstable. APIs will be changed.
+ class TextDomain
+
+ attr_reader :output_charset
+ attr_reader :mofiles
+ attr_reader :name
+
+ @@cached = ! $DEBUG
+ # Cache the mo-file or not.
+ # Default is true. If $DEBUG is set then false.
+ def self.cached?
+ @@cached
+ end
+
+ # Set to cache the mo-file or not.
+ # * val: true if cached, otherwise false.
+ def self.cached=(val)
+ @@cached = val
+ end
+
+ # Add default locale path. Usually you should use GetText.add_default_locale_path instead.
+ # * path: a new locale path. (e.g.) "/usr/share/locale/%{lang}/LC_MESSAGES/%{name}.mo"
+ # ('locale' => "ja_JP", 'name' => "textdomain")
+ # * Returns: the new DEFAULT_LOCALE_PATHS
+ def self.add_default_locale_path(path)
+ warn "Deprecated. Use GetText::LocalePath.add_default_rule instead."
+ LocalePath.add_default_rule(path)
+ end
+
+ # Creates a new GetText::TextDomain.
+ # * name: the textdomain name.
+ # * topdir: the locale path ("%{topdir}/%{lang}/LC_MESSAGES/%{name}.mo") or nil.
+ # * output_charset: output charset.
+ # * Returns: a newly created GetText::TextDomain object.
+ def initialize(name, topdir = nil, output_charset = nil)
+ @name, @output_charset = name, output_charset
+
+ @locale_path = LocalePath.new(@name, topdir)
+ @mofiles = {}
+ end
+
+ # Translates the translated string.
+ # * lang: Locale::Tag::Simple's subclass.
+ # * msgid: the original message.
+ # * Returns: the translated string or nil.
+ def translate_singluar_message(lang, msgid)
+ return "" if msgid == "" or msgid.nil?
+
+ lang_key = lang.to_s
+
+ mofile = nil
+ if self.class.cached?
+ mofile = @mofiles[lang_key]
+ end
+ unless mofile
+ mofile = load_mo(lang)
+ end
+
+ if (! mofile) or (mofile ==:empty)
+ return nil
+ end
+
+ msgstr = mofile[msgid]
+ if msgstr and (msgstr.size > 0)
+ msgstr
+ elsif msgid.include?("\000")
+ # Check "aaa\000bbb" and show warning but return the singluar part.
+ ret = nil
+ msgid_single = msgid.split("\000")[0]
+ mofile.each{|key, val|
+ if key =~ /^#{Regexp.quote(msgid_single)}\000/
+ # Usually, this is not caused to make po-files from rgettext.
+ warn %Q[Warning: n_("#{msgid_single}", "#{msgid.split("\000")[1]}") and n_("#{key.gsub(/\000/, '", "')}") are duplicated.]
+ ret = val
+ break
+ end
+ }
+ ret
+ else
+ ret = nil
+ mofile.each{|key, val|
+ if key =~ /^#{Regexp.quote(msgid)}\000/
+ ret = val.split("\000")[0]
+ break
+ end
+ }
+ ret
+ end
+ end
+
+ DEFAULT_PLURAL_CALC = Proc.new{|n| n != 1}
+ DEFAULT_SINGLE_CALC = Proc.new{|n| 0}
+
+ # Translates the translated string.
+ # * lang: Locale::Tag::Simple's subclass.
+ # * msgid: the original message.
+ # * msgid_plural: the original message(plural).
+ # * Returns: the translated string as an Array ([[msgstr1, msgstr2, ...], cond]) or nil.
+ def translate_plural_message(lang, msgid, msgid_plural) #:nodoc:
+ key = msgid + "\000" + msgid_plural
+ msg = translate_singluar_message(lang, key)
+ ret = nil
+ if ! msg
+ ret = nil
+ elsif msg.include?("\000")
+ # [[msgstr[0], msgstr[1], msgstr[2],...], cond]
+ mofile = @mofiles[lang.to_posix.to_s]
+ cond = (mofile and mofile != :empty) ? mofile.plural_as_proc : DEFAULT_PLURAL_CALC
+ ret = [msg.split("\000"), cond]
+ else
+ ret = [[msg], DEFAULT_SINGLE_CALC]
+ end
+ ret
+ end
+
+ # Clear cached mofiles.
+ def clear
+ @mofiles = {}
+ end
+
+ # Set output_charset.
+ # * charset: output charset.
+ def output_charset=(charset)
+ @output_charset = charset
+ clear
+ end
+
+ private
+ # Load a mo-file from the file.
+ # lang is the subclass of Locale::Tag::Simple.
+ def load_mo(lang)
+ lang = lang.to_posix unless lang.kind_of? Locale::Tag::Posix
+ lang_key = lang.to_s
+
+ mofile = @mofiles[lang_key]
+ if mofile
+ if mofile == :empty
+ return :empty
+ elsif ! self.class.cached?
+ mofile.update!
+ end
+ return mofile
+ end
+
+ path = @locale_path.current_path(lang)
+
+ if path
+ charset = @output_charset || lang.charset || Locale.charset || "UTF-8"
+ @mofiles[lang_key] = MOFile.open(path, charset)
+ else
+ @mofiles[lang_key] = :empty
+ end
+ end
+ end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain_group.rb b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain_group.rb
new file mode 100644
index 000000000..b2ffd2dd2
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain_group.rb
@@ -0,0 +1,24 @@
+=begin
+ 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.
+
+=end
+
+module GetText
+
+ class TextDomainGroup
+ attr_reader :textdomains
+
+ def initialize
+ @textdomains = []
+ end
+
+ def add(textdomain)
+ @textdomains.unshift(textdomain) unless @textdomains.include? textdomain
+ end
+ end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain_manager.rb b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain_manager.rb
new file mode 100644
index 000000000..09d879521
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/runtime/textdomain_manager.rb
@@ -0,0 +1,211 @@
+=begin
+ gettext/textdomain_manager - GetText::TextDomainManager class
+
+ Copyright (C) 2009 Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+
+=end
+
+require 'gettext/runtime/class_info'
+require 'gettext/runtime/textdomain'
+require 'gettext/runtime/textdomain_group'
+
+module GetText
+
+ module TextDomainManager
+
+ @@textdomain_pool = {}
+ @@textdomain_group_pool = {}
+
+ @@output_charset = nil
+ @@gettext_classes = []
+
+ @@singular_message_cache = {}
+ @@plural_message_cache = {}
+ @@cached = ! $DEBUG
+
+ extend self
+
+ # Find textdomain by name
+ def textdomain_pool(domainname)
+ @@textdomain_pool[domainname]
+ end
+
+ # Set the value whether cache messages or not.
+ # true to cache messages, otherwise false.
+ #
+ # Default is true. If $DEBUG is false, messages are not checked even if
+ # this value is true.
+ def cached=(val)
+ @@cached = val
+ TextDomain.cached = val
+ end
+
+ # Return the cached value.
+ def cached?
+ TextDomain.cached?
+ end
+
+ # Gets the output charset.
+ def output_charset
+ @@output_charset
+ end
+
+ # Sets the output charset.The program can have a output charset.
+ def output_charset=(charset)
+ @@output_charset = charset
+ @@textdomain_pool.each do |key, textdomain|
+ textdomain.output_charset = charset
+ end
+ end
+
+ # bind textdomain to the class.
+ def bind_to(klass, domainname, options = {})
+ warn "Bind the domain '#{domainname}' to '#{klass}'. " if $DEBUG
+
+ charset = options[:output_charset] || self.output_charset
+ textdomain = create_or_find_textdomain(domainname,options[:path],charset)
+ target_klass = ClassInfo.normalize_class(klass)
+ create_or_find_textdomain_group(target_klass).add(textdomain)
+ @@gettext_classes << target_klass unless @@gettext_classes.include? target_klass
+
+ textdomain
+ end
+
+ def each_textdomains(klass) #:nodoc:
+ lang = Locale.candidates[0]
+ ClassInfo.related_classes(klass, @@gettext_classes).each do |target|
+ msg = nil
+ if group = @@textdomain_group_pool[target]
+ group.textdomains.each do |textdomain|
+ yield textdomain, lang
+ end
+ end
+ end
+ end
+
+ # Translates msgid, but if there are no localized text,
+ # it returns a last part of msgid separeted "div" or whole of the msgid with no "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".
+ def translate_singluar_message(klass, msgid, div = nil)
+ klass = ClassInfo.normalize_class(klass)
+ key = [Locale.current, klass, msgid, div].hash
+ msg = @@singular_message_cache[key]
+ return msg if msg and @@cached
+ # Find messages from related classes.
+ each_textdomains(klass) do |textdomain, lang|
+ msg = textdomain.translate_singluar_message(lang, msgid)
+ break if msg
+ end
+
+ # If not found, return msgid.
+ msg ||= msgid
+ if div and msg == msgid
+ if index = msg.rindex(div)
+ msg = msg[(index + 1)..-1]
+ end
+ end
+ @@singular_message_cache[key] = msg
+ end
+
+ # This function is similar to the get_singluar_message function
+ # as it finds the message catalogs in the same way.
+ # But it takes two extra arguments for plural form.
+ # The msgid parameter must contain the singular form of the string to be converted.
+ # It is also used as the key for the search in the catalog.
+ # The msgid_plural parameter is the plural form.
+ # The parameter n is used to determine the plural form.
+ # If no message catalog is found msgid1 is returned if n == 1, otherwise msgid2.
+ # And if msgid includes "div", it returns a last part of msgid separeted "div".
+ #
+ # * msgid: the singular form with "div". (e.g. "Special|An apple", "An apple")
+ # * msgid_plural: the plural form. (e.g. "%{num} Apples")
+ # * n: a number used to determine the plural form.
+ # * div: the separator. Default is "|".
+ # * 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.
+ #
+ # or
+ #
+ # * [msgid, msgid_plural] : msgid and msgid_plural an Array
+ # * n: a number used to determine the plural form.
+ # * div: the separator. Default is "|".
+ def translate_plural_message(klass, arg1, arg2, arg3 = "|", arg4 = "|")
+ klass = ClassInfo.normalize_class(klass)
+ # parse arguments
+ if arg1.kind_of?(Array)
+ msgid = arg1[0]
+ msgid_plural = arg1[1]
+ n = arg2
+ if arg3 and arg3.kind_of? Numeric
+ raise ArgumentError, _("3rd parmeter is wrong: value = %{number}") % {:number => arg3}
+ end
+ div = arg3
+ else
+ msgid = arg1
+ msgid_plural = arg2
+ n = arg3
+ div = arg4
+ end
+
+ key = [Locale.current, klass, msgid, msgid_plural, div].hash
+ msgs = @@plural_message_cache[key]
+ unless (msgs and @@cached)
+ # Find messages from related classes.
+ msgs = nil
+ each_textdomains(klass) do |textdomain, lang|
+ msgs = textdomain.translate_plural_message(lang, msgid, msgid_plural)
+ break if msgs
+ end
+
+ msgs = [[msgid, msgid_plural], TextDomain::DEFAULT_PLURAL_CALC] unless msgs
+
+ msgstrs = msgs[0]
+ if div and msgstrs[0] == msgid and index = msgstrs[0].rindex(div)
+ msgstrs[0] = msgstrs[0][(index + 1)..-1]
+ end
+ @@plural_message_cache[key] = msgs
+ end
+
+ # Return the singular or plural message.
+ msgstrs = msgs[0]
+ plural = msgs[1].call(n)
+ return msgstrs[plural] if plural.kind_of?(Numeric)
+ return plural ? msgstrs[1] : msgstrs[0]
+ end
+
+ # for testing.
+ def clear_all_textdomains
+ @@textdomain_pool = {}
+ @@textdomain_group_pool = {}
+ @@gettext_classes = []
+ clear_caches
+ end
+
+ # for testing.
+ def clear_caches
+ @@singular_message_cache = {}
+ @@plural_message_cache = {}
+ end
+
+ def create_or_find_textdomain_group(klass) #:nodoc:
+ group = @@textdomain_group_pool[klass]
+ return group if group
+
+ @@textdomain_group_pool[klass] = TextDomainGroup.new
+ end
+
+ def create_or_find_textdomain(name, path, charset)#:nodoc:
+ textdomain = @@textdomain_pool[name]
+ return textdomain if textdomain
+
+ @@textdomain_pool[name] = TextDomain.new(name, path, charset)
+ end
+ end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/tools.rb b/vendor/gems/gettext-2.1.0/lib/gettext/tools.rb
new file mode 100644
index 000000000..d0ccd8dd9
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/tools.rb
@@ -0,0 +1,195 @@
+=begin
+ tools.rb - Utility functions
+
+ Copyright (C) 2005-2008 Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+=end
+
+require 'rbconfig'
+if /mingw|mswin|mswin32/ =~ RUBY_PLATFORM
+ ENV['PATH'] = %w(bin lib).collect{|dir|
+ "#{Config::CONFIG["prefix"]}\\lib\\GTK\\#{dir};"
+ }.join('') + ENV['PATH']
+end
+
+require 'gettext/tools/rgettext'
+require 'gettext/tools/rmsgfmt'
+require 'gettext/runtime/mofile'
+require 'fileutils'
+
+module GetText
+ bindtextdomain "rgettext"
+
+ BOM_UTF8 = [0xef, 0xbb, 0xbf].pack("c3")
+
+ # Currently, GNU msgmerge doesn't accept BOM.
+ # This mesthod remove the UTF-8 BOM from the po-file.
+ 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
+
+ # 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
+ 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
+
+ # 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.
+ 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
+
+
+ # 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(http://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)
+ 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
+
+ private
+
+ # Merge 2 po files, using msgmerge
+ def merge_po_files(po_a,po_b,msgmerge_options=[],verbose=false)
+ return File.read(po_b) unless FileTest.exist? po_a
+
+ cmd = ENV["MSGMERGE_PATH"] || "msgmerge"
+ ensure_command_exists(cmd)
+
+ remove_bom(po_a)
+
+ cmd_params = array_to_cli_options(msgmerge_options)
+ to_run = "#{cmd} #{cmd_params} #{po_a} #{po_b}"
+ puts "\nrunning #{to_run}" if verbose
+ `#{to_run}`
+ end
+
+ # convert an array of String/Symbol to cli options
+ def array_to_cli_options(array)
+ [*array].map do |o|
+ o.kind_of?(Symbol) ? "--#{o}".gsub('_','-') : o.to_s
+ end.join(' ')
+ end
+
+ def ensure_command_exists(cmd)
+ `#{cmd} --help`
+ unless $? && $?.success?
+ raise _("`%{cmd}' can not be found. \nInstall GNU Gettext then set PATH or MSGMERGE_PATH correctly.") % {:cmd => cmd}
+ end
+ end
+
+ # where lies the mo file for a given po_file
+ # generare directory unless it exists
+ def mo_file_from_po_file(po_file,options)
+ options = {
+ :mo_root => "./data/locale",
+ :mo_path_rule => "%{lang}/LC_MESSAGES"
+ }.merge(options)
+
+ lang, textdomain = %r[/([^/]+?)/(.*)\.po].match(po_file[options[:po_root].size..-1]).to_a[1,2]
+
+ mo_dir_rule = File.join(options[:mo_root], options[:mo_path_rule])
+ mo_dir = mo_dir_rule % {:lang => lang}
+ File.join(mo_dir, "#{textdomain}.mo")
+ end
+end
+
+if __FILE__ == $0
+ GetText.update_pofiles("foo", ARGV, "foo 1.1.0")
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/erb.rb b/vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/erb.rb
new file mode 100644
index 000000000..0aee9d461
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/erb.rb
@@ -0,0 +1,52 @@
+=begin
+ parser/erb.rb - parser for ERB
+
+ Copyright (C) 2005-2009 Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+=end
+
+require 'erb'
+require 'gettext/tools/parser/ruby'
+
+module GetText
+ module ErbParser
+ extend self
+
+ @config = {
+ :extnames => ['.rhtml', '.erb']
+ }
+
+ # Sets some preferences to parse ERB files.
+ # * config: a Hash of the config. It can takes some values below:
+ # * :extnames: An Array of target files extension. Default is [".rhtml"].
+ def init(config)
+ config.each{|k, v|
+ @config[k] = v
+ }
+ end
+
+ def parse(file, targets = []) # :nodoc:
+ src = ERB.new(IO.readlines(file).join).src
+ # Remove magic comment prepended by erb in Ruby 1.9.
+ src.sub!(/\A#.*?coding[:=].*?\n/, '') if src.respond_to?(:encode)
+ erb = src.split(/$/)
+ RubyParser.parse_lines(file, erb, targets)
+ end
+
+ def target?(file) # :nodoc:
+ @config[:extnames].each do |v|
+ return true if File.extname(file) == v
+ end
+ false
+ end
+ end
+end
+
+if __FILE__ == $0
+ # ex) ruby glade.rhtml foo.rhtml bar.rhtml
+ ARGV.each do |file|
+ p GetText::ErbParser.parse(file)
+ end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/glade.rb b/vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/glade.rb
new file mode 100644
index 000000000..ab77beede
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/glade.rb
@@ -0,0 +1,98 @@
+=begin
+ parser/glade.rb - parser for Glade-2
+
+ Copyright (C) 2004,2005 Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+=end
+
+require 'cgi'
+require 'gettext'
+
+module GetText
+ module GladeParser
+ extend GetText
+ extend self
+
+ bindtextdomain("rgettext")
+
+ TARGET1 = /<property.*translatable="yes">(.*)/
+ TARGET2 = /(.*)<\/property>/
+
+ def parse(file, targets = []) # :nodoc:
+ lines = IO.readlines(file)
+ parse_lines(file, lines, targets)
+ end
+
+ #from ary of lines.
+ def parse_lines(file, lines, targets) # :nodoc:
+ cnt = 0
+ target = false
+ line_no = 0
+ val = nil
+
+ loop do
+ line = lines.shift
+ break unless line
+
+ cnt += 1
+ if TARGET1 =~ line
+ line_no = cnt
+ val = $1 + "\n"
+ target = true
+ if TARGET2 =~ $1
+ val = $1
+ add_target(val, file, line_no, targets)
+ val = nil
+ target = false
+ end
+ elsif target
+ if TARGET2 =~ line
+ val << $1
+ add_target(val, file, line_no, targets)
+ val = nil
+ target = false
+ else
+ val << line
+ end
+ end
+ end
+ targets
+ end
+
+ XML_RE = /<\?xml/
+ GLADE_RE = /glade-2.0.dtd/
+
+ def target?(file) # :nodoc:
+ data = IO.readlines(file)
+ if XML_RE =~ data[0] and GLADE_RE =~ data[1]
+ true
+ else
+ if File.extname(file) == '.glade'
+ raise _("`%{file}' is not glade-2.0 format.") % {:file => file}
+ end
+ false
+ end
+ end
+
+ def add_target(val, file, line_no, targets) # :nodoc:
+ return unless val.size > 0
+ assoc_data = targets.assoc(val)
+ val = CGI.unescapeHTML(val)
+ if assoc_data
+ targets[targets.index(assoc_data)] = assoc_data << "#{file}:#{line_no}"
+ else
+ targets << [val.gsub(/\n/, '\n'), "#{file}:#{line_no}"]
+ end
+ targets
+ end
+ end
+end
+
+if __FILE__ == $0
+ # ex) ruby glade.rb foo.glade bar.glade
+ ARGV.each do |file|
+ p GetText::GladeParser.parse(file)
+ end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/ruby.rb b/vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/ruby.rb
new file mode 100644
index 000000000..9d16401ce
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/tools/parser/ruby.rb
@@ -0,0 +1,226 @@
+#!/usr/bin/ruby
+=begin
+ parser/ruby.rb - parser for ruby script
+
+ Copyright (C) 2003-2009 Masao Mutoh
+ Copyright (C) 2005 speakillof
+ Copyright (C) 2001,2002 Yasushi Shoji, Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+
+=end
+
+require 'irb/ruby-lex.rb'
+require 'stringio'
+require 'gettext/tools/pomessage'
+
+module GetText
+ class RubyLexX < RubyLex # :nodoc: all
+ # Parser#parse resemlbes RubyLex#lex
+ def parse
+ until ( (tk = token).kind_of?(RubyToken::TkEND_OF_SCRIPT) && !@continue or tk.nil? )
+ s = get_readed
+ if RubyToken::TkSTRING === tk
+ def tk.value
+ @value
+ end
+
+ def tk.value=(s)
+ @value = s
+ end
+
+ if @here_header
+ s = s.sub(/\A.*?\n/, '').sub(/^.*\n\Z/, '')
+ else
+ begin
+ s = eval(s)
+ rescue Exception
+ # Do nothing.
+ end
+ end
+
+ tk.value = s
+ end
+
+ if $DEBUG
+ if tk.is_a? TkSTRING
+ $stderr.puts("#{tk}: #{tk.value}")
+ elsif tk.is_a? TkIDENTIFIER
+ $stderr.puts("#{tk}: #{tk.name}")
+ else
+ $stderr.puts(tk)
+ end
+ end
+
+ yield tk
+ end
+ return nil
+ end
+
+ # Original parser does not keep the content of the comments,
+ # so monkey patching this with new token type and extended
+ # identify_comment implementation
+ RubyToken.def_token :TkCOMMENT_WITH_CONTENT, TkVal
+
+ def identify_comment
+ @ltype = "#"
+ get_readed # skip the hash sign itself
+
+ while ch = getc
+ if ch == "\n"
+ @ltype = nil
+ ungetc
+ break
+ end
+ end
+ return Token(TkCOMMENT_WITH_CONTENT, get_readed)
+ end
+
+ end
+
+ # Extends PoMessage for RubyParser.
+ # Implements a sort of state machine to assist the parser.
+ module PoMessageForRubyParser
+ # Supports parsing by setting attributes by and by.
+ def set_current_attribute(str)
+ param = @param_type[@param_number]
+ raise ParseError, 'no more string parameters expected' unless param
+ set_value(param, str)
+ end
+
+ def init_param
+ @param_number = 0
+ self
+ end
+
+ def advance_to_next_attribute
+ @param_number += 1
+ end
+ end
+ class PoMessage
+ include PoMessageForRubyParser
+ alias :initialize_old :initialize
+ def initialize(type)
+ initialize_old(type)
+ init_param
+ end
+ end
+
+ module RubyParser
+ extend self
+
+ ID = ['gettext', '_', 'N_', 'sgettext', 's_']
+ PLURAL_ID = ['ngettext', 'n_', 'Nn_', 'ns_', 'nsgettext']
+ MSGCTXT_ID = ['pgettext', 'p_']
+ MSGCTXT_PLURAL_ID = ['npgettext', 'np_']
+
+ # (Since 2.1.0) the 2nd parameter is deprecated
+ # (and ignored here).
+ # And You don't need to keep the pomessages as unique.
+
+ def parse(path, deprecated = []) # :nodoc:
+ lines = IO.readlines(path)
+ parse_lines(path, lines, deprecated)
+ end
+
+ def parse_lines(path, lines, deprecated = []) # :nodoc:
+ pomessages = deprecated
+ file = StringIO.new(lines.join + "\n")
+ rl = RubyLexX.new
+ rl.set_input(file)
+ rl.skip_space = true
+ #rl.readed_auto_clean_up = true
+
+ pomessage = nil
+ line_no = nil
+ last_comment = ''
+ reset_comment = false
+ rl.parse do |tk|
+ begin
+ case tk
+ when RubyToken::TkIDENTIFIER, RubyToken::TkCONSTANT
+ store_pomessage(pomessages, pomessage, path, line_no, last_comment)
+ if ID.include?(tk.name)
+ pomessage = PoMessage.new(:normal)
+ elsif PLURAL_ID.include?(tk.name)
+ pomessage = PoMessage.new(:plural)
+ elsif MSGCTXT_ID.include?(tk.name)
+ pomessage = PoMessage.new(:msgctxt)
+ elsif MSGCTXT_PLURAL_ID.include?(tk.name)
+ pomessage = PoMessage.new(:msgctxt_plural)
+ else
+ pomessage = nil
+ end
+ line_no = tk.line_no.to_s
+ when RubyToken::TkSTRING
+ pomessage.set_current_attribute tk.value if pomessage
+ when RubyToken::TkPLUS, RubyToken::TkNL
+ #do nothing
+ when RubyToken::TkCOMMA
+ pomessage.advance_to_next_attribute if pomessage
+ else
+ if store_pomessage(pomessages, pomessage, path, line_no, last_comment)
+ pomessage = nil
+ end
+ end
+ rescue
+ $stderr.print "\n\nError"
+ $stderr.print " parsing #{path}:#{tk.line_no}\n\t #{lines[tk.line_no - 1]}" if tk
+ $stderr.print "\n #{$!.inspect} in\n"
+ $stderr.print $!.backtrace.join("\n")
+ $stderr.print "\n"
+ exit 1
+ end
+
+ case tk
+ when RubyToken::TkCOMMENT_WITH_CONTENT
+ last_comment = "" if reset_comment
+ if last_comment.empty?
+ # new comment from programmer to translator?
+ comment1 = tk.value.lstrip
+ if comment1 =~ /^TRANSLATORS\:/
+ last_comment = $'
+ end
+ else
+ last_comment += "\n"
+ last_comment += tk.value
+ end
+ reset_comment = false
+ when RubyToken::TkNL
+ else
+ reset_comment = true
+ end
+ end
+ pomessages
+ end
+
+ def target?(file) # :nodoc:
+ true # always true, as the default parser.
+ end
+
+ private
+ def store_pomessage(pomessages, pomessage, file_name, line_no, last_comment) #:nodoc:
+ if pomessage && pomessage.msgid
+ pomessage.sources << file_name + ":" + line_no
+ pomessage.add_comment(last_comment) unless last_comment.empty?
+ pomessages << pomessage
+ true
+ else
+ false
+ end
+ end
+ end
+end
+
+if __FILE__ == $0
+ require 'pp'
+ ARGV.each do |path|
+ pp GetText::RubyParser.parse(path)
+ end
+
+ #rl = GetText::RubyLexX.new; rl.set_input(ARGF)
+ #rl.parse do |tk|
+ #p tk
+ #end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/tools/pomessage.rb b/vendor/gems/gettext-2.1.0/lib/gettext/tools/pomessage.rb
new file mode 100644
index 000000000..b5efe7221
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/tools/pomessage.rb
@@ -0,0 +1,197 @@
+module GetText
+ class ParseError < StandardError
+ end
+
+ # Contains data related to the expression or sentence that
+ # is to be translated.
+ class PoMessage
+ PARAMS = {
+ :normal => [:msgid],
+ :plural => [:msgid, :msgid_plural],
+ :msgctxt => [:msgctxt, :msgid],
+ :msgctxt_plural => [:msgctxt, :msgid, :msgid_plural]
+ }
+
+ @@max_line_length = 70
+
+ # Sets the max line length.
+ def self.max_line_length=(len)
+ @@max_line_length = len
+ end
+
+ # Gets the max line length.
+ def self.max_line_length
+ @@max_line_length
+ end
+
+ # Required
+ attr_accessor :type # :normal, :plural, :msgctxt, :msgctxt_plural
+ attr_accessor :msgid
+ # Options
+ attr_accessor :msgid_plural
+ attr_accessor :msgctxt
+ attr_accessor :sources # ["file1:line1", "file2:line2", ...]
+ attr_accessor :comment
+
+ # Create the object. +type+ should be :normal, :plural, :msgctxt or :msgctxt_plural.
+ def initialize(type)
+ @type = type
+ @sources = []
+ @param_type = PARAMS[@type]
+ end
+
+ # Support for extracted comments. Explanation s.
+ # http://www.gnu.org/software/gettext/manual/gettext.html#Names
+ def add_comment(new_comment)
+ if (new_comment and ! new_comment.empty?)
+ @comment ||= ""
+ @comment += new_comment
+ end
+ to_s
+ end
+
+ # Returns a parameter representation suitable for po-files
+ # and other purposes.
+ def escaped(param_name)
+ orig = self.send param_name
+ orig.gsub(/"/, '\"').gsub(/\r/, '')
+ end
+
+ # Checks if the other translation target is mergeable with
+ # the current one. Relevant are msgid and translation context (msgctxt).
+ def ==(other)
+ other.msgid == self.msgid && other.msgctxt == self.msgctxt
+ end
+
+ # Merges two translation targets with the same msgid and returns the merged
+ # result. If one is declared as plural and the other not, then the one
+ # with the plural wins.
+ def merge(other)
+ return self unless other
+ raise ParseError, "Translation targets do not match: \n" \
+ " self: #{self.inspect}\n other: '#{other.inspect}'" unless self == other
+ if other.msgid_plural && !self.msgid_plural
+ res = other
+ unless (res.sources.include? self.sources[0])
+ res.sources += self.sources
+ res.add_comment(self.comment)
+ end
+ else
+ res = self
+ unless (res.sources.include? other.sources[0])
+ res.sources += other.sources
+ res.add_comment(other.comment)
+ end
+ end
+ res
+ end
+
+ # Output the po message for the po-file.
+ def to_po_str
+ raise "msgid is nil." unless @msgid
+ raise "sources is nil." unless @sources
+
+ str = ""
+ # extracted comments
+ if comment
+ comment.split("\n").each do |comment_line|
+ str << "\n#. #{comment_line.strip}"
+ end
+ end
+
+ # references
+ curr_pos = @@max_line_length
+ sources.each do |e|
+ if curr_pos + e.size > @@max_line_length
+ str << "\n#:"
+ curr_pos = 3
+ else
+ curr_pos += (e.size + 1)
+ end
+ str << " " << e
+ end
+
+ # msgctxt, msgid, msgstr
+ str << "\nmsgctxt \"" << msgctxt << "\"" if msgctxt?
+ str << "\nmsgid \"" << escaped(:msgid) << "\"\n"
+ if plural?
+ str << "msgid_plural \"" << escaped(:msgid_plural) << "\"\n"
+ str << "msgstr[0] \"\"\n"
+ str << "msgstr[1] \"\"\n"
+ else
+ str << "msgstr \"\"\n"
+ end
+ str
+ end
+
+ # Returns true if the type is kind of msgctxt.
+ # And if this is a kind of msgctxt and msgctxt property
+ # is nil, then raise an RuntimeException.
+ def msgctxt?
+ if [:msgctxt, :msgctxt_plural].include? @type
+ raise "This PoMessage is a kind of msgctxt but the msgctxt property is nil. msgid: #{msgid}" unless @msgctxt
+ true
+ end
+ end
+
+ # Returns true if the type is kind of plural.
+ # And if this is a kind of plural and msgid_plural property
+ # is nil, then raise an RuntimeException.
+ def plural?
+ if [:plural, :msgctxt_plural].include? @type
+ raise "This PoMessage is a kind of plural but the msgid_plural property is nil. msgid: #{msgid}" unless @msgid_plural
+ true
+ end
+ end
+
+ private
+
+ # sets or extends the value of a translation target params like msgid,
+ # msgctxt etc.
+ # param is symbol with the name of param
+ # value - new value
+ def set_value(param, value)
+ send "#{param}=", (send(param) || '') + value.gsub(/\n/, '\n')
+ end
+
+ public
+ # For backward comatibility. This doesn't support "comment".
+ # ary = [msgid1, "file1:line1", "file2:line"]
+ def self.new_from_ary(ary)
+ ary = ary.dup
+ msgid = ary.shift
+ sources = ary
+ type = :normal
+ msgctxt = nil
+ msgid_plural = nil
+
+ if msgid.include? "\004"
+ msgctxt, msgid = msgid.split(/\004/)
+ type = :msgctxt
+ end
+ if msgid.include? "\000"
+ ids = msgid.split(/\000/)
+ msgid = ids[0]
+ msgid_plural = ids[1]
+ if type == :msgctxt
+ type = :msgctxt_plural
+ else
+ type = :plural
+ end
+ end
+ ret = self.new(type)
+ ret.msgid = msgid
+ ret.sources = sources
+ ret.msgctxt = msgctxt
+ ret.msgid_plural = msgid_plural
+ ret
+ end
+
+ def [](number)
+ param = @param_type[number]
+ raise ParseError, 'no more string parameters expected' unless param
+ send param
+ end
+ end
+
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/tools/poparser.rb b/vendor/gems/gettext-2.1.0/lib/gettext/tools/poparser.rb
new file mode 100644
index 000000000..827a99c2f
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/tools/poparser.rb
@@ -0,0 +1,356 @@
+=begin
+ poparser.rb - Generate a .mo
+
+ Copyright (C) 2003-2009 Masao Mutoh <mutomasa at gmail.com>
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby.
+=end
+
+#
+# DO NOT MODIFY!!!!
+# This file is automatically generated by Racc 1.4.6
+# from Racc grammer file "".
+#
+
+require 'racc/parser.rb'
+module GetText
+ class PoParser < Racc::Parser
+
+module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 108)
+ include GetText
+ GetText.bindtextdomain("rgettext")
+
+ def unescape(orig)
+ ret = orig.gsub(/\\n/, "\n")
+ ret.gsub!(/\\t/, "\t")
+ ret.gsub!(/\\r/, "\r")
+ ret.gsub!(/\\"/, "\"")
+ ret
+ end
+
+ def parse(str, data, ignore_fuzzy = true)
+ @comments = []
+ @data = data
+ @fuzzy = false
+ @msgctxt = ""
+ $ignore_fuzzy = ignore_fuzzy
+
+ str.strip!
+ @q = []
+ until str.empty? do
+ case str
+ when /\A\s+/
+ str = $'
+ when /\Amsgctxt/
+ @q.push [:MSGCTXT, $&]
+ str = $'
+ when /\Amsgid_plural/
+ @q.push [:MSGID_PLURAL, $&]
+ str = $'
+ when /\Amsgid/
+ @q.push [:MSGID, $&]
+ str = $'
+ when /\Amsgstr/
+ @q.push [:MSGSTR, $&]
+ str = $'
+ when /\A\[(\d+)\]/
+ @q.push [:PLURAL_NUM, $1]
+ str = $'
+ when /\A\#~(.*)/
+ $stderr.print _("Warning: obsolete msgid exists.\n")
+ $stderr.print " #{$&}\n"
+ @q.push [:COMMENT, $&]
+ str = $'
+ when /\A\#(.*)/
+ @q.push [:COMMENT, $&]
+ str = $'
+ when /\A\"(.*)\"/
+ @q.push [:STRING, $1]
+ str = $'
+ else
+ #c = str[0,1]
+ #@q.push [:STRING, c]
+ str = str[1..-1]
+ end
+ end
+ @q.push [false, '$end']
+ if $DEBUG
+ @q.each do |a,b|
+ puts "[#{a}, #{b}]"
+ end
+ end
+ @yydebug = true if $DEBUG
+ do_parse
+
+ if @comments.size > 0
+ @data.set_comment(:last, @comments.join("\n"))
+ end
+ @data
+ end
+
+ def next_token
+ @q.shift
+ end
+
+ def on_message(msgid, msgstr)
+ if msgstr.size > 0
+ @data[msgid] = msgstr
+ @data.set_comment(msgid, @comments.join("\n"))
+ end
+ @comments.clear
+ @msgctxt = ""
+ end
+
+ def on_comment(comment)
+ @fuzzy = true if (/fuzzy/ =~ comment)
+ @comments << comment
+ end
+
+ def parse_file(po_file, data, ignore_fuzzy = true)
+ args = [ po_file ]
+ # In Ruby 1.9, we must detect proper encoding of a PO file.
+ if String.instance_methods.include?(:encode)
+ encoding = detect_file_encoding(po_file)
+ args << "r:#{encoding}"
+ end
+ @po_file = po_file
+ parse(File.open(*args) {|io| io.read }, data, ignore_fuzzy)
+ end
+
+ def detect_file_encoding(po_file)
+ open(po_file, :encoding => 'ASCII-8BIT') do |input|
+ input.lines.each do |line|
+ return Encoding.find($1) if %r["Content-Type:.*\scharset=(.*)\\n"] =~ line
+ end
+ end
+ Encoding.default_external
+ end
+ private :detect_file_encoding
+...end poparser.ry/module_eval...
+##### State transition tables begin ###
+
+racc_action_table = [
+ 3, 13, 5, 7, 9, 15, 16, 17, 20, 17,
+ 13, 17, 13, 13, 11, 17, 23, 20, 13, 17 ]
+
+racc_action_check = [
+ 1, 16, 1, 1, 1, 12, 12, 12, 18, 18,
+ 7, 14, 15, 9, 3, 19, 20, 21, 23, 25 ]
+
+racc_action_pointer = [
+ nil, 0, nil, 14, nil, nil, nil, 3, nil, 6,
+ nil, nil, 0, nil, 4, 5, -6, nil, 2, 8,
+ 8, 11, nil, 11, nil, 12 ]
+
+racc_action_default = [
+ -1, -16, -2, -16, -3, -13, -4, -16, -6, -16,
+ -7, 26, -16, -15, -5, -16, -16, -14, -16, -8,
+ -16, -9, -11, -16, -10, -12 ]
+
+racc_goto_table = [
+ 12, 22, 14, 4, 24, 6, 2, 8, 18, 19,
+ 10, 21, 1, nil, nil, nil, 25 ]
+
+racc_goto_check = [
+ 5, 9, 5, 3, 9, 4, 2, 6, 5, 5,
+ 7, 8, 1, nil, nil, nil, 5 ]
+
+racc_goto_pointer = [
+ nil, 12, 5, 2, 4, -7, 6, 9, -7, -17 ]
+
+racc_goto_default = [
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ]
+
+racc_reduce_table = [
+ 0, 0, :racc_error,
+ 0, 10, :_reduce_none,
+ 2, 10, :_reduce_none,
+ 2, 10, :_reduce_none,
+ 2, 10, :_reduce_none,
+ 2, 12, :_reduce_5,
+ 1, 13, :_reduce_none,
+ 1, 13, :_reduce_none,
+ 4, 15, :_reduce_8,
+ 5, 16, :_reduce_9,
+ 2, 17, :_reduce_10,
+ 1, 17, :_reduce_none,
+ 3, 18, :_reduce_12,
+ 1, 11, :_reduce_13,
+ 2, 14, :_reduce_14,
+ 1, 14, :_reduce_15 ]
+
+racc_reduce_n = 16
+
+racc_shift_n = 26
+
+racc_token_table = {
+ false => 0,
+ :error => 1,
+ :COMMENT => 2,
+ :MSGID => 3,
+ :MSGCTXT => 4,
+ :MSGID_PLURAL => 5,
+ :MSGSTR => 6,
+ :STRING => 7,
+ :PLURAL_NUM => 8 }
+
+racc_nt_base = 9
+
+racc_use_result_var = true
+
+Racc_arg = [
+ racc_action_table,
+ racc_action_check,
+ racc_action_default,
+ racc_action_pointer,
+ racc_goto_table,
+ racc_goto_check,
+ racc_goto_default,
+ racc_goto_pointer,
+ racc_nt_base,
+ racc_reduce_table,
+ racc_token_table,
+ racc_shift_n,
+ racc_reduce_n,
+ racc_use_result_var ]
+
+Racc_token_to_s_table = [
+ "$end",
+ "error",
+ "COMMENT",
+ "MSGID",
+ "MSGCTXT",
+ "MSGID_PLURAL",
+ "MSGSTR",
+ "STRING",
+ "PLURAL_NUM",
+ "$start",
+ "msgfmt",
+ "comment",
+ "msgctxt",
+ "message",
+ "string_list",
+ "single_message",
+ "plural_message",
+ "msgstr_plural",
+ "msgstr_plural_line" ]
+
+Racc_debug_parser = true
+
+##### State transition tables end #####
+
+# reduce 0 omitted
+
+# reduce 1 omitted
+
+# reduce 2 omitted
+
+# reduce 3 omitted
+
+# reduce 4 omitted
+
+module_eval(<<'.,.,', 'poparser.ry', 23)
+ def _reduce_5(val, _values, result)
+ @msgctxt = unescape(val[1]) + "\004"
+
+ result
+ end
+.,.,
+
+# reduce 6 omitted
+
+# reduce 7 omitted
+
+module_eval(<<'.,.,', 'poparser.ry', 35)
+ def _reduce_8(val, _values, result)
+ if @fuzzy and $ignore_fuzzy
+ if val[1] != ""
+ $stderr.print _("Warning: fuzzy message was ignored.\n")
+ $stderr.print " #{@po_file}: msgid '#{val[1]}'\n"
+ else
+ on_message('', unescape(val[3]))
+ end
+ @fuzzy = false
+ else
+ on_message(@msgctxt + unescape(val[1]), unescape(val[3]))
+ end
+ result = ""
+
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'poparser.ry', 52)
+ def _reduce_9(val, _values, result)
+ if @fuzzy and $ignore_fuzzy
+ if val[1] != ""
+ $stderr.print _("Warning: fuzzy message was ignored.\n")
+ $stderr.print "msgid = '#{val[1]}\n"
+ else
+ on_message('', unescape(val[3]))
+ end
+ @fuzzy = false
+ else
+ on_message(@msgctxt + unescape(val[1]) + "\000" + unescape(val[3]), unescape(val[4]))
+ end
+ result = ""
+
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'poparser.ry', 70)
+ def _reduce_10(val, _values, result)
+ if val[0].size > 0
+ result = val[0] + "\000" + val[1]
+ else
+ result = ""
+ end
+
+ result
+ end
+.,.,
+
+# reduce 11 omitted
+
+module_eval(<<'.,.,', 'poparser.ry', 82)
+ def _reduce_12(val, _values, result)
+ result = val[2]
+
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'poparser.ry', 89)
+ def _reduce_13(val, _values, result)
+ on_comment(val[0])
+
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'poparser.ry', 97)
+ def _reduce_14(val, _values, result)
+ result = val.delete_if{|item| item == ""}.join
+
+ result
+ end
+.,.,
+
+module_eval(<<'.,.,', 'poparser.ry', 101)
+ def _reduce_15(val, _values, result)
+ result = val[0]
+
+ result
+ end
+.,.,
+
+def _reduce_none(val, _values, result)
+ val[0]
+end
+
+ end # class PoParser
+ end # module GetText
+
+
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/tools/rgettext.rb b/vendor/gems/gettext-2.1.0/lib/gettext/tools/rgettext.rb
new file mode 100644
index 000000000..a66ed2fe0
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/tools/rgettext.rb
@@ -0,0 +1,226 @@
+#! /usr/bin/env ruby
+=begin
+ rgettext.rb - Generate a .pot file.
+
+ Copyright (C) 2003-2009 Masao Mutoh
+ Copyright (C) 2001,2002 Yasushi Shoji, Masao Mutoh
+
+ Yasushi Shoji <yashi at atmark-techno.com>
+ Masao Mutoh <mutomasa at gmail.com>
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+=end
+
+require 'optparse'
+require 'gettext'
+require 'rbconfig'
+
+module GetText
+
+ module RGetText #:nodoc:
+ extend GetText
+
+ bindtextdomain("rgettext")
+
+ # constant values
+ VERSION = GetText::VERSION
+
+ @ex_parsers = []
+ [
+ ["glade.rb", "GladeParser"],
+ ["erb.rb", "ErbParser"],
+# ["ripper.rb", "RipperParser"],
+ ["ruby.rb", "RubyParser"] # Default parser.
+ ].each do |f, klass|
+ begin
+ require "gettext/tools/parser/#{f}"
+ @ex_parsers << GetText.const_get(klass)
+ rescue
+ $stderr.puts _("'%{klass}' is ignored.") % {:klass => klass}
+ $stderr.puts $! if $DEBUG
+ end
+ end
+
+ module_function
+
+ # Add an option parser
+ # the option parser module requires to have target?(file) and parser(file, ary) method.
+ #
+ # require 'gettext/tools/rgettext'
+ # module FooParser
+ # module_function
+ # def target?(file)
+ # File.extname(file) == '.foo' # *.foo file only.
+ # end
+ # def parse(file, ary)
+ # :
+ # return ary # [["msgid1", "foo.rb:200"], ["msgid2", "bar.rb:300", "baz.rb:400"], ...]
+ # end
+ # end
+ #
+ # GetText::RGetText.add_parser(FooParser)
+ def add_parser(klass)
+ @ex_parsers.insert(0, klass)
+ end
+
+ def generate_pot_header # :nodoc:
+ time = Time.now.strftime("%Y-%m-%d %H:%M")
+ off = Time.now.utc_offset
+ sign = off <= 0 ? '-' : '+'
+ time += sprintf('%s%02d%02d', sign, *(off.abs / 60).divmod(60))
+
+ <<TITLE
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\\n"
+"POT-Creation-Date: #{time}\\n"
+"PO-Revision-Date: #{time}\\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
+"Language-Team: LANGUAGE <LL@li.org>\\n"
+"MIME-Version: 1.0\\n"
+"Content-Type: text/plain; charset=UTF-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n"
+TITLE
+ end
+
+ def generate_pot(paths) # :nodoc:
+ pomessages = parse(paths)
+ str = ""
+ pomessages.each do |target|
+ str << target.to_po_str
+ end
+ str
+ end
+
+ def parse(paths) # :nodoc:
+ pomessages = []
+ paths.each do |path|
+ begin
+ @ex_parsers.each do |klass|
+ if klass.target?(path)
+ if klass.method(:parse).arity == 1
+ targets = klass.parse(path)
+ else
+ # For backward compatibility.
+ targets = klass.parse(path, [])
+ end
+
+ targets.each{|pomessage|
+ if pomessage.kind_of? Array
+ pomessage = PoMessage.new_from_ary(pomessage)
+ end
+
+ # Save the previous target.
+ existing = pomessages.find_index {|t| t == pomessage}
+ if existing
+ pomessage = pomessages[existing].merge(pomessage)
+ pomessages[existing] = pomessage
+ else
+ pomessages << pomessage
+ end
+ }
+ break
+ end
+ end
+ rescue
+ puts _("Error parsing %{path}") % {:path => path}
+ raise
+ end
+ end
+ pomessages
+ end
+
+ def check_options # :nodoc:
+ output = STDOUT
+
+ opts = OptionParser.new
+ opts.banner = _("Usage: %s input.rb [-r parser.rb] [-o output.pot]") % $0
+ opts.separator("")
+ opts.separator(_("Extract translatable strings from given input files."))
+ opts.separator("")
+ opts.separator(_("Specific options:"))
+
+ opts.on("-o", "--output=FILE", _("write output to specified file")) do |out|
+ unless FileTest.exist? out
+ output = File.new(File.expand_path(out), "w+")
+ else
+ $stderr.puts(_("File '%s' already exists.") % out)
+ exit 1
+ end
+ end
+
+ opts.on("-r", "--require=library", _("require the library before executing rgettext")) do |out|
+ require out
+ end
+
+ opts.on("-d", "--debug", _("run in debugging mode")) do
+ $DEBUG = true
+ end
+
+ opts.on_tail("--version", _("display version information and exit")) do
+ puts "#{$0} #{VERSION}"
+ puts "#{File.join(Config::CONFIG["bindir"], Config::CONFIG["RUBY_INSTALL_NAME"])} #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
+ exit
+ end
+
+ opts.parse!(ARGV)
+
+ if ARGV.size == 0
+ puts opts.help
+ exit 1
+ end
+
+ [ARGV, output]
+ end
+
+ def run(paths = nil, out = STDOUT) # :nodoc:
+ if paths.is_a? String
+ paths = [paths]
+ elsif ! paths
+ paths, out = check_options
+ end
+
+ if paths.size == 0
+ raise ArgumentError, _("no input files")
+ end
+
+ if out.is_a? String
+ File.open(File.expand_path(out), "w+") do |file|
+ file.puts generate_pot_header
+ file.puts generate_pot(paths)
+ end
+ else
+ out.puts generate_pot_header
+ out.puts generate_pot(paths)
+ end
+ self
+ end
+ end
+ extend self
+ # 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
+ def rgettext(paths = nil, out = STDOUT)
+ RGetText.run(paths, out)
+ self
+ end
+end
+
+if $0 == __FILE__
+ GetText.rgettext
+# GetText.rgettext($0, "tmp.txt")
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/tools/rmsgfmt.rb b/vendor/gems/gettext-2.1.0/lib/gettext/tools/rmsgfmt.rb
new file mode 100644
index 000000000..2aa428c55
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/tools/rmsgfmt.rb
@@ -0,0 +1,84 @@
+=begin
+ rmsgfmt.rb - Generate a .mo
+
+ Copyright (C) 2003-2009 Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+=end
+
+require 'optparse'
+require 'fileutils'
+require 'gettext'
+require 'gettext/tools/poparser'
+require 'rbconfig'
+
+module GetText
+
+ module RMsgfmt #:nodoc:
+ extend GetText
+ extend self
+
+ bindtextdomain "rgettext"
+
+ def run(targetfile = nil, output_path = nil) # :nodoc:
+ unless targetfile
+ targetfile, output_path = check_options
+ end
+ unless targetfile
+ raise ArgumentError, _("no input files")
+ end
+ unless output_path
+ output_path = "messages.mo"
+ end
+
+ parser = PoParser.new
+ data = MOFile.new
+
+ parser.parse_file(targetfile, data)
+ data.save_to_file(output_path)
+ end
+
+ def check_options # :nodoc:
+ output = nil
+
+ opts = OptionParser.new
+ opts.banner = _("Usage: %s input.po [-o output.mo]" % $0)
+ opts.separator("")
+ opts.separator(_("Generate binary message catalog from textual translation description."))
+ opts.separator("")
+ opts.separator(_("Specific options:"))
+
+ opts.on("-o", "--output=FILE", _("write output to specified file")) do |out|
+ output = out
+ end
+
+ opts.on_tail("--version", _("display version information and exit")) do
+ puts "#{$0} #{GetText::VERSION}"
+ puts "#{File.join(Config::CONFIG["bindir"], Config::CONFIG["RUBY_INSTALL_NAME"])} #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
+ exit
+ end
+ opts.parse!(ARGV)
+
+ if ARGV.size == 0
+ puts opts.help
+ exit 1
+ end
+
+ [ARGV[0], output]
+ end
+ end
+
+ # 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.
+ def rmsgfmt(targetfile = nil, output_path = nil)
+ RMsgfmt.run(targetfile, output_path)
+ end
+end
+
+if $0 == __FILE__ then
+ GetText.rmsgfmt
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/tools/rmsgmerge.rb b/vendor/gems/gettext-2.1.0/lib/gettext/tools/rmsgmerge.rb
new file mode 100644
index 000000000..802ba20bc
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/tools/rmsgmerge.rb
@@ -0,0 +1,498 @@
+=begin
+ rmsgmerge.rb - Merge old .po to new .po
+
+ Copyright (C) 2005-2009 Masao Mutoh
+ Copyright (C) 2005,2006 speakillof
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+=end
+
+require 'optparse'
+require 'gettext'
+require 'gettext/tools/poparser'
+require 'rbconfig'
+
+module GetText
+
+ module RMsgMerge
+
+ class PoData #:nodoc:
+
+ attr_reader :msgids
+
+ def initialize
+ @msgid2msgstr = {}
+ @msgid2comment = {}
+ @msgids = []
+ end
+
+ def set_comment(msgid_or_sym, comment)
+ @msgid2comment[msgid_or_sym] = comment
+ end
+
+ def msgstr(msgid)
+ @msgid2msgstr[msgid]
+ end
+
+ def comment(msgid)
+ @msgid2comment[msgid]
+ end
+
+ def [](msgid)
+ @msgid2msgstr[msgid]
+ end
+
+ def []=(msgid, msgstr)
+ # Retain the order
+ unless @msgid2msgstr[msgid]
+ @msgids << msgid
+ end
+
+ @msgid2msgstr[msgid] = msgstr
+ end
+
+ def each_msgid
+ arr = @msgids.delete_if{|i| Symbol === i or i == ''}
+ arr.each do |i|
+ yield i
+ end
+ end
+
+ def msgid?(msgid)
+ !(Symbol === msgid) and @msgid2msgstr[msgid] and (msgid != '')
+ end
+
+ # Is it necessary to implement this method?
+ def search_msgid_fuzzy(msgid, used_msgids)
+ nil
+ end
+
+ def nplural
+ unless @msgid2msgstr['']
+ return 0
+ else
+ if /\s*nplural\s*=\s*(\d+)/ =~ @msgid2msgstr['']
+ return $1.to_i
+ else
+ return 0
+ end
+
+ end
+ end
+
+ def generate_po
+ str = ''
+ str << generate_po_header
+
+ self.each_msgid do |id|
+ str << self.generate_po_entry(id)
+ end
+
+ str << @msgid2comment[:last]
+ str
+ end
+
+ def generate_po_header
+ str = ""
+
+ str << @msgid2comment[''].strip << "\n"
+ str << 'msgid ""' << "\n"
+ str << 'msgstr ""' << "\n"
+ msgstr = @msgid2msgstr[''].gsub(/"/, '\"').gsub(/\r/, '')
+ msgstr = msgstr.gsub(/^(.*)$/, '"\1\n"')
+ str << msgstr
+ str << "\n"
+
+ str
+ end
+
+ def generate_po_entry(msgid)
+ str = ""
+ str << @msgid2comment[msgid]
+ if str[-1] != "\n"[0]
+ str << "\n"
+ end
+
+ id = msgid.gsub(/"/, '\"').gsub(/\r/, '')
+ msgstr = @msgid2msgstr[msgid].gsub(/"/, '\"').gsub(/\r/, '')
+
+ if id.include?("\000")
+ ids = id.split(/\000/)
+ str << "msgid " << __conv(ids[0]) << "\n"
+ ids[1..-1].each do |single_id|
+ str << "msgid_plural " << __conv(single_id) << "\n"
+ end
+
+ msgstr.split("\000").each_with_index do |m, n|
+ str << "msgstr[#{n}] " << __conv(m) << "\n"
+ end
+ else
+ str << "msgid " << __conv(id) << "\n"
+ str << "msgstr " << __conv(msgstr) << "\n"
+ end
+
+ str << "\n"
+ str
+ end
+
+ def __conv(str)
+ s = ''
+
+ if str.count("\n") > 1
+ s << '""' << "\n"
+ s << str.gsub(/^(.*)$/, '"\1\n"')
+ else
+ s << '"' << str.sub("\n", "\\n") << '"'
+ end
+
+ s.rstrip
+ end
+
+ end
+
+ class Merger #:nodoc:
+
+ # From GNU gettext source.
+ #
+ # Merge the reference with the definition: take the #. and
+ # #: comments from the reference, take the # comments from
+ # the definition, take the msgstr from the definition. Add
+ # this merged entry to the output message list.
+ DOT_COMMENT_RE = /\A#\./
+ SEMICOLON_COMMENT_RE = /\A#\:/
+ FUZZY_RE = /\A#\,/
+ NOT_SPECIAL_COMMENT_RE = /\A#([^:.,]|\z)/
+
+ CRLF_RE = /\r?\n/
+ POT_DATE_EXTRACT_RE = /POT-Creation-Date:\s*(.*)?\s*$/
+ POT_DATE_RE = /POT-Creation-Date:.*?$/
+
+ def merge(definition, reference)
+ # deep copy
+ result = Marshal.load( Marshal.dump(reference) )
+
+ used = []
+ merge_header(result, definition)
+
+ result.each_msgid do |msgid|
+ if definition.msgid?(msgid)
+ used << msgid
+ merge_message(msgid, result, msgid, definition)
+ elsif other_msgid = definition.search_msgid_fuzzy(msgid, used)
+ used << other_msgid
+ merge_fuzzy_message(msgid, result, other_msgid, definition)
+ elsif msgid.index("\000") and ( reference.msgstr(msgid).gsub("\000", '') == '' )
+ # plural
+ result[msgid] = "\000" * definition.nplural
+ else
+ change_reference_comment(msgid, result)
+ end
+ end
+
+ ###################################################################
+ # msgids which are not used in reference are handled as obsolete. #
+ ###################################################################
+ last_comment = result.comment(:last) || ''
+ definition.each_msgid do |msgid|
+ unless used.include?(msgid)
+ last_comment << "\n"
+ last_comment << definition.generate_po_entry(msgid).strip.gsub(/^/, '#. ')
+ last_comment << "\n"
+ end
+ end
+ result.set_comment(:last, last_comment)
+
+ result
+ end
+
+ def merge_message(msgid, target, def_msgid, definition)
+ merge_comment(msgid, target, def_msgid, definition)
+
+ ############################################
+ # check mismatch of msgid and msgid_plural #
+ ############################################
+ def_msgstr = definition[def_msgid]
+ if msgid.index("\000")
+ if def_msgstr.index("\000")
+ # OK
+ target[msgid] = def_msgstr
+ else
+ # NG
+ s = ''
+ definition.nplural.times {
+ s << def_msgstr
+ s << "\000"
+ }
+ target[msgid] = s
+ end
+ else
+ if def_msgstr.index("\000")
+ # NG
+ target[msgid] = def_msgstr.split("\000")[0]
+ else
+ # OK
+ target[msgid] = def_msgstr
+ end
+ end
+ end
+
+ # for the future
+ def merge_fuzzy_message(msgid, target, def_msgid, definition)
+ merge_message(msgid, target, def_msgid, definition)
+ end
+
+ def merge_comment(msgid, target, def_msgid, definition)
+ ref_comment = target.comment(msgid)
+ def_comment = definition.comment(def_msgid)
+
+ normal_comment = []
+ dot_comment = []
+ semi_comment = []
+ is_fuzzy = false
+
+ def_comment.split(CRLF_RE).each do |l|
+ if NOT_SPECIAL_COMMENT_RE =~ l
+ normal_comment << l
+ end
+ end
+
+ ref_comment.split(CRLF_RE).each do |l|
+ if DOT_COMMENT_RE =~ l
+ dot_comment << l
+ elsif SEMICOLON_COMMENT_RE =~ l
+ semi_comment << l
+ elsif FUZZY_RE =~ l
+ is_fuzzy = true
+ end
+ end
+
+ str = format_comment(normal_comment, dot_comment, semi_comment, is_fuzzy)
+ target.set_comment(msgid, str)
+ end
+
+ def change_reference_comment(msgid, podata)
+ normal_comment = []
+ dot_comment = []
+ semi_comment = []
+ is_fuzzy = false
+
+ podata.comment(msgid).split(CRLF_RE).each do |l|
+ if DOT_COMMENT_RE =~ l
+ dot_comment << l
+ elsif SEMICOLON_COMMENT_RE =~ l
+ semi_comment << l
+ elsif FUZZY_RE =~ l
+ is_fuzzy = true
+ else
+ normal_comment << l
+ end
+ end
+
+ str = format_comment(normal_comment, dot_comment, semi_comment, is_fuzzy)
+ podata.set_comment(msgid, str)
+ end
+
+ def format_comment(normal_comment, dot_comment, semi_comment, is_fuzzy)
+ str = ''
+
+ str << normal_comment.join("\n").gsub(/^#(\s*)/){|sss|
+ if $1 == ""
+ "# "
+ else
+ sss
+ end
+ }
+ if normal_comment.size > 0
+ str << "\n"
+ end
+
+ str << dot_comment.join("\n").gsub(/^#.(\s*)/){|sss|
+ if $1 == ""
+ "#. "
+ else
+ sss
+ end
+ }
+ if dot_comment.size > 0
+ str << "\n"
+ end
+
+ str << semi_comment.join("\n").gsub(/^#:\s*/, "#: ")
+ if semi_comment.size > 0
+ str << "\n"
+ end
+
+ if is_fuzzy
+ str << "#, fuzzy\n"
+ end
+
+ str
+ end
+
+ def merge_header(target, definition)
+ merge_comment('', target, '', definition)
+
+ msg = target.msgstr('')
+ def_msg = definition.msgstr('')
+ if POT_DATE_EXTRACT_RE =~ msg
+ time = $1
+ def_msg = def_msg.sub(POT_DATE_RE, "POT-Creation-Date: #{time}")
+ end
+
+ target[''] = def_msg
+ end
+
+ end
+
+ end
+
+end
+
+module GetText::RMsgMerge #:nodoc:
+
+ class Config #:nodoc:
+
+ attr_accessor :defpo, :refpot, :output, :fuzzy, :update
+
+ # update mode options
+ attr_accessor :backup, :suffix
+
+=begin
+The result is written back to def.po.
+ --backup=CONTROL make a backup of def.po
+ --suffix=SUFFIX override the usual backup suffix
+The version control method may be selected via the --backup option or through
+the VERSION_CONTROL environment variable. Here are the values:
+ none, off never make backups (even if --backup is given)
+ numbered, t make numbered backups
+ existing, nil numbered if numbered backups exist, simple otherwise
+ simple, never always make simple backups
+The backup suffix is `~', unless set with --suffix or the SIMPLE_BACKUP_SUFFIX
+environment variable.
+=end
+
+ def initialize
+ @output = STDOUT
+ @fuzzy = nil
+ @update = nil
+ @backup = ENV["VERSION_CONTROL"]
+ @suffix= ENV["SIMPLE_BACKUP_SUFFIX"] || "~"
+ @input_dirs = ["."]
+ end
+
+ end
+
+end
+
+module GetText
+
+ module RMsgMerge
+ extend GetText
+ extend self
+
+ bindtextdomain("rgettext")
+
+ # constant values
+ VERSION = GetText::VERSION
+ DATE = %w($Date: 2007/07/21 15:03:05 $)[1]
+
+ def check_options(config)
+ opts = OptionParser.new
+ opts.banner = _("Usage: %s def.po ref.pot [-o output.pot]") % $0
+ #opts.summary_width = 80
+ opts.separator("")
+ opts.separator(_("Merges two Uniforum style .po files together. The def.po file is an existing PO file with translations. The ref.pot file is the last created PO file with up-to-date source references. ref.pot is generally created by rgettext."))
+ opts.separator("")
+ opts.separator(_("Specific options:"))
+
+ opts.on("-o", "--output=FILE", _("write output to specified file")) do |out|
+ unless FileTest.exist? out
+ config.output = out
+ else
+ #$stderr.puts(_("File '%s' has already existed.") % out)
+ #exit 1
+ end
+ end
+
+ #opts.on("-F", "--fuzzy-matching")
+
+ opts.on_tail("--version", _("display version information and exit")) do
+ puts "#{$0} #{VERSION} (#{DATE})"
+ puts "#{File.join(::Config::CONFIG["bindir"], ::Config::CONFIG["RUBY_INSTALL_NAME"])} #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
+ exit
+ end
+
+ opts.parse!(ARGV)
+
+ if ARGV.size != 2
+ puts opts.help
+ exit 1
+ end
+
+ config.defpo = ARGV[0]
+ config.refpot = ARGV[1]
+ end
+
+ def run(reference = nil, definition = nil, out = STDOUT)
+ config = GetText::RMsgMerge::Config.new
+ config.refpot = reference
+ config.defpo = definition
+ config.output = out
+
+ check_options(config)
+
+ if config.defpo.nil?
+ raise ArgumentError, _("definition po is not given.")
+ elsif config.refpot.nil?
+ raise ArgumentError, _("reference pot is not given.")
+ end
+
+ parser = PoParser.new
+ defpo = parser.parse_file(config.defpo, PoData.new, false)
+ refpot = parser.parse_file(config.refstrrefstr, PoData.new, false)
+
+ m = Merger.new
+ result = m.merge(defpo, refpot)
+ p result if $DEBUG
+ print result.generate_po if $DEBUG
+
+ begin
+ if out.is_a? String
+ File.open(File.expand_path(out), "w+") do |file|
+ file.write(result.generate_po)
+ end
+ else
+ out.puts(result.generate_po)
+ end
+ ensure
+ out.close
+ end
+ end
+
+ end
+
+end
+
+
+
+module GetText
+
+ # Experimental
+ def rmsgmerge(reference = nil, definition = nil, out = STDOUT)
+ RMsgMerge.run(reference, definition, out)
+ end
+
+end
+
+
+
+if $0 == __FILE__ then
+ require 'pp'
+
+ #parser = GetText::RMsgMerge::PoParser.new;
+ #parser = GetText::PoParser.new;
+ #pp parser.parse(ARGF.read)
+
+ GetText.rmsgmerge
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/utils.rb b/vendor/gems/gettext-2.1.0/lib/gettext/utils.rb
new file mode 100644
index 000000000..e4f1be4e8
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/utils.rb
@@ -0,0 +1,37 @@
+=begin
+ utils.rb - Utility functions
+
+ Copyright (C) 2005,2006 Masao Mutoh
+
+ You may redistribute it and/or modify it under the same
+ license terms as Ruby or LGPL.
+=end
+
+require 'gettext/tools'
+
+warn "'gettext/utils.rb' is deprecated. Use gettext/tools.rb."
+
+module GetText
+
+ alias :create_mofiles_org :create_mofiles #:nodoc:
+ alias :update_pofiles_org :update_pofiles #:nodoc:
+
+
+ # Deprecated. Use gettext/tools instead.
+ def create_mofiles(verbose = false,
+ podir = "./po", targetdir = "./data/locale",
+ targetpath_rule = "%s/LC_MESSAGES") # :nodoc:
+ warn "'gettext/utils.rb' is deprecated. Use gettext/tools.rb."
+ create_mofiles_org(:verbose => verbose,
+ :po_root => podir,
+ :mo_root => targetdir,
+ :mo_root_rule => targetpath_rule)
+ end
+
+ # Deprecated. Use gettext/tools instead.
+ def update_pofiles(textdomain, files, app_version, po_root = "po", refpot = "tmp.pot") # :nodoc:
+ warn "'gettext/utils.rb' is deprecated. Use gettext/tools.rb."
+ options = {:po_root => po_root}
+ update_pofiles_org(textdomain, files, app_version, options)
+ end
+end
diff --git a/vendor/gems/gettext-2.1.0/lib/gettext/version.rb b/vendor/gems/gettext-2.1.0/lib/gettext/version.rb
new file mode 100644
index 000000000..c1de5bc07
--- /dev/null
+++ b/vendor/gems/gettext-2.1.0/lib/gettext/version.rb
@@ -0,0 +1,12 @@
+#! /usr/bin/ruby
+=begin
+ 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 or LGPL.
+=end
+module GetText
+ VERSION = "2.1.0"
+end