i18n 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +125 -0
- data/lib/i18n.rb +398 -0
- data/lib/i18n/backend.rb +21 -0
- data/lib/i18n/backend/base.rb +284 -0
- data/lib/i18n/backend/cache.rb +113 -0
- data/lib/i18n/backend/cache_file.rb +36 -0
- data/lib/i18n/backend/cascade.rb +56 -0
- data/lib/i18n/backend/chain.rb +127 -0
- data/lib/i18n/backend/fallbacks.rb +84 -0
- data/lib/i18n/backend/flatten.rb +115 -0
- data/lib/i18n/backend/gettext.rb +85 -0
- data/lib/i18n/backend/interpolation_compiler.rb +123 -0
- data/lib/i18n/backend/key_value.rb +206 -0
- data/lib/i18n/backend/memoize.rb +54 -0
- data/lib/i18n/backend/metadata.rb +71 -0
- data/lib/i18n/backend/pluralization.rb +55 -0
- data/lib/i18n/backend/simple.rb +111 -0
- data/lib/i18n/backend/transliterator.rb +108 -0
- data/lib/i18n/config.rb +165 -0
- data/lib/i18n/core_ext/hash.rb +47 -0
- data/lib/i18n/exceptions.rb +111 -0
- data/lib/i18n/gettext.rb +28 -0
- data/lib/i18n/gettext/helpers.rb +75 -0
- data/lib/i18n/gettext/po_parser.rb +329 -0
- data/lib/i18n/interpolate/ruby.rb +39 -0
- data/lib/i18n/locale.rb +8 -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/middleware.rb +17 -0
- data/lib/i18n/tests.rb +14 -0
- data/lib/i18n/tests/basics.rb +60 -0
- data/lib/i18n/tests/defaults.rb +52 -0
- data/lib/i18n/tests/interpolation.rb +159 -0
- data/lib/i18n/tests/link.rb +56 -0
- data/lib/i18n/tests/localization.rb +19 -0
- data/lib/i18n/tests/localization/date.rb +117 -0
- data/lib/i18n/tests/localization/date_time.rb +103 -0
- data/lib/i18n/tests/localization/procs.rb +116 -0
- data/lib/i18n/tests/localization/time.rb +103 -0
- data/lib/i18n/tests/lookup.rb +81 -0
- data/lib/i18n/tests/pluralization.rb +35 -0
- data/lib/i18n/tests/procs.rb +55 -0
- data/lib/i18n/version.rb +5 -0
- metadata +124 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# I18n Pluralization are useful when you want your application to
|
4
|
+
# customize pluralization rules.
|
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, key) 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,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'i18n/backend/base'
|
4
|
+
|
5
|
+
module I18n
|
6
|
+
module Backend
|
7
|
+
# A simple backend that reads translations from YAML files and stores them in
|
8
|
+
# an in-memory hash. Relies on the Base backend.
|
9
|
+
#
|
10
|
+
# The implementation is provided by a Implementation module allowing to easily
|
11
|
+
# extend Simple backend's behavior by including modules. E.g.:
|
12
|
+
#
|
13
|
+
# module I18n::Backend::Pluralization
|
14
|
+
# def pluralize(*args)
|
15
|
+
# # extended pluralization logic
|
16
|
+
# super
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# I18n::Backend::Simple.include(I18n::Backend::Pluralization)
|
21
|
+
class Simple
|
22
|
+
using I18n::HashRefinements
|
23
|
+
|
24
|
+
(class << self; self; end).class_eval { public :include }
|
25
|
+
|
26
|
+
module Implementation
|
27
|
+
include Base
|
28
|
+
|
29
|
+
def initialized?
|
30
|
+
@initialized ||= false
|
31
|
+
end
|
32
|
+
|
33
|
+
# Stores translations for the given locale in memory.
|
34
|
+
# This uses a deep merge for the translations hash, so existing
|
35
|
+
# translations will be overwritten by new ones only at the deepest
|
36
|
+
# level of the hash.
|
37
|
+
def store_translations(locale, data, options = EMPTY_HASH)
|
38
|
+
if I18n.enforce_available_locales &&
|
39
|
+
I18n.available_locales_initialized? &&
|
40
|
+
!I18n.available_locales.include?(locale.to_sym) &&
|
41
|
+
!I18n.available_locales.include?(locale.to_s)
|
42
|
+
return data
|
43
|
+
end
|
44
|
+
locale = locale.to_sym
|
45
|
+
translations[locale] ||= {}
|
46
|
+
data = data.deep_symbolize_keys
|
47
|
+
translations[locale].deep_merge!(data)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get available locales from the translations hash
|
51
|
+
def available_locales
|
52
|
+
init_translations unless initialized?
|
53
|
+
translations.inject([]) do |locales, (locale, data)|
|
54
|
+
locales << locale unless data.size <= 1 && (data.empty? || data.has_key?(:i18n))
|
55
|
+
locales
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Clean up translations hash and set initialized to false on reload!
|
60
|
+
def reload!
|
61
|
+
@initialized = false
|
62
|
+
@translations = nil
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
66
|
+
def eager_load!
|
67
|
+
init_translations unless initialized?
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
def translations(do_init: false)
|
72
|
+
# To avoid returning empty translations,
|
73
|
+
# call `init_translations`
|
74
|
+
init_translations if do_init && !initialized?
|
75
|
+
|
76
|
+
@translations ||= {}
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
def init_translations
|
82
|
+
load_translations
|
83
|
+
@initialized = true
|
84
|
+
end
|
85
|
+
|
86
|
+
# Looks up a translation from the translations hash. Returns nil if
|
87
|
+
# either key is nil, or locale, scope or key do not exist as a key in the
|
88
|
+
# nested translations hash. Splits keys or scopes containing dots
|
89
|
+
# into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
|
90
|
+
# <tt>%w(currency format)</tt>.
|
91
|
+
def lookup(locale, key, scope = [], options = EMPTY_HASH)
|
92
|
+
init_translations unless initialized?
|
93
|
+
keys = I18n.normalize_keys(locale, key, scope, options[:separator])
|
94
|
+
|
95
|
+
keys.inject(translations) do |result, _key|
|
96
|
+
return nil unless result.is_a?(Hash)
|
97
|
+
unless result.has_key?(_key)
|
98
|
+
_key = _key.to_s.to_sym
|
99
|
+
return nil unless result.has_key?(_key)
|
100
|
+
end
|
101
|
+
result = result[_key]
|
102
|
+
result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol)
|
103
|
+
result
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
include Implementation
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module I18n
|
5
|
+
module Backend
|
6
|
+
module Transliterator
|
7
|
+
DEFAULT_REPLACEMENT_CHAR = "?"
|
8
|
+
|
9
|
+
# Given a locale and a UTF-8 string, return the locale's ASCII
|
10
|
+
# approximation for the string.
|
11
|
+
def transliterate(locale, string, replacement = nil)
|
12
|
+
@transliterators ||= {}
|
13
|
+
@transliterators[locale] ||= Transliterator.get I18n.t(:'i18n.transliterate.rule',
|
14
|
+
:locale => locale, :resolve => false, :default => {})
|
15
|
+
@transliterators[locale].transliterate(string, replacement)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get a transliterator instance.
|
19
|
+
def self.get(rule = nil)
|
20
|
+
if !rule || rule.kind_of?(Hash)
|
21
|
+
HashTransliterator.new(rule)
|
22
|
+
elsif rule.kind_of? Proc
|
23
|
+
ProcTransliterator.new(rule)
|
24
|
+
else
|
25
|
+
raise I18n::ArgumentError, "Transliteration rule must be a proc or a hash."
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# A transliterator which accepts a Proc as its transliteration rule.
|
30
|
+
class ProcTransliterator
|
31
|
+
def initialize(rule)
|
32
|
+
@rule = rule
|
33
|
+
end
|
34
|
+
|
35
|
+
def transliterate(string, replacement = nil)
|
36
|
+
@rule.call(string)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# A transliterator which accepts a Hash of characters as its translation
|
41
|
+
# rule.
|
42
|
+
class HashTransliterator
|
43
|
+
DEFAULT_APPROXIMATIONS = {
|
44
|
+
"À"=>"A", "Á"=>"A", "Â"=>"A", "Ã"=>"A", "Ä"=>"A", "Å"=>"A", "Æ"=>"AE",
|
45
|
+
"Ç"=>"C", "È"=>"E", "É"=>"E", "Ê"=>"E", "Ë"=>"E", "Ì"=>"I", "Í"=>"I",
|
46
|
+
"Î"=>"I", "Ï"=>"I", "Ð"=>"D", "Ñ"=>"N", "Ò"=>"O", "Ó"=>"O", "Ô"=>"O",
|
47
|
+
"Õ"=>"O", "Ö"=>"O", "×"=>"x", "Ø"=>"O", "Ù"=>"U", "Ú"=>"U", "Û"=>"U",
|
48
|
+
"Ü"=>"U", "Ý"=>"Y", "Þ"=>"Th", "ß"=>"ss", "à"=>"a", "á"=>"a", "â"=>"a",
|
49
|
+
"ã"=>"a", "ä"=>"a", "å"=>"a", "æ"=>"ae", "ç"=>"c", "è"=>"e", "é"=>"e",
|
50
|
+
"ê"=>"e", "ë"=>"e", "ì"=>"i", "í"=>"i", "î"=>"i", "ï"=>"i", "ð"=>"d",
|
51
|
+
"ñ"=>"n", "ò"=>"o", "ó"=>"o", "ô"=>"o", "õ"=>"o", "ö"=>"o", "ø"=>"o",
|
52
|
+
"ù"=>"u", "ú"=>"u", "û"=>"u", "ü"=>"u", "ý"=>"y", "þ"=>"th", "ÿ"=>"y",
|
53
|
+
"Ā"=>"A", "ā"=>"a", "Ă"=>"A", "ă"=>"a", "Ą"=>"A", "ą"=>"a", "Ć"=>"C",
|
54
|
+
"ć"=>"c", "Ĉ"=>"C", "ĉ"=>"c", "Ċ"=>"C", "ċ"=>"c", "Č"=>"C", "č"=>"c",
|
55
|
+
"Ď"=>"D", "ď"=>"d", "Đ"=>"D", "đ"=>"d", "Ē"=>"E", "ē"=>"e", "Ĕ"=>"E",
|
56
|
+
"ĕ"=>"e", "Ė"=>"E", "ė"=>"e", "Ę"=>"E", "ę"=>"e", "Ě"=>"E", "ě"=>"e",
|
57
|
+
"Ĝ"=>"G", "ĝ"=>"g", "Ğ"=>"G", "ğ"=>"g", "Ġ"=>"G", "ġ"=>"g", "Ģ"=>"G",
|
58
|
+
"ģ"=>"g", "Ĥ"=>"H", "ĥ"=>"h", "Ħ"=>"H", "ħ"=>"h", "Ĩ"=>"I", "ĩ"=>"i",
|
59
|
+
"Ī"=>"I", "ī"=>"i", "Ĭ"=>"I", "ĭ"=>"i", "Į"=>"I", "į"=>"i", "İ"=>"I",
|
60
|
+
"ı"=>"i", "IJ"=>"IJ", "ij"=>"ij", "Ĵ"=>"J", "ĵ"=>"j", "Ķ"=>"K", "ķ"=>"k",
|
61
|
+
"ĸ"=>"k", "Ĺ"=>"L", "ĺ"=>"l", "Ļ"=>"L", "ļ"=>"l", "Ľ"=>"L", "ľ"=>"l",
|
62
|
+
"Ŀ"=>"L", "ŀ"=>"l", "Ł"=>"L", "ł"=>"l", "Ń"=>"N", "ń"=>"n", "Ņ"=>"N",
|
63
|
+
"ņ"=>"n", "Ň"=>"N", "ň"=>"n", "ʼn"=>"'n", "Ŋ"=>"NG", "ŋ"=>"ng",
|
64
|
+
"Ō"=>"O", "ō"=>"o", "Ŏ"=>"O", "ŏ"=>"o", "Ő"=>"O", "ő"=>"o", "Œ"=>"OE",
|
65
|
+
"œ"=>"oe", "Ŕ"=>"R", "ŕ"=>"r", "Ŗ"=>"R", "ŗ"=>"r", "Ř"=>"R", "ř"=>"r",
|
66
|
+
"Ś"=>"S", "ś"=>"s", "Ŝ"=>"S", "ŝ"=>"s", "Ş"=>"S", "ş"=>"s", "Š"=>"S",
|
67
|
+
"š"=>"s", "Ţ"=>"T", "ţ"=>"t", "Ť"=>"T", "ť"=>"t", "Ŧ"=>"T", "ŧ"=>"t",
|
68
|
+
"Ũ"=>"U", "ũ"=>"u", "Ū"=>"U", "ū"=>"u", "Ŭ"=>"U", "ŭ"=>"u", "Ů"=>"U",
|
69
|
+
"ů"=>"u", "Ű"=>"U", "ű"=>"u", "Ų"=>"U", "ų"=>"u", "Ŵ"=>"W", "ŵ"=>"w",
|
70
|
+
"Ŷ"=>"Y", "ŷ"=>"y", "Ÿ"=>"Y", "Ź"=>"Z", "ź"=>"z", "Ż"=>"Z", "ż"=>"z",
|
71
|
+
"Ž"=>"Z", "ž"=>"z"
|
72
|
+
}.freeze
|
73
|
+
|
74
|
+
def initialize(rule = nil)
|
75
|
+
@rule = rule
|
76
|
+
add_default_approximations
|
77
|
+
add rule if rule
|
78
|
+
end
|
79
|
+
|
80
|
+
def transliterate(string, replacement = nil)
|
81
|
+
replacement ||= DEFAULT_REPLACEMENT_CHAR
|
82
|
+
string.gsub(/[^\x00-\x7f]/u) do |char|
|
83
|
+
approximations[char] || replacement
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def approximations
|
90
|
+
@approximations ||= {}
|
91
|
+
end
|
92
|
+
|
93
|
+
def add_default_approximations
|
94
|
+
DEFAULT_APPROXIMATIONS.each do |key, value|
|
95
|
+
approximations[key] = value
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Add transliteration rules to the approximations hash.
|
100
|
+
def add(hash)
|
101
|
+
hash.each do |key, value|
|
102
|
+
approximations[key.to_s] = value.to_s
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/i18n/config.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module I18n
|
6
|
+
class Config
|
7
|
+
# The only configuration value that is not global and scoped to thread is :locale.
|
8
|
+
# It defaults to the default_locale.
|
9
|
+
def locale
|
10
|
+
defined?(@locale) && @locale != nil ? @locale : default_locale
|
11
|
+
end
|
12
|
+
|
13
|
+
# Sets the current locale pseudo-globally, i.e. in the Thread.current hash.
|
14
|
+
def locale=(locale)
|
15
|
+
I18n.enforce_available_locales!(locale)
|
16
|
+
@locale = locale && locale.to_sym
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns the current backend. Defaults to +Backend::Simple+.
|
20
|
+
def backend
|
21
|
+
@@backend ||= Backend::Simple.new
|
22
|
+
end
|
23
|
+
|
24
|
+
# Sets the current backend. Used to set a custom backend.
|
25
|
+
def backend=(backend)
|
26
|
+
@@backend = backend
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the current default locale. Defaults to :'en'
|
30
|
+
def default_locale
|
31
|
+
@@default_locale ||= :en
|
32
|
+
end
|
33
|
+
|
34
|
+
# Sets the current default locale. Used to set a custom default locale.
|
35
|
+
def default_locale=(locale)
|
36
|
+
I18n.enforce_available_locales!(locale)
|
37
|
+
@@default_locale = locale && locale.to_sym
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns an array of locales for which translations are available.
|
41
|
+
# Unless you explicitely set these through I18n.available_locales=
|
42
|
+
# the call will be delegated to the backend.
|
43
|
+
def available_locales
|
44
|
+
@@available_locales ||= nil
|
45
|
+
@@available_locales || backend.available_locales
|
46
|
+
end
|
47
|
+
|
48
|
+
# Caches the available locales list as both strings and symbols in a Set, so
|
49
|
+
# that we can have faster lookups to do the available locales enforce check.
|
50
|
+
def available_locales_set #:nodoc:
|
51
|
+
@@available_locales_set ||= available_locales.inject(Set.new) do |set, locale|
|
52
|
+
set << locale.to_s << locale.to_sym
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Sets the available locales.
|
57
|
+
def available_locales=(locales)
|
58
|
+
@@available_locales = Array(locales).map { |locale| locale.to_sym }
|
59
|
+
@@available_locales = nil if @@available_locales.empty?
|
60
|
+
@@available_locales_set = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns true if the available_locales have been initialized
|
64
|
+
def available_locales_initialized?
|
65
|
+
( !!defined?(@@available_locales) && !!@@available_locales )
|
66
|
+
end
|
67
|
+
|
68
|
+
# Clears the available locales set so it can be recomputed again after I18n
|
69
|
+
# gets reloaded.
|
70
|
+
def clear_available_locales_set #:nodoc:
|
71
|
+
@@available_locales_set = nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the current default scope separator. Defaults to '.'
|
75
|
+
def default_separator
|
76
|
+
@@default_separator ||= '.'
|
77
|
+
end
|
78
|
+
|
79
|
+
# Sets the current default scope separator.
|
80
|
+
def default_separator=(separator)
|
81
|
+
@@default_separator = separator
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns the current exception handler. Defaults to an instance of
|
85
|
+
# I18n::ExceptionHandler.
|
86
|
+
def exception_handler
|
87
|
+
@@exception_handler ||= ExceptionHandler.new
|
88
|
+
end
|
89
|
+
|
90
|
+
# Sets the exception handler.
|
91
|
+
def exception_handler=(exception_handler)
|
92
|
+
@@exception_handler = exception_handler
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the current handler for situations when interpolation argument
|
96
|
+
# is missing. MissingInterpolationArgument will be raised by default.
|
97
|
+
def missing_interpolation_argument_handler
|
98
|
+
@@missing_interpolation_argument_handler ||= lambda do |missing_key, provided_hash, string|
|
99
|
+
raise MissingInterpolationArgument.new(missing_key, provided_hash, string)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Sets the missing interpolation argument handler. It can be any
|
104
|
+
# object that responds to #call. The arguments that will be passed to #call
|
105
|
+
# are the same as for MissingInterpolationArgument initializer. Use +Proc.new+
|
106
|
+
# if you don't care about arity.
|
107
|
+
#
|
108
|
+
# == Example:
|
109
|
+
# You can supress raising an exception and return string instead:
|
110
|
+
#
|
111
|
+
# I18n.config.missing_interpolation_argument_handler = Proc.new do |key|
|
112
|
+
# "#{key} is missing"
|
113
|
+
# end
|
114
|
+
def missing_interpolation_argument_handler=(exception_handler)
|
115
|
+
@@missing_interpolation_argument_handler = exception_handler
|
116
|
+
end
|
117
|
+
|
118
|
+
# Allow clients to register paths providing translation data sources. The
|
119
|
+
# backend defines acceptable sources.
|
120
|
+
#
|
121
|
+
# E.g. the provided SimpleBackend accepts a list of paths to translation
|
122
|
+
# files which are either named *.rb and contain plain Ruby Hashes or are
|
123
|
+
# named *.yml and contain YAML data. So for the SimpleBackend clients may
|
124
|
+
# register translation files like this:
|
125
|
+
# I18n.load_path << 'path/to/locale/en.yml'
|
126
|
+
def load_path
|
127
|
+
@@load_path ||= []
|
128
|
+
end
|
129
|
+
|
130
|
+
# Sets the load path instance. Custom implementations are expected to
|
131
|
+
# behave like a Ruby Array.
|
132
|
+
def load_path=(load_path)
|
133
|
+
@@load_path = load_path
|
134
|
+
@@available_locales_set = nil
|
135
|
+
backend.reload!
|
136
|
+
end
|
137
|
+
|
138
|
+
# Whether or not to verify if locales are in the list of available locales.
|
139
|
+
# Defaults to true.
|
140
|
+
@@enforce_available_locales = true
|
141
|
+
def enforce_available_locales
|
142
|
+
@@enforce_available_locales
|
143
|
+
end
|
144
|
+
|
145
|
+
def enforce_available_locales=(enforce_available_locales)
|
146
|
+
@@enforce_available_locales = enforce_available_locales
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns the current interpolation patterns. Defaults to
|
150
|
+
# I18n::DEFAULT_INTERPOLATION_PATTERNS.
|
151
|
+
def interpolation_patterns
|
152
|
+
@@interpolation_patterns ||= I18n::DEFAULT_INTERPOLATION_PATTERNS.dup
|
153
|
+
end
|
154
|
+
|
155
|
+
# Sets the current interpolation patterns. Used to set a interpolation
|
156
|
+
# patterns.
|
157
|
+
#
|
158
|
+
# E.g. using {{}} as a placeholder like "{{hello}}, world!":
|
159
|
+
#
|
160
|
+
# I18n.config.interpolation_patterns << /\{\{(\w+)\}\}/
|
161
|
+
def interpolation_patterns=(interpolation_patterns)
|
162
|
+
@@interpolation_patterns = interpolation_patterns
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module I18n
|
2
|
+
module HashRefinements
|
3
|
+
refine Hash do
|
4
|
+
using I18n::HashRefinements
|
5
|
+
def except(*keys)
|
6
|
+
dup.except!(*keys)
|
7
|
+
end
|
8
|
+
|
9
|
+
def except!(*keys)
|
10
|
+
keys.each { |key| delete(key) }
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def deep_symbolize_keys
|
15
|
+
each_with_object({}) do |(key, value), result|
|
16
|
+
result[symbolize_key(key)] = deep_symbolize_keys_in_object(value)
|
17
|
+
result
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# deep_merge_hash! by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
|
22
|
+
def deep_merge!(data)
|
23
|
+
merger = lambda do |_key, v1, v2|
|
24
|
+
Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2
|
25
|
+
end
|
26
|
+
merge!(data, &merger)
|
27
|
+
end
|
28
|
+
|
29
|
+
def symbolize_key(key)
|
30
|
+
key.respond_to?(:to_sym) ? key.to_sym : key
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def deep_symbolize_keys_in_object(value)
|
36
|
+
case value
|
37
|
+
when Hash
|
38
|
+
value.deep_symbolize_keys
|
39
|
+
when Array
|
40
|
+
value.map { |e| deep_symbolize_keys_in_object(e) }
|
41
|
+
else
|
42
|
+
value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|