i18n 0.4.0 → 1.14.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +0 -0
- data/README.md +127 -0
- data/lib/i18n/backend/base.rb +189 -111
- data/lib/i18n/backend/cache.rb +58 -22
- data/lib/i18n/backend/cache_file.rb +36 -0
- data/lib/i18n/backend/cascade.rb +9 -10
- data/lib/i18n/backend/chain.rb +95 -42
- data/lib/i18n/backend/fallbacks.rb +68 -22
- data/lib/i18n/backend/flatten.rb +13 -8
- data/lib/i18n/backend/gettext.rb +33 -25
- data/lib/i18n/backend/interpolation_compiler.rb +12 -14
- data/lib/i18n/backend/key_value.rb +112 -10
- data/lib/i18n/backend/lazy_loadable.rb +184 -0
- data/lib/i18n/backend/memoize.rb +13 -7
- data/lib/i18n/backend/metadata.rb +12 -6
- data/lib/i18n/backend/pluralization.rb +64 -25
- data/lib/i18n/backend/simple.rb +44 -18
- data/lib/i18n/backend/transliterator.rb +43 -33
- data/lib/i18n/backend.rb +5 -3
- data/lib/i18n/config.rb +91 -10
- data/lib/i18n/exceptions.rb +118 -22
- data/lib/i18n/gettext/helpers.rb +14 -4
- data/lib/i18n/gettext/po_parser.rb +7 -7
- data/lib/i18n/gettext.rb +6 -5
- data/lib/i18n/interpolate/ruby.rb +53 -0
- data/lib/i18n/locale/fallbacks.rb +33 -26
- data/lib/i18n/locale/tag/parents.rb +8 -8
- data/lib/i18n/locale/tag/rfc4646.rb +0 -2
- data/lib/i18n/locale/tag/simple.rb +2 -4
- data/lib/i18n/locale.rb +2 -0
- data/lib/i18n/middleware.rb +17 -0
- data/lib/i18n/tests/basics.rb +58 -0
- data/lib/i18n/tests/defaults.rb +52 -0
- data/lib/i18n/tests/interpolation.rb +167 -0
- data/lib/i18n/tests/link.rb +66 -0
- data/lib/i18n/tests/localization/date.rb +122 -0
- data/lib/i18n/tests/localization/date_time.rb +103 -0
- data/lib/i18n/tests/localization/procs.rb +118 -0
- data/lib/i18n/tests/localization/time.rb +103 -0
- data/lib/i18n/tests/localization.rb +19 -0
- data/lib/i18n/tests/lookup.rb +81 -0
- data/lib/i18n/tests/pluralization.rb +35 -0
- data/lib/i18n/tests/procs.rb +66 -0
- data/lib/i18n/tests.rb +14 -0
- data/lib/i18n/utils.rb +55 -0
- data/lib/i18n/version.rb +3 -1
- data/lib/i18n.rb +200 -87
- metadata +64 -56
- data/CHANGELOG.textile +0 -135
- data/README.textile +0 -93
- data/lib/i18n/backend/active_record/missing.rb +0 -65
- data/lib/i18n/backend/active_record/store_procs.rb +0 -38
- data/lib/i18n/backend/active_record/translation.rb +0 -93
- data/lib/i18n/backend/active_record.rb +0 -61
- data/lib/i18n/backend/cldr.rb +0 -100
- data/lib/i18n/core_ext/hash.rb +0 -29
- data/lib/i18n/core_ext/string/interpolate.rb +0 -98
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
# Locale Fallbacks
|
4
2
|
#
|
5
3
|
# Extends the I18n module to hold a fallbacks instance which is set to an
|
@@ -17,22 +15,15 @@
|
|
17
15
|
# * all parent locales of a given locale (e.g. :es for :"es-MX") first,
|
18
16
|
# * the current default locales and all of their parents second
|
19
17
|
#
|
20
|
-
# The default locales are set to [
|
21
|
-
# set to something else.
|
18
|
+
# The default locales are set to [] by default but can be set to something else.
|
22
19
|
#
|
23
20
|
# One can additionally add any number of additional fallback locales manually.
|
24
21
|
# These will be added before the default locales to the fallback chain. For
|
25
22
|
# example:
|
26
23
|
#
|
27
|
-
# # using the default locale as default fallback locale
|
28
|
-
#
|
29
|
-
# I18n.default_locale = :"en-US"
|
30
|
-
# I18n.fallbacks = I18n::Fallbacks.new(:"de-AT" => :"de-DE")
|
31
|
-
# I18n.fallbacks[:"de-AT"] # => [:"de-AT", :"de-DE", :de, :"en-US", :en]
|
32
|
-
#
|
33
24
|
# # using a custom locale as default fallback locale
|
34
25
|
#
|
35
|
-
# I18n.fallbacks = I18n::Fallbacks.new(:"en-GB", :"de-AT" => :de, :"de-CH" => :de)
|
26
|
+
# I18n.fallbacks = I18n::Locale::Fallbacks.new(:"en-GB", :"de-AT" => :de, :"de-CH" => :de)
|
36
27
|
# I18n.fallbacks[:"de-AT"] # => [:"de-AT", :de, :"en-GB", :en]
|
37
28
|
# I18n.fallbacks[:"de-CH"] # => [:"de-CH", :de, :"en-GB", :en]
|
38
29
|
#
|
@@ -48,7 +39,7 @@
|
|
48
39
|
# fallbacks[:"ar-PS"] # => [:"ar-PS", :ar, :"he-IL", :he, :"en-US", :en]
|
49
40
|
# fallbacks[:"ar-EG"] # => [:"ar-EG", :ar, :"en-US", :en]
|
50
41
|
#
|
51
|
-
# # people speaking Sami as spoken in
|
42
|
+
# # people speaking Sami as spoken in Finland also speak Swedish and Finnish as spoken in Finland
|
52
43
|
# fallbacks.map(:sms => [:"se-FI", :"fi-FI"])
|
53
44
|
# fallbacks[:sms] # => [:sms, :"se-FI", :se, :"fi-FI", :fi, :"en-US", :en]
|
54
45
|
|
@@ -58,40 +49,56 @@ module I18n
|
|
58
49
|
def initialize(*mappings)
|
59
50
|
@map = {}
|
60
51
|
map(mappings.pop) if mappings.last.is_a?(Hash)
|
61
|
-
self.defaults = mappings.empty? ? [
|
52
|
+
self.defaults = mappings.empty? ? [] : mappings
|
62
53
|
end
|
63
54
|
|
64
55
|
def defaults=(defaults)
|
65
|
-
@defaults = defaults.
|
56
|
+
@defaults = defaults.flat_map { |default| compute(default, false) }
|
66
57
|
end
|
67
58
|
attr_reader :defaults
|
68
59
|
|
69
60
|
def [](locale)
|
70
61
|
raise InvalidLocale.new(locale) if locale.nil?
|
62
|
+
raise Disabled.new('fallback#[]') if locale == false
|
71
63
|
locale = locale.to_sym
|
72
64
|
super || store(locale, compute(locale))
|
73
65
|
end
|
74
66
|
|
75
|
-
def map(
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
67
|
+
def map(*args, &block)
|
68
|
+
if args.count == 1 && !block_given?
|
69
|
+
mappings = args.first
|
70
|
+
mappings.each do |from, to|
|
71
|
+
from, to = from.to_sym, Array(to)
|
72
|
+
to.each do |_to|
|
73
|
+
@map[from] ||= []
|
74
|
+
@map[from] << _to.to_sym
|
75
|
+
end
|
81
76
|
end
|
77
|
+
else
|
78
|
+
@map.map(*args, &block)
|
82
79
|
end
|
83
80
|
end
|
84
81
|
|
82
|
+
def empty?
|
83
|
+
@map.empty? && @defaults.empty?
|
84
|
+
end
|
85
|
+
|
86
|
+
def inspect
|
87
|
+
"#<#{self.class.name} @map=#{@map.inspect} @defaults=#{@defaults.inspect}>"
|
88
|
+
end
|
89
|
+
|
85
90
|
protected
|
86
91
|
|
87
|
-
def compute(tags, include_defaults = true)
|
88
|
-
result = Array(tags).
|
89
|
-
tags = I18n::Locale::Tag.tag(tag).self_and_parents.map! { |t| t.to_sym }
|
90
|
-
tags.each { |
|
92
|
+
def compute(tags, include_defaults = true, exclude = [])
|
93
|
+
result = Array(tags).flat_map do |tag|
|
94
|
+
tags = I18n::Locale::Tag.tag(tag).self_and_parents.map! { |t| t.to_sym } - exclude
|
95
|
+
tags.each { |_tag| tags += compute(@map[_tag], false, exclude + tags) if @map[_tag] }
|
91
96
|
tags
|
92
|
-
end
|
97
|
+
end
|
93
98
|
result.push(*defaults) if include_defaults
|
94
|
-
result.uniq
|
99
|
+
result.uniq!
|
100
|
+
result.compact!
|
101
|
+
result
|
95
102
|
end
|
96
103
|
end
|
97
104
|
end
|
@@ -1,22 +1,22 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module I18n
|
4
2
|
module Locale
|
5
3
|
module Tag
|
6
4
|
module Parents
|
7
5
|
def parent
|
8
|
-
@parent ||=
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
@parent ||=
|
7
|
+
begin
|
8
|
+
segs = to_a
|
9
|
+
segs.compact!
|
10
|
+
segs.length > 1 ? self.class.tag(*segs[0..(segs.length - 2)].join('-')) : nil
|
11
|
+
end
|
12
12
|
end
|
13
13
|
|
14
14
|
def self_and_parents
|
15
|
-
@self_and_parents ||= [self]
|
15
|
+
@self_and_parents ||= [self].concat parents
|
16
16
|
end
|
17
17
|
|
18
18
|
def parents
|
19
|
-
@parents ||=
|
19
|
+
@parents ||= parent ? [parent].concat(parent.parents) : []
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -1,7 +1,5 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
# Simple Locale tag implementation that computes subtags by simply splitting
|
4
|
-
# the locale tag at '-'
|
2
|
+
# the locale tag at '-' occurrences.
|
5
3
|
module I18n
|
6
4
|
module Locale
|
7
5
|
module Tag
|
@@ -21,7 +19,7 @@ module I18n
|
|
21
19
|
end
|
22
20
|
|
23
21
|
def subtags
|
24
|
-
@subtags = tag.to_s.split('-').map
|
22
|
+
@subtags = tag.to_s.split('-').map!(&:to_s)
|
25
23
|
end
|
26
24
|
|
27
25
|
def to_sym
|
data/lib/i18n/locale.rb
CHANGED
@@ -0,0 +1,58 @@
|
|
1
|
+
module I18n
|
2
|
+
module Tests
|
3
|
+
module Basics
|
4
|
+
def teardown
|
5
|
+
I18n.available_locales = nil
|
6
|
+
end
|
7
|
+
|
8
|
+
test "available_locales returns the available_locales produced by the backend, by default" do
|
9
|
+
I18n.backend.store_translations('de', :foo => 'bar')
|
10
|
+
I18n.backend.store_translations('en', :foo => 'foo')
|
11
|
+
|
12
|
+
assert_equal I18n.available_locales, I18n.backend.available_locales
|
13
|
+
end
|
14
|
+
|
15
|
+
test "available_locales can be set to something else independently from the actual locale data" do
|
16
|
+
I18n.backend.store_translations('de', :foo => 'bar')
|
17
|
+
I18n.backend.store_translations('en', :foo => 'foo')
|
18
|
+
|
19
|
+
I18n.available_locales = :foo
|
20
|
+
assert_equal [:foo], I18n.available_locales
|
21
|
+
|
22
|
+
I18n.available_locales = [:foo, 'bar']
|
23
|
+
assert_equal [:foo, :bar], I18n.available_locales
|
24
|
+
|
25
|
+
I18n.available_locales = nil
|
26
|
+
assert_equal I18n.available_locales, I18n.backend.available_locales
|
27
|
+
end
|
28
|
+
|
29
|
+
test "available_locales memoizes when set explicitly" do
|
30
|
+
I18n.backend.expects(:available_locales).never
|
31
|
+
I18n.available_locales = [:foo]
|
32
|
+
I18n.backend.store_translations('de', :bar => 'baz')
|
33
|
+
I18n.reload!
|
34
|
+
assert_equal [:foo], I18n.available_locales
|
35
|
+
end
|
36
|
+
|
37
|
+
test "available_locales delegates to the backend when not set explicitly" do
|
38
|
+
original_available_locales_value = I18n.backend.available_locales
|
39
|
+
I18n.backend.expects(:available_locales).returns(original_available_locales_value).twice
|
40
|
+
assert_equal I18n.backend.available_locales, I18n.available_locales
|
41
|
+
end
|
42
|
+
|
43
|
+
test "exists? is implemented by the backend" do
|
44
|
+
I18n.backend.store_translations(:foo, :bar => 'baz')
|
45
|
+
assert I18n.exists?(:bar, :foo)
|
46
|
+
end
|
47
|
+
|
48
|
+
test "storing a nil value as a translation removes it from the available locale data" do
|
49
|
+
I18n.backend.store_translations(:en, :to_be_deleted => 'bar')
|
50
|
+
assert_equal 'bar', I18n.t(:to_be_deleted, :default => 'baz')
|
51
|
+
|
52
|
+
I18n.cache_store.clear if I18n.respond_to?(:cache_store) && I18n.cache_store
|
53
|
+
I18n.backend.store_translations(:en, :to_be_deleted => nil)
|
54
|
+
assert_equal 'baz', I18n.t(:to_be_deleted, :default => 'baz')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Tests
|
5
|
+
module Defaults
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
I18n.backend.store_translations(:en, :foo => { :bar => 'bar', :baz => 'baz' })
|
9
|
+
end
|
10
|
+
|
11
|
+
test "defaults: given nil as a key it returns the given default" do
|
12
|
+
assert_equal 'default', I18n.t(nil, :default => 'default')
|
13
|
+
end
|
14
|
+
|
15
|
+
test "defaults: given a symbol as a default it translates the symbol" do
|
16
|
+
assert_equal 'bar', I18n.t(nil, :default => :'foo.bar')
|
17
|
+
end
|
18
|
+
|
19
|
+
test "defaults: given a symbol as a default and a scope it stays inside the scope when looking up the symbol" do
|
20
|
+
assert_equal 'bar', I18n.t(:missing, :default => :bar, :scope => :foo)
|
21
|
+
end
|
22
|
+
|
23
|
+
test "defaults: given an array as a default it returns the first match" do
|
24
|
+
assert_equal 'bar', I18n.t(:does_not_exist, :default => [:does_not_exist_2, :'foo.bar'])
|
25
|
+
end
|
26
|
+
|
27
|
+
test "defaults: given an array as a default with false it returns false" do
|
28
|
+
assert_equal false, I18n.t(:does_not_exist, :default => [false])
|
29
|
+
end
|
30
|
+
|
31
|
+
test "defaults: given false it returns false" do
|
32
|
+
assert_equal false, I18n.t(:does_not_exist, :default => false)
|
33
|
+
end
|
34
|
+
|
35
|
+
test "defaults: given nil it returns nil" do
|
36
|
+
assert_nil I18n.t(:does_not_exist, :default => nil)
|
37
|
+
end
|
38
|
+
|
39
|
+
test "defaults: given an array of missing keys it raises a MissingTranslationData exception" do
|
40
|
+
assert_raises I18n::MissingTranslationData do
|
41
|
+
I18n.t(:does_not_exist, :default => [:does_not_exist_2, :does_not_exist_3], :raise => true)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
test "defaults: using a custom scope separator" do
|
46
|
+
# data must have been stored using the custom separator when using the ActiveRecord backend
|
47
|
+
I18n.backend.store_translations(:en, { :foo => { :bar => 'bar' } }, { :separator => '|' })
|
48
|
+
assert_equal 'bar', I18n.t(nil, :default => :'foo|bar', :separator => '|')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Tests
|
5
|
+
module Interpolation
|
6
|
+
# If no interpolation parameter is not given, I18n should not alter the string.
|
7
|
+
# This behavior is due to three reasons:
|
8
|
+
#
|
9
|
+
# * Checking interpolation keys in all strings hits performance, badly;
|
10
|
+
#
|
11
|
+
# * This allows us to retrieve untouched values through I18n. For example
|
12
|
+
# I could have a middleware that returns I18n lookup results in JSON
|
13
|
+
# to be processed through Javascript. Leaving the keys untouched allows
|
14
|
+
# the interpolation to happen at the javascript level;
|
15
|
+
#
|
16
|
+
# * Security concerns: if I allow users to translate a web site, they can
|
17
|
+
# insert %{} in messages causing the I18n lookup to fail in every request.
|
18
|
+
#
|
19
|
+
test "interpolation: given no values it does not alter the string" do
|
20
|
+
assert_equal 'Hi %{name}!', interpolate(:default => 'Hi %{name}!')
|
21
|
+
end
|
22
|
+
|
23
|
+
test "interpolation: given values it interpolates them into the string" do
|
24
|
+
assert_equal 'Hi David!', interpolate(:default => 'Hi %{name}!', :name => 'David')
|
25
|
+
end
|
26
|
+
|
27
|
+
test "interpolation: works with a pipe" do
|
28
|
+
assert_equal 'Hi david!', interpolate(:default => 'Hi %{name|lowercase}!', :'name|lowercase' => 'david')
|
29
|
+
end
|
30
|
+
|
31
|
+
test "interpolation: given a nil value it still interpolates it into the string" do
|
32
|
+
assert_equal 'Hi !', interpolate(:default => 'Hi %{name}!', :name => nil)
|
33
|
+
end
|
34
|
+
|
35
|
+
test "interpolation: given a lambda as a value it calls it if the string contains the key" do
|
36
|
+
assert_equal 'Hi David!', interpolate(:default => 'Hi %{name}!', :name => lambda { |*args| 'David' })
|
37
|
+
end
|
38
|
+
|
39
|
+
test "interpolation: given a lambda as a value it does not call it if the string does not contain the key" do
|
40
|
+
assert_nothing_raised { interpolate(:default => 'Hi!', :name => lambda { |*args| raise 'fail' }) }
|
41
|
+
end
|
42
|
+
|
43
|
+
test "interpolation: given values but missing a key it raises I18n::MissingInterpolationArgument" do
|
44
|
+
assert_raises(I18n::MissingInterpolationArgument) do
|
45
|
+
interpolate(:default => '%{foo}', :bar => 'bar')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
test "interpolation: it does not raise I18n::MissingInterpolationArgument for escaped variables" do
|
50
|
+
assert_nothing_raised do
|
51
|
+
assert_equal 'Barr %{foo}', interpolate(:default => '%{bar} %%{foo}', :bar => 'Barr')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
test "interpolation: it does not change the original, stored translation string" do
|
56
|
+
I18n.backend.store_translations(:en, :interpolate => 'Hi %{name}!')
|
57
|
+
assert_equal 'Hi David!', interpolate(:interpolate, :name => 'David')
|
58
|
+
assert_equal 'Hi Yehuda!', interpolate(:interpolate, :name => 'Yehuda')
|
59
|
+
end
|
60
|
+
|
61
|
+
test "interpolation: given an array interpolates each element" do
|
62
|
+
I18n.backend.store_translations(:en, :array_interpolate => ['Hi', 'Mr. %{name}', 'or sir %{name}'])
|
63
|
+
assert_equal ['Hi', 'Mr. Bartuz', 'or sir Bartuz'], interpolate(:array_interpolate, :name => 'Bartuz')
|
64
|
+
end
|
65
|
+
|
66
|
+
test "interpolation: given the translation is in utf-8 it still works" do
|
67
|
+
assert_equal 'Häi David!', interpolate(:default => 'Häi %{name}!', :name => 'David')
|
68
|
+
end
|
69
|
+
|
70
|
+
test "interpolation: given the value is in utf-8 it still works" do
|
71
|
+
assert_equal 'Hi ゆきひろ!', interpolate(:default => 'Hi %{name}!', :name => 'ゆきひろ')
|
72
|
+
end
|
73
|
+
|
74
|
+
test "interpolation: given the translation and the value are in utf-8 it still works" do
|
75
|
+
assert_equal 'こんにちは、ゆきひろさん!', interpolate(:default => 'こんにちは、%{name}さん!', :name => 'ゆきひろ')
|
76
|
+
end
|
77
|
+
|
78
|
+
if Object.const_defined?(:Encoding)
|
79
|
+
test "interpolation: given a euc-jp translation and a utf-8 value it raises Encoding::CompatibilityError" do
|
80
|
+
assert_raises(Encoding::CompatibilityError) do
|
81
|
+
interpolate(:default => euc_jp('こんにちは、%{name}さん!'), :name => 'ゆきひろ')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
test "interpolation: given a utf-8 translation and a euc-jp value it raises Encoding::CompatibilityError" do
|
86
|
+
assert_raises(Encoding::CompatibilityError) do
|
87
|
+
interpolate(:default => 'こんにちは、%{name}さん!', :name => euc_jp('ゆきひろ'))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
test "interpolation: ASCII strings in the backend should be encoded to UTF8 if interpolation options are in UTF8" do
|
92
|
+
I18n.backend.store_translations 'en', 'encoding' => ('%{who} let me go'.force_encoding("ASCII"))
|
93
|
+
result = I18n.t 'encoding', :who => "måmmå miå"
|
94
|
+
assert_equal Encoding::UTF_8, result.encoding
|
95
|
+
end
|
96
|
+
|
97
|
+
test "interpolation: UTF8 strings in the backend are still returned as UTF8 with ASCII interpolation" do
|
98
|
+
I18n.backend.store_translations 'en', 'encoding' => 'måmmå miå %{what}'
|
99
|
+
result = I18n.t 'encoding', :what => 'let me go'.force_encoding("ASCII")
|
100
|
+
assert_equal Encoding::UTF_8, result.encoding
|
101
|
+
end
|
102
|
+
|
103
|
+
test "interpolation: UTF8 strings in the backend are still returned as UTF8 even with numbers interpolation" do
|
104
|
+
I18n.backend.store_translations 'en', 'encoding' => '%{count} times: måmmå miå'
|
105
|
+
result = I18n.t 'encoding', :count => 3
|
106
|
+
assert_equal Encoding::UTF_8, result.encoding
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
test "interpolation: given a translations containing a reserved key it raises I18n::ReservedInterpolationKey" do
|
111
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{exception_handler}') }
|
112
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{default}') }
|
113
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{separator}') }
|
114
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{scope}') }
|
115
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:default => '%{scope}') }
|
116
|
+
|
117
|
+
I18n.backend.store_translations(:en, :interpolate => 'Hi %{scope}!')
|
118
|
+
assert_raises(I18n::ReservedInterpolationKey) { interpolate(:interpolate) }
|
119
|
+
end
|
120
|
+
|
121
|
+
test "interpolation: deep interpolation for default string" do
|
122
|
+
assert_equal 'Hi %{name}!', interpolate(:default => 'Hi %{name}!', :deep_interpolation => true)
|
123
|
+
end
|
124
|
+
|
125
|
+
test "interpolation: deep interpolation for interpolated string" do
|
126
|
+
assert_equal 'Hi Ann!', interpolate(:default => 'Hi %{name}!', :name => 'Ann', :deep_interpolation => true)
|
127
|
+
end
|
128
|
+
|
129
|
+
test "interpolation: deep interpolation for Hash" do
|
130
|
+
people = { :people => { :ann => 'Ann is %{ann}', :john => 'John is %{john}' } }
|
131
|
+
interpolated_people = { :people => { :ann => 'Ann is good', :john => 'John is big' } }
|
132
|
+
assert_equal interpolated_people, interpolate(:default => people, :ann => 'good', :john => 'big', :deep_interpolation => true)
|
133
|
+
end
|
134
|
+
|
135
|
+
test "interpolation: deep interpolation for Array" do
|
136
|
+
people = { :people => ['Ann is %{ann}', 'John is %{john}'] }
|
137
|
+
interpolated_people = { :people => ['Ann is good', 'John is big'] }
|
138
|
+
assert_equal interpolated_people, interpolate(:default => people, :ann => 'good', :john => 'big', :deep_interpolation => true)
|
139
|
+
end
|
140
|
+
|
141
|
+
protected
|
142
|
+
|
143
|
+
def capture(stream)
|
144
|
+
begin
|
145
|
+
stream = stream.to_s
|
146
|
+
eval "$#{stream} = StringIO.new"
|
147
|
+
yield
|
148
|
+
result = eval("$#{stream}").string
|
149
|
+
ensure
|
150
|
+
eval("$#{stream} = #{stream.upcase}")
|
151
|
+
end
|
152
|
+
|
153
|
+
result
|
154
|
+
end
|
155
|
+
|
156
|
+
def euc_jp(string)
|
157
|
+
string.encode!(Encoding::EUC_JP)
|
158
|
+
end
|
159
|
+
|
160
|
+
def interpolate(*args)
|
161
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
162
|
+
key = args.pop
|
163
|
+
I18n.backend.translate('en', key, options)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Tests
|
5
|
+
module Link
|
6
|
+
test "linked lookup: if a key resolves to a symbol it looks up the symbol" do
|
7
|
+
I18n.backend.store_translations 'en', {
|
8
|
+
:link => :linked,
|
9
|
+
:linked => 'linked'
|
10
|
+
}
|
11
|
+
assert_equal 'linked', I18n.backend.translate('en', :link)
|
12
|
+
end
|
13
|
+
|
14
|
+
test "linked lookup: if a key resolves to a dot-separated symbol it looks up the symbol" do
|
15
|
+
I18n.backend.store_translations 'en', {
|
16
|
+
:link => :"foo.linked",
|
17
|
+
:foo => { :linked => 'linked' }
|
18
|
+
}
|
19
|
+
assert_equal('linked', I18n.backend.translate('en', :link))
|
20
|
+
end
|
21
|
+
|
22
|
+
test "linked lookup: if a dot-separated key resolves to a symbol it looks up the symbol" do
|
23
|
+
I18n.backend.store_translations 'en', {
|
24
|
+
:foo => { :link => :linked },
|
25
|
+
:linked => 'linked'
|
26
|
+
}
|
27
|
+
assert_equal('linked', I18n.backend.translate('en', :'foo.link'))
|
28
|
+
end
|
29
|
+
|
30
|
+
test "linked lookup: if a dot-separated key resolves to a dot-separated symbol it looks up the symbol" do
|
31
|
+
I18n.backend.store_translations 'en', {
|
32
|
+
:foo => { :link => :"bar.linked" },
|
33
|
+
:bar => { :linked => 'linked' }
|
34
|
+
}
|
35
|
+
assert_equal('linked', I18n.backend.translate('en', :'foo.link'))
|
36
|
+
end
|
37
|
+
|
38
|
+
test "linked lookup: links always refer to the absolute key" do
|
39
|
+
I18n.backend.store_translations 'en', {
|
40
|
+
:foo => { :link => :linked, :linked => 'linked in foo' },
|
41
|
+
:linked => 'linked absolutely'
|
42
|
+
}
|
43
|
+
assert_equal 'linked absolutely', I18n.backend.translate('en', :link, :scope => :foo)
|
44
|
+
end
|
45
|
+
|
46
|
+
test "linked lookup: a link can resolve to a namespace in the middle of a dot-separated key" do
|
47
|
+
I18n.backend.store_translations 'en', {
|
48
|
+
:activemodel => { :errors => { :messages => { :blank => "can't be blank" } } },
|
49
|
+
:activerecord => { :errors => { :messages => :"activemodel.errors.messages" } }
|
50
|
+
}
|
51
|
+
assert_equal "can't be blank", I18n.t(:"activerecord.errors.messages.blank")
|
52
|
+
assert_equal "can't be blank", I18n.t(:"activerecord.errors.messages.blank")
|
53
|
+
end
|
54
|
+
|
55
|
+
test "linked lookup: a link can resolve with option :count" do
|
56
|
+
I18n.backend.store_translations 'en', {
|
57
|
+
:counter => :counted,
|
58
|
+
:counted => { :foo => { :one => "one", :other => "other" }, :bar => "bar" }
|
59
|
+
}
|
60
|
+
assert_equal "one", I18n.t(:'counter.foo', count: 1)
|
61
|
+
assert_equal "other", I18n.t(:'counter.foo', count: 2)
|
62
|
+
assert_equal "bar", I18n.t(:'counter.bar', count: 3)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Tests
|
5
|
+
module Localization
|
6
|
+
module Date
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
setup_date_translations
|
10
|
+
@date = ::Date.new(2008, 3, 1)
|
11
|
+
end
|
12
|
+
|
13
|
+
test "localize Date: given the short format it uses it" do
|
14
|
+
assert_equal '01. Mär', I18n.l(@date, :format => :short, :locale => :de)
|
15
|
+
end
|
16
|
+
|
17
|
+
test "localize Date: given the long format it uses it" do
|
18
|
+
assert_equal '01. März 2008', I18n.l(@date, :format => :long, :locale => :de)
|
19
|
+
end
|
20
|
+
|
21
|
+
test "localize Date: given the default format it uses it" do
|
22
|
+
assert_equal '01.03.2008', I18n.l(@date, :format => :default, :locale => :de)
|
23
|
+
end
|
24
|
+
|
25
|
+
test "localize Date: given a day name format it returns the correct day name" do
|
26
|
+
assert_equal 'Samstag', I18n.l(@date, :format => '%A', :locale => :de)
|
27
|
+
end
|
28
|
+
|
29
|
+
test "localize Date: given a uppercased day name format it returns the correct day name in upcase" do
|
30
|
+
assert_equal 'samstag'.upcase, I18n.l(@date, :format => '%^A', :locale => :de)
|
31
|
+
end
|
32
|
+
|
33
|
+
test "localize Date: given an abbreviated day name format it returns the correct abbreviated day name" do
|
34
|
+
assert_equal 'Sa', I18n.l(@date, :format => '%a', :locale => :de)
|
35
|
+
end
|
36
|
+
|
37
|
+
test "localize Date: given an meridian indicator format it returns the correct meridian indicator" do
|
38
|
+
assert_equal 'AM', I18n.l(@date, :format => '%p', :locale => :de)
|
39
|
+
assert_equal 'am', I18n.l(@date, :format => '%P', :locale => :de)
|
40
|
+
end
|
41
|
+
|
42
|
+
test "localize Date: given an abbreviated and uppercased day name format it returns the correct abbreviated day name in upcase" do
|
43
|
+
assert_equal 'sa'.upcase, I18n.l(@date, :format => '%^a', :locale => :de)
|
44
|
+
end
|
45
|
+
|
46
|
+
test "localize Date: given a month name format it returns the correct month name" do
|
47
|
+
assert_equal 'März', I18n.l(@date, :format => '%B', :locale => :de)
|
48
|
+
end
|
49
|
+
|
50
|
+
test "localize Date: given a uppercased month name format it returns the correct month name in upcase" do
|
51
|
+
assert_equal 'märz'.upcase, I18n.l(@date, :format => '%^B', :locale => :de)
|
52
|
+
end
|
53
|
+
|
54
|
+
test "localize Date: given an abbreviated month name format it returns the correct abbreviated month name" do
|
55
|
+
assert_equal 'Mär', I18n.l(@date, :format => '%b', :locale => :de)
|
56
|
+
end
|
57
|
+
|
58
|
+
test "localize Date: given an abbreviated and uppercased month name format it returns the correct abbreviated month name in upcase" do
|
59
|
+
assert_equal 'mär'.upcase, I18n.l(@date, :format => '%^b', :locale => :de)
|
60
|
+
end
|
61
|
+
|
62
|
+
test "localize Date: given a date format with the month name upcased it returns the correct value" do
|
63
|
+
assert_equal '1. FEBRUAR 2008', I18n.l(::Date.new(2008, 2, 1), :format => "%-d. %^B %Y", :locale => :de)
|
64
|
+
end
|
65
|
+
|
66
|
+
test "localize Date: given missing translations it returns the correct error message" do
|
67
|
+
assert_equal 'Translation missing: fr.date.abbr_month_names', I18n.l(@date, :format => '%b', :locale => :fr)
|
68
|
+
end
|
69
|
+
|
70
|
+
test "localize Date: given an unknown format it does not fail" do
|
71
|
+
assert_nothing_raised { I18n.l(@date, :format => '%x') }
|
72
|
+
end
|
73
|
+
|
74
|
+
test "localize Date: does not modify the options hash" do
|
75
|
+
options = { :format => '%b', :locale => :de }
|
76
|
+
assert_equal 'Mär', I18n.l(@date, **options)
|
77
|
+
assert_equal({ :format => '%b', :locale => :de }, options)
|
78
|
+
assert_nothing_raised { I18n.l(@date, **options.freeze) }
|
79
|
+
end
|
80
|
+
|
81
|
+
test "localize Date: given nil with default value it returns default" do
|
82
|
+
assert_equal 'default', I18n.l(nil, :default => 'default')
|
83
|
+
end
|
84
|
+
|
85
|
+
test "localize Date: given nil it raises I18n::ArgumentError" do
|
86
|
+
assert_raises(I18n::ArgumentError) { I18n.l(nil) }
|
87
|
+
end
|
88
|
+
|
89
|
+
test "localize Date: given a plain Object it raises I18n::ArgumentError" do
|
90
|
+
assert_raises(I18n::ArgumentError) { I18n.l(Object.new) }
|
91
|
+
end
|
92
|
+
|
93
|
+
test "localize Date: given a format is missing it raises I18n::MissingTranslationData" do
|
94
|
+
assert_raises(I18n::MissingTranslationData) { I18n.l(@date, :format => :missing) }
|
95
|
+
end
|
96
|
+
|
97
|
+
test "localize Date: it does not alter the format string" do
|
98
|
+
assert_equal '01. Februar 2009', I18n.l(::Date.parse('2009-02-01'), :format => :long, :locale => :de)
|
99
|
+
assert_equal '01. Oktober 2009', I18n.l(::Date.parse('2009-10-01'), :format => :long, :locale => :de)
|
100
|
+
end
|
101
|
+
|
102
|
+
protected
|
103
|
+
|
104
|
+
def setup_date_translations
|
105
|
+
I18n.backend.store_translations :de, {
|
106
|
+
:date => {
|
107
|
+
:formats => {
|
108
|
+
:default => "%d.%m.%Y",
|
109
|
+
:short => "%d. %b",
|
110
|
+
:long => "%d. %B %Y",
|
111
|
+
},
|
112
|
+
:day_names => %w(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag),
|
113
|
+
:abbr_day_names => %w(So Mo Di Mi Do Fr Sa),
|
114
|
+
:month_names => %w(Januar Februar März April Mai Juni Juli August September Oktober November Dezember).unshift(nil),
|
115
|
+
:abbr_month_names => %w(Jan Feb Mär Apr Mai Jun Jul Aug Sep Okt Nov Dez).unshift(nil)
|
116
|
+
}
|
117
|
+
}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|