sayso-i18n 0.5.0.001
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.textile +152 -0
- data/MIT-LICENSE +20 -0
- data/README.textile +103 -0
- data/ci/Gemfile.no-rails +5 -0
- data/ci/Gemfile.no-rails.lock +14 -0
- data/ci/Gemfile.rails-2.3.x +9 -0
- data/ci/Gemfile.rails-2.3.x.lock +23 -0
- data/ci/Gemfile.rails-3.x +9 -0
- data/ci/Gemfile.rails-3.x.lock +23 -0
- data/lib/i18n.rb +324 -0
- data/lib/i18n/backend.rb +19 -0
- data/lib/i18n/backend/base.rb +174 -0
- data/lib/i18n/backend/cache.rb +102 -0
- data/lib/i18n/backend/cascade.rb +53 -0
- data/lib/i18n/backend/chain.rb +80 -0
- data/lib/i18n/backend/fallbacks.rb +70 -0
- data/lib/i18n/backend/flatten.rb +113 -0
- data/lib/i18n/backend/flatten_yml.rb +70 -0
- data/lib/i18n/backend/gettext.rb +71 -0
- data/lib/i18n/backend/interpolation_compiler.rb +121 -0
- data/lib/i18n/backend/key_value.rb +100 -0
- data/lib/i18n/backend/memoize.rb +46 -0
- data/lib/i18n/backend/metadata.rb +65 -0
- data/lib/i18n/backend/pluralization.rb +55 -0
- data/lib/i18n/backend/simple.rb +87 -0
- data/lib/i18n/backend/transliterator.rb +98 -0
- data/lib/i18n/config.rb +86 -0
- data/lib/i18n/core_ext/hash.rb +29 -0
- data/lib/i18n/core_ext/kernel/surpress_warnings.rb +9 -0
- data/lib/i18n/core_ext/string/interpolate.rb +105 -0
- data/lib/i18n/exceptions.rb +88 -0
- data/lib/i18n/gettext.rb +25 -0
- data/lib/i18n/gettext/helpers.rb +64 -0
- data/lib/i18n/gettext/po_parser.rb +329 -0
- data/lib/i18n/interpolate/ruby.rb +31 -0
- data/lib/i18n/locale.rb +6 -0
- data/lib/i18n/locale/fallbacks.rb +96 -0
- data/lib/i18n/locale/tag.rb +28 -0
- data/lib/i18n/locale/tag/parents.rb +22 -0
- data/lib/i18n/locale/tag/rfc4646.rb +74 -0
- data/lib/i18n/locale/tag/simple.rb +39 -0
- data/lib/i18n/tests.rb +12 -0
- data/lib/i18n/tests/basics.rb +54 -0
- data/lib/i18n/tests/defaults.rb +40 -0
- data/lib/i18n/tests/interpolation.rb +133 -0
- data/lib/i18n/tests/link.rb +56 -0
- data/lib/i18n/tests/localization.rb +19 -0
- data/lib/i18n/tests/localization/date.rb +84 -0
- data/lib/i18n/tests/localization/date_time.rb +77 -0
- data/lib/i18n/tests/localization/procs.rb +116 -0
- data/lib/i18n/tests/localization/time.rb +76 -0
- data/lib/i18n/tests/lookup.rb +74 -0
- data/lib/i18n/tests/pluralization.rb +35 -0
- data/lib/i18n/tests/procs.rb +55 -0
- data/lib/i18n/version.rb +3 -0
- data/test/all.rb +8 -0
- data/test/api/all_features_test.rb +58 -0
- data/test/api/cascade_test.rb +28 -0
- data/test/api/chain_test.rb +24 -0
- data/test/api/fallbacks_test.rb +30 -0
- data/test/api/flatten_yml_test.rb +32 -0
- data/test/api/key_value_test.rb +28 -0
- data/test/api/memoize_test.rb +60 -0
- data/test/api/pluralization_test.rb +30 -0
- data/test/api/simple_test.rb +28 -0
- data/test/backend/cache_test.rb +83 -0
- data/test/backend/cascade_test.rb +85 -0
- data/test/backend/chain_test.rb +72 -0
- data/test/backend/exceptions_test.rb +23 -0
- data/test/backend/fallbacks_test.rb +120 -0
- data/test/backend/flatten_yml_test.rb +49 -0
- data/test/backend/interpolation_compiler_test.rb +102 -0
- data/test/backend/key_value_test.rb +46 -0
- data/test/backend/memoize_test.rb +47 -0
- data/test/backend/metadata_test.rb +67 -0
- data/test/backend/pluralization_test.rb +44 -0
- data/test/backend/simple_test.rb +83 -0
- data/test/backend/transliterator_test.rb +81 -0
- data/test/core_ext/hash_test.rb +30 -0
- data/test/core_ext/string/interpolate_test.rb +99 -0
- data/test/gettext/api_test.rb +206 -0
- data/test/gettext/backend_test.rb +93 -0
- data/test/i18n/exceptions_test.rb +116 -0
- data/test/i18n/interpolate_test.rb +61 -0
- data/test/i18n/load_path_test.rb +26 -0
- data/test/i18n_test.rb +236 -0
- data/test/locale/fallbacks_test.rb +124 -0
- data/test/locale/tag/rfc4646_test.rb +142 -0
- data/test/locale/tag/simple_test.rb +32 -0
- data/test/run_all.rb +21 -0
- data/test/test_data/locales/de.po +72 -0
- data/test/test_data/locales/en.rb +3 -0
- data/test/test_data/locales/en.yml +3 -0
- data/test/test_data/locales/invalid/empty.yml +1 -0
- data/test/test_data/locales/plurals.rb +113 -0
- data/test/test_helper.rb +56 -0
- metadata +194 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
# Memoize module simply memoizes the values returned by lookup using
|
2
|
+
# a flat hash and can tremendously speed up the lookup process in a backend.
|
3
|
+
#
|
4
|
+
# To enable it you can simply include the Memoize module to your backend:
|
5
|
+
#
|
6
|
+
# I18n::Backend::Simple.include(I18n::Backend::Memoize)
|
7
|
+
#
|
8
|
+
# Notice that it's the responsibility of the backend to define whenever the
|
9
|
+
# cache should be cleaned.
|
10
|
+
module I18n
|
11
|
+
module Backend
|
12
|
+
module Memoize
|
13
|
+
def available_locales
|
14
|
+
@memoized_locales ||= super
|
15
|
+
end
|
16
|
+
|
17
|
+
def store_translations(locale, data, options = {})
|
18
|
+
reset_memoizations!(locale)
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def reload!
|
23
|
+
reset_memoizations!
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def lookup(locale, key, scope = nil, options = {})
|
30
|
+
flat_key = I18n::Backend::Flatten.normalize_flat_keys(locale,
|
31
|
+
key, scope, options[:separator]).to_sym
|
32
|
+
flat_hash = memoized_lookup[locale.to_sym]
|
33
|
+
flat_hash.key?(flat_key) ? flat_hash[flat_key] : (flat_hash[flat_key] = super)
|
34
|
+
end
|
35
|
+
|
36
|
+
def memoized_lookup
|
37
|
+
@memoized_lookup ||= Hash.new { |h, k| h[k] = {} }
|
38
|
+
end
|
39
|
+
|
40
|
+
def reset_memoizations!(locale=nil)
|
41
|
+
@memoized_locales = nil
|
42
|
+
(locale ? memoized_lookup[locale.to_sym] : memoized_lookup).clear
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# I18n translation metadata is useful when you want to access information
|
2
|
+
# about how a translation was looked up, pluralized or interpolated in
|
3
|
+
# your application.
|
4
|
+
#
|
5
|
+
# msg = I18n.t(:message, :default => 'Hi!', :scope => :foo)
|
6
|
+
# msg.translation_metadata
|
7
|
+
# # => { :key => :message, :scope => :foo, :default => 'Hi!' }
|
8
|
+
#
|
9
|
+
# If a :count option was passed to #translate it will be set to the metadata.
|
10
|
+
# Likewise, if any interpolation variables were passed they will also be set.
|
11
|
+
#
|
12
|
+
# To enable translation metadata you can simply include the Metadata module
|
13
|
+
# into the Simple backend class - or whatever other backend you are using:
|
14
|
+
#
|
15
|
+
# I18n::Backend::Simple.include(I18n::Backend::Metadata)
|
16
|
+
#
|
17
|
+
module I18n
|
18
|
+
module Backend
|
19
|
+
module Metadata
|
20
|
+
class << self
|
21
|
+
def included(base)
|
22
|
+
Object.class_eval do
|
23
|
+
def translation_metadata
|
24
|
+
@translation_metadata ||= {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def translation_metadata=(translation_metadata)
|
28
|
+
@translation_metadata = translation_metadata
|
29
|
+
end
|
30
|
+
end unless Object.method_defined?(:translation_metadata)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def translate(locale, key, options = {})
|
35
|
+
metadata = {
|
36
|
+
:locale => locale,
|
37
|
+
:key => key,
|
38
|
+
:scope => options[:scope],
|
39
|
+
:default => options[:default],
|
40
|
+
:separator => options[:separator],
|
41
|
+
:values => options.reject { |name, value| RESERVED_KEYS.include?(name) }
|
42
|
+
}
|
43
|
+
with_metadata(metadata) { super }
|
44
|
+
end
|
45
|
+
|
46
|
+
def interpolate(locale, entry, values = {})
|
47
|
+
metadata = entry.translation_metadata.merge(:original => entry)
|
48
|
+
with_metadata(metadata) { super }
|
49
|
+
end
|
50
|
+
|
51
|
+
def pluralize(locale, entry, count)
|
52
|
+
with_metadata(:count => count) { super }
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def with_metadata(metadata, &block)
|
58
|
+
result = yield
|
59
|
+
result.translation_metadata = result.translation_metadata.merge(metadata) if result
|
60
|
+
result
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# I18n locale fallbacks are useful when you want your application to use
|
2
|
+
# translations from other locales when translations for the current locale are
|
3
|
+
# missing. E.g. you might want to use :en translations when translations in
|
4
|
+
# your applications main locale :de are missing.
|
5
|
+
#
|
6
|
+
# To enable locale specific pluralizations you can simply include the
|
7
|
+
# Pluralization module to the Simple backend - or whatever other backend you
|
8
|
+
# are using.
|
9
|
+
#
|
10
|
+
# I18n::Backend::Simple.include(I18n::Backend::Pluralization)
|
11
|
+
#
|
12
|
+
# You also need to make sure to provide pluralization algorithms to the
|
13
|
+
# backend, i.e. include them to your I18n.load_path accordingly.
|
14
|
+
module I18n
|
15
|
+
module Backend
|
16
|
+
module Pluralization
|
17
|
+
# Overwrites the Base backend translate method so that it will check the
|
18
|
+
# translation meta data space (:i18n) for a locale specific pluralization
|
19
|
+
# rule and use it to pluralize the given entry. I.e. the library expects
|
20
|
+
# pluralization rules to be stored at I18n.t(:'i18n.plural.rule')
|
21
|
+
#
|
22
|
+
# Pluralization rules are expected to respond to #call(count) and
|
23
|
+
# return a pluralization key. Valid keys depend on the translation data
|
24
|
+
# hash (entry) but it is generally recommended to follow CLDR's style,
|
25
|
+
# i.e., return one of the keys :zero, :one, :few, :many, :other.
|
26
|
+
#
|
27
|
+
# The :zero key is always picked directly when count equals 0 AND the
|
28
|
+
# translation data has the key :zero. This way translators are free to
|
29
|
+
# either pick a special :zero translation even for languages where the
|
30
|
+
# pluralizer does not return a :zero key.
|
31
|
+
def pluralize(locale, entry, count)
|
32
|
+
return entry unless entry.is_a?(Hash) and count
|
33
|
+
|
34
|
+
pluralizer = pluralizer(locale)
|
35
|
+
if pluralizer.respond_to?(:call)
|
36
|
+
key = count == 0 && entry.has_key?(:zero) ? :zero : pluralizer.call(count)
|
37
|
+
raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
|
38
|
+
entry[key]
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def pluralizers
|
47
|
+
@pluralizers ||= {}
|
48
|
+
end
|
49
|
+
|
50
|
+
def pluralizer(locale)
|
51
|
+
pluralizers[locale] ||= I18n.t(:'i18n.plural.rule', :locale => locale, :resolve => false)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module I18n
|
2
|
+
module Backend
|
3
|
+
# A simple backend that reads translations from YAML files and stores them in
|
4
|
+
# an in-memory hash. Relies on the Base backend.
|
5
|
+
#
|
6
|
+
# The implementation is provided by a Implementation module allowing to easily
|
7
|
+
# extend Simple backend's behavior by including modules. E.g.:
|
8
|
+
#
|
9
|
+
# module I18n::Backend::Pluralization
|
10
|
+
# def pluralize(*args)
|
11
|
+
# # extended pluralization logic
|
12
|
+
# super
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# I18n::Backend::Simple.include(I18n::Backend::Pluralization)
|
17
|
+
class Simple
|
18
|
+
(class << self; self; end).class_eval { public :include }
|
19
|
+
|
20
|
+
module Implementation
|
21
|
+
include Base
|
22
|
+
|
23
|
+
def initialized?
|
24
|
+
@initialized ||= false
|
25
|
+
end
|
26
|
+
|
27
|
+
# Stores translations for the given locale in memory.
|
28
|
+
# This uses a deep merge for the translations hash, so existing
|
29
|
+
# translations will be overwritten by new ones only at the deepest
|
30
|
+
# level of the hash.
|
31
|
+
def store_translations(locale, data, options = {})
|
32
|
+
locale = locale.to_sym
|
33
|
+
translations[locale] ||= {}
|
34
|
+
data = data.deep_symbolize_keys
|
35
|
+
translations[locale].deep_merge!(data)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Get available locales from the translations hash
|
39
|
+
def available_locales
|
40
|
+
init_translations unless initialized?
|
41
|
+
translations.inject([]) do |locales, (locale, data)|
|
42
|
+
locales << locale unless (data.keys - [:i18n]).empty?
|
43
|
+
locales
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Clean up translations hash and set initialized to false on reload!
|
48
|
+
def reload!
|
49
|
+
@initialized = false
|
50
|
+
@translations = nil
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def init_translations
|
57
|
+
load_translations
|
58
|
+
@initialized = true
|
59
|
+
end
|
60
|
+
|
61
|
+
def translations
|
62
|
+
@translations ||= {}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Looks up a translation from the translations hash. Returns nil if
|
66
|
+
# eiher key is nil, or locale, scope or key do not exist as a key in the
|
67
|
+
# nested translations hash. Splits keys or scopes containing dots
|
68
|
+
# into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
|
69
|
+
# <tt>%w(currency format)</tt>.
|
70
|
+
def lookup(locale, key, scope = [], options = {})
|
71
|
+
init_translations unless initialized?
|
72
|
+
keys = I18n.normalize_keys(locale, key, scope, options[:separator])
|
73
|
+
|
74
|
+
keys.inject(translations) do |result, _key|
|
75
|
+
_key = _key.to_sym
|
76
|
+
return nil unless result.is_a?(Hash) && result.has_key?(_key)
|
77
|
+
result = result[_key]
|
78
|
+
result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
|
79
|
+
result
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
include Implementation
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module I18n
|
3
|
+
module Backend
|
4
|
+
module Transliterator
|
5
|
+
DEFAULT_REPLACEMENT_CHAR = "?"
|
6
|
+
|
7
|
+
# Given a locale and a UTF-8 string, return the locale's ASCII
|
8
|
+
# approximation for the string.
|
9
|
+
def transliterate(locale, string, replacement = nil)
|
10
|
+
@transliterators ||= {}
|
11
|
+
@transliterators[locale] ||= Transliterator.get I18n.t(:'i18n.transliterate.rule',
|
12
|
+
:locale => locale, :resolve => false, :default => {})
|
13
|
+
@transliterators[locale].transliterate(string, replacement)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Get a transliterator instance.
|
17
|
+
def self.get(rule = nil)
|
18
|
+
if !rule || rule.kind_of?(Hash)
|
19
|
+
HashTransliterator.new(rule)
|
20
|
+
elsif rule.kind_of? Proc
|
21
|
+
ProcTransliterator.new(rule)
|
22
|
+
else
|
23
|
+
raise I18n::ArgumentError, "Transliteration rule must be a proc or a hash."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# A transliterator which accepts a Proc as its transliteration rule.
|
28
|
+
class ProcTransliterator
|
29
|
+
def initialize(rule)
|
30
|
+
@rule = rule
|
31
|
+
end
|
32
|
+
|
33
|
+
def transliterate(string, replacement = nil)
|
34
|
+
@rule.call(string)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# A transliterator which accepts a Hash of characters as its translation
|
39
|
+
# rule.
|
40
|
+
class HashTransliterator
|
41
|
+
DEFAULT_APPROXIMATIONS = {
|
42
|
+
"À"=>"A", "Á"=>"A", "Â"=>"A", "Ã"=>"A", "Ä"=>"A", "Å"=>"A", "Æ"=>"AE",
|
43
|
+
"Ç"=>"C", "È"=>"E", "É"=>"E", "Ê"=>"E", "Ë"=>"E", "Ì"=>"I", "Í"=>"I",
|
44
|
+
"Î"=>"I", "Ï"=>"I", "Ð"=>"D", "Ñ"=>"N", "Ò"=>"O", "Ó"=>"O", "Ô"=>"O",
|
45
|
+
"Õ"=>"O", "Ö"=>"O", "×"=>"x", "Ø"=>"O", "Ù"=>"U", "Ú"=>"U", "Û"=>"U",
|
46
|
+
"Ü"=>"U", "Ý"=>"Y", "Þ"=>"Th", "ß"=>"ss", "à"=>"a", "á"=>"a", "â"=>"a",
|
47
|
+
"ã"=>"a", "ä"=>"a", "å"=>"a", "æ"=>"ae", "ç"=>"c", "è"=>"e", "é"=>"e",
|
48
|
+
"ê"=>"e", "ë"=>"e", "ì"=>"i", "í"=>"i", "î"=>"i", "ï"=>"i", "ð"=>"d",
|
49
|
+
"ñ"=>"n", "ò"=>"o", "ó"=>"o", "ô"=>"o", "õ"=>"o", "ö"=>"o", "ø"=>"o",
|
50
|
+
"ù"=>"u", "ú"=>"u", "û"=>"u", "ü"=>"u", "ý"=>"y", "þ"=>"th", "ÿ"=>"y",
|
51
|
+
"Ā"=>"A", "ā"=>"a", "Ă"=>"A", "ă"=>"a", "Ą"=>"A", "ą"=>"a", "Ć"=>"C",
|
52
|
+
"ć"=>"c", "Ĉ"=>"C", "ĉ"=>"c", "Ċ"=>"C", "ċ"=>"c", "Č"=>"C", "č"=>"c",
|
53
|
+
"Ď"=>"D", "ď"=>"d", "Đ"=>"D", "đ"=>"d", "Ē"=>"E", "ē"=>"e", "Ĕ"=>"E",
|
54
|
+
"ĕ"=>"e", "Ė"=>"E", "ė"=>"e", "Ę"=>"E", "ę"=>"e", "Ě"=>"E", "ě"=>"e",
|
55
|
+
"Ĝ"=>"G", "ĝ"=>"g", "Ğ"=>"G", "ğ"=>"g", "Ġ"=>"G", "ġ"=>"g", "Ģ"=>"G",
|
56
|
+
"ģ"=>"g", "Ĥ"=>"H", "ĥ"=>"h", "Ħ"=>"H", "ħ"=>"h", "Ĩ"=>"I", "ĩ"=>"i",
|
57
|
+
"Ī"=>"I", "ī"=>"i", "Ĭ"=>"I", "ĭ"=>"i", "Į"=>"I", "į"=>"i", "İ"=>"I",
|
58
|
+
"ı"=>"i", "IJ"=>"IJ", "ij"=>"ij", "Ĵ"=>"J", "ĵ"=>"j", "Ķ"=>"K", "ķ"=>"k",
|
59
|
+
"ĸ"=>"k", "Ĺ"=>"L", "ĺ"=>"l", "Ļ"=>"L", "ļ"=>"l", "Ľ"=>"L", "ľ"=>"l",
|
60
|
+
"Ŀ"=>"L", "ŀ"=>"l", "Ł"=>"L", "ł"=>"l", "Ń"=>"N", "ń"=>"n", "Ņ"=>"N",
|
61
|
+
"ņ"=>"n", "Ň"=>"N", "ň"=>"n", "ʼn"=>"'n", "Ŋ"=>"NG", "ŋ"=>"ng",
|
62
|
+
"Ō"=>"O", "ō"=>"o", "Ŏ"=>"O", "ŏ"=>"o", "Ő"=>"O", "ő"=>"o", "Œ"=>"OE",
|
63
|
+
"œ"=>"oe", "Ŕ"=>"R", "ŕ"=>"r", "Ŗ"=>"R", "ŗ"=>"r", "Ř"=>"R", "ř"=>"r",
|
64
|
+
"Ś"=>"S", "ś"=>"s", "Ŝ"=>"S", "ŝ"=>"s", "Ş"=>"S", "ş"=>"s", "Š"=>"S",
|
65
|
+
"š"=>"s", "Ţ"=>"T", "ţ"=>"t", "Ť"=>"T", "ť"=>"t", "Ŧ"=>"T", "ŧ"=>"t",
|
66
|
+
"Ũ"=>"U", "ũ"=>"u", "Ū"=>"U", "ū"=>"u", "Ŭ"=>"U", "ŭ"=>"u", "Ů"=>"U",
|
67
|
+
"ů"=>"u", "Ű"=>"U", "ű"=>"u", "Ų"=>"U", "ų"=>"u", "Ŵ"=>"W", "ŵ"=>"w",
|
68
|
+
"Ŷ"=>"Y", "ŷ"=>"y", "Ÿ"=>"Y", "Ź"=>"Z", "ź"=>"z", "Ż"=>"Z", "ż"=>"z",
|
69
|
+
"Ž"=>"Z", "ž"=>"z"
|
70
|
+
}
|
71
|
+
|
72
|
+
def initialize(rule = nil)
|
73
|
+
@rule = rule
|
74
|
+
add DEFAULT_APPROXIMATIONS
|
75
|
+
add rule if rule
|
76
|
+
end
|
77
|
+
|
78
|
+
def transliterate(string, replacement = nil)
|
79
|
+
string.gsub(/[^\x00-\x7f]/u) do |char|
|
80
|
+
approximations[char] || replacement || DEFAULT_REPLACEMENT_CHAR
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def approximations
|
87
|
+
@approximations ||= {}
|
88
|
+
end
|
89
|
+
|
90
|
+
# Add transliteration rules to the approximations hash.
|
91
|
+
def add(hash)
|
92
|
+
hash.keys.each {|key| hash[key.to_s] = hash.delete(key).to_s}
|
93
|
+
approximations.merge! hash
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/i18n/config.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
module I18n
|
2
|
+
class Config
|
3
|
+
# The only configuration value that is not global and scoped to thread is :locale.
|
4
|
+
# It defaults to the default_locale.
|
5
|
+
def locale
|
6
|
+
@locale ||= default_locale
|
7
|
+
end
|
8
|
+
|
9
|
+
# Sets the current locale pseudo-globally, i.e. in the Thread.current hash.
|
10
|
+
def locale=(locale)
|
11
|
+
@locale = locale.to_sym rescue nil
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns the current backend. Defaults to +Backend::Simple+.
|
15
|
+
def backend
|
16
|
+
@@backend ||= Backend::Simple.new
|
17
|
+
end
|
18
|
+
|
19
|
+
# Sets the current backend. Used to set a custom backend.
|
20
|
+
def backend=(backend)
|
21
|
+
@@backend = backend
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the current default locale. Defaults to :'en'
|
25
|
+
def default_locale
|
26
|
+
@@default_locale ||= :en
|
27
|
+
end
|
28
|
+
|
29
|
+
# Sets the current default locale. Used to set a custom default locale.
|
30
|
+
def default_locale=(locale)
|
31
|
+
@@default_locale = locale.to_sym rescue nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns an array of locales for which translations are available.
|
35
|
+
# Unless you explicitely set these through I18n.available_locales=
|
36
|
+
# the call will be delegated to the backend.
|
37
|
+
def available_locales
|
38
|
+
@@available_locales ||= nil
|
39
|
+
@@available_locales || backend.available_locales
|
40
|
+
end
|
41
|
+
|
42
|
+
# Sets the available locales.
|
43
|
+
def available_locales=(locales)
|
44
|
+
@@available_locales = Array(locales).map { |locale| locale.to_sym }
|
45
|
+
@@available_locales = nil if @@available_locales.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the current default scope separator. Defaults to '.'
|
49
|
+
def default_separator
|
50
|
+
@@default_separator ||= '.'
|
51
|
+
end
|
52
|
+
|
53
|
+
# Sets the current default scope separator.
|
54
|
+
def default_separator=(separator)
|
55
|
+
@@default_separator = separator
|
56
|
+
end
|
57
|
+
|
58
|
+
# Return the current exception handler. Defaults to :default_exception_handler.
|
59
|
+
def exception_handler
|
60
|
+
@@exception_handler ||= ExceptionHandler.new
|
61
|
+
end
|
62
|
+
|
63
|
+
# Sets the exception handler.
|
64
|
+
def exception_handler=(exception_handler)
|
65
|
+
@@exception_handler = exception_handler
|
66
|
+
end
|
67
|
+
|
68
|
+
# Allow clients to register paths providing translation data sources. The
|
69
|
+
# backend defines acceptable sources.
|
70
|
+
#
|
71
|
+
# E.g. the provided SimpleBackend accepts a list of paths to translation
|
72
|
+
# files which are either named *.rb and contain plain Ruby Hashes or are
|
73
|
+
# named *.yml and contain YAML data. So for the SimpleBackend clients may
|
74
|
+
# register translation files like this:
|
75
|
+
# I18n.load_path << 'path/to/locale/en.yml'
|
76
|
+
def load_path
|
77
|
+
@@load_path ||= []
|
78
|
+
end
|
79
|
+
|
80
|
+
# Sets the load path instance. Custom implementations are expected to
|
81
|
+
# behave like a Ruby Array.
|
82
|
+
def load_path=(load_path)
|
83
|
+
@@load_path = load_path
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Hash
|
2
|
+
def slice(*keep_keys)
|
3
|
+
h = {}
|
4
|
+
keep_keys.each { |key| h[key] = fetch(key) }
|
5
|
+
h
|
6
|
+
end unless Hash.method_defined?(:slice)
|
7
|
+
|
8
|
+
def except(*less_keys)
|
9
|
+
slice(*keys - less_keys)
|
10
|
+
end unless Hash.method_defined?(:except)
|
11
|
+
|
12
|
+
def deep_symbolize_keys
|
13
|
+
inject({}) { |result, (key, value)|
|
14
|
+
value = value.deep_symbolize_keys if value.is_a?(Hash)
|
15
|
+
result[(key.to_sym rescue key) || key] = value
|
16
|
+
result
|
17
|
+
}
|
18
|
+
end unless Hash.method_defined?(:deep_symbolize_keys)
|
19
|
+
|
20
|
+
# deep_merge_hash! by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
|
21
|
+
MERGER = proc do |key, v1, v2|
|
22
|
+
Hash === v1 && Hash === v2 ? v1.merge(v2, &MERGER) : v2
|
23
|
+
end
|
24
|
+
|
25
|
+
def deep_merge!(data)
|
26
|
+
merge!(data, &MERGER)
|
27
|
+
end unless Hash.method_defined?(:deep_merge!)
|
28
|
+
end
|
29
|
+
|