Commit 9c08077d authored by Hleb Valoshka's avatar Hleb Valoshka

Imported Upstream version 2.2.1

parent f90d75c4
......@@ -14,10 +14,10 @@
$:.unshift "./lib"
require "tempfile"
require 'rake'
require 'rubygems'
require "yard/rake/yardoc_task"
require 'rake/testtask'
require 'gettext/version'
require "bundler/gem_helper"
......@@ -34,37 +34,35 @@ PKG_VERSION = GetText::VERSION
############################################################
# GetText tasks for developing
############################################################
desc "Create lib/gettext/tools/poparser.rb"
task :poparser do
poparser_path = "lib/gettext/tools/poparser.rb"
racc = File.join(Config::CONFIG['bindir'], "racc")
if ! FileTest.exist?(racc)
puts "racc was not found: #{racc}"
exit 1
else FileTest.exist?(racc)
ruby "#{racc} -g src/poparser.ry -o src/poparser.tmp.rb"
$stderr.puts %Q[ruby #{racc} -g src/poparser.ry -o src/poparser.tmp.rb]
file = open(poparser_path, "w")
file.print "=begin\n"
file.print <<-EOS
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.
EOS
file.print "=end\n\n"
tmpfile = open("src/poparser.tmp.rb")
file.print tmpfile.read
file.close
tmpfile.close
File.delete("src/poparser.tmp.rb")
$stderr.puts "Create #{poparser_path}."
poparser_rb_path = "lib/gettext/tools/poparser.rb"
desc "Create #{poparser_rb_path}"
task :poparser => poparser_rb_path
poparser_ry_path = "src/poparser.ry"
file poparser_rb_path => poparser_ry_path do
racc = File.join(Gem.bindir, "racc")
tempfile = Tempfile.new("gettext-poparser")
command_line = "#{racc} -g #{poparser_ry_path} -o #{tempfile.path}"
ruby(command_line)
$stderr.puts("ruby #{command_line}")
File.open(poparser_rb_path, "w") do |poparser_rb|
poparser_rb.puts(<<-EOH)
# -*- coding: utf-8 -*-
#
# poparser.rb - Generate a .mo
#
# Copyright (C) 2003-2009 Masao Mutoh <mutomasa at gmail.com>
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
#
# You may redistribute it and/or modify it under the same
# license terms as Ruby or LGPL.
EOH
poparser_rb.puts(tempfile.read)
end
$stderr.puts "Create #{poparser_rb_path}."
end
......@@ -162,18 +160,60 @@ end
task :package => [:makemo]
############################################################
# Misc tasks
############################################################
namespace :test do
namespace :pot do
pot_base_dir = "test/pot"
directory pot_base_dir
pot_paths = []
ruby_base_paths = [
"non_ascii", "npgettext", "nsgettext",
"pgettext", "backslash",
]
ruby_paths = Dir.glob("test/testlib/{#{ruby_base_paths.join(',')}}.rb")
ruby_paths.each do |ruby_path|
pot_base_path = File.basename(ruby_path).sub(/\.rb\z/, ".pot")
pot_path = "#{pot_base_dir}/#{pot_base_path}"
pot_paths << pot_path
file pot_path => [pot_base_dir, ruby_path] do
require "gettext/tools"
GetText.rgettext(ruby_path, pot_path)
end
end
desc "Update pot files for testing"
task :update => pot_paths
end
namespace :mo do
mo_paths = []
language_paths = Dir.glob("test/po/*")
language_paths.each do |language_path|
language = File.basename(language_path)
po_paths = Dir.glob("#{language_path}/*.po")
po_paths.each do |po_path|
mo_base_path = File.basename(po_path).sub(/\.po\z/, ".mo")
mo_path = "test/locale/#{language}/LC_MESSAGES/#{mo_base_path}"
mo_paths << mo_path
file mo_path => [po_path, poparser_rb_path] do
require "gettext/tools"
GetText.rmsgfmt(po_path, mo_path)
end
end
end
desc "Update mo files for testing"
task :update => mo_paths
end
desc "Prepare test environment"
task :prepare => "test:mo:update"
end
desc 'Run all tests'
task :test do
Dir.chdir("test") do
if RUBY_PLATFORM =~ /win32/
sh "rake.bat", "test"
else
ruby "-S", "rake", "test"
end
end
task :test => "test:prepare" do
options = ARGV - Rake.application.top_level_tasks
ruby "test/run-test.rb", *options
end
YARD::Rake::YardocTask.new do |t|
......
......@@ -28,5 +28,8 @@ So you can use GNU GetText tools for maintaining.
end
s.add_runtime_dependency("locale")
s.add_development_dependency("racc")
s.add_development_dependency("yard")
s.add_development_dependency("test-unit")
s.add_development_dependency("test-unit-notify")
end
......@@ -20,64 +20,68 @@ class String
alias :bytesize :size
end
alias :_old_format_m :% # :nodoc:
begin
"%<key>" % {:key => "value"}
rescue ArgumentError
alias :_old_format_m :% # :nodoc:
PERCENT_MATCH_RE = Regexp.union(
/%%/,
/%\{(.+?)\}/,
/%<(.+?)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/
)
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
# 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
......
......@@ -20,7 +20,7 @@
require 'stringio'
module GetText
class MOFile < Hash
class MoFile < Hash
class InvalidFormat < RuntimeError; end;
attr_reader :filename
......@@ -122,23 +122,24 @@ module GetText
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)
msgids = 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])
msgids[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])
msgstr = io.read(trans_table_data[i * 2 + 0])
if (! original_strings[i]) || original_strings[i] == ""
if str
msgid = msgids[i]
if msgid.nil? || msgid.empty?
if msgstr
@charset = nil
@nplurals = nil
@plural = nil
str.each_line{|line|
msgstr.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
......@@ -151,11 +152,9 @@ module GetText
@plural = "0" unless @plural
end
else
if @charset and @output_charset
str = convert_encoding(str, original_strings[i])
end
msgstr = convert_encoding(msgstr, msgid)
end
self[original_strings[i]] = str.freeze
self[convert_encoding(msgid, msgid)] = msgstr.freeze
end
self
end
......@@ -303,6 +302,8 @@ module GetText
private
if "".respond_to?(:encode)
def convert_encoding(string, original_string)
return string if @output_charset.nil? or @charset.nil?
begin
string.encode(@output_charset, @charset)
rescue EncodingError
......@@ -331,6 +332,9 @@ module GetText
end
end
end
# Just for backward compatibility.
MOFile = MoFile
end
# Test
......@@ -342,7 +346,7 @@ if $0 == __FILE__
end
ARGV.each{ |item|
mo = GetText::MOFile.open(item)
mo = GetText::MoFile.open(item)
puts "------------------------------------------------------------------"
puts "charset = \"#{mo.charset}\""
puts "nplurals = \"#{mo.nplurals}\""
......
......@@ -170,7 +170,7 @@ module GetText
if path
charset = @output_charset || lang.charset || Locale.charset || "UTF-8"
@mofiles[lang_key] = MOFile.open(path, charset)
@mofiles[lang_key] = MoFile.open(path, charset)
else
@mofiles[lang_key] = :empty
end
......
......@@ -183,6 +183,22 @@ module GetText
return plural ? msgstrs[1] : msgstrs[0]
end
# for testing.
def dump_all_textdomains
[
@@textdomain_pool.dup,
@@textdomain_group_pool.dup,
@@gettext_classes.dup,
]
end
# for testing.
def restore_all_textdomains(dumped_all_textdomains)
@@textdomain_pool, @@textdomain_group_pool, @@gettext_classes =
dumped_all_textdomains
clear_caches
end
# for testing.
def clear_all_textdomains
@@textdomain_pool = {}
......
# encoding: utf-8
=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
# -*- coding: utf-8 -*-
#
# poparser.rb - Generate a .mo
#
# Copyright (C) 2003-2009 Masao Mutoh <mutomasa at gmail.com>
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
#
# You may redistribute it and/or modify it under the same
# license terms as Ruby or LGPL.
#
# DO NOT MODIFY!!!!
# This file is automatically generated by Racc 1.4.6
# This file is automatically generated by Racc 1.4.8
# from Racc grammer file "".
#
......@@ -19,9 +18,30 @@ 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")
module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 114)
if GetText.respond_to?(:bindtextdomain)
include GetText
GetText.bindtextdomain("rgettext")
else
def _(message_id)
message_id
end
private :_
end
attr_writer :ignore_fuzzy, :report_warning
def initialize
@ignore_fuzzy = true
@report_warning = true
end
def ignore_fuzzy?
@ignore_fuzzy
end
def report_warning?
@report_warning
end
def unescape(orig)
ret = orig.gsub(/\\n/, "\n")
......@@ -30,50 +50,57 @@ module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 108)
ret.gsub!(/\\"/, "\"")
ret
end
private :unescape
def unescape_string(string)
string.gsub(/\\\\/, "\\")
end
private :unescape_string
def parse(str, data, ignore_fuzzy = true)
def parse(str, data)
@comments = []
@data = data
@fuzzy = false
@msgctxt = ""
$ignore_fuzzy = ignore_fuzzy
str.strip!
@q = []
until str.empty? do
case str
when /\A\s+/
str = $'
str = $'
when /\Amsgctxt/
@q.push [:MSGCTXT, $&]
str = $'
@q.push [:MSGCTXT, $&]
str = $'
when /\Amsgid_plural/
@q.push [:MSGID_PLURAL, $&]
str = $'
@q.push [:MSGID_PLURAL, $&]
str = $'
when /\Amsgid/
@q.push [:MSGID, $&]
str = $'
@q.push [:MSGID, $&]
str = $'
when /\Amsgstr/
@q.push [:MSGSTR, $&]
str = $'
@q.push [:MSGSTR, $&]
str = $'
when /\A\[(\d+)\]/
@q.push [:PLURAL_NUM, $1]
str = $'
@q.push [:PLURAL_NUM, $1]
str = $'
when /\A\#~(.*)/
$stderr.print _("Warning: obsolete msgid exists.\n")
$stderr.print " #{$&}\n"
@q.push [:COMMENT, $&]
str = $'
if report_warning?
$stderr.print _("Warning: obsolete msgid exists.\n")
$stderr.print " #{$&}\n"
end
@q.push [:COMMENT, $&]
str = $'
when /\A\#(.*)/
@q.push [:COMMENT, $&]
str = $'
@q.push [:COMMENT, $&]
str = $'
when /\A\"(.*)\"/
@q.push [:STRING, $1]
str = $'
@q.push [:STRING, unescape_string($1)]
str = $'
else
#c = str[0,1]
#@q.push [:STRING, c]
str = str[1..-1]
#c = str[0,1]
#@q.push [:STRING, c]
str = str[1..-1]
end
end
@q.push [false, '$end']
......@@ -109,7 +136,7 @@ module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 108)
@comments << comment
end
def parse_file(po_file, data, ignore_fuzzy = true)
def parse_file(po_file, data)
args = [ po_file ]
# In Ruby 1.9, we must detect proper encoding of a PO file.
if String.instance_methods.include?(:encode)
......@@ -117,7 +144,7 @@ module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 108)
args << "r:#{encoding}"
end
@po_file = po_file
parse(File.open(*args) {|io| io.read }, data, ignore_fuzzy)
parse(File.open(*args) {|io| io.read }, data)
end
def detect_file_encoding(po_file)
......@@ -133,33 +160,33 @@ module_eval(<<'...end poparser.ry/module_eval...', 'poparser.ry', 108)
##### 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 ]
2, 13, 10, 9, 6, 17, 16, 15, 22, 15,
15, 13, 13, 13, 15, 11, 22, 24, 13, 15 ]
racc_action_check = [
1, 16, 1, 1, 1, 12, 12, 12, 18, 18,
7, 14, 15, 9, 3, 19, 20, 21, 23, 25 ]
1, 17, 1, 1, 1, 14, 14, 14, 19, 19,
12, 6, 16, 9, 18, 2, 20, 22, 24, 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 ]
nil, 0, 15, nil, nil, nil, 4, nil, nil, 6,
nil, nil, 3, nil, 0, nil, 5, -6, 7, 2,
10, nil, 9, nil, 11, 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 ]
-1, -16, -16, -2, -3, -4, -16, -6, -7, -16,
-13, 26, -5, -15, -16, -14, -16, -16, -8, -16,
-9, -11, -16, -10, -16, -12 ]
racc_goto_table = [
12, 22, 14, 4, 24, 6, 2, 8, 18, 19,
10, 21, 1, nil, nil, nil, 25 ]
12, 21, 23, 14, 4, 5, 3, 7, 8, 20,
18, 19, 1, nil, nil, nil, nil, nil, 25 ]
racc_goto_check = [
5, 9, 5, 3, 9, 4, 2, 6, 5, 5,
7, 8, 1, nil, nil, nil, 5 ]
5, 9, 9, 5, 3, 4, 2, 6, 7, 8,
5, 5, 1, nil, nil, nil, nil, nil, 5 ]
racc_goto_pointer = [
nil, 12, 5, 2, 4, -7, 6, 9, -7, -17 ]
nil, 12, 5, 3, 4, -6, 6, 7, -10, -18 ]
racc_goto_default = [
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ]
......@@ -252,10 +279,10 @@ Racc_debug_parser = true
# reduce 4 omitted
module_eval(<<'.,.,', 'poparser.ry', 23)
module_eval(<<'.,.,', 'poparser.ry', 25)
def _reduce_5(val, _values, result)
@msgctxt = unescape(val[1]) + "\004"
result
end
.,.,
......@@ -264,12 +291,14 @@ module_eval(<<'.,.,', 'poparser.ry', 23)
# reduce 7 omitted
module_eval(<<'.,.,', 'poparser.ry', 35)
module_eval(<<'.,.,', 'poparser.ry', 37)
def _reduce_8(val, _values, result)
if @fuzzy and $ignore_fuzzy
if @fuzzy and ignore_fuzzy?
if val[1] != ""
$stderr.print _("Warning: fuzzy message was ignored.\n")
$stderr.print " #{@po_file}: msgid '#{val[1]}'\n"
if report_warning?
$stderr.print _("Warning: fuzzy message was ignored.\n")
$stderr.print " #{@po_file}: msgid '#{val[1]}'\n"
end
else
on_message('', unescape(val[3]))
end
......@@ -278,17 +307,19 @@ module_eval(<<'.,.,', 'poparser.ry', 35)
on_message(@msgctxt + unescape(val[1]), unescape(val[3]))
end
result = ""
result
end
.,.,
module_eval(<<'.,.,', 'poparser.ry', 52)
module_eval(<<'.,.,', 'poparser.ry', 56)
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"
if report_warning?
$stderr.print _("Warning: fuzzy message was ignored.\n")
$stderr.print "msgid = '#{val[1]}\n"
end
else
on_message('', unescape(val[3]))
end
......@@ -297,53 +328,53 @@ module_eval(<<'.,.,', 'poparser.ry', 52)
on_message(@msgctxt + unescape(val[1]) + "\000" + unescape(val[3]), unescape(val[4]))
end
result = ""
result
end
.,.,
module_eval(<<'.,.,', 'poparser.ry', 70)
module_eval(<<'.,.,', 'poparser.ry', 76)
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)
module_eval(<<'.,.,', 'poparser.ry', 88)
def _reduce_12(val, _values, result)
result = val[2]
result
end
.,.,
module_eval(<<'.,.,', 'poparser.ry', 89)
module_eval(<<'.,.,', 'poparser.ry', 95)
def _reduce_13(val, _values, result)
on_comment(val[0])
result
end
.,.,
module_eval(<<'.,.,', 'poparser.ry', 97)
module_eval(<<'.,.,', 'poparser.ry', 103)
def _reduce_14(val, _values, result)