i18n 1.6.0
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 +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
|