i18n-0.6.9/0000755000004100000410000000000012260335253012336 5ustar www-datawww-datai18n-0.6.9/MIT-LICENSE0000644000004100000410000000204512260335253013773 0ustar www-datawww-dataCopyright (c) 2008 The Ruby I18n team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.i18n-0.6.9/lib/0000755000004100000410000000000012260335253013104 5ustar www-datawww-datai18n-0.6.9/lib/i18n/0000755000004100000410000000000012260335253013663 5ustar www-datawww-datai18n-0.6.9/lib/i18n/tests.rb0000644000004100000410000000070012260335253015347 0ustar www-datawww-datamodule I18n module Tests autoload :Basics, 'i18n/tests/basics' autoload :Defaults, 'i18n/tests/defaults' autoload :Interpolation, 'i18n/tests/interpolation' autoload :Link, 'i18n/tests/link' autoload :Localization, 'i18n/tests/localization' autoload :Lookup, 'i18n/tests/lookup' autoload :Pluralization, 'i18n/tests/pluralization' autoload :Procs, 'i18n/tests/procs' end end i18n-0.6.9/lib/i18n/tests/0000755000004100000410000000000012260335253015025 5ustar www-datawww-datai18n-0.6.9/lib/i18n/tests/lookup.rb0000644000004100000410000000545412260335253016673 0ustar www-datawww-data# encoding: utf-8 module I18n module Tests module Lookup def setup super I18n.backend.store_translations(:en, :foo => { :bar => 'bar', :baz => 'baz' }, :falsy => false, :truthy => true, :string => "a", :array => %w(a b c), :hash => { "a" => "b" }) end test "lookup: it returns a string" do assert_equal("a", I18n.t(:string)) end test "lookup: it returns hash" do assert_equal({ :a => "b" }, I18n.t(:hash)) end test "lookup: it returns a array" do assert_equal(%w(a b c), I18n.t(:array)) end test "lookup: it returns a native true" do assert I18n.t(:truthy) === true end test "lookup: it returns a native false" do assert I18n.t(:falsy) === false end test "lookup: given a missing key, no default and no raise option it returns an error message" do assert_equal "translation missing: en.missing", I18n.t(:missing) end test "lookup: given a missing key, no default and the raise option it raises MissingTranslationData" do assert_raise(I18n::MissingTranslationData) { I18n.t(:missing, :raise => true) } end test "lookup: does not raise an exception if no translation data is present for the given locale" do assert_nothing_raised { I18n.t(:foo, :locale => :xx) } end test "lookup: does not modify the options hash" do options = {} assert_equal "a", I18n.t(:string, options) assert_equal({}, options) assert_nothing_raised { I18n.t(:string, options.freeze) } end test "lookup: given an array of keys it translates all of them" do assert_equal %w(bar baz), I18n.t([:bar, :baz], :scope => [:foo]) end test "lookup: using a custom scope separator" do # data must have been stored using the custom separator when using the ActiveRecord backend I18n.backend.store_translations(:en, { :foo => { :bar => 'bar' } }, { :separator => '|' }) assert_equal 'bar', I18n.t('foo|bar', :separator => '|') end # In fact it probably *should* fail but Rails currently relies on using the default locale instead. # So we'll stick to this for now until we get it fixed in Rails. test "lookup: given nil as a locale it does not raise but use the default locale" do # assert_raise(I18n::InvalidLocale) { I18n.t(:bar, :locale => nil) } assert_nothing_raised { I18n.t(:bar, :locale => nil) } end test "lookup: a resulting String is not frozen" do assert !I18n.t(:string).frozen? end test "lookup: a resulting Array is not frozen" do assert !I18n.t(:array).frozen? end test "lookup: a resulting Hash is not frozen" do assert !I18n.t(:hash).frozen? end end end end i18n-0.6.9/lib/i18n/tests/localization.rb0000644000004100000410000000111312260335253020036 0ustar www-datawww-datamodule I18n module Tests module Localization autoload :Date, 'i18n/tests/localization/date' autoload :DateTime, 'i18n/tests/localization/date_time' autoload :Time, 'i18n/tests/localization/time' autoload :Procs, 'i18n/tests/localization/procs' def self.included(base) base.class_eval do include I18n::Tests::Localization::Date include I18n::Tests::Localization::DateTime include I18n::Tests::Localization::Procs include I18n::Tests::Localization::Time end end end end endi18n-0.6.9/lib/i18n/tests/interpolation.rb0000644000004100000410000001357012260335253020247 0ustar www-datawww-data# encoding: utf-8 module I18n module Tests module Interpolation # If no interpolation parameter is not given, I18n should not alter the string. # This behavior is due to three reasons: # # * Checking interpolation keys in all strings hits performance, badly; # # * This allows us to retrieve untouched values through I18n. For example # I could have a middleware that returns I18n lookup results in JSON # to be processed through Javascript. Leaving the keys untouched allows # the interpolation to happen at the javascript level; # # * Security concerns: if I allow users to translate a web site, they can # insert %{} in messages causing the I18n lookup to fail in every request. # test "interpolation: given no values it does not alter the string" do assert_equal 'Hi %{name}!', interpolate(:default => 'Hi %{name}!') end test "interpolation: given values it interpolates them into the string" do assert_equal 'Hi David!', interpolate(:default => 'Hi %{name}!', :name => 'David') end test "interpolation: given a nil value it still interpolates it into the string" do assert_equal 'Hi !', interpolate(:default => 'Hi %{name}!', :name => nil) end test "interpolation: given a lambda as a value it calls it if the string contains the key" do assert_equal 'Hi David!', interpolate(:default => 'Hi %{name}!', :name => lambda { |*args| 'David' }) end test "interpolation: given a lambda as a value it does not call it if the string does not contain the key" do assert_nothing_raised { interpolate(:default => 'Hi!', :name => lambda { |*args| raise 'fail' }) } end test "interpolation: given values but missing a key it raises I18n::MissingInterpolationArgument" do assert_raise(I18n::MissingInterpolationArgument) do interpolate(:default => '%{foo}', :bar => 'bar') end end test "interpolation: it does not raise I18n::MissingInterpolationArgument for escaped variables" do assert_nothing_raised(I18n::MissingInterpolationArgument) do assert_equal 'Barr %{foo}', interpolate(:default => '%{bar} %%{foo}', :bar => 'Barr') end end test "interpolation: it does not change the original, stored translation string" do I18n.backend.store_translations(:en, :interpolate => 'Hi %{name}!') assert_equal 'Hi David!', interpolate(:interpolate, :name => 'David') assert_equal 'Hi Yehuda!', interpolate(:interpolate, :name => 'Yehuda') end test "interpolation: given the translation is in utf-8 it still works" do assert_equal 'Häi David!', interpolate(:default => 'Häi %{name}!', :name => 'David') end test "interpolation: given the value is in utf-8 it still works" do assert_equal 'Hi ゆきひろ!', interpolate(:default => 'Hi %{name}!', :name => 'ゆきひろ') end test "interpolation: given the translation and the value are in utf-8 it still works" do assert_equal 'こんにちは、ゆきひろさん!', interpolate(:default => 'こんにちは、%{name}さん!', :name => 'ゆきひろ') end if Object.const_defined?(:Encoding) test "interpolation: given a euc-jp translation and a utf-8 value it raises Encoding::CompatibilityError" do assert_raise(Encoding::CompatibilityError) do interpolate(:default => euc_jp('こんにちは、%{name}さん!'), :name => 'ゆきひろ') end end test "interpolation: given a utf-8 translation and a euc-jp value it raises Encoding::CompatibilityError" do assert_raise(Encoding::CompatibilityError) do interpolate(:default => 'こんにちは、%{name}さん!', :name => euc_jp('ゆきひろ')) end end test "interpolation: ASCII strings in the backend should be encoded to UTF8 if interpolation options are in UTF8" do I18n.backend.store_translations 'en', 'encoding' => ('%{who} let me go'.force_encoding("ASCII")) result = I18n.t 'encoding', :who => "måmmå miå" assert_equal Encoding::UTF_8, result.encoding end test "interpolation: UTF8 strings in the backend are still returned as UTF8 with ASCII interpolation" do I18n.backend.store_translations 'en', 'encoding' => 'måmmå miå %{what}' result = I18n.t 'encoding', :what => 'let me go'.force_encoding("ASCII") assert_equal Encoding::UTF_8, result.encoding end test "interpolation: UTF8 strings in the backend are still returned as UTF8 even with numbers interpolation" do I18n.backend.store_translations 'en', 'encoding' => '%{count} times: måmmå miå' result = I18n.t 'encoding', :count => 3 assert_equal Encoding::UTF_8, result.encoding end end test "interpolation: given a translations containing a reserved key it raises I18n::ReservedInterpolationKey" do assert_raise(I18n::ReservedInterpolationKey) { interpolate(:default => '%{default}', :foo => :bar) } assert_raise(I18n::ReservedInterpolationKey) { interpolate(:default => '%{scope}', :foo => :bar) } assert_raise(I18n::ReservedInterpolationKey) { interpolate(:default => '%{separator}', :foo => :bar) } end protected def capture(stream) begin stream = stream.to_s eval "$#{stream} = StringIO.new" yield result = eval("$#{stream}").string ensure eval("$#{stream} = #{stream.upcase}") end result end def euc_jp(string) string.encode!(Encoding::EUC_JP) end def interpolate(*args) options = args.last.is_a?(Hash) ? args.pop : {} key = args.pop I18n.backend.translate('en', key, options) end end end end i18n-0.6.9/lib/i18n/tests/basics.rb0000644000004100000410000000421512260335253016620 0ustar www-datawww-datamodule I18n module Tests module Basics def teardown I18n.available_locales = nil end test "available_locales returns the locales stored to the backend by default" do I18n.backend.store_translations('de', :foo => 'bar') I18n.backend.store_translations('en', :foo => 'foo') assert I18n.available_locales.include?(:de) assert I18n.available_locales.include?(:en) end test "available_locales can be set to something else independently from the actual locale data" do I18n.backend.store_translations('de', :foo => 'bar') I18n.backend.store_translations('en', :foo => 'foo') I18n.available_locales = :foo assert_equal [:foo], I18n.available_locales I18n.available_locales = [:foo, 'bar'] assert_equal [:foo, :bar], I18n.available_locales I18n.available_locales = nil assert I18n.available_locales.include?(:de) assert I18n.available_locales.include?(:en) end test "available_locales memoizes when set explicitely" do I18n.backend.expects(:available_locales).never I18n.available_locales = [:foo] I18n.backend.store_translations('de', :bar => 'baz') I18n.reload! assert_equal [:foo], I18n.available_locales end test "available_locales delegates to the backend when not set explicitely" do I18n.backend.expects(:available_locales).twice assert_equal I18n.available_locales, I18n.available_locales end test "exists? is implemented by the backend" do I18n.backend.store_translations(:foo, :bar => 'baz') assert I18n.exists?(:bar, :foo) end test "storing a nil value as a translation removes it from the available locale data" do I18n.backend.store_translations(:en, :to_be_deleted => 'bar') assert_equal 'bar', I18n.t(:to_be_deleted, :default => 'baz') I18n.cache_store.clear if I18n.respond_to?(:cache_store) && I18n.cache_store I18n.backend.store_translations(:en, :to_be_deleted => nil) assert_equal 'baz', I18n.t(:to_be_deleted, :default => 'baz') end end end end i18n-0.6.9/lib/i18n/tests/link.rb0000644000004100000410000000422712260335253016314 0ustar www-datawww-data# encoding: utf-8 module I18n module Tests module Link test "linked lookup: if a key resolves to a symbol it looks up the symbol" do I18n.backend.store_translations 'en', { :link => :linked, :linked => 'linked' } assert_equal 'linked', I18n.backend.translate('en', :link) end test "linked lookup: if a key resolves to a dot-separated symbol it looks up the symbol" do I18n.backend.store_translations 'en', { :link => :"foo.linked", :foo => { :linked => 'linked' } } assert_equal('linked', I18n.backend.translate('en', :link)) end test "linked lookup: if a dot-separated key resolves to a symbol it looks up the symbol" do I18n.backend.store_translations 'en', { :foo => { :link => :linked }, :linked => 'linked' } assert_equal('linked', I18n.backend.translate('en', :'foo.link')) end test "linked lookup: if a dot-separated key resolves to a dot-separated symbol it looks up the symbol" do I18n.backend.store_translations 'en', { :foo => { :link => :"bar.linked" }, :bar => { :linked => 'linked' } } assert_equal('linked', I18n.backend.translate('en', :'foo.link')) end test "linked lookup: links always refer to the absolute key" do I18n.backend.store_translations 'en', { :foo => { :link => :linked, :linked => 'linked in foo' }, :linked => 'linked absolutely' } assert_equal 'linked absolutely', I18n.backend.translate('en', :link, :scope => :foo) end test "linked lookup: a link can resolve to a namespace in the middle of a dot-separated key" do I18n.backend.store_translations 'en', { :activemodel => { :errors => { :messages => { :blank => "can't be blank" } } }, :activerecord => { :errors => { :messages => :"activemodel.errors.messages" } } } assert_equal "can't be blank", I18n.t(:"activerecord.errors.messages.blank") assert_equal "can't be blank", I18n.t(:"activerecord.errors.messages.blank") end end end end i18n-0.6.9/lib/i18n/tests/defaults.rb0000644000004100000410000000301112260335253017154 0ustar www-datawww-data# encoding: utf-8 module I18n module Tests module Defaults def setup super I18n.backend.store_translations(:en, :foo => { :bar => 'bar', :baz => 'baz' }) end test "defaults: given nil as a key it returns the given default" do assert_equal 'default', I18n.t(nil, :default => 'default') end test "defaults: given a symbol as a default it translates the symbol" do assert_equal 'bar', I18n.t(nil, :default => :'foo.bar') end test "defaults: given a symbol as a default and a scope it stays inside the scope when looking up the symbol" do assert_equal 'bar', I18n.t(:missing, :default => :bar, :scope => :foo) end test "defaults: given an array as a default it returns the first match" do assert_equal 'bar', I18n.t(:does_not_exist, :default => [:does_not_exist_2, :'foo.bar']) end test "defaults: given an array of missing keys it raises a MissingTranslationData exception" do assert_raise I18n::MissingTranslationData do I18n.t(:does_not_exist, :default => [:does_not_exist_2, :does_not_exist_3], :raise => true) end end test "defaults: using a custom scope separator" do # data must have been stored using the custom separator when using the ActiveRecord backend I18n.backend.store_translations(:en, { :foo => { :bar => 'bar' } }, { :separator => '|' }) assert_equal 'bar', I18n.t(nil, :default => :'foo|bar', :separator => '|') end end end end i18n-0.6.9/lib/i18n/tests/pluralization.rb0000644000004100000410000000252012260335253020246 0ustar www-datawww-data# encoding: utf-8 module I18n module Tests module Pluralization test "pluralization: given 0 it returns the :zero translation if it is defined" do assert_equal 'zero', I18n.t(:default => { :zero => 'zero' }, :count => 0) end test "pluralization: given 0 it returns the :other translation if :zero is not defined" do assert_equal 'bars', I18n.t(:default => { :other => 'bars' }, :count => 0) end test "pluralization: given 1 it returns the singular translation" do assert_equal 'bar', I18n.t(:default => { :one => 'bar' }, :count => 1) end test "pluralization: given 2 it returns the :other translation" do assert_equal 'bars', I18n.t(:default => { :other => 'bars' }, :count => 2) end test "pluralization: given 3 it returns the :other translation" do assert_equal 'bars', I18n.t(:default => { :other => 'bars' }, :count => 3) end test "pluralization: given nil it returns the whole entry" do assert_equal({ :one => 'bar' }, I18n.t(:default => { :one => 'bar' }, :count => nil)) end test "pluralization: given incomplete pluralization data it raises I18n::InvalidPluralizationData" do assert_raise(I18n::InvalidPluralizationData) { I18n.t(:default => { :one => 'bar' }, :count => 2) } end end end end i18n-0.6.9/lib/i18n/tests/localization/0000755000004100000410000000000012260335253017515 5ustar www-datawww-datai18n-0.6.9/lib/i18n/tests/localization/date_time.rb0000644000004100000410000000636412260335253022006 0ustar www-datawww-data# encoding: utf-8 module I18n module Tests module Localization module DateTime def setup super setup_datetime_translations @datetime = ::DateTime.new(2008, 3, 1, 6) @other_datetime = ::DateTime.new(2008, 3, 1, 18) end test "localize DateTime: given the short format it uses it" do # TODO should be Mrz, shouldn't it? assert_equal '01. Mar 06:00', I18n.l(@datetime, :format => :short, :locale => :de) end test "localize DateTime: given the long format it uses it" do assert_equal '01. März 2008 06:00', I18n.l(@datetime, :format => :long, :locale => :de) end test "localize DateTime: given the default format it uses it" do # TODO should be Mrz, shouldn't it? assert_equal 'Sa, 01. Mar 2008 06:00:00 +0000', I18n.l(@datetime, :format => :default, :locale => :de) end test "localize DateTime: given a day name format it returns the correct day name" do assert_equal 'Samstag', I18n.l(@datetime, :format => '%A', :locale => :de) end test "localize DateTime: given an abbreviated day name format it returns the correct abbreviated day name" do assert_equal 'Sa', I18n.l(@datetime, :format => '%a', :locale => :de) end test "localize DateTime: given a month name format it returns the correct month name" do assert_equal 'März', I18n.l(@datetime, :format => '%B', :locale => :de) end test "localize DateTime: given an abbreviated month name format it returns the correct abbreviated month name" do # TODO should be Mrz, shouldn't it? assert_equal 'Mar', I18n.l(@datetime, :format => '%b', :locale => :de) end test "localize DateTime: given a meridian indicator format it returns the correct meridian indicator" do assert_equal 'AM', I18n.l(@datetime, :format => '%p', :locale => :de) assert_equal 'PM', I18n.l(@other_datetime, :format => '%p', :locale => :de) end test "localize DateTime: given a meridian indicator format it returns the correct meridian indicator in downcase" do assert_equal 'am', I18n.l(@datetime, :format => '%P', :locale => :de) assert_equal 'pm', I18n.l(@other_datetime, :format => '%P', :locale => :de) end test "localize DateTime: given an unknown format it does not fail" do assert_nothing_raised { I18n.l(@datetime, :format => '%x') } end test "localize DateTime: given a format is missing it raises I18n::MissingTranslationData" do assert_raise(I18n::MissingTranslationData) { I18n.l(@datetime, :format => :missing) } end protected def setup_datetime_translations # time translations might have been set up in Tests::Api::Localization::Time I18n.backend.store_translations :de, { :time => { :formats => { :default => "%a, %d. %b %Y %H:%M:%S %z", :short => "%d. %b %H:%M", :long => "%d. %B %Y %H:%M" }, :am => 'am', :pm => 'pm' } } end end end end end i18n-0.6.9/lib/i18n/tests/localization/time.rb0000644000004100000410000000613412260335253021004 0ustar www-datawww-data# encoding: utf-8 module I18n module Tests module Localization module Time def setup super setup_time_translations @time = ::Time.utc(2008, 3, 1, 6, 0) @other_time = ::Time.utc(2008, 3, 1, 18, 0) end test "localize Time: given the short format it uses it" do # TODO should be Mrz, shouldn't it? assert_equal '01. Mar 06:00', I18n.l(@time, :format => :short, :locale => :de) end test "localize Time: given the long format it uses it" do assert_equal '01. März 2008 06:00', I18n.l(@time, :format => :long, :locale => :de) end # TODO Seems to break on Windows because ENV['TZ'] is ignored. What's a better way to do this? # def test_localize_given_the_default_format_it_uses_it # assert_equal 'Sa, 01. Mar 2008 06:00:00 +0000', I18n.l(@time, :format => :default, :locale => :de) # end test "localize Time: given a day name format it returns the correct day name" do assert_equal 'Samstag', I18n.l(@time, :format => '%A', :locale => :de) end test "localize Time: given an abbreviated day name format it returns the correct abbreviated day name" do assert_equal 'Sa', I18n.l(@time, :format => '%a', :locale => :de) end test "localize Time: given a month name format it returns the correct month name" do assert_equal 'März', I18n.l(@time, :format => '%B', :locale => :de) end test "localize Time: given an abbreviated month name format it returns the correct abbreviated month name" do # TODO should be Mrz, shouldn't it? assert_equal 'Mar', I18n.l(@time, :format => '%b', :locale => :de) end test "localize Time: given a meridian indicator format it returns the correct meridian indicator" do assert_equal 'AM', I18n.l(@time, :format => '%p', :locale => :de) assert_equal 'PM', I18n.l(@other_time, :format => '%p', :locale => :de) end test "localize Time: given a meridian indicator format it returns the correct meridian indicator in upcase" do assert_equal 'am', I18n.l(@time, :format => '%P', :locale => :de) assert_equal 'pm', I18n.l(@other_time, :format => '%P', :locale => :de) end test "localize Time: given an unknown format it does not fail" do assert_nothing_raised { I18n.l(@time, :format => '%x') } end test "localize Time: given a format is missing it raises I18n::MissingTranslationData" do assert_raise(I18n::MissingTranslationData) { I18n.l(@time, :format => :missing) } end protected def setup_time_translations I18n.backend.store_translations :de, { :time => { :formats => { :default => "%a, %d. %b %Y %H:%M:%S %z", :short => "%d. %b %H:%M", :long => "%d. %B %Y %H:%M", }, :am => 'am', :pm => 'pm' } } end end end end end i18n-0.6.9/lib/i18n/tests/localization/date.rb0000644000004100000410000000707512260335253020770 0ustar www-datawww-data# encoding: utf-8 module I18n module Tests module Localization module Date def setup super setup_date_translations @date = ::Date.new(2008, 3, 1) end test "localize Date: given the short format it uses it" do # TODO should be Mrz, shouldn't it? assert_equal '01. Mar', I18n.l(@date, :format => :short, :locale => :de) end test "localize Date: given the long format it uses it" do assert_equal '01. März 2008', I18n.l(@date, :format => :long, :locale => :de) end test "localize Date: given the default format it uses it" do assert_equal '01.03.2008', I18n.l(@date, :format => :default, :locale => :de) end test "localize Date: given a day name format it returns the correct day name" do assert_equal 'Samstag', I18n.l(@date, :format => '%A', :locale => :de) end test "localize Date: given an abbreviated day name format it returns the correct abbreviated day name" do assert_equal 'Sa', I18n.l(@date, :format => '%a', :locale => :de) end test "localize Date: given a month name format it returns the correct month name" do assert_equal 'März', I18n.l(@date, :format => '%B', :locale => :de) end test "localize Date: given an abbreviated month name format it returns the correct abbreviated month name" do # TODO should be Mrz, shouldn't it? assert_equal 'Mar', I18n.l(@date, :format => '%b', :locale => :de) end test "localize Date: given an unknown format it does not fail" do assert_nothing_raised { I18n.l(@date, :format => '%x') } end test "localize Date: does not modify the options hash" do options = { :format => '%b', :locale => :de } assert_equal 'Mar', I18n.l(@date, options) assert_equal({ :format => '%b', :locale => :de }, options) assert_nothing_raised { I18n.l(@date, options.freeze) } end test "localize Date: given nil it raises I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.l(nil) } end test "localize Date: given a plain Object it raises I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.l(Object.new) } end test "localize Date: given a format is missing it raises I18n::MissingTranslationData" do assert_raise(I18n::MissingTranslationData) { I18n.l(@date, :format => :missing) } end test "localize Date: it does not alter the format string" do assert_equal '01. Februar 2009', I18n.l(::Date.parse('2009-02-01'), :format => :long, :locale => :de) assert_equal '01. Oktober 2009', I18n.l(::Date.parse('2009-10-01'), :format => :long, :locale => :de) end protected def setup_date_translations I18n.backend.store_translations :de, { :date => { :formats => { :default => "%d.%m.%Y", :short => "%d. %b", :long => "%d. %B %Y", }, :day_names => %w(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag), :abbr_day_names => %w(So Mo Di Mi Do Fr Sa), :month_names => %w(Januar Februar März April Mai Juni Juli August September Oktober November Dezember).unshift(nil), :abbr_month_names => %w(Jan Feb Mar Apr Mai Jun Jul Aug Sep Okt Nov Dez).unshift(nil) } } end end end end end i18n-0.6.9/lib/i18n/tests/localization/procs.rb0000644000004100000410000001250212260335253021170 0ustar www-datawww-data# encoding: utf-8 module I18n module Tests module Localization module Procs test "localize: using day names from lambdas" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) assert_match(/Суббота/, I18n.l(time, :format => "%A, %d %B", :locale => :ru)) assert_match(/суббота/, I18n.l(time, :format => "%d %B (%A)", :locale => :ru)) end test "localize: using month names from lambdas" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) assert_match(/марта/, I18n.l(time, :format => "%d %B %Y", :locale => :ru)) assert_match(/Март /, I18n.l(time, :format => "%B %Y", :locale => :ru)) end test "localize: using abbreviated day names from lambdas" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) assert_match(/марта/, I18n.l(time, :format => "%d %b %Y", :locale => :ru)) assert_match(/март /, I18n.l(time, :format => "%b %Y", :locale => :ru)) end test "localize Date: given a format that resolves to a Proc it calls the Proc with the object" do setup_time_proc_translations date = ::Date.new(2008, 3, 1) assert_equal '[Sat, 01 Mar 2008, {}]', I18n.l(date, :format => :proc, :locale => :ru) end test "localize Date: given a format that resolves to a Proc it calls the Proc with the object and extra options" do setup_time_proc_translations date = ::Date.new(2008, 3, 1) assert_equal '[Sat, 01 Mar 2008, {:foo=>"foo"}]', I18n.l(date, :format => :proc, :foo => 'foo', :locale => :ru) end test "localize DateTime: given a format that resolves to a Proc it calls the Proc with the object" do setup_time_proc_translations datetime = ::DateTime.new(2008, 3, 1, 6) assert_equal '[Sat, 01 Mar 2008 06:00:00 +00:00, {}]', I18n.l(datetime, :format => :proc, :locale => :ru) end test "localize DateTime: given a format that resolves to a Proc it calls the Proc with the object and extra options" do setup_time_proc_translations datetime = ::DateTime.new(2008, 3, 1, 6) assert_equal '[Sat, 01 Mar 2008 06:00:00 +00:00, {:foo=>"foo"}]', I18n.l(datetime, :format => :proc, :foo => 'foo', :locale => :ru) end test "localize Time: given a format that resolves to a Proc it calls the Proc with the object" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) assert_equal inspect_args([time, {}]), I18n.l(time, :format => :proc, :locale => :ru) end test "localize Time: given a format that resolves to a Proc it calls the Proc with the object and extra options" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) options = { :foo => 'foo' } assert_equal inspect_args([time, options]), I18n.l(time, options.merge(:format => :proc, :locale => :ru)) end protected def inspect_args(args) args = args.map do |arg| case arg when ::Time, ::DateTime arg.strftime('%a, %d %b %Y %H:%M:%S %Z').sub('+0000', '+00:00') when ::Date arg.strftime('%a, %d %b %Y') when Hash arg.delete(:fallback) arg.inspect else arg.inspect end end "[#{args.join(', ')}]" end def setup_time_proc_translations I18n.backend.store_translations :ru, { :time => { :formats => { :proc => lambda { |*args| inspect_args(args) } } }, :date => { :formats => { :proc => lambda { |*args| inspect_args(args) } }, :'day_names' => lambda { |key, options| (options[:format] =~ /^%A/) ? %w(Воскресенье Понедельник Вторник Среда Четверг Пятница Суббота) : %w(воскресенье понедельник вторник среда четверг пятница суббота) }, :'month_names' => lambda { |key, options| (options[:format] =~ /(%d|%e)(\s*)?(%B)/) ? %w(января февраля марта апреля мая июня июля августа сентября октября ноября декабря).unshift(nil) : %w(Январь Февраль Март Апрель Май Июнь Июль Август Сентябрь Октябрь Ноябрь Декабрь).unshift(nil) }, :'abbr_month_names' => lambda { |key, options| (options[:format] =~ /(%d|%e)(\s*)(%b)/) ? %w(янв. февр. марта апр. мая июня июля авг. сент. окт. нояб. дек.).unshift(nil) : %w(янв. февр. март апр. май июнь июль авг. сент. окт. нояб. дек.).unshift(nil) }, } } end end end end end i18n-0.6.9/lib/i18n/tests/procs.rb0000644000004100000410000000525212260335253016504 0ustar www-datawww-data# encoding: utf-8 module I18n module Tests module Procs test "lookup: given a translation is a proc it calls the proc with the key and interpolation values" do I18n.backend.store_translations(:en, :a_lambda => lambda { |*args| filter_args(*args) }) assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(:a_lambda, :foo => 'foo') end test "defaults: given a default is a Proc it calls it with the key and interpolation values" do proc = lambda { |*args| filter_args(*args) } assert_equal '[nil, {:foo=>"foo"}]', I18n.t(nil, :default => proc, :foo => 'foo') end test "defaults: given a default is a key that resolves to a Proc it calls it with the key and interpolation values" do I18n.backend.store_translations(:en, :a_lambda => lambda { |*args| filter_args(*args) }) assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(nil, :default => :a_lambda, :foo => 'foo') assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(nil, :default => [nil, :a_lambda], :foo => 'foo') end test "interpolation: given an interpolation value is a lambda it calls it with key and values before interpolating it" do proc = lambda { |*args| filter_args(*args) } assert_match %r(\[\{:foo=>#\}\]), I18n.t(nil, :default => '%{foo}', :foo => proc) end test "interpolation: given a key resolves to a Proc that returns a string then interpolation still works" do proc = lambda { |*args| "%{foo}: " + filter_args(*args) } assert_equal 'foo: [nil, {:foo=>"foo"}]', I18n.t(nil, :default => proc, :foo => 'foo') end test "pluralization: given a key resolves to a Proc that returns valid data then pluralization still works" do proc = lambda { |*args| { :zero => 'zero', :one => 'one', :other => 'other' } } assert_equal 'zero', I18n.t(:default => proc, :count => 0) assert_equal 'one', I18n.t(:default => proc, :count => 1) assert_equal 'other', I18n.t(:default => proc, :count => 2) end test "lookup: given the option :resolve => false was passed it does not resolve proc translations" do I18n.backend.store_translations(:en, :a_lambda => lambda { |*args| filter_args(*args) }) assert_equal Proc, I18n.t(:a_lambda, :resolve => false).class end test "lookup: given the option :resolve => false was passed it does not resolve proc default" do assert_equal Proc, I18n.t(nil, :default => lambda { |*args| filter_args(*args) }, :resolve => false).class end protected def filter_args(*args) args.map {|arg| arg.delete(:fallback) if arg.is_a?(Hash) ; arg }.inspect end end end end i18n-0.6.9/lib/i18n/core_ext/0000755000004100000410000000000012260335253015473 5ustar www-datawww-datai18n-0.6.9/lib/i18n/core_ext/hash.rb0000644000004100000410000000142512260335253016745 0ustar www-datawww-dataclass Hash def slice(*keep_keys) h = {} keep_keys.each { |key| h[key] = fetch(key) } h end unless Hash.method_defined?(:slice) def except(*less_keys) slice(*keys - less_keys) end unless Hash.method_defined?(:except) def deep_symbolize_keys inject({}) { |result, (key, value)| value = value.deep_symbolize_keys if value.is_a?(Hash) result[(key.to_sym rescue key) || key] = value result } end unless Hash.method_defined?(:deep_symbolize_keys) # deep_merge_hash! by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809 MERGER = proc do |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &MERGER) : v2 end def deep_merge!(data) merge!(data, &MERGER) end unless Hash.method_defined?(:deep_merge!) end i18n-0.6.9/lib/i18n/core_ext/kernel/0000755000004100000410000000000012260335253016753 5ustar www-datawww-datai18n-0.6.9/lib/i18n/core_ext/kernel/surpress_warnings.rb0000644000004100000410000000024512260335253023077 0ustar www-datawww-datamodule Kernel def suppress_warnings original_verbosity = $VERBOSE $VERBOSE = nil result = yield $VERBOSE = original_verbosity result end end i18n-0.6.9/lib/i18n/core_ext/string/0000755000004100000410000000000012260335253017001 5ustar www-datawww-datai18n-0.6.9/lib/i18n/core_ext/string/interpolate.rb0000644000004100000410000000771212260335253021663 0ustar www-datawww-data# This backports the Ruby 1.9 String interpolation syntax to Ruby 1.8. # # This backport has been shipped with I18n for a number of versions. Meanwhile # Rails has started to rely on it and we are going to move it to ActiveSupport. # See https://rails.lighthouseapp.com/projects/8994/tickets/6013-move-19-string-interpolation-syntax-backport-from-i18n-to-activesupport # # Once the above patch has been applied to Rails the following code will be # removed from I18n. =begin heavily based on Masao Mutoh's gettext String interpolation extension http://github.com/mutoh/gettext/blob/f6566738b981fe0952548c421042ad1e0cdfb31e/lib/gettext/core_ext/string.rb Copyright (C) 2005-2009 Masao Mutoh You may redistribute it and/or modify it under the same license terms as Ruby. =end begin raise ArgumentError if ("a %{x}" % {:x=>'b'}) != 'a b' rescue ArgumentError # KeyError is raised by String#% when the string contains a named placeholder # that is not contained in the given arguments hash. Ruby 1.9 includes and # raises this exception natively. We define it to mimic Ruby 1.9's behaviour # in Ruby 1.8.x class KeyError < IndexError def initialize(message = nil) super(message || "key not found") end end unless defined?(KeyError) # 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 # For older ruby versions, such as ruby-1.8.5 alias :bytesize :size unless instance_methods.find {|m| m.to_s == 'bytesize'} alias :interpolate_without_ruby_19_syntax :% # :nodoc: INTERPOLATION_PATTERN = Regexp.union( /%\{(\w+)\}/, # matches placeholders like "%{foo}" /%<(\w+)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/ # matches placeholders like "%.d" ) INTERPOLATION_PATTERN_WITH_ESCAPE = Regexp.union( /%%/, INTERPOLATION_PATTERN ) # % uses self (i.e. the String) as a format specification and returns the # result of applying it to the given arguments. In other words it interpolates # the given arguments to the string according to the formats the string # defines. # # There are three ways to use it: # # * Using a single argument or Array of arguments. # # This is the default behaviour of the String class. See Kernel#sprintf for # more details about the format string. # # Example: # # "%d %s" % [1, "message"] # # => "1 message" # # * Using a Hash as an argument and unformatted, named placeholders. # # When you pass a Hash as an argument and specify placeholders with %{foo} # it will interpret the hash values as named arguments. # # Example: # # "%{firstname}, %{lastname}" % {:firstname => "Masao", :lastname => "Mutoh"} # # => "Masao Mutoh" # # * Using a Hash as an argument and formatted, named placeholders. # # When you pass a Hash as an argument and specify placeholders with %d # it will interpret the hash values as named arguments and format the value # according to the formatting instruction appended to the closing >. # # Example: # # "%d, %.1f" % { :integer => 10, :float => 43.4 } # # => "10, 43.3" def %(args) if args.kind_of?(Hash) dup.gsub(INTERPOLATION_PATTERN_WITH_ESCAPE) do |match| if match == '%%' '%' else key = ($1 || $2).to_sym raise KeyError unless args.has_key?(key) $3 ? sprintf("%#{$3}", args[key]) : args[key] end end elsif self =~ INTERPOLATION_PATTERN raise ArgumentError.new('one hash required') else result = gsub(/%([{<])/, '%%\1') result.send :'interpolate_without_ruby_19_syntax', args end end end end i18n-0.6.9/lib/i18n/gettext/0000755000004100000410000000000012260335253015347 5ustar www-datawww-datai18n-0.6.9/lib/i18n/gettext/helpers.rb0000644000004100000410000000414112260335253017336 0ustar www-datawww-datarequire 'i18n/gettext' module I18n module Gettext # Implements classical Gettext style accessors. To use this include the # module to the global namespace or wherever you want to use it. # # include I18n::Gettext::Helpers module Helpers def gettext(msgid, options = {}) I18n.t(msgid, { :default => msgid, :separator => '|' }.merge(options)) end alias _ gettext def sgettext(msgid, separator = '|') scope, msgid = I18n::Gettext.extract_scope(msgid, separator) I18n.t(msgid, :scope => scope, :default => msgid, :separator => separator) end alias s_ sgettext def pgettext(msgctxt, msgid) separator = I18n::Gettext::CONTEXT_SEPARATOR sgettext([msgctxt, msgid].join(separator), separator) end alias p_ pgettext def ngettext(msgid, msgid_plural, n = 1) nsgettext(msgid, msgid_plural, n) end alias n_ ngettext # Method signatures: # nsgettext('Fruits|apple', 'apples', 2) # nsgettext(['Fruits|apple', 'apples'], 2) def nsgettext(msgid, msgid_plural, n = 1, separator = '|') if msgid.is_a?(Array) msgid, msgid_plural, n, separator = msgid[0], msgid[1], msgid_plural, n separator = '|' unless separator.is_a?(::String) end scope, msgid = I18n::Gettext.extract_scope(msgid, separator) default = { :one => msgid, :other => msgid_plural } I18n.t(msgid, :default => default, :count => n, :scope => scope, :separator => separator) end alias ns_ nsgettext # Method signatures: # npgettext('Fruits', 'apple', 'apples', 2) # npgettext('Fruits', ['apple', 'apples'], 2) def npgettext(msgctxt, msgid, msgid_plural, n = 1) separator = I18n::Gettext::CONTEXT_SEPARATOR if msgid.is_a?(Array) msgid_plural, msgid, n = msgid[1], [msgctxt, msgid[0]].join(separator), msgid_plural else msgid = [msgctxt, msgid].join(separator) end nsgettext(msgid, msgid_plural, n, separator) end alias np_ npgettext end end end i18n-0.6.9/lib/i18n/gettext/po_parser.rb0000644000004100000410000001513012260335253017666 0ustar www-datawww-data=begin poparser.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. =end #MODIFIED # removed include GetText etc # added stub translation method _(x) require 'racc/parser' module GetText class PoParser < Racc::Parser def _(x) x end module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry', 108 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 ..end src/poparser.ry modeval..id7a99570e05 ##### racc 1.4.5 generates ### 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_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_token_table = { false => 0, Object.new => 1, :COMMENT => 2, :MSGID => 3, :MSGCTXT => 4, :MSGID_PLURAL => 5, :MSGSTR => 6, :STRING => 7, :PLURAL_NUM => 8 } racc_use_result_var = true racc_nt_base = 9 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 ##### racc system variables end ##### # reduce 0 omitted # reduce 1 omitted # reduce 2 omitted # reduce 3 omitted # reduce 4 omitted module_eval <<'.,.,', 'src/poparser.ry', 25 def _reduce_5( val, _values, result ) @msgctxt = unescape(val[1]) + "\004" result end .,., # reduce 6 omitted # reduce 7 omitted module_eval <<'.,.,', 'src/poparser.ry', 48 def _reduce_8( 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]), unescape(val[3])) end result = "" result end .,., module_eval <<'.,.,', 'src/poparser.ry', 65 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 <<'.,.,', 'src/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 <<'.,.,', 'src/poparser.ry', 84 def _reduce_12( val, _values, result ) result = val[2] result end .,., module_eval <<'.,.,', 'src/poparser.ry', 91 def _reduce_13( val, _values, result ) on_comment(val[0]) result end .,., module_eval <<'.,.,', 'src/poparser.ry', 99 def _reduce_14( val, _values, result ) result = val.delete_if{|item| item == ""}.join result end .,., module_eval <<'.,.,', 'src/poparser.ry', 103 def _reduce_15( val, _values, result ) result = val[0] result end .,., def _reduce_none( val, _values, result ) result end end # class PoParser end # module GetText i18n-0.6.9/lib/i18n/version.rb0000644000004100000410000000004412260335253015673 0ustar www-datawww-datamodule I18n VERSION = "0.6.9" end i18n-0.6.9/lib/i18n/config.rb0000644000004100000410000001015712260335253015461 0ustar www-datawww-datamodule I18n class Config # The only configuration value that is not global and scoped to thread is :locale. # It defaults to the default_locale. def locale @locale ||= default_locale end # Sets the current locale pseudo-globally, i.e. in the Thread.current hash. def locale=(locale) I18n.enforce_available_locales!(locale) @locale = locale.to_sym rescue nil end # Returns the current backend. Defaults to +Backend::Simple+. def backend @@backend ||= Backend::Simple.new end # Sets the current backend. Used to set a custom backend. def backend=(backend) @@backend = backend end # Returns the current default locale. Defaults to :'en' def default_locale @@default_locale ||= :en end # Sets the current default locale. Used to set a custom default locale. def default_locale=(locale) I18n.enforce_available_locales!(locale) @@default_locale = locale.to_sym rescue nil end # Returns an array of locales for which translations are available. # Unless you explicitely set these through I18n.available_locales= # the call will be delegated to the backend. def available_locales @@available_locales ||= nil @@available_locales || backend.available_locales end # Sets the available locales. def available_locales=(locales) @@available_locales = Array(locales).map { |locale| locale.to_sym } @@available_locales = nil if @@available_locales.empty? end # Returns the current default scope separator. Defaults to '.' def default_separator @@default_separator ||= '.' end # Sets the current default scope separator. def default_separator=(separator) @@default_separator = separator end # Return the current exception handler. Defaults to :default_exception_handler. def exception_handler @@exception_handler ||= ExceptionHandler.new end # Sets the exception handler. def exception_handler=(exception_handler) @@exception_handler = exception_handler end # Returns the current handler for situations when interpolation argument # is missing. MissingInterpolationArgument will be raised by default. def missing_interpolation_argument_handler @@missing_interpolation_argument_handler ||= lambda do |missing_key, provided_hash, string| raise MissingInterpolationArgument.new(missing_key, provided_hash, string) end end # Sets the missing interpolation argument handler. It can be any # object that responds to #call. The arguments that will be passed to #call # are the same as for MissingInterpolationArgument initializer. Use +Proc.new+ # if you don't care about arity. # # == Example: # You can supress raising an exception and return string instead: # # I18n.config.missing_interpolation_argument_handler = Proc.new do |key| # "#{key} is missing" # end def missing_interpolation_argument_handler=(exception_handler) @@missing_interpolation_argument_handler = exception_handler end # Allow clients to register paths providing translation data sources. The # backend defines acceptable sources. # # E.g. the provided SimpleBackend accepts a list of paths to translation # files which are either named *.rb and contain plain Ruby Hashes or are # named *.yml and contain YAML data. So for the SimpleBackend clients may # register translation files like this: # I18n.load_path << 'path/to/locale/en.yml' def load_path @@load_path ||= [] end # Sets the load path instance. Custom implementations are expected to # behave like a Ruby Array. def load_path=(load_path) @@load_path = load_path end # [Deprecated] this will default to true in the future # Defaults to nil so that it triggers the deprecation warning def enforce_available_locales defined?(@@enforce_available_locales) ? @@enforce_available_locales : nil end def enforce_available_locales=(enforce_available_locales) @@enforce_available_locales = enforce_available_locales end end end i18n-0.6.9/lib/i18n/gettext.rb0000644000004100000410000000122012260335253015667 0ustar www-datawww-datamodule I18n module Gettext PLURAL_SEPARATOR = "\001" CONTEXT_SEPARATOR = "\004" autoload :Helpers, 'i18n/gettext/helpers' @@plural_keys = { :en => [:one, :other] } class << self # returns an array of plural keys for the given locale so that we can # convert from gettext's integer-index based style # TODO move this information to the pluralization module def plural_keys(locale) @@plural_keys[locale] || @@plural_keys[:en] end def extract_scope(msgid, separator) scope = msgid.to_s.split(separator) msgid = scope.pop [scope, msgid] end end end end i18n-0.6.9/lib/i18n/backend.rb0000644000004100000410000000161012260335253015575 0ustar www-datawww-datamodule I18n module Backend autoload :Base, 'i18n/backend/base' autoload :InterpolationCompiler, 'i18n/backend/interpolation_compiler' autoload :Cache, 'i18n/backend/cache' autoload :Cascade, 'i18n/backend/cascade' autoload :Chain, 'i18n/backend/chain' autoload :Fallbacks, 'i18n/backend/fallbacks' autoload :Flatten, 'i18n/backend/flatten' autoload :Gettext, 'i18n/backend/gettext' autoload :KeyValue, 'i18n/backend/key_value' autoload :Memoize, 'i18n/backend/memoize' autoload :Metadata, 'i18n/backend/metadata' autoload :Pluralization, 'i18n/backend/pluralization' autoload :Simple, 'i18n/backend/simple' autoload :Transliterator, 'i18n/backend/transliterator' end end i18n-0.6.9/lib/i18n/backend/0000755000004100000410000000000012260335253015252 5ustar www-datawww-datai18n-0.6.9/lib/i18n/backend/cache.rb0000644000004100000410000000623712260335253016652 0ustar www-datawww-data# This module allows you to easily cache all responses from the backend - thus # speeding up the I18n aspects of your application quite a bit. # # To enable caching you can simply include the Cache module to the Simple # backend - or whatever other backend you are using: # # I18n::Backend::Simple.send(:include, I18n::Backend::Cache) # # You will also need to set a cache store implementation that you want to use: # # I18n.cache_store = ActiveSupport::Cache.lookup_store(:memory_store) # # You can use any cache implementation you want that provides the same API as # ActiveSupport::Cache (only the methods #fetch and #write are being used). # # The cache_key implementation assumes that you only pass values to # I18n.translate that return a valid key from #hash (see # http://www.ruby-doc.org/core/classes/Object.html#M000337). # # If you use a lambda as a default value in your translation like this: # # I18n.t(:"date.order", :default => lambda {[:month, :day, :year]}) # # Then you will always have a cache miss, because each time this method # is called the lambda will have a different hash value. If you know # the result of the lambda is a constant as in the example above, then # to cache this you can make the lambda a constant, like this: # # DEFAULT_DATE_ORDER = lambda {[:month, :day, :year]} # ... # I18n.t(:"date.order", :default => DEFAULT_DATE_ORDER) # # If the lambda may result in different values for each call then consider # also using the Memoize backend. # module I18n class << self @@cache_store = nil @@cache_namespace = nil def cache_store @@cache_store end def cache_store=(store) @@cache_store = store end def cache_namespace @@cache_namespace end def cache_namespace=(namespace) @@cache_namespace = namespace end def perform_caching? !cache_store.nil? end end module Backend # TODO Should the cache be cleared if new translations are stored? module Cache def translate(locale, key, options = {}) I18n.perform_caching? ? fetch(cache_key(locale, key, options)) { super } : super end protected def fetch(cache_key, &block) result = _fetch(cache_key, &block) throw(:exception, result) if result.is_a?(MissingTranslation) result = result.dup if result.frozen? rescue result result end def _fetch(cache_key, &block) result = I18n.cache_store.read(cache_key) and return result result = catch(:exception, &block) I18n.cache_store.write(cache_key, result) unless result.is_a?(Proc) result end def cache_key(locale, key, options) # This assumes that only simple, native Ruby values are passed to I18n.translate. "i18n/#{I18n.cache_namespace}/#{locale}/#{key.hash}/#{USE_INSPECT_HASH ? options.inspect.hash : options.hash}" end private # In Ruby < 1.9 the following is true: { :foo => 1, :bar => 2 }.hash == { :foo => 2, :bar => 1 }.hash # Therefore we must use the hash of the inspect string instead to avoid cache key colisions. USE_INSPECT_HASH = RUBY_VERSION <= "1.9" end end end i18n-0.6.9/lib/i18n/backend/cascade.rb0000644000004100000410000000416012260335253017163 0ustar www-datawww-data# The Cascade module adds the ability to do cascading lookups to backends that # are compatible to the Simple backend. # # By cascading lookups we mean that for any key that can not be found the # Cascade module strips one segment off the scope part of the key and then # tries to look up the key in that scope. # # E.g. when a lookup for the key :"foo.bar.baz" does not yield a result then # the segment :bar will be stripped off the scope part :"foo.bar" and the new # scope :foo will be used to look up the key :baz. If that does not succeed # then the remaining scope segment :foo will be omitted, too, and again the # key :baz will be looked up (now with no scope). # # To enable a cascading lookup one passes the :cascade option: # # I18n.t(:'foo.bar.baz', :cascade => true) # # This will return the first translation found for :"foo.bar.baz", :"foo.baz" # or :baz in this order. # # The cascading lookup takes precedence over resolving any given defaults. # I.e. defaults will kick in after the cascading lookups haven't succeeded. # # This behavior is useful for libraries like ActiveRecord validations where # the library wants to give users a bunch of more or less fine-grained options # of scopes for a particular key. # # Thanks to Clemens Kofler for the initial idea and implementation! See # http://github.com/clemens/i18n-cascading-backend module I18n module Backend module Cascade def lookup(locale, key, scope = [], options = {}) return super unless cascade = options[:cascade] cascade = { :step => 1 } unless cascade.is_a?(Hash) step = cascade[:step] || 1 offset = cascade[:offset] || 1 separator = options[:separator] || I18n.default_separator skip_root = cascade.has_key?(:skip_root) ? cascade[:skip_root] : true scope = I18n.normalize_keys(nil, key, scope, separator) key = (scope.slice!(-offset, offset) || []).join(separator) begin result = super return result unless result.nil? scope = scope.dup end while (!scope.empty? || !skip_root) && scope.slice!(-step, step) end end end end i18n-0.6.9/lib/i18n/backend/fallbacks.rb0000644000004100000410000000501712260335253017524 0ustar www-datawww-data# I18n locale fallbacks are useful when you want your application to use # translations from other locales when translations for the current locale are # missing. E.g. you might want to use :en translations when translations in # your applications main locale :de are missing. # # To enable locale fallbacks you can simply include the Fallbacks module to # the Simple backend - or whatever other backend you are using: # # I18n::Backend::Simple.include(I18n::Backend::Fallbacks) module I18n @@fallbacks = nil class << self # Returns the current fallbacks implementation. Defaults to +I18n::Locale::Fallbacks+. def fallbacks @@fallbacks ||= I18n::Locale::Fallbacks.new end # Sets the current fallbacks implementation. Use this to set a different fallbacks implementation. def fallbacks=(fallbacks) @@fallbacks = fallbacks end end module Backend module Fallbacks # Overwrites the Base backend translate method so that it will try each # locale given by I18n.fallbacks for the given locale. E.g. for the # locale :"de-DE" it might try the locales :"de-DE", :de and :en # (depends on the fallbacks implementation) until it finds a result with # the given options. If it does not find any result for any of the # locales it will then throw MissingTranslation as usual. # # The default option takes precedence over fallback locales only when # it's a Symbol. When the default contains a String, Proc or Hash # it is evaluated last after all the fallback locales have been tried. def translate(locale, key, options = {}) return super if options[:fallback] default = extract_non_symbol_default!(options) if options[:default] options[:fallback] = true I18n.fallbacks[locale].each do |fallback| catch(:exception) do result = super(fallback, key, options) return result unless result.nil? end end options.delete(:fallback) return super(locale, nil, options.merge(:default => default)) if default throw(:exception, I18n::MissingTranslation.new(locale, key, options)) end def extract_non_symbol_default!(options) defaults = [options[:default]].flatten first_non_symbol_default = defaults.detect{|default| !default.is_a?(Symbol)} if first_non_symbol_default options[:default] = defaults[0, defaults.index(first_non_symbol_default)] end return first_non_symbol_default end end end end i18n-0.6.9/lib/i18n/backend/transliterator.rb0000644000004100000410000001043312260335253020655 0ustar www-datawww-data# encoding: utf-8 module I18n module Backend module Transliterator DEFAULT_REPLACEMENT_CHAR = "?" # Given a locale and a UTF-8 string, return the locale's ASCII # approximation for the string. def transliterate(locale, string, replacement = nil) @transliterators ||= {} @transliterators[locale] ||= Transliterator.get I18n.t(:'i18n.transliterate.rule', :locale => locale, :resolve => false, :default => {}) @transliterators[locale].transliterate(string, replacement) end # Get a transliterator instance. def self.get(rule = nil) if !rule || rule.kind_of?(Hash) HashTransliterator.new(rule) elsif rule.kind_of? Proc ProcTransliterator.new(rule) else raise I18n::ArgumentError, "Transliteration rule must be a proc or a hash." end end # A transliterator which accepts a Proc as its transliteration rule. class ProcTransliterator def initialize(rule) @rule = rule end def transliterate(string, replacement = nil) @rule.call(string) end end # A transliterator which accepts a Hash of characters as its translation # rule. class HashTransliterator DEFAULT_APPROXIMATIONS = { "À"=>"A", "Á"=>"A", "Â"=>"A", "Ã"=>"A", "Ä"=>"A", "Å"=>"A", "Æ"=>"AE", "Ç"=>"C", "È"=>"E", "É"=>"E", "Ê"=>"E", "Ë"=>"E", "Ì"=>"I", "Í"=>"I", "Î"=>"I", "Ï"=>"I", "Ð"=>"D", "Ñ"=>"N", "Ò"=>"O", "Ó"=>"O", "Ô"=>"O", "Õ"=>"O", "Ö"=>"O", "×"=>"x", "Ø"=>"O", "Ù"=>"U", "Ú"=>"U", "Û"=>"U", "Ü"=>"U", "Ý"=>"Y", "Þ"=>"Th", "ß"=>"ss", "à"=>"a", "á"=>"a", "â"=>"a", "ã"=>"a", "ä"=>"a", "å"=>"a", "æ"=>"ae", "ç"=>"c", "è"=>"e", "é"=>"e", "ê"=>"e", "ë"=>"e", "ì"=>"i", "í"=>"i", "î"=>"i", "ï"=>"i", "ð"=>"d", "ñ"=>"n", "ò"=>"o", "ó"=>"o", "ô"=>"o", "õ"=>"o", "ö"=>"o", "ø"=>"o", "ù"=>"u", "ú"=>"u", "û"=>"u", "ü"=>"u", "ý"=>"y", "þ"=>"th", "ÿ"=>"y", "Ā"=>"A", "ā"=>"a", "Ă"=>"A", "ă"=>"a", "Ą"=>"A", "ą"=>"a", "Ć"=>"C", "ć"=>"c", "Ĉ"=>"C", "ĉ"=>"c", "Ċ"=>"C", "ċ"=>"c", "Č"=>"C", "č"=>"c", "Ď"=>"D", "ď"=>"d", "Đ"=>"D", "đ"=>"d", "Ē"=>"E", "ē"=>"e", "Ĕ"=>"E", "ĕ"=>"e", "Ė"=>"E", "ė"=>"e", "Ę"=>"E", "ę"=>"e", "Ě"=>"E", "ě"=>"e", "Ĝ"=>"G", "ĝ"=>"g", "Ğ"=>"G", "ğ"=>"g", "Ġ"=>"G", "ġ"=>"g", "Ģ"=>"G", "ģ"=>"g", "Ĥ"=>"H", "ĥ"=>"h", "Ħ"=>"H", "ħ"=>"h", "Ĩ"=>"I", "ĩ"=>"i", "Ī"=>"I", "ī"=>"i", "Ĭ"=>"I", "ĭ"=>"i", "Į"=>"I", "į"=>"i", "İ"=>"I", "ı"=>"i", "IJ"=>"IJ", "ij"=>"ij", "Ĵ"=>"J", "ĵ"=>"j", "Ķ"=>"K", "ķ"=>"k", "ĸ"=>"k", "Ĺ"=>"L", "ĺ"=>"l", "Ļ"=>"L", "ļ"=>"l", "Ľ"=>"L", "ľ"=>"l", "Ŀ"=>"L", "ŀ"=>"l", "Ł"=>"L", "ł"=>"l", "Ń"=>"N", "ń"=>"n", "Ņ"=>"N", "ņ"=>"n", "Ň"=>"N", "ň"=>"n", "ʼn"=>"'n", "Ŋ"=>"NG", "ŋ"=>"ng", "Ō"=>"O", "ō"=>"o", "Ŏ"=>"O", "ŏ"=>"o", "Ő"=>"O", "ő"=>"o", "Œ"=>"OE", "œ"=>"oe", "Ŕ"=>"R", "ŕ"=>"r", "Ŗ"=>"R", "ŗ"=>"r", "Ř"=>"R", "ř"=>"r", "Ś"=>"S", "ś"=>"s", "Ŝ"=>"S", "ŝ"=>"s", "Ş"=>"S", "ş"=>"s", "Š"=>"S", "š"=>"s", "Ţ"=>"T", "ţ"=>"t", "Ť"=>"T", "ť"=>"t", "Ŧ"=>"T", "ŧ"=>"t", "Ũ"=>"U", "ũ"=>"u", "Ū"=>"U", "ū"=>"u", "Ŭ"=>"U", "ŭ"=>"u", "Ů"=>"U", "ů"=>"u", "Ű"=>"U", "ű"=>"u", "Ų"=>"U", "ų"=>"u", "Ŵ"=>"W", "ŵ"=>"w", "Ŷ"=>"Y", "ŷ"=>"y", "Ÿ"=>"Y", "Ź"=>"Z", "ź"=>"z", "Ż"=>"Z", "ż"=>"z", "Ž"=>"Z", "ž"=>"z" }.freeze def initialize(rule = nil) @rule = rule add DEFAULT_APPROXIMATIONS.dup add rule if rule end def transliterate(string, replacement = nil) string.gsub(/[^\x00-\x7f]/u) do |char| approximations[char] || replacement || DEFAULT_REPLACEMENT_CHAR end end private def approximations @approximations ||= {} end # Add transliteration rules to the approximations hash. def add(hash) hash.each do |key, value| approximations[key.to_s] = value.to_s end end end end end endi18n-0.6.9/lib/i18n/backend/metadata.rb0000644000004100000410000000401212260335253017354 0ustar www-datawww-data# I18n translation metadata is useful when you want to access information # about how a translation was looked up, pluralized or interpolated in # your application. # # msg = I18n.t(:message, :default => 'Hi!', :scope => :foo) # msg.translation_metadata # # => { :key => :message, :scope => :foo, :default => 'Hi!' } # # If a :count option was passed to #translate it will be set to the metadata. # Likewise, if any interpolation variables were passed they will also be set. # # To enable translation metadata you can simply include the Metadata module # into the Simple backend class - or whatever other backend you are using: # # I18n::Backend::Simple.include(I18n::Backend::Metadata) # module I18n module Backend module Metadata class << self def included(base) Object.class_eval do def translation_metadata @translation_metadata ||= {} end def translation_metadata=(translation_metadata) @translation_metadata = translation_metadata end end unless Object.method_defined?(:translation_metadata) end end def translate(locale, key, options = {}) metadata = { :locale => locale, :key => key, :scope => options[:scope], :default => options[:default], :separator => options[:separator], :values => options.reject { |name, value| RESERVED_KEYS.include?(name) } } with_metadata(metadata) { super } end def interpolate(locale, entry, values = {}) metadata = entry.translation_metadata.merge(:original => entry) with_metadata(metadata) { super } end def pluralize(locale, entry, count) with_metadata(:count => count) { super } end protected def with_metadata(metadata, &block) result = yield result.translation_metadata = result.translation_metadata.merge(metadata) if result result end end end end i18n-0.6.9/lib/i18n/backend/simple.rb0000644000004100000410000000544312260335253017076 0ustar www-datawww-datamodule I18n module Backend # A simple backend that reads translations from YAML files and stores them in # an in-memory hash. Relies on the Base backend. # # The implementation is provided by a Implementation module allowing to easily # extend Simple backend's behavior by including modules. E.g.: # # module I18n::Backend::Pluralization # def pluralize(*args) # # extended pluralization logic # super # end # end # # I18n::Backend::Simple.include(I18n::Backend::Pluralization) class Simple (class << self; self; end).class_eval { public :include } module Implementation include Base def initialized? @initialized ||= false end # Stores translations for the given locale in memory. # This uses a deep merge for the translations hash, so existing # translations will be overwritten by new ones only at the deepest # level of the hash. def store_translations(locale, data, options = {}) locale = locale.to_sym translations[locale] ||= {} data = data.deep_symbolize_keys translations[locale].deep_merge!(data) end # Get available locales from the translations hash def available_locales init_translations unless initialized? translations.inject([]) do |locales, (locale, data)| locales << locale unless (data.keys - [:i18n]).empty? locales end end # Clean up translations hash and set initialized to false on reload! def reload! @initialized = false @translations = nil super end protected def init_translations load_translations @initialized = true end def translations @translations ||= {} end # Looks up a translation from the translations hash. Returns nil if # eiher key is nil, or locale, scope or key do not exist as a key in the # nested translations hash. Splits keys or scopes containing dots # into multiple keys, i.e. currency.format is regarded the same as # %w(currency format). def lookup(locale, key, scope = [], options = {}) init_translations unless initialized? keys = I18n.normalize_keys(locale, key, scope, options[:separator]) keys.inject(translations) do |result, _key| _key = _key.to_sym return nil unless result.is_a?(Hash) && result.has_key?(_key) result = result[_key] result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol) result end end end include Implementation end end end i18n-0.6.9/lib/i18n/backend/interpolation_compiler.rb0000644000004100000410000000726712260335253022374 0ustar www-datawww-data# The InterpolationCompiler module contains optimizations that can tremendously # speed up the interpolation process on the Simple backend. # # It works by defining a pre-compiled method on stored translation Strings that # already bring all the knowledge about contained interpolation variables etc. # so that the actual recurring interpolation will be very fast. # # To enable pre-compiled interpolations you can simply include the # InterpolationCompiler module to the Simple backend: # # I18n::Backend::Simple.include(I18n::Backend::InterpolationCompiler) # # Note that InterpolationCompiler does not yield meaningful results and consequently # should not be used with Ruby 1.9 (YARV) but improves performance everywhere else # (jRuby, Rubinius and 1.8.7). module I18n module Backend module InterpolationCompiler module Compiler extend self TOKENIZER = /(%%\{[^\}]+\}|%\{[^\}]+\})/ INTERPOLATION_SYNTAX_PATTERN = /(%)?(%\{([^\}]+)\})/ def compile_if_an_interpolation(string) if interpolated_str?(string) string.instance_eval <<-RUBY_EVAL, __FILE__, __LINE__ def i18n_interpolate(v = {}) "#{compiled_interpolation_body(string)}" end RUBY_EVAL end string end def interpolated_str?(str) str.kind_of?(::String) && str =~ INTERPOLATION_SYNTAX_PATTERN end protected # tokenize("foo %{bar} baz %%{buz}") # => ["foo ", "%{bar}", " baz ", "%%{buz}"] def tokenize(str) str.split(TOKENIZER) end def compiled_interpolation_body(str) tokenize(str).map do |token| (matchdata = token.match(INTERPOLATION_SYNTAX_PATTERN)) ? handle_interpolation_token(token, matchdata) : escape_plain_str(token) end.join end def handle_interpolation_token(interpolation, matchdata) escaped, pattern, key = matchdata.values_at(1, 2, 3) escaped ? pattern : compile_interpolation_token(key.to_sym) end def compile_interpolation_token(key) "\#{#{interpolate_or_raise_missing(key)}}" end def interpolate_or_raise_missing(key) escaped_key = escape_key_sym(key) RESERVED_KEYS.include?(key) ? reserved_key(escaped_key) : interpolate_key(escaped_key) end def interpolate_key(key) [direct_key(key), nil_key(key), missing_key(key)].join('||') end def direct_key(key) "((t = v[#{key}]) && t.respond_to?(:call) ? t.call : t)" end def nil_key(key) "(v.has_key?(#{key}) && '')" end def missing_key(key) "I18n.config.missing_interpolation_argument_handler.call(#{key}, v, self)" end def reserved_key(key) "raise(ReservedInterpolationKey.new(#{key}, self))" end def escape_plain_str(str) str.gsub(/"|\\|#/) {|x| "\\#{x}"} end def escape_key_sym(key) # rely on Ruby to do all the hard work :) key.to_sym.inspect end end def interpolate(locale, string, values) if string.respond_to?(:i18n_interpolate) string.i18n_interpolate(values) elsif values super else string end end def store_translations(locale, data, options = {}) compile_all_strings_in(data) super end protected def compile_all_strings_in(data) data.each_value do |value| Compiler.compile_if_an_interpolation(value) compile_all_strings_in(value) if value.kind_of?(Hash) end end end end end i18n-0.6.9/lib/i18n/backend/chain.rb0000644000004100000410000000527112260335253016666 0ustar www-datawww-datamodule I18n module Backend # Backend that chains multiple other backends and checks each of them when # a translation needs to be looked up. This is useful when you want to use # standard translations with a Simple backend but store custom application # translations in a database or other backends. # # To use the Chain backend instantiate it and set it to the I18n module. # You can add chained backends through the initializer or backends # accessor: # # # preserves the existing Simple backend set to I18n.backend # I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n.backend) # # The implementation assumes that all backends added to the Chain implement # a lookup method with the same API as Simple backend does. class Chain module Implementation include Base attr_accessor :backends def initialize(*backends) self.backends = backends end def reload! backends.each { |backend| backend.reload! } end def store_translations(locale, data, options = {}) backends.first.store_translations(locale, data, options) end def available_locales backends.map { |backend| backend.available_locales }.flatten.uniq end def translate(locale, key, default_options = {}) namespace = nil options = default_options.except(:default) backends.each do |backend| catch(:exception) do options = default_options if backend == backends.last translation = backend.translate(locale, key, options) if namespace_lookup?(translation, options) namespace = translation.merge(namespace || {}) elsif !translation.nil? return translation end end end return namespace if namespace throw(:exception, I18n::MissingTranslation.new(locale, key, options)) end def exists?(locale, key) backends.any? do |backend| backend.exists?(locale, key) end end def localize(locale, object, format = :default, options = {}) backends.each do |backend| catch(:exception) do result = backend.localize(locale, object, format, options) and return result end end throw(:exception, I18n::MissingTranslation.new(locale, format, options)) end protected def namespace_lookup?(result, options) result.is_a?(Hash) && !options.has_key?(:count) end end include Implementation end end end i18n-0.6.9/lib/i18n/backend/memoize.rb0000644000004100000410000000247512260335253017254 0ustar www-datawww-data# Memoize module simply memoizes the values returned by lookup using # a flat hash and can tremendously speed up the lookup process in a backend. # # To enable it you can simply include the Memoize module to your backend: # # I18n::Backend::Simple.include(I18n::Backend::Memoize) # # Notice that it's the responsibility of the backend to define whenever the # cache should be cleaned. module I18n module Backend module Memoize def available_locales @memoized_locales ||= super end def store_translations(locale, data, options = {}) reset_memoizations!(locale) super end def reload! reset_memoizations! super end protected def lookup(locale, key, scope = nil, options = {}) flat_key = I18n::Backend::Flatten.normalize_flat_keys(locale, key, scope, options[:separator]).to_sym flat_hash = memoized_lookup[locale.to_sym] flat_hash.key?(flat_key) ? flat_hash[flat_key] : (flat_hash[flat_key] = super) end def memoized_lookup @memoized_lookup ||= Hash.new { |h, k| h[k] = {} } end def reset_memoizations!(locale=nil) @memoized_locales = nil (locale ? memoized_lookup[locale.to_sym] : memoized_lookup).clear end end end end i18n-0.6.9/lib/i18n/backend/gettext.rb0000644000004100000410000000466012260335253017271 0ustar www-datawww-datarequire 'i18n/gettext' require 'i18n/gettext/po_parser' # Experimental support for using Gettext po files to store translations. # # To use this you can simply include the module to the Simple backend - or # whatever other backend you are using. # # I18n::Backend::Simple.include(I18n::Backend::Gettext) # # Now you should be able to include your Gettext translation (*.po) files to # the I18n.load_path so they're loaded to the backend and you can use them as # usual: # # I18n.load_path += Dir["path/to/locales/*.po"] # # Following the Gettext convention this implementation expects that your # translation files are named by their locales. E.g. the file en.po would # contain the translations for the English locale. module I18n module Backend module Gettext class PoData < Hash def set_comment(msgid_or_sym, comment) # ignore end end protected def load_po(filename) locale = ::File.basename(filename, '.po').to_sym data = normalize(locale, parse(filename)) { locale => data } end def parse(filename) GetText::PoParser.new.parse(::File.read(filename), PoData.new) end def normalize(locale, data) data.inject({}) do |result, (key, value)| unless key.nil? || key.empty? key = key.gsub(I18n::Gettext::CONTEXT_SEPARATOR, '|') key, value = normalize_pluralization(locale, key, value) if key.index("\000") parts = key.split('|').reverse normalized = parts.inject({}) do |_normalized, part| { part => _normalized.empty? ? value : _normalized } end result.deep_merge!(normalized) end result end end def normalize_pluralization(locale, key, value) # FIXME po_parser includes \000 chars that can not be turned into Symbols key = key.gsub("\000", I18n::Gettext::PLURAL_SEPARATOR).split(I18n::Gettext::PLURAL_SEPARATOR).first keys = I18n::Gettext.plural_keys(locale) values = value.split("\000") raise "invalid number of plurals: #{values.size}, keys: #{keys.inspect} on #{locale} locale for msgid #{key.inspect} with values #{values.inspect}" if values.size != keys.size result = {} values.each_with_index { |_value, ix| result[keys[ix]] = _value } [key, result] end end end end i18n-0.6.9/lib/i18n/backend/key_value.rb0000644000004100000410000000710612260335253017567 0ustar www-datawww-datarequire 'i18n/backend/base' require 'active_support/json' require 'active_support/ordered_hash' # active_support/json/encoding uses ActiveSupport::OrderedHash but does not require it module I18n module Backend # This is a basic backend for key value stores. It receives on # initialization the store, which should respond to three methods: # # * store#[](key) - Used to get a value # * store#[]=(key, value) - Used to set a value # * store#keys - Used to get all keys # # Since these stores only supports string, all values are converted # to JSON before being stored, allowing it to also store booleans, # hashes and arrays. However, this store does not support Procs. # # As the ActiveRecord backend, Symbols are just supported when loading # translations from the filesystem or through explicit store translations. # # Also, avoid calling I18n.available_locales since it's a somehow # expensive operation in most stores. # # == Example # # To setup I18n to use TokyoCabinet in memory is quite straightforward: # # require 'rufus/tokyo/cabinet' # gem install rufus-tokyo # I18n.backend = I18n::Backend::KeyValue.new(Rufus::Tokyo::Cabinet.new('*')) # # == Performance # # You may make this backend even faster by including the Memoize module. # However, notice that you should properly clear the cache if you change # values directly in the key-store. # # == Subtrees # # In most backends, you are allowed to retrieve part of a translation tree: # # I18n.backend.store_translations :en, :foo => { :bar => :baz } # I18n.t "foo" #=> { :bar => :baz } # # This backend supports this feature by default, but it slows down the storage # of new data considerably and makes hard to delete entries. That said, you are # allowed to disable the storage of subtrees on initialization: # # I18n::Backend::KeyValue.new(@store, false) # # This is useful if you are using a KeyValue backend chained to a Simple backend. class KeyValue module Implementation attr_accessor :store include Base, Flatten def initialize(store, subtrees=true) @store, @subtrees = store, subtrees end def store_translations(locale, data, options = {}) escape = options.fetch(:escape, true) flatten_translations(locale, data, escape, @subtrees).each do |key, value| key = "#{locale}.#{key}" case value when Hash if @subtrees && (old_value = @store[key]) old_value = ActiveSupport::JSON.decode(old_value) value = old_value.deep_symbolize_keys.deep_merge!(value) if old_value.is_a?(Hash) end when Proc raise "Key-value stores cannot handle procs" end @store[key] = ActiveSupport::JSON.encode(value) unless value.is_a?(Symbol) end end def available_locales locales = @store.keys.map { |k| k =~ /\./; $` } locales.uniq! locales.compact! locales.map! { |k| k.to_sym } locales end protected def lookup(locale, key, scope = [], options = {}) key = normalize_flat_keys(locale, key, scope, options[:separator]) value = @store["#{locale}.#{key}"] value = ActiveSupport::JSON.decode(value) if value value.is_a?(Hash) ? value.deep_symbolize_keys : value end end include Implementation end end end i18n-0.6.9/lib/i18n/backend/flatten.rb0000644000004100000410000000734612260335253017246 0ustar www-datawww-datamodule I18n module Backend # This module contains several helpers to assist flattening translations. # You may want to flatten translations for: # # 1) speed up lookups, as in the Memoize backend; # 2) In case you want to store translations in a data store, as in ActiveRecord backend; # # You can check both backends above for some examples. # This module also keeps all links in a hash so they can be properly resolved when flattened. module Flatten SEPARATOR_ESCAPE_CHAR = "\001" FLATTEN_SEPARATOR = "." # normalize_keys the flatten way. This method is significantly faster # and creates way less objects than the one at I18n.normalize_keys. # It also handles escaping the translation keys. def self.normalize_flat_keys(locale, key, scope, separator) keys = [scope, key].flatten.compact separator ||= I18n.default_separator if separator != FLATTEN_SEPARATOR keys.map! do |k| k.to_s.tr("#{FLATTEN_SEPARATOR}#{separator}", "#{SEPARATOR_ESCAPE_CHAR}#{FLATTEN_SEPARATOR}") end end keys.join(".") end # Receives a string and escape the default separator. def self.escape_default_separator(key) #:nodoc: key.to_s.tr(FLATTEN_SEPARATOR, SEPARATOR_ESCAPE_CHAR) end # Shortcut to I18n::Backend::Flatten.normalize_flat_keys # and then resolve_links. def normalize_flat_keys(locale, key, scope, separator) key = I18n::Backend::Flatten.normalize_flat_keys(locale, key, scope, separator) resolve_link(locale, key) end # Store flattened links. def links @links ||= Hash.new { |h,k| h[k] = {} } end # Flatten keys for nested Hashes by chaining up keys: # # >> { "a" => { "b" => { "c" => "d", "e" => "f" }, "g" => "h" }, "i" => "j"}.wind # => { "a.b.c" => "d", "a.b.e" => "f", "a.g" => "h", "i" => "j" } # def flatten_keys(hash, escape, prev_key=nil, &block) hash.each_pair do |key, value| key = escape_default_separator(key) if escape curr_key = [prev_key, key].compact.join(FLATTEN_SEPARATOR).to_sym yield curr_key, value flatten_keys(value, escape, curr_key, &block) if value.is_a?(Hash) end end # Receives a hash of translations (where the key is a locale and # the value is another hash) and return a hash with all # translations flattened. # # Nested hashes are included in the flattened hash just if subtree # is true and Symbols are automatically stored as links. def flatten_translations(locale, data, escape, subtree) hash = {} flatten_keys(data, escape) do |key, value| if value.is_a?(Hash) hash[key] = value if subtree else store_link(locale, key, value) if value.is_a?(Symbol) hash[key] = value end end hash end protected def store_link(locale, key, link) links[locale.to_sym][key.to_s] = link.to_s end def resolve_link(locale, key) key, locale = key.to_s, locale.to_sym links = self.links[locale] if links.key?(key) links[key] elsif link = find_link(locale, key) store_link(locale, key, key.gsub(*link)) else key end end def find_link(locale, key) #:nodoc: links[locale].each do |from, to| return [from, to] if key[0, from.length] == from end && nil end def escape_default_separator(key) #:nodoc: I18n::Backend::Flatten.escape_default_separator(key) end end end endi18n-0.6.9/lib/i18n/backend/base.rb0000644000004100000410000001735012260335253016517 0ustar www-datawww-datarequire 'yaml' require 'i18n/core_ext/hash' require 'i18n/core_ext/kernel/surpress_warnings' module I18n module Backend module Base include I18n::Backend::Transliterator # Accepts a list of paths to translation files. Loads translations from # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml # for details. def load_translations(*filenames) filenames = I18n.load_path if filenames.empty? filenames.flatten.each { |filename| load_file(filename) } end # This method receives a locale, a data hash and options for storing translations. # Should be implemented def store_translations(locale, data, options = {}) raise NotImplementedError end def translate(locale, key, options = {}) raise InvalidLocale.new(locale) unless locale entry = key && lookup(locale, key, options[:scope], options) if options.empty? entry = resolve(locale, key, entry, options) else count, default = options.values_at(:count, :default) values = options.except(*RESERVED_KEYS) entry = entry.nil? && default ? default(locale, key, default, options) : resolve(locale, key, entry, options) end throw(:exception, I18n::MissingTranslation.new(locale, key, options)) if entry.nil? entry = entry.dup if entry.is_a?(String) entry = pluralize(locale, entry, count) if count entry = interpolate(locale, entry, values) if values entry end def exists?(locale, key) lookup(locale, key) != nil end # Acts the same as +strftime+, but uses a localized version of the # format string. Takes a key from the date/time formats translations as # a format argument (e.g., :short in :'date.formats'). def localize(locale, object, format = :default, options = {}) raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) if Symbol === format key = format type = object.respond_to?(:sec) ? 'time' : 'date' options = options.merge(:raise => true, :object => object, :locale => locale) format = I18n.t(:"#{type}.formats.#{key}", options) end # format = resolve(locale, object, format, options) format = format.to_s.gsub(/%[aAbBpP]/) do |match| case match when '%a' then I18n.t(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday] when '%A' then I18n.t(:"date.day_names", :locale => locale, :format => format)[object.wday] when '%b' then I18n.t(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon] when '%B' then I18n.t(:"date.month_names", :locale => locale, :format => format)[object.mon] when '%p' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).upcase if object.respond_to? :hour when '%P' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).downcase if object.respond_to? :hour end end object.strftime(format) end # Returns an array of locales for which translations are available # ignoring the reserved translation meta data key :i18n. def available_locales raise NotImplementedError end def reload! @skip_syntax_deprecation = false end protected # The method which actually looks up for the translation in the store. def lookup(locale, key, scope = [], options = {}) raise NotImplementedError end # Evaluates defaults. # If given subject is an Array, it walks the array and returns the # first translation that can be resolved. Otherwise it tries to resolve # the translation directly. def default(locale, object, subject, options = {}) options = options.dup.reject { |key, value| key == :default } case subject when Array subject.each do |item| result = resolve(locale, object, item, options) and return result end and nil else resolve(locale, object, subject, options) end end # Resolves a translation. # If the given subject is a Symbol, it will be translated with the # given options. If it is a Proc then it will be evaluated. All other # subjects will be returned directly. def resolve(locale, object, subject, options = {}) return subject if options[:resolve] == false result = catch(:exception) do case subject when Symbol I18n.translate(subject, options.merge(:locale => locale, :throw => true)) when Proc date_or_time = options.delete(:object) || object resolve(locale, object, subject.call(date_or_time, options)) else subject end end result unless result.is_a?(MissingTranslation) end # Picks a translation from a pluralized mnemonic subkey according to English # pluralization rules : # - It will pick the :one subkey if count is equal to 1. # - It will pick the :other subkey otherwise. # - It will pick the :zero subkey in the special case where count is # equal to 0 and there is a :zero subkey present. This behaviour is # not stand with regards to the CLDR pluralization rules. # Other backends can implement more flexible or complex pluralization rules. def pluralize(locale, entry, count) return entry unless entry.is_a?(Hash) && count key = :zero if count == 0 && entry.has_key?(:zero) key ||= count == 1 ? :one : :other raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) entry[key] end # Interpolates values into a given string. # # interpolate "file %{file} opened by %%{user}", :file => 'test.txt', :user => 'Mr. X' # # => "file test.txt opened by %{user}" def interpolate(locale, string, values = {}) if string.is_a?(::String) && !values.empty? I18n.interpolate(string, values) else string end end # Loads a single translations file by delegating to #load_rb or # #load_yml depending on the file extension and directly merges the # data to the existing translations. Raises I18n::UnknownFileType # for all other file extensions. def load_file(filename) type = File.extname(filename).tr('.', '').downcase raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}", true) data = send(:"load_#{type}", filename) unless data.is_a?(Hash) raise InvalidLocaleData.new(filename, 'expects it to return a hash, but does not') end data.each { |locale, d| store_translations(locale, d || {}) } end # Loads a plain Ruby translations file. eval'ing the file must yield # a Hash containing translation data with locales as toplevel keys. def load_rb(filename) eval(IO.read(filename), binding, filename) end # Loads a YAML translations file. The data must have locales as # toplevel keys. def load_yml(filename) begin YAML.load_file(filename) rescue TypeError, ScriptError, StandardError => e raise InvalidLocaleData.new(filename, e.inspect) end end end end end i18n-0.6.9/lib/i18n/backend/pluralization.rb0000644000004100000410000000405312260335253020476 0ustar www-datawww-data# I18n Pluralization are useful when you want your application to # customize pluralization rules. # # To enable locale specific pluralizations you can simply include the # Pluralization module to the Simple backend - or whatever other backend you # are using. # # I18n::Backend::Simple.include(I18n::Backend::Pluralization) # # You also need to make sure to provide pluralization algorithms to the # backend, i.e. include them to your I18n.load_path accordingly. module I18n module Backend module Pluralization # Overwrites the Base backend translate method so that it will check the # translation meta data space (:i18n) for a locale specific pluralization # rule and use it to pluralize the given entry. I.e. the library expects # pluralization rules to be stored at I18n.t(:'i18n.plural.rule') # # Pluralization rules are expected to respond to #call(count) and # return a pluralization key. Valid keys depend on the translation data # hash (entry) but it is generally recommended to follow CLDR's style, # i.e., return one of the keys :zero, :one, :few, :many, :other. # # The :zero key is always picked directly when count equals 0 AND the # translation data has the key :zero. This way translators are free to # either pick a special :zero translation even for languages where the # pluralizer does not return a :zero key. def pluralize(locale, entry, count) return entry unless entry.is_a?(Hash) and count pluralizer = pluralizer(locale) if pluralizer.respond_to?(:call) key = count == 0 && entry.has_key?(:zero) ? :zero : pluralizer.call(count) raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key) entry[key] else super end end protected def pluralizers @pluralizers ||= {} end def pluralizer(locale) pluralizers[locale] ||= I18n.t(:'i18n.plural.rule', :locale => locale, :resolve => false) end end end end i18n-0.6.9/lib/i18n/exceptions.rb0000644000004100000410000000763312260335253016402 0ustar www-datawww-datarequire 'cgi' module I18n # Handles exceptions raised in the backend. All exceptions except for # MissingTranslationData exceptions are re-thrown. When a MissingTranslationData # was caught the handler returns an error message string containing the key/scope. # Note that the exception handler is not called when the option :throw was given. class ExceptionHandler include Module.new { def call(exception, locale, key, options) if exception.is_a?(MissingTranslation) # # TODO: this block is to be replaced by `exception.message` when # rescue_format is removed if options[:rescue_format] == :html if @rescue_format_deprecation $stderr.puts "[DEPRECATED] I18n's :recue_format option will be removed from a future release. All exception messages will be plain text. If you need the exception handler to return an html format please set or pass a custom exception handler." @rescue_format_deprecation = true end exception.html_message else exception.message end elsif exception.is_a?(Exception) raise exception else throw :exception, exception end end } end class ArgumentError < ::ArgumentError; end class InvalidLocale < ArgumentError attr_reader :locale def initialize(locale) @locale = locale super "#{locale.inspect} is not a valid locale" end end class InvalidLocaleData < ArgumentError attr_reader :filename def initialize(filename, exception_message) @filename, @exception_message = filename, exception_message super "can not load translations from #{filename}: #{exception_message}" end end class MissingTranslation module Base attr_reader :locale, :key, :options def initialize(locale, key, options = nil) @key, @locale, @options = key, locale, options.dup || {} options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) } end def html_message key = CGI.escapeHTML titleize(keys.last) path = CGI.escapeHTML keys.join('.') %(#{key}) end def keys @keys ||= I18n.normalize_keys(locale, key, options[:scope]).tap do |keys| keys << 'no key' if keys.size < 2 end end def message "translation missing: #{keys.join('.')}" end alias :to_s :message def to_exception MissingTranslationData.new(locale, key, options) end protected # TODO : remove when #html_message is removed def titleize(key) key.to_s.gsub('_', ' ').gsub(/\b('?[a-z])/) { $1.capitalize } end end include Base end class MissingTranslationData < ArgumentError include MissingTranslation::Base end class InvalidPluralizationData < ArgumentError attr_reader :entry, :count def initialize(entry, count) @entry, @count = entry, count super "translation data #{entry.inspect} can not be used with :count => #{count}" end end class MissingInterpolationArgument < ArgumentError attr_reader :key, :values, :string def initialize(key, values, string) @key, @values, @string = key, values, string super "missing interpolation argument #{key.inspect} in #{string.inspect} (#{values.inspect} given)" end end class ReservedInterpolationKey < ArgumentError attr_reader :key, :string def initialize(key, string) @key, @string = key, string super "reserved key #{key.inspect} used in #{string.inspect}" end end class UnknownFileType < ArgumentError attr_reader :type, :filename def initialize(type, filename) @type, @filename = type, filename super "can not load translations from #{filename}, the file type #{type} is not known" end end end i18n-0.6.9/lib/i18n/interpolate/0000755000004100000410000000000012260335253016211 5ustar www-datawww-datai18n-0.6.9/lib/i18n/interpolate/ruby.rb0000644000004100000410000000261712260335253017525 0ustar www-datawww-data# heavily based on Masao Mutoh's gettext String interpolation extension # http://github.com/mutoh/gettext/blob/f6566738b981fe0952548c421042ad1e0cdfb31e/lib/gettext/core_ext/string.rb module I18n INTERPOLATION_PATTERN = Regexp.union( /%%/, /%\{(\w+)\}/, # matches placeholders like "%{foo}" /%<(\w+)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/ # matches placeholders like "%.d" ) class << self # Return String or raises MissingInterpolationArgument exception. # Missing argument's logic is handled by I18n.config.missing_interpolation_argument_handler. def interpolate(string, values) raise ReservedInterpolationKey.new($1.to_sym, string) if string =~ RESERVED_KEYS_PATTERN raise ArgumentError.new('Interpolation values must be a Hash.') unless values.kind_of?(Hash) interpolate_hash(string, values) end def interpolate_hash(string, values) string.gsub(INTERPOLATION_PATTERN) do |match| if match == '%%' '%' else key = ($1 || $2).to_sym value = if values.key?(key) values[key] else config.missing_interpolation_argument_handler.call(key, values, string) end value = value.call(values) if value.respond_to?(:call) $3 ? sprintf("%#{$3}", value) : value end end end end end i18n-0.6.9/lib/i18n/locale.rb0000644000004100000410000000017612260335253015453 0ustar www-datawww-datamodule I18n module Locale autoload :Fallbacks, 'i18n/locale/fallbacks' autoload :Tag, 'i18n/locale/tag' end end i18n-0.6.9/lib/i18n/locale/0000755000004100000410000000000012260335253015122 5ustar www-datawww-datai18n-0.6.9/lib/i18n/locale/fallbacks.rb0000644000004100000410000000644212260335253017377 0ustar www-datawww-data# Locale Fallbacks # # Extends the I18n module to hold a fallbacks instance which is set to an # instance of I18n::Locale::Fallbacks by default but can be swapped with a # different implementation. # # Locale fallbacks will compute a number of fallback locales for a given locale. # For example: # #

# I18n.fallbacks[:"es-MX"] # => [:"es-MX", :es, :en] 
# # Locale fallbacks always fall back to # # * all parent locales of a given locale (e.g. :es for :"es-MX") first, # * the current default locales and all of their parents second # # The default locales are set to [I18n.default_locale] by default but can be # set to something else. # # One can additionally add any number of additional fallback locales manually. # These will be added before the default locales to the fallback chain. For # example: # # # using the default locale as default fallback locale # # I18n.default_locale = :"en-US" # I18n.fallbacks = I18n::Locale::Fallbacks.new(:"de-AT" => :"de-DE") # I18n.fallbacks[:"de-AT"] # => [:"de-AT", :"de-DE", :de, :"en-US", :en] # # # using a custom locale as default fallback locale # # I18n.fallbacks = I18n::Locale::Fallbacks.new(:"en-GB", :"de-AT" => :de, :"de-CH" => :de) # I18n.fallbacks[:"de-AT"] # => [:"de-AT", :de, :"en-GB", :en] # I18n.fallbacks[:"de-CH"] # => [:"de-CH", :de, :"en-GB", :en] # # # mapping fallbacks to an existing instance # # # people speaking Catalan also speak Spanish as spoken in Spain # fallbacks = I18n.fallbacks # fallbacks.map(:ca => :"es-ES") # fallbacks[:ca] # => [:ca, :"es-ES", :es, :"en-US", :en] # # # people speaking Arabian as spoken in Palestine also speak Hebrew as spoken in Israel # fallbacks.map(:"ar-PS" => :"he-IL") # fallbacks[:"ar-PS"] # => [:"ar-PS", :ar, :"he-IL", :he, :"en-US", :en] # fallbacks[:"ar-EG"] # => [:"ar-EG", :ar, :"en-US", :en] # # # people speaking Sami as spoken in Finnland also speak Swedish and Finnish as spoken in Finnland # fallbacks.map(:sms => [:"se-FI", :"fi-FI"]) # fallbacks[:sms] # => [:sms, :"se-FI", :se, :"fi-FI", :fi, :"en-US", :en] module I18n module Locale class Fallbacks < Hash def initialize(*mappings) @map = {} map(mappings.pop) if mappings.last.is_a?(Hash) self.defaults = mappings.empty? ? [I18n.default_locale.to_sym] : mappings end def defaults=(defaults) @defaults = defaults.map { |default| compute(default, false) }.flatten end attr_reader :defaults def [](locale) raise InvalidLocale.new(locale) if locale.nil? locale = locale.to_sym super || store(locale, compute(locale)) end def map(mappings) mappings.each do |from, to| from, to = from.to_sym, Array(to) to.each do |_to| @map[from] ||= [] @map[from] << _to.to_sym end end end protected def compute(tags, include_defaults = true, exclude = []) result = Array(tags).collect do |tag| tags = I18n::Locale::Tag.tag(tag).self_and_parents.map! { |t| t.to_sym } - exclude tags.each { |_tag| tags += compute(@map[_tag], false, exclude + tags) if @map[_tag] } tags end.flatten result.push(*defaults) if include_defaults result.uniq.compact end end end end i18n-0.6.9/lib/i18n/locale/tag.rb0000644000004100000410000000145212260335253016224 0ustar www-datawww-data# encoding: utf-8 module I18n module Locale module Tag autoload :Parents, 'i18n/locale/tag/parents' autoload :Rfc4646, 'i18n/locale/tag/rfc4646' autoload :Simple, 'i18n/locale/tag/simple' class << self # Returns the current locale tag implementation. Defaults to +I18n::Locale::Tag::Simple+. def implementation @@implementation ||= Simple end # Sets the current locale tag implementation. Use this to set a different locale tag implementation. def implementation=(implementation) @@implementation = implementation end # Factory method for locale tags. Delegates to the current locale tag implementation. def tag(tag) implementation.tag(tag) end end end end end i18n-0.6.9/lib/i18n/locale/tag/0000755000004100000410000000000012260335253015675 5ustar www-datawww-datai18n-0.6.9/lib/i18n/locale/tag/parents.rb0000644000004100000410000000074412260335253017703 0ustar www-datawww-datamodule I18n module Locale module Tag module Parents def parent @parent ||= begin segs = to_a.compact segs.length > 1 ? self.class.tag(*segs[0..(segs.length-2)].join('-')) : nil end end def self_and_parents @self_and_parents ||= [self] + parents end def parents @parents ||= ([parent] + (parent ? parent.parents : [])).compact end end end end end i18n-0.6.9/lib/i18n/locale/tag/simple.rb0000644000004100000410000000124012260335253017510 0ustar www-datawww-data# Simple Locale tag implementation that computes subtags by simply splitting # the locale tag at '-' occurences. module I18n module Locale module Tag class Simple class << self def tag(tag) new(tag) end end include Parents attr_reader :tag def initialize(*tag) @tag = tag.join('-').to_sym end def subtags @subtags = tag.to_s.split('-').map { |subtag| subtag.to_s } end def to_sym tag end def to_s tag.to_s end def to_a subtags end end end end end i18n-0.6.9/lib/i18n/locale/tag/rfc4646.rb0000644000004100000410000000466312260335253017331 0ustar www-datawww-data# RFC 4646/47 compliant Locale tag implementation that parses locale tags to # subtags such as language, script, region, variant etc. # # For more information see by http://en.wikipedia.org/wiki/IETF_language_tag # # Rfc4646::Parser does not implement grandfathered tags. module I18n module Locale module Tag RFC4646_SUBTAGS = [ :language, :script, :region, :variant, :extension, :privateuse, :grandfathered ] RFC4646_FORMATS = { :language => :downcase, :script => :capitalize, :region => :upcase, :variant => :downcase } class Rfc4646 < Struct.new(*RFC4646_SUBTAGS) class << self # Parses the given tag and returns a Tag instance if it is valid. # Returns false if the given tag is not valid according to RFC 4646. def tag(tag) matches = parser.match(tag) new(*matches) if matches end def parser @@parser ||= Rfc4646::Parser end def parser=(parser) @@parser = parser end end include Parents RFC4646_FORMATS.each do |name, format| define_method(name) { self[name].send(format) unless self[name].nil? } end def to_sym to_s.to_sym end def to_s @tag ||= to_a.compact.join("-") end def to_a members.collect { |attr| self.send(attr) } end module Parser PATTERN = %r{\A(?: ([a-z]{2,3}(?:(?:-[a-z]{3}){0,3})?|[a-z]{4}|[a-z]{5,8}) # language (?:-([a-z]{4}))? # script (?:-([a-z]{2}|\d{3}))? # region (?:-([0-9a-z]{5,8}|\d[0-9a-z]{3}))* # variant (?:-([0-9a-wyz](?:-[0-9a-z]{2,8})+))* # extension (?:-(x(?:-[0-9a-z]{1,8})+))?| # privateuse subtag (x(?:-[0-9a-z]{1,8})+)| # privateuse tag /* ([a-z]{1,3}(?:-[0-9a-z]{2,8}){1,2}) */ # grandfathered )\z}xi class << self def match(tag) c = PATTERN.match(tag.to_s).captures c[0..4] << (c[5].nil? ? c[6] : c[5]) << c[7] # TODO c[7] is grandfathered, throw a NotImplemented exception here? rescue false end end end end end end end i18n-0.6.9/lib/i18n.rb0000755000004100000410000003421212260335253014215 0ustar www-datawww-datarequire 'i18n/version' require 'i18n/exceptions' require 'i18n/interpolate/ruby' module I18n autoload :Backend, 'i18n/backend' autoload :Config, 'i18n/config' autoload :Gettext, 'i18n/gettext' autoload :Locale, 'i18n/locale' autoload :Tests, 'i18n/tests' RESERVED_KEYS = [:scope, :default, :separator, :resolve, :object, :fallback, :format, :cascade, :throw, :raise, :rescue_format] RESERVED_KEYS_PATTERN = /%\{(#{RESERVED_KEYS.join("|")})\}/ extend(Module.new { # Gets I18n configuration object. def config Thread.current[:i18n_config] ||= I18n::Config.new end # Sets I18n configuration object. def config=(value) Thread.current[:i18n_config] = value end # Write methods which delegates to the configuration object %w(locale backend default_locale available_locales default_separator exception_handler load_path enforce_available_locales).each do |method| module_eval <<-DELEGATORS, __FILE__, __LINE__ + 1 def #{method} config.#{method} end def #{method}=(value) config.#{method} = (value) end DELEGATORS end # Tells the backend to reload translations. Used in situations like the # Rails development environment. Backends can implement whatever strategy # is useful. def reload! config.backend.reload! end # Translates, pluralizes and interpolates a given key using a given locale, # scope, and default, as well as interpolation values. # # *LOOKUP* # # Translation data is organized as a nested hash using the upper-level keys # as namespaces. E.g., ActionView ships with the translation: # :date => {:formats => {:short => "%b %d"}}. # # Translations can be looked up at any level of this hash using the key argument # and the scope option. E.g., in this example I18n.t :date # returns the whole translations hash {:formats => {:short => "%b %d"}}. # # Key can be either a single key or a dot-separated key (both Strings and Symbols # work). E.g., the short format can be looked up using both: # I18n.t 'date.formats.short' # I18n.t :'date.formats.short' # # Scope can be either a single key, a dot-separated key or an array of keys # or dot-separated keys. Keys and scopes can be combined freely. So these # examples will all look up the same short date format: # I18n.t 'date.formats.short' # I18n.t 'formats.short', :scope => 'date' # I18n.t 'short', :scope => 'date.formats' # I18n.t 'short', :scope => %w(date formats) # # *INTERPOLATION* # # Translations can contain interpolation variables which will be replaced by # values passed to #translate as part of the options hash, with the keys matching # the interpolation variable names. # # E.g., with a translation :foo => "foo %{bar}" the option # value for the key +bar+ will be interpolated into the translation: # I18n.t :foo, :bar => 'baz' # => 'foo baz' # # *PLURALIZATION* # # Translation data can contain pluralized translations. Pluralized translations # are arrays of singluar/plural versions of translations like ['Foo', 'Foos']. # # Note that I18n::Backend::Simple only supports an algorithm for English # pluralization rules. Other algorithms can be supported by custom backends. # # This returns the singular version of a pluralized translation: # I18n.t :foo, :count => 1 # => 'Foo' # # These both return the plural version of a pluralized translation: # I18n.t :foo, :count => 0 # => 'Foos' # I18n.t :foo, :count => 2 # => 'Foos' # # The :count option can be used both for pluralization and interpolation. # E.g., with the translation # :foo => ['%{count} foo', '%{count} foos'], count will # be interpolated to the pluralized translation: # I18n.t :foo, :count => 1 # => '1 foo' # # *DEFAULTS* # # This returns the translation for :foo or default if no translation was found: # I18n.t :foo, :default => 'default' # # This returns the translation for :foo or the translation for :bar if no # translation for :foo was found: # I18n.t :foo, :default => :bar # # Returns the translation for :foo or the translation for :bar # or default if no translations for :foo and :bar were found. # I18n.t :foo, :default => [:bar, 'default'] # # *BULK LOOKUP* # # This returns an array with the translations for :foo and :bar. # I18n.t [:foo, :bar] # # Can be used with dot-separated nested keys: # I18n.t [:'baz.foo', :'baz.bar'] # # Which is the same as using a scope option: # I18n.t [:foo, :bar], :scope => :baz # # *LAMBDAS* # # Both translations and defaults can be given as Ruby lambdas. Lambdas will be # called and passed the key and options. # # E.g. assuming the key :salutation resolves to: # lambda { |key, options| options[:gender] == 'm' ? "Mr. %{options[:name]}" : "Mrs. %{options[:name]}" } # # Then I18n.t(:salutation, :gender => 'w', :name => 'Smith') will result in "Mrs. Smith". # # It is recommended to use/implement lambdas in an "idempotent" way. E.g. when # a cache layer is put in front of I18n.translate it will generate a cache key # from the argument values passed to #translate. Therefor your lambdas should # always return the same translations/values per unique combination of argument # values. def translate(*args) options = args.last.is_a?(Hash) ? args.pop.dup : {} key = args.shift backend = config.backend locale = options.delete(:locale) || config.locale handling = options.delete(:throw) && :throw || options.delete(:raise) && :raise # TODO deprecate :raise enforce_available_locales!(locale) raise I18n::ArgumentError if key.is_a?(String) && key.empty? result = catch(:exception) do if key.is_a?(Array) key.map { |k| backend.translate(locale, k, options) } else backend.translate(locale, key, options) end end result.is_a?(MissingTranslation) ? handle_exception(handling, result, locale, key, options) : result end alias :t :translate # Wrapper for translate that adds :raise => true. With # this option, if no translation is found, it will raise I18n::MissingTranslationData def translate!(key, options={}) translate(key, options.merge(:raise => true)) end alias :t! :translate! # Returns true if a translation exists for a given key, otherwise returns false. def exists?(key, locale = config.locale) raise I18n::ArgumentError if key.is_a?(String) && key.empty? config.backend.exists?(locale, key) end # Transliterates UTF-8 characters to ASCII. By default this method will # transliterate only Latin strings to an ASCII approximation: # # I18n.transliterate("Ærøskøbing") # # => "AEroskobing" # # I18n.transliterate("日本語") # # => "???" # # It's also possible to add support for per-locale transliterations. I18n # expects transliteration rules to be stored at # i18n.transliterate.rule. # # Transliteration rules can either be a Hash or a Proc. Procs must accept a # single string argument. Hash rules inherit the default transliteration # rules, while Procs do not. # # *Examples* # # Setting a Hash in .yml: # # i18n: # transliterate: # rule: # ü: "ue" # ö: "oe" # # Setting a Hash using Ruby: # # store_translations(:de, :i18n => { # :transliterate => { # :rule => { # "ü" => "ue", # "ö" => "oe" # } # } # ) # # Setting a Proc: # # translit = lambda {|string| MyTransliterator.transliterate(string) } # store_translations(:xx, :i18n => {:transliterate => {:rule => translit}) # # Transliterating strings: # # I18n.locale = :en # I18n.transliterate("Jürgen") # => "Jurgen" # I18n.locale = :de # I18n.transliterate("Jürgen") # => "Juergen" # I18n.transliterate("Jürgen", :locale => :en) # => "Jurgen" # I18n.transliterate("Jürgen", :locale => :de) # => "Juergen" def transliterate(*args) options = args.pop.dup if args.last.is_a?(Hash) key = args.shift locale = options && options.delete(:locale) || config.locale handling = options && (options.delete(:throw) && :throw || options.delete(:raise) && :raise) replacement = options && options.delete(:replacement) enforce_available_locales!(locale) config.backend.transliterate(locale, key, replacement) rescue I18n::ArgumentError => exception handle_exception(handling, exception, locale, key, options || {}) end # Localizes certain objects, such as dates and numbers to local formatting. def localize(object, options = nil) options = options ? options.dup : {} locale = options.delete(:locale) || config.locale format = options.delete(:format) || :default enforce_available_locales!(locale) config.backend.localize(locale, object, format, options) end alias :l :localize # Executes block with given I18n.locale set. def with_locale(tmp_locale = nil) if tmp_locale current_locale = self.locale self.locale = tmp_locale end yield ensure self.locale = current_locale if tmp_locale end # Merges the given locale, key and scope into a single array of keys. # Splits keys that contain dots into multiple keys. Makes sure all # keys are Symbols. def normalize_keys(locale, key, scope, separator = nil) separator ||= I18n.default_separator keys = [] keys.concat normalize_key(locale, separator) keys.concat normalize_key(scope, separator) keys.concat normalize_key(key, separator) keys end # Returns true when the passed locale is in I18.available_locales. # Returns false otherwise. # Compare with Strings as `locale` may be coming from user input def locale_available?(locale) I18n.available_locales.map(&:to_s).include?(locale.to_s) end # Raises an InvalidLocale exception when the passed locale is not # included in I18n.available_locales. # Returns false otherwise def enforce_available_locales!(locale) handle_enforce_available_locales_deprecation if config.enforce_available_locales raise I18n::InvalidLocale.new(locale) if !locale_available?(locale) end end # making these private until Ruby 1.9.2 can send to protected methods again # see http://redmine.ruby-lang.org/repositories/revision/ruby-19?rev=24280 private # Any exceptions thrown in translate will be sent to the @@exception_handler # which can be a Symbol, a Proc or any other Object unless they're forced to # be raised or thrown (MissingTranslation). # # If exception_handler is a Symbol then it will simply be sent to I18n as # a method call. A Proc will simply be called. In any other case the # method #call will be called on the exception_handler object. # # Examples: # # I18n.exception_handler = :default_exception_handler # this is the default # I18n.default_exception_handler(exception, locale, key, options) # will be called like this # # I18n.exception_handler = lambda { |*args| ... } # a lambda # I18n.exception_handler.call(exception, locale, key, options) # will be called like this # # I18n.exception_handler = I18nExceptionHandler.new # an object # I18n.exception_handler.call(exception, locale, key, options) # will be called like this def handle_exception(handling, exception, locale, key, options) case handling when :raise raise(exception.respond_to?(:to_exception) ? exception.to_exception : exception) when :throw throw :exception, exception else case handler = options[:exception_handler] || config.exception_handler when Symbol send(handler, exception, locale, key, options) else handler.call(exception, locale, key, options) end end end def normalize_key(key, separator) normalized_key_cache[separator][key] ||= case key when Array key.map { |k| normalize_key(k, separator) }.flatten else keys = key.to_s.split(separator) keys.delete('') keys.map! { |k| k.to_sym } keys end end def normalized_key_cache @normalized_key_cache ||= Hash.new { |h,k| h[k] = {} } end # DEPRECATED. Use I18n.normalize_keys instead. def normalize_translation_keys(locale, key, scope, separator = nil) puts "I18n.normalize_translation_keys is deprecated. Please use the class I18n.normalize_keys instead." normalize_keys(locale, key, scope, separator) end # DEPRECATED. Please use the I18n::ExceptionHandler class instead. def default_exception_handler(exception, locale, key, options) puts "I18n.default_exception_handler is deprecated. Please use the class I18n::ExceptionHandler instead " + "(an instance of which is set to I18n.exception_handler by default)." exception.is_a?(MissingTranslation) ? exception.message : raise(exception) end def handle_enforce_available_locales_deprecation if config.enforce_available_locales.nil? && !@unenforced_available_locales_deprecation $stderr.puts "[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message." @unenforced_available_locales_deprecation = true end end }) end i18n-0.6.9/metadata.yml0000644000004100000410000001240112260335253014637 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: i18n version: !ruby/object:Gem::Version hash: 21 prerelease: segments: - 0 - 6 - 9 version: 0.6.9 platform: ruby authors: - Sven Fuchs - Joshua Harvey - Matt Aimonetti - Stephan Soller - Saimon Moore autorequire: bindir: bin cert_chain: [] date: 2013-12-03 00:00:00 Z dependencies: - !ruby/object:Gem::Dependency name: activesupport prerelease: false requirement: &id001 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 7 segments: - 3 - 0 - 0 version: 3.0.0 type: :development version_requirements: *id001 - !ruby/object:Gem::Dependency name: sqlite3 prerelease: false requirement: &id002 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" type: :development version_requirements: *id002 - !ruby/object:Gem::Dependency name: mocha prerelease: false requirement: &id003 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" type: :development version_requirements: *id003 - !ruby/object:Gem::Dependency name: test_declarative prerelease: false requirement: &id004 !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" type: :development version_requirements: *id004 description: New wave Internationalization support for Ruby. email: rails-i18n@googlegroups.com executables: [] extensions: [] extra_rdoc_files: [] files: - ci/Gemfile.no-rails - ci/Gemfile.no-rails.lock - ci/Gemfile.rails-2.3.x - ci/Gemfile.rails-2.3.x.lock - ci/Gemfile.rails-3.x - ci/Gemfile.rails-3.x.lock - lib/i18n/backend/base.rb - lib/i18n/backend/cache.rb - lib/i18n/backend/cascade.rb - lib/i18n/backend/chain.rb - lib/i18n/backend/fallbacks.rb - lib/i18n/backend/flatten.rb - lib/i18n/backend/gettext.rb - lib/i18n/backend/interpolation_compiler.rb - lib/i18n/backend/key_value.rb - lib/i18n/backend/memoize.rb - lib/i18n/backend/metadata.rb - lib/i18n/backend/pluralization.rb - lib/i18n/backend/simple.rb - lib/i18n/backend/transliterator.rb - lib/i18n/backend.rb - lib/i18n/config.rb - lib/i18n/core_ext/hash.rb - lib/i18n/core_ext/kernel/surpress_warnings.rb - lib/i18n/core_ext/string/interpolate.rb - lib/i18n/exceptions.rb - lib/i18n/gettext/helpers.rb - lib/i18n/gettext/po_parser.rb - lib/i18n/gettext.rb - lib/i18n/interpolate/ruby.rb - lib/i18n/locale/fallbacks.rb - lib/i18n/locale/tag/parents.rb - lib/i18n/locale/tag/rfc4646.rb - lib/i18n/locale/tag/simple.rb - lib/i18n/locale/tag.rb - lib/i18n/locale.rb - lib/i18n/tests/basics.rb - lib/i18n/tests/defaults.rb - lib/i18n/tests/interpolation.rb - lib/i18n/tests/link.rb - lib/i18n/tests/localization/date.rb - lib/i18n/tests/localization/date_time.rb - lib/i18n/tests/localization/procs.rb - lib/i18n/tests/localization/time.rb - lib/i18n/tests/localization.rb - lib/i18n/tests/lookup.rb - lib/i18n/tests/pluralization.rb - lib/i18n/tests/procs.rb - lib/i18n/tests.rb - lib/i18n/version.rb - lib/i18n.rb - test/all.rb - test/api/all_features_test.rb - test/api/cascade_test.rb - test/api/chain_test.rb - test/api/fallbacks_test.rb - test/api/key_value_test.rb - test/api/memoize_test.rb - test/api/override_test.rb - test/api/pluralization_test.rb - test/api/simple_test.rb - test/backend/cache_test.rb - test/backend/cascade_test.rb - test/backend/chain_test.rb - test/backend/exceptions_test.rb - test/backend/fallbacks_test.rb - test/backend/interpolation_compiler_test.rb - test/backend/key_value_test.rb - test/backend/memoize_test.rb - test/backend/metadata_test.rb - test/backend/pluralization_test.rb - test/backend/simple_test.rb - test/backend/transliterator_test.rb - test/core_ext/hash_test.rb - test/core_ext/string/interpolate_test.rb - test/gettext/api_test.rb - test/gettext/backend_test.rb - test/i18n/exceptions_test.rb - test/i18n/interpolate_test.rb - test/i18n/load_path_test.rb - test/i18n_test.rb - test/locale/fallbacks_test.rb - test/locale/tag/rfc4646_test.rb - test/locale/tag/simple_test.rb - test/run_all.rb - test/test_data/locales/de.po - test/test_data/locales/en.rb - test/test_data/locales/en.yml - test/test_data/locales/invalid/empty.yml - test/test_data/locales/invalid/syntax.yml - test/test_data/locales/plurals.rb - test/test_helper.rb - README.textile - MIT-LICENSE homepage: http://github.com/svenfuchs/i18n licenses: - MIT post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 3 segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ">=" - !ruby/object:Gem::Version hash: 17 segments: - 1 - 3 - 5 version: 1.3.5 requirements: [] rubyforge_project: "[none]" rubygems_version: 1.8.6 signing_key: specification_version: 3 summary: New wave Internationalization support for Ruby test_files: [] i18n-0.6.9/test/0000755000004100000410000000000012260335253013315 5ustar www-datawww-datai18n-0.6.9/test/core_ext/0000755000004100000410000000000012260335253015125 5ustar www-datawww-datai18n-0.6.9/test/core_ext/string/0000755000004100000410000000000012260335253016433 5ustar www-datawww-datai18n-0.6.9/test/core_ext/string/interpolate_test.rb0000644000004100000410000000744712260335253022361 0ustar www-datawww-datarequire 'test_helper' # thanks to Masao's String extensions these should work the same in # Ruby 1.8 (patched) and Ruby 1.9 (native) # some tests taken from Masao's tests # http://github.com/mutoh/gettext/blob/edbbe1fa8238fa12c7f26f2418403015f0270e47/test/test_string.rb class I18nCoreExtStringInterpolationTest < Test::Unit::TestCase test "String interpolates a single argument" do assert_equal "Masao", "%s" % "Masao" end test "String interpolates an array argument" do assert_equal "1 message", "%d %s" % [1, 'message'] end test "String interpolates a hash argument w/ named placeholders" do assert_equal "Masao Mutoh", "%{first} %{last}" % { :first => 'Masao', :last => 'Mutoh' } end test "String interpolates a hash argument w/ named placeholders (reverse order)" do assert_equal "Mutoh, Masao", "%{last}, %{first}" % { :first => 'Masao', :last => 'Mutoh' } end test "String interpolates named placeholders with sprintf syntax" do assert_equal "10, 43.4", "%d, %.1f" % {:integer => 10, :float => 43.4} end test "String interpolates named placeholders with sprintf syntax, does not recurse" do assert_equal "%s", "%{msg}" % { :msg => '%s', :not_translated => 'should not happen' } end test "String interpolation does not replace anything when no placeholders are given" do assert_equal("aaa", "aaa" % {:num => 1}) assert_equal("bbb", "bbb" % [1]) end test "String interpolation sprintf behaviour equals Ruby 1.9 behaviour" do assert_equal("1", "%d" % {:num => 1}) assert_equal("0b1", "%#b" % {:num => 1}) assert_equal("foo", "%s" % {:msg => "foo"}) assert_equal("1.000000", "%f" % {:num => 1.0}) assert_equal(" 1", "%3.0f" % {:num => 1.0}) assert_equal("100.00", "%2.2f" % {:num => 100.0}) assert_equal("0x64", "%#x" % {:num => 100.0}) assert_raise(ArgumentError) { "%,d" % {:num => 100} } assert_raise(ArgumentError) { "%/d" % {:num => 100} } end test "String interpolation old-style sprintf still works" do assert_equal("foo 1.000000", "%s %f" % ["foo", 1.0]) end test "String interpolation raises an ArgumentError when the string has extra placeholders (Array)" do assert_raise(ArgumentError) do # Ruby 1.9 msg: "too few arguments" "%s %s" % %w(Masao) end end test "String interpolation raises a KeyError when the string has extra placeholders (Hash)" do assert_raise(KeyError) do # Ruby 1.9 msg: "key not found" "%{first} %{last}" % { :first => 'Masao' } end end test "String interpolation does not raise when passed extra values (Array)" do assert_nothing_raised do assert_equal "Masao", "%s" % %w(Masao Mutoh) end end test "String interpolation does not raise when passed extra values (Hash)" do assert_nothing_raised do assert_equal "Masao Mutoh", "%{first} %{last}" % { :first => 'Masao', :last => 'Mutoh', :salutation => 'Mr.' } end end test "% acts as escape character in String interpolation" do assert_equal "%{first}", "%%{first}" % { :first => 'Masao' } assert_equal("% 1", "%% %d" % {:num => 1.0}) assert_equal("%{num} %d", "%%{num} %%d" % {:num => 1}) end test "% can be used in Ruby's own sprintf behavior" do assert_equal "70%", "%d%%" % 70 assert_equal "70-100%", "%d-%d%%" % [70, 100] assert_equal "+2.30%", "%+.2f%%" % 2.3 end def test_sprintf_mix_unformatted_and_formatted_named_placeholders assert_equal("foo 1.000000", "%{name} %f" % {:name => "foo", :num => 1.0}) end def test_string_interpolation_raises_an_argument_error_when_mixing_named_and_unnamed_placeholders assert_raise(ArgumentError) { "%{name} %f" % [1.0] } assert_raise(ArgumentError) { "%{name} %f" % [1.0, 2.0] } end end i18n-0.6.9/test/core_ext/hash_test.rb0000644000004100000410000000156512260335253017443 0ustar www-datawww-datarequire 'test_helper' require 'i18n/core_ext/hash' class I18nCoreExtHashInterpolationTest < Test::Unit::TestCase test "#deep_symbolize_keys" do hash = { 'foo' => { 'bar' => { 'baz' => 'bar' } } } expected = { :foo => { :bar => { :baz => 'bar' } } } assert_equal expected, hash.deep_symbolize_keys end test "#slice" do hash = { :foo => 'bar', :baz => 'bar' } expected = { :foo => 'bar' } assert_equal expected, hash.slice(:foo) end test "#except" do hash = { :foo => 'bar', :baz => 'bar' } expected = { :foo => 'bar' } assert_equal expected, hash.except(:baz) end test "#deep_merge!" do hash = { :foo => { :bar => { :baz => 'bar' } }, :baz => 'bar' } hash.deep_merge!(:foo => { :bar => { :baz => 'foo' } }) expected = { :foo => { :bar => { :baz => 'foo' } }, :baz => 'bar' } assert_equal expected, hash end end i18n-0.6.9/test/i18n_test.rb0000644000004100000410000003036312260335253015465 0ustar www-datawww-data# encoding: utf-8 require 'test_helper' class I18nTest < Test::Unit::TestCase def setup I18n.backend.store_translations(:'en', :currency => { :format => { :separator => '.', :delimiter => ',', } }) I18n.backend.store_translations(:'nl', :currency => { :format => { :separator => ',', :delimiter => '.', } }) end test "exposes its VERSION constant" do assert I18n::VERSION end test "uses the simple backend by default" do assert I18n.backend.is_a?(I18n::Backend::Simple) end test "can set the backend" do begin assert_nothing_raised { I18n.backend = self } assert_equal self, I18n.backend ensure I18n.backend = I18n::Backend::Simple.new end end test "uses :en as a default_locale by default" do assert_equal :en, I18n.default_locale end test "can set the default locale" do begin assert_nothing_raised { I18n.default_locale = 'de' } assert_equal :de, I18n.default_locale ensure I18n.default_locale = :en end end test "raises an I18n::InvalidLocale exception when setting an unavailable default locale" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.default_locale = :klingon } ensure I18n.config.enforce_available_locales = false end end test "uses the default locale as a locale by default" do assert_equal I18n.default_locale, I18n.locale end test "sets the current locale to Thread.current" do assert_nothing_raised { I18n.locale = 'de' } assert_equal :de, I18n.locale assert_equal :de, Thread.current[:i18n_config].locale I18n.locale = :en end test "raises an I18n::InvalidLocale exception when setting an unavailable locale" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.locale = :klingon } ensure I18n.config.enforce_available_locales = false end end test "can set the configuration object" do begin I18n.config = self assert_equal self, I18n.config assert_equal self, Thread.current[:i18n_config] ensure I18n.config = ::I18n::Config.new end end test "locale is not shared between configurations" do a = I18n::Config.new b = I18n::Config.new a.locale = :fr b.locale = :es assert_equal :fr, a.locale assert_equal :es, b.locale assert_equal :en, I18n.locale end test "other options are shared between configurations" do begin a = I18n::Config.new b = I18n::Config.new a.default_locale = :fr b.default_locale = :es assert_equal :es, a.default_locale assert_equal :es, b.default_locale assert_equal :es, I18n.default_locale ensure I18n.default_locale = :en end end test "uses a dot as a default_separator by default" do assert_equal '.', I18n.default_separator end test "can set the default_separator" do begin assert_nothing_raised { I18n.default_separator = "\001" } ensure I18n.default_separator = '.' end end test "normalize_keys normalizes given locale, keys and scope to an array of single-key symbols" do assert_equal [:en, :foo, :bar], I18n.normalize_keys(:en, :bar, :foo) assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, :'baz.buz', :'foo.bar') assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, 'baz.buz', 'foo.bar') assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, %w(baz buz), %w(foo bar)) assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, [:baz, :buz], [:foo, :bar]) end test "normalize_keys discards empty keys" do assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, :'baz..buz', :'foo..bar') assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, :'baz......buz', :'foo......bar') assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, ['baz', nil, '', 'buz'], ['foo', nil, '', 'bar']) end test "normalize_keys uses a given separator" do assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, :'baz|buz', :'foo|bar', '|') end test "can set the exception_handler" do begin previous_exception_handler = I18n.exception_handler assert_nothing_raised { I18n.exception_handler = :custom_exception_handler } ensure I18n.exception_handler = previous_exception_handler end end test "uses a custom exception handler set to I18n.exception_handler" do begin previous_exception_handler = I18n.exception_handler I18n.exception_handler = :custom_exception_handler I18n.expects(:custom_exception_handler) I18n.translate :bogus ensure I18n.exception_handler = previous_exception_handler end end test "uses a custom exception handler passed as an option" do I18n.expects(:custom_exception_handler) I18n.translate(:bogus, :exception_handler => :custom_exception_handler) end test "delegates translate calls to the backend" do I18n.backend.expects(:translate).with('de', :foo, {}) I18n.translate :foo, :locale => 'de' end test "delegates localize calls to the backend" do I18n.backend.expects(:localize).with('de', :whatever, :default, {}) I18n.localize :whatever, :locale => 'de' end test "translate given no locale uses the current locale" do I18n.backend.expects(:translate).with(:en, :foo, {}) I18n.translate :foo end test "translate works with nested symbol keys" do assert_equal ".", I18n.t(:'currency.format.separator') end test "translate works with nested string keys" do assert_equal ".", I18n.t('currency.format.separator') end test "translate with an array as a scope works" do assert_equal ".", I18n.t(:separator, :scope => %w(currency format)) end test "translate with an array containing dot separated strings as a scope works" do assert_equal ".", I18n.t(:separator, :scope => ['currency.format']) end test "translate with an array of keys and a dot separated string as a scope works" do assert_equal [".", ","], I18n.t(%w(separator delimiter), :scope => 'currency.format') end test "translate with an array of dot separated keys and a scope works" do assert_equal [".", ","], I18n.t(%w(format.separator format.delimiter), :scope => 'currency') end # def test_translate_given_no_args_raises_missing_translation_data # assert_equal "translation missing: en, no key", I18n.t # end test "translate given a bogus key returns an error message" do assert_equal "translation missing: en.bogus", I18n.t(:bogus) end test "translate given an empty string as a key raises an I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.t("") } end test "translate given an unavailable locale rases an I18n::InvalidLocale" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.t(:foo, :locale => 'klingon') } ensure I18n.config.enforce_available_locales = false end end test "exists? given an existing key will return true" do assert_equal true, I18n.exists?(:currency) end test "exists? given a non-existing key will return false" do assert_equal false, I18n.exists?(:bogus) end test "exists? given an existing dot-separated key will return true" do assert_equal true, I18n.exists?('currency.format.delimiter') end test "exists? given a non-existing dot-separated key will return false" do assert_equal false, I18n.exists?('currency.format.bogus') end test "exists? given an existing key and an existing locale will return true" do assert_equal true, I18n.exists?(:currency, :nl) end test "exists? given a non-existing key and an existing locale will return false" do assert_equal false, I18n.exists?(:bogus, :nl) end test "localize given nil raises an I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.l nil } end test "localize given an Object raises an I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.l Object.new } end test "localize given an unavailable locale rases an I18n::InvalidLocale" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.l(Time.now, :locale => 'klingon') } ensure I18n.config.enforce_available_locales = false end end test "can use a lambda as an exception handler" do begin previous_exception_handler = I18n.exception_handler I18n.exception_handler = Proc.new { |exception, locale, key, options| key } assert_equal :test_proc_handler, I18n.translate(:test_proc_handler) ensure I18n.exception_handler = previous_exception_handler end end test "can use an object responding to #call as an exception handler" do begin previous_exception_handler = I18n.exception_handler I18n.exception_handler = Class.new do def call(exception, locale, key, options); key; end end.new assert_equal :test_proc_handler, I18n.translate(:test_proc_handler) ensure I18n.exception_handler = previous_exception_handler end end test "I18n.with_locale temporarily sets the given locale" do store_translations(:en, :foo => 'Foo in :en') store_translations(:de, :foo => 'Foo in :de') store_translations(:pl, :foo => 'Foo in :pl') I18n.with_locale { assert_equal [:en, 'Foo in :en'], [I18n.locale, I18n.t(:foo)] } I18n.with_locale(:de) { assert_equal [:de, 'Foo in :de'], [I18n.locale, I18n.t(:foo)] } I18n.with_locale(:pl) { assert_equal [:pl, 'Foo in :pl'], [I18n.locale, I18n.t(:foo)] } I18n.with_locale(:en) { assert_equal [:en, 'Foo in :en'], [I18n.locale, I18n.t(:foo)] } assert_equal I18n.default_locale, I18n.locale end test "I18n.with_locale resets the locale in case of errors" do assert_raise(I18n::ArgumentError) { I18n.with_locale(:pl) { raise I18n::ArgumentError } } assert_equal I18n.default_locale, I18n.locale end test "I18n.translitarate handles I18n::ArgumentError exception" do I18n::Backend::Transliterator.stubs(:get).raises(I18n::ArgumentError) I18n.exception_handler.expects(:call).raises(I18n::ArgumentError) assert_raise(I18n::ArgumentError) { I18n.transliterate("ąćó") } end test "I18n.translitarate raises I18n::ArgumentError exception" do I18n::Backend::Transliterator.stubs(:get).raises(I18n::ArgumentError) I18n.exception_handler.expects(:call).never assert_raise(I18n::ArgumentError) { I18n.transliterate("ąćó", :raise => true) } end test "transliterate given an unavailable locale rases an I18n::InvalidLocale" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.transliterate('string', :locale => 'klingon') } ensure I18n.config.enforce_available_locales = false end end test "I18n.locale_available? returns true when the passed locale is available" do I18n.available_locales = [:en, :de] assert_equal true, I18n.locale_available?(:de) end test "I18n.locale_available? returns true when the passed locale is a string and is available" do I18n.available_locales = [:en, :de] assert_equal true, I18n.locale_available?('de') end test "I18n.locale_available? returns false when the passed locale is unavailable" do assert_equal false, I18n.locale_available?(:klingon) end test "I18n.enforce_available_locales! raises an I18n::InvalidLocale when the passed locale is unavailable" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.enforce_available_locales!(:klingon) } ensure I18n.config.enforce_available_locales = false end end test "I18n.enforce_available_locales! does nothing when the passed locale is available" do I18n.available_locales = [:en, :de] begin I18n.config.enforce_available_locales = true assert_nothing_raised { I18n.enforce_available_locales!(:en) } ensure I18n.config.enforce_available_locales = false end end test "I18n.enforce_available_locales config can be set to false" do begin I18n.config.enforce_available_locales = false assert_equal false, I18n.config.enforce_available_locales ensure I18n.config.enforce_available_locales = false end end end i18n-0.6.9/test/i18n/0000755000004100000410000000000012260335253014074 5ustar www-datawww-datai18n-0.6.9/test/i18n/load_path_test.rb0000644000004100000410000000204312260335253017412 0ustar www-datawww-datarequire 'test_helper' class I18nLoadPathTest < Test::Unit::TestCase def setup I18n.locale = :en I18n.backend = I18n::Backend::Simple.new store_translations(:en, :foo => {:bar => 'bar', :baz => 'baz'}) end test "nested load paths do not break locale loading" do I18n.load_path = [[locales_dir + '/en.yml']] assert_equal "baz", I18n.t(:'foo.bar') end test "loading an empty yml file raises an InvalidLocaleData exception" do assert_raise I18n::InvalidLocaleData do I18n.load_path = [[locales_dir + '/invalid/empty.yml']] I18n.t(:'foo.bar', :default => "baz") end end test "loading an invalid yml file raises an InvalidLocaleData exception" do assert_raise I18n::InvalidLocaleData do I18n.load_path = [[locales_dir + '/invalid/syntax.yml']] I18n.t(:'foo.bar', :default => "baz") end end test "adding arrays of filenames to the load path does not break locale loading" do I18n.load_path << Dir[locales_dir + '/*.{rb,yml}'] assert_equal "baz", I18n.t(:'foo.bar') end end i18n-0.6.9/test/i18n/interpolate_test.rb0000644000004100000410000000713212260335253020011 0ustar www-datawww-datarequire 'test_helper' require 'i18n/core_ext/string/interpolate' # thanks to Masao's String extensions, some tests taken from Masao's tests # http://github.com/mutoh/gettext/blob/edbbe1fa8238fa12c7f26f2418403015f0270e47/test/test_string.rb class I18nInterpolateTest < Test::Unit::TestCase test "String interpolates a hash argument w/ named placeholders" do assert_equal "Masao Mutoh", I18n.interpolate("%{first} %{last}", :first => 'Masao', :last => 'Mutoh' ) end test "String interpolates a hash argument w/ named placeholders (reverse order)" do assert_equal "Mutoh, Masao", I18n.interpolate("%{last}, %{first}", :first => 'Masao', :last => 'Mutoh' ) end test "String interpolates named placeholders with sprintf syntax" do assert_equal "10, 43.4", I18n.interpolate("%d, %.1f", :integer => 10, :float => 43.4) end test "String interpolates named placeholders with sprintf syntax, does not recurse" do assert_equal "%s", I18n.interpolate("%{msg}", :msg => '%s', :not_translated => 'should not happen' ) end test "String interpolation does not replace anything when no placeholders are given" do assert_equal "aaa", I18n.interpolate("aaa", :num => 1) end test "String interpolation sprintf behaviour equals Ruby 1.9 behaviour" do assert_equal "1", I18n.interpolate("%d", :num => 1) assert_equal "0b1", I18n.interpolate("%#b", :num => 1) assert_equal "foo", I18n.interpolate("%s", :msg => "foo") assert_equal "1.000000", I18n.interpolate("%f", :num => 1.0) assert_equal " 1", I18n.interpolate("%3.0f", :num => 1.0) assert_equal "100.00", I18n.interpolate("%2.2f", :num => 100.0) assert_equal "0x64", I18n.interpolate("%#x", :num => 100.0) assert_raise(ArgumentError) { I18n.interpolate("%,d", :num => 100) } assert_raise(ArgumentError) { I18n.interpolate("%/d", :num => 100) } end test "String interpolation raises an I18n::MissingInterpolationArgument when the string has extra placeholders" do assert_raise(I18n::MissingInterpolationArgument) do # Ruby 1.9 msg: "key not found" I18n.interpolate("%{first} %{last}", :first => 'Masao') end end test "String interpolation does not raise when extra values were passed" do assert_nothing_raised do assert_equal "Masao Mutoh", I18n.interpolate("%{first} %{last}", :first => 'Masao', :last => 'Mutoh', :salutation => 'Mr.' ) end end test "% acts as escape character in String interpolation" do assert_equal "%{first}", I18n.interpolate("%%{first}", :first => 'Masao') assert_equal "% 1", I18n.interpolate("%% %d", :num => 1.0) assert_equal "%{num} %d", I18n.interpolate("%%{num} %%d", :num => 1) end def test_sprintf_mix_unformatted_and_formatted_named_placeholders assert_equal "foo 1.000000", I18n.interpolate("%{name} %f", :name => "foo", :num => 1.0) end end class I18nMissingInterpolationCustomHandlerTest < Test::Unit::TestCase def setup @old_handler = I18n.config.missing_interpolation_argument_handler I18n.config.missing_interpolation_argument_handler = lambda do |key, values, string| "missing key is #{key}, values are #{values.inspect}, given string is '#{string}'" end end def teardown I18n.config.missing_interpolation_argument_handler = @old_handler end test "String interpolation can use custom missing interpolation handler" do assert_equal %|Masao missing key is last, values are {:first=>"Masao"}, given string is '%{first} %{last}'|, I18n.interpolate("%{first} %{last}", :first => 'Masao') end end i18n-0.6.9/test/i18n/exceptions_test.rb0000644000004100000410000001070612260335253017645 0ustar www-datawww-datarequire 'test_helper' class I18nExceptionsTest < Test::Unit::TestCase def test_invalid_locale_stores_locale force_invalid_locale rescue I18n::ArgumentError => e assert_nil exception.locale end test "passing an invalid locale raises an InvalidLocale exception" do force_invalid_locale do |exception| assert_equal 'nil is not a valid locale', exception.message end end test "MissingTranslationData exception stores locale, key and options" do force_missing_translation_data do |exception| assert_equal 'de', exception.locale assert_equal :foo, exception.key assert_equal({:scope => :bar}, exception.options) end end test "MissingTranslationData message contains the locale and scoped key" do force_missing_translation_data do |exception| assert_equal 'translation missing: de.bar.foo', exception.message end end test "MissingTranslationData html_message is a span with the titlelized last key token" do exception = I18n::MissingTranslationData.new(:de, :foo, :scope => :bar) assert_equal 'Foo', exception.html_message end test "MissingTranslationData html_message html escapes key names" do exception = I18n::MissingTranslationData.new(:de, '', :scope => '