babelfish-ruby 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +137 -0
- data/Rakefile +25 -0
- data/babelfish.gemspec +27 -0
- data/lib/babelfish-ruby.rb +2 -0
- data/lib/babelfish.rb +289 -0
- data/lib/babelfish/phrase/compiler.rb +70 -0
- data/lib/babelfish/phrase/literal.rb +12 -0
- data/lib/babelfish/phrase/node.rb +14 -0
- data/lib/babelfish/phrase/parser.rb +173 -0
- data/lib/babelfish/phrase/parser_base.rb +73 -0
- data/lib/babelfish/phrase/plural_forms.rb +65 -0
- data/lib/babelfish/phrase/plural_forms_parser.rb +64 -0
- data/lib/babelfish/phrase/pluralizer.rb +409 -0
- data/lib/babelfish/phrase/string_to_compile.rb +8 -0
- data/lib/babelfish/phrase/variable.rb +12 -0
- data/lib/babelfish/version.rb +4 -0
- data/spec/lib/babelfish_spec.rb +105 -0
- data/spec/locales/test.en-US.yml +7 -0
- data/spec/locales/test.ru-RU.yml +9 -0
- data/spec/spec_helper.rb +21 -0
- metadata +147 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1ed8121d4c95af80ac52863c5a56764ae14d401b
|
4
|
+
data.tar.gz: 1c2f02c33e27f7ef0cd9149b7887f208098316d8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 307e241634ea1b3b76183e8ff5a15bdc80397ddcb127e723a1bea2070d233d21f186eeec7e1ca4dfc62ce128804f7fe4e55cded255f83011a704bb1bb14036ec
|
7
|
+
data.tar.gz: 5a3eb4545f188926ce0495ba435b7872321d9c05f1eb83cded96d01d956867ae4a9d5d12a0ad556ddf801e6932861fa45265b78f814d498adb1d65306b5616c1
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (C) 2014 by Akzhan Abdulin
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
BabelFish - human friendly i18n for Ruby
|
2
|
+
========================================
|
3
|
+
|
4
|
+
Internationalisation with easy syntax for Ruby, Perl, node.js and browser. Classic solutions
|
5
|
+
use multiple phrases for plurals. But we define plurals inline - that's more
|
6
|
+
compact, and easy for programmers. Also, phrases are grouped into nested scopes,
|
7
|
+
like in Ruby.
|
8
|
+
|
9
|
+
We support all pluralisation rules from [unicode CLDR](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html),
|
10
|
+
version [2.0.1](http://cldr.unicode.org/index/downloads).
|
11
|
+
|
12
|
+
### Installation
|
13
|
+
|
14
|
+
```bash
|
15
|
+
gem ins babelfish
|
16
|
+
|
17
|
+
# or simply bundle it into your Gemfile
|
18
|
+
```
|
19
|
+
|
20
|
+
### Phrases Syntax
|
21
|
+
|
22
|
+
- `#{varname}` Echoes value of variable
|
23
|
+
- `((Singular|Plural1|Plural2)):count` Plural form
|
24
|
+
|
25
|
+
example:
|
26
|
+
|
27
|
+
- `А у меня в кармане #{nails_count} ((гвоздь|гвоздя|гвоздей)):nails_count`
|
28
|
+
|
29
|
+
You can also omit anchor variable for plurals, by default it will be `count`.
|
30
|
+
Thus following variants are equal:
|
31
|
+
|
32
|
+
- `I have #{count} ((nail|nails))`
|
33
|
+
- `I have #{count} ((nail|nails)):count`
|
34
|
+
|
35
|
+
Also you can use variables in plural parts:
|
36
|
+
|
37
|
+
- `I have ((#{count} nail|#{count} nails))`
|
38
|
+
|
39
|
+
Need special zero form or overwrite any specific value? No problems:
|
40
|
+
|
41
|
+
- `I have ((=0 no nails|#{count} nail|#{count} nails))`
|
42
|
+
|
43
|
+
|
44
|
+
##### Escape chars
|
45
|
+
|
46
|
+
If you need `#{`, `((`, `|` or `))` somewhere in text, where it can be considered
|
47
|
+
as markup part - just escape them with `\`.
|
48
|
+
|
49
|
+
|
50
|
+
##### Example with YAML
|
51
|
+
|
52
|
+
As BabelFish flatten scopes, it's really fun and nice to store translations in
|
53
|
+
YAML files:
|
54
|
+
|
55
|
+
```yaml
|
56
|
+
---
|
57
|
+
ru-RU:
|
58
|
+
profile: Профиль
|
59
|
+
forums: Форумы
|
60
|
+
apps:
|
61
|
+
forums:
|
62
|
+
new_topic: Новая тема
|
63
|
+
last_post:
|
64
|
+
title : Последнее сообщение
|
65
|
+
by : от
|
66
|
+
demo:
|
67
|
+
apples: На столе лежит #{count} ((яблоко|яблока|яблок))
|
68
|
+
```
|
69
|
+
|
70
|
+
### Usage
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
# Create new instance of Babelfish with default language/locale: 'en-GB'
|
74
|
+
require 'babelfish'
|
75
|
+
i18n = new Babelfish('en-GB');
|
76
|
+
|
77
|
+
|
78
|
+
# Fill in some phrases
|
79
|
+
i18n.addPhrase('en-GB', 'demo.hello', 'Hello, #{user.name}.');
|
80
|
+
i18n.addPhrase('en-GB', 'demo.conv.wazup', 'Whats up?');
|
81
|
+
i18n.addPhrase('en-GB', 'demo.conv.alright', 'Alright, man!');
|
82
|
+
i18n.addPhrase('en-GB', 'demo.coerce', 'Total: #{count}.');
|
83
|
+
|
84
|
+
i18n.addPhrase('ru-RU', 'demo.hello', 'Привет, #{user.name}.');
|
85
|
+
i18n.addPhrase('ru-RU', 'demo.conv.wazup', 'Как дела?');
|
86
|
+
|
87
|
+
i18n.addPhrase('uk-UA', 'demo.hello', 'Здоровенькі були, #{user.name}.');
|
88
|
+
|
89
|
+
|
90
|
+
# Set locale fallback to use the most appropriate translation when possible
|
91
|
+
i18n.setFallback('uk-UA', 'ru-RU');
|
92
|
+
|
93
|
+
|
94
|
+
# Translate
|
95
|
+
var params = {user: {name: 'ixti'}};
|
96
|
+
|
97
|
+
i18n.t('ru-RU', 'demo.hello', params); // -> 'Привет, ixti.'
|
98
|
+
i18n.t('ru-RU', 'demo.conv.wazup'); // -> 'Как дела?'
|
99
|
+
i18n.t('ru-RU', 'demo.conv.alright'); // -> 'Alright, man!'
|
100
|
+
|
101
|
+
i18n.t('uk-UA', 'demo.hello', params); // -> 'Здоровенькі були, ixti.'
|
102
|
+
i18n.t('uk-UA', 'demo.conv.wazup'); // -> 'Как дела?'
|
103
|
+
i18n.t('uk-UA', 'demo.conv.alright'); // -> 'Alright, man!'
|
104
|
+
|
105
|
+
# When params is number or strings, it will be coerced to
|
106
|
+
# `{ count: XXX, value: XXX }` - use any of those in phrase.
|
107
|
+
i18n.t('en-GB', 'demo.coerce', 5); // -> 'Total: 5.'
|
108
|
+
|
109
|
+
|
110
|
+
# You may wish to "dump" translations to load in browser later
|
111
|
+
# Dump will include all fallback translations and fallback rules
|
112
|
+
var locale_dump = i18n.stringify('ru-RU');
|
113
|
+
|
114
|
+
var i18n_new = require('babelfish')('en-GB'); // init without `new` also works
|
115
|
+
i18n_new.load(locale_dump);
|
116
|
+
|
117
|
+
|
118
|
+
# Use objects instead of strings (object/array/number/boolean) - can be
|
119
|
+
# useful to prepare bulk data for external libraries.
|
120
|
+
# Note, only JSON-supported types are ok (no date & regex)
|
121
|
+
i18n.addPhrase('en-GB', 'demo.boolean', true);
|
122
|
+
i18n.addPhrase('en-GB', 'demo.number', 123);
|
123
|
+
i18n.addPhrase('en-GB', 'demo.array', [1, 2, 3]);
|
124
|
+
# fourth param required for hashes (objects) to disable flattening,
|
125
|
+
# other types are autodetected
|
126
|
+
i18n.addPhrase('en-GB', 'demo.array', { foo:1, bar:"2" }, false);
|
127
|
+
```
|
128
|
+
|
129
|
+
|
130
|
+
### Implementations in other languages
|
131
|
+
|
132
|
+
- Perl - [Locale::Babelfish](https://metacpan.org/pod/Locale::Babelfish)
|
133
|
+
|
134
|
+
|
135
|
+
### License
|
136
|
+
|
137
|
+
View the [LICENSE](https://github.com/regru/babelfish-ruby/blob/master/LICENSE) file (MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
APP_ROOT = File.dirname(__FILE__).freeze
|
4
|
+
|
5
|
+
require 'bundler/setup'
|
6
|
+
Bundler::GemHelper.install_tasks
|
7
|
+
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
|
10
|
+
RSpec::Core::RakeTask.new
|
11
|
+
|
12
|
+
RSpec::Core::RakeTask.new(:rcov) do |t|
|
13
|
+
t.rcov = true
|
14
|
+
t.ruby_opts = '-w'
|
15
|
+
t.rcov_opts = %q[-Ilib --exclude "spec/*,gems/*"]
|
16
|
+
end
|
17
|
+
|
18
|
+
task :default => :spec
|
19
|
+
|
20
|
+
require 'yard'
|
21
|
+
|
22
|
+
YARD::Rake::YardocTask.new do |yard|
|
23
|
+
version = File.exists?('VERSION') ? IO.read('VERSION') : ""
|
24
|
+
yard.options << "--title='git-commit-notifier #{version}'"
|
25
|
+
end
|
data/babelfish.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
GEM_ROOT = File.dirname(__FILE__).freeze unless defined?(GEM_ROOT)
|
2
|
+
|
3
|
+
lib_path = File.expand_path('lib', GEM_ROOT)
|
4
|
+
$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include? lib_path
|
5
|
+
|
6
|
+
require 'babelfish/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |s|
|
9
|
+
s.name = "babelfish-ruby"
|
10
|
+
s.version = Babelfish::VERSION.dup
|
11
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
12
|
+
s.summary = "Babelfish syntax internationalization module."
|
13
|
+
s.email = "akzhan.abdulin@gmail.com"
|
14
|
+
s.homepage = "http://regru.github.io/babelfish-ruby/"
|
15
|
+
s.description = "Human friendly i18n in both JavaScript, Ruby, Perl whatever."
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.author = "Akzhan Abdulin"
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
21
|
+
s.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
s.add_development_dependency('rake', ['~> 0.8', '!= 0.9.0'])
|
23
|
+
s.add_development_dependency('yard', '~> 0.8.7')
|
24
|
+
s.add_development_dependency('redcarpet', '~> 3.0')
|
25
|
+
s.add_development_dependency(%q<rspec>, [">= 3.0"])
|
26
|
+
end
|
27
|
+
|
data/lib/babelfish.rb
ADDED
@@ -0,0 +1,289 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'find'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
require 'babelfish/phrase/string_to_compile'
|
6
|
+
require 'babelfish/phrase/parser'
|
7
|
+
require 'babelfish/phrase/compiler'
|
8
|
+
|
9
|
+
class Babelfish
|
10
|
+
attr_accessor :dictionaries, :dirs, :suffix, :default_locale
|
11
|
+
attr_accessor :fallbacks, :fallback_cache
|
12
|
+
attr_accessor :file_filter, :watch, :watchers
|
13
|
+
attr_accessor :compiler, :parser
|
14
|
+
attr_accessor :_cfg
|
15
|
+
|
16
|
+
def _built_config(cfg)
|
17
|
+
{
|
18
|
+
dictionaries: {},
|
19
|
+
dirs: [ "./locales" ],
|
20
|
+
fallbacks: {},
|
21
|
+
fallback_cache: {},
|
22
|
+
suffix: cfg[:suffix] || 'yml',
|
23
|
+
default_locale: cfg[:default_locale] || 'en_US',
|
24
|
+
watch: cfg[:watch] || 0,
|
25
|
+
watchers: {},
|
26
|
+
}.merge( cfg || {} )
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(cfg = {})
|
30
|
+
cfg = {
|
31
|
+
_cfg: cfg,
|
32
|
+
}.merge( _built_config(cfg) )
|
33
|
+
|
34
|
+
cfg.keys.each do |key|
|
35
|
+
send("#{key}=", cfg[key]) if respond_to?("#{key}=")
|
36
|
+
end
|
37
|
+
|
38
|
+
self.parser = Babelfish::Phrase::Parser.new
|
39
|
+
self.compiler = Babelfish::Phrase::Compiler.new
|
40
|
+
|
41
|
+
load_dictionaries( file_filter )
|
42
|
+
self.locale = default_locale
|
43
|
+
end
|
44
|
+
|
45
|
+
def locale
|
46
|
+
@locale
|
47
|
+
end
|
48
|
+
|
49
|
+
def locale=(new_locale)
|
50
|
+
@locale = detect_locale( new_locale )
|
51
|
+
end
|
52
|
+
|
53
|
+
def watch?
|
54
|
+
!! watch
|
55
|
+
end
|
56
|
+
|
57
|
+
def prepare_to_compile
|
58
|
+
dictionaries.each_pair do |locale, dic|
|
59
|
+
dic.each_pair do |key, value|
|
60
|
+
if phrase_need_compilation( value, key )
|
61
|
+
dic[key] = Babelfish::Phrase::StringToCompile.new(value) # lazy compile
|
62
|
+
#dic[key] = compiler.compile( parser.parse(value, locale) );
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def detect_locale(locale)
|
71
|
+
return locale if dictionaries.has_key?(locale)
|
72
|
+
alt_locale = dictionaries.keys.find { |loc| loc =~ /^#{Regexp.escape(locale)}[\-_]/i }
|
73
|
+
if alt_locale && dictionaries.has_key?(alt_locale)
|
74
|
+
# Lets locale dictionary will refer to alt locale dictinary.
|
75
|
+
# This speeds up all subsequent calls of t/detect/exists on this locale.
|
76
|
+
dictionaries[locale] = dictionaries[alt_locale]
|
77
|
+
|
78
|
+
fallback_cache[locale] = fallback_cache[alt_locale] if fallback_cache.has_key?(alt_locale)
|
79
|
+
|
80
|
+
fallbacks[locale] = fallbacks[alt_locale] if fallbacks.has_key?(alt_locale)
|
81
|
+
|
82
|
+
return locale
|
83
|
+
end
|
84
|
+
return default_locale if dictionaries.has_key?(default_locale)
|
85
|
+
raise "bad locale: #{locale} and bad default_locale: #{default_locale}."
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def load_dictionaries(filter)
|
90
|
+
dirs.each do |dir|
|
91
|
+
fdir = File.absolute_path( dir )
|
92
|
+
Find.find(dir) do |file|
|
93
|
+
file_path = File.absolute_path(file)
|
94
|
+
next unless FileTest.file? file_path
|
95
|
+
return if filter && !filter( file_path )
|
96
|
+
directories, base = File.split( file_path )
|
97
|
+
tmp = base.split('.')
|
98
|
+
cur_suffix = tmp.pop
|
99
|
+
return if cur_suffix != suffix
|
100
|
+
locale = tmp.pop
|
101
|
+
dictname = tmp.join('.')
|
102
|
+
subdir = directories
|
103
|
+
if subdir =~ /^#{Regexp.escape(fdir)}[\\\/](.+)$/
|
104
|
+
dictname = "#{$1}#{dictname}"
|
105
|
+
end
|
106
|
+
_load_dictionary( dictname, locale, file )
|
107
|
+
end
|
108
|
+
end
|
109
|
+
prepare_to_compile
|
110
|
+
end
|
111
|
+
|
112
|
+
def _load_dictionary( dictname, lang, file )
|
113
|
+
dictionaries[lang] ||= {}
|
114
|
+
|
115
|
+
yaml = YAML.load_file( file )
|
116
|
+
_flat_hash_keys( yaml, "#{dictname}.", dictionaries[lang] )
|
117
|
+
|
118
|
+
return unless watch?
|
119
|
+
watchers[file] = File.mtime(file)
|
120
|
+
end
|
121
|
+
|
122
|
+
def phrase_need_compilation( phrase, key )
|
123
|
+
raise "L10N: #{key} is undef" if phrase.nil?
|
124
|
+
return phrase.kind_of?(String) && phrase =~ /(?:\(\(|\#\{|\\\\)/
|
125
|
+
end
|
126
|
+
|
127
|
+
def on_watcher_change
|
128
|
+
_cfg.keys.each do |key|
|
129
|
+
send("#{key}=", nil) if respond_to?("#{key}=")
|
130
|
+
end
|
131
|
+
|
132
|
+
new_cfg = _built_config( _cfg )
|
133
|
+
new_cfg.keys.each do |key|
|
134
|
+
send("#{key}=", new_cfg[key]) if respond_to?("#{key}=")
|
135
|
+
end
|
136
|
+
load_dictionaries
|
137
|
+
self.locale = default_locale
|
138
|
+
end
|
139
|
+
|
140
|
+
def look_for_watchers
|
141
|
+
ok = true
|
142
|
+
watchers.each_pair do | file, mtime |
|
143
|
+
new_mtime = File.mtime(file)
|
144
|
+
if mtime.nil? || new_mtime.nil? || new_mtime != mtime
|
145
|
+
ok = false
|
146
|
+
break
|
147
|
+
end
|
148
|
+
end
|
149
|
+
return if ok;
|
150
|
+
on_watcher_change
|
151
|
+
end
|
152
|
+
|
153
|
+
def t_or_undef( dictname_key, params = nil, custom_locale = nil )
|
154
|
+
# disallow non-ASCII keys
|
155
|
+
raise("wrong dictname_key: #{dictname_key}") if dictname_key =~ /\P{ASCII}/;
|
156
|
+
|
157
|
+
look_for_watchers if watch?
|
158
|
+
|
159
|
+
_locale = custom_locale ? detect_locale( custom_locale ) : self.locale
|
160
|
+
|
161
|
+
r = dictionaries[_locale][dictname_key]
|
162
|
+
|
163
|
+
unless r.nil?
|
164
|
+
if r.kind_of?(Babelfish::Phrase::StringToCompile)
|
165
|
+
dictionaries[_locale][dictname_key] = r = compiler.compile(
|
166
|
+
parser.parse( r, _locale ),
|
167
|
+
)
|
168
|
+
end
|
169
|
+
# fallbacks
|
170
|
+
else
|
171
|
+
fallback_cache[_locale] ||= {}
|
172
|
+
# Cache can contain undef, as unexistent value.
|
173
|
+
if fallback_cache[_locale].has_key?(dictname_key)
|
174
|
+
r = fallback_cache[_locale][dictname_key]
|
175
|
+
else
|
176
|
+
fallback_locales = fallbacks[_locale] || []
|
177
|
+
fallback_locales.each do |fallback|
|
178
|
+
r = dictionaries[fallback][dictname_key]
|
179
|
+
unless r.nil?
|
180
|
+
if r.kind_of?(Babelfish::Phrase::StringToCompile)
|
181
|
+
dictionaries[fallback][dictname_key] = r = compiler.compile(
|
182
|
+
parser.parse( r, fallback ),
|
183
|
+
)
|
184
|
+
end
|
185
|
+
break
|
186
|
+
end
|
187
|
+
end
|
188
|
+
fallback_cache[_locale][dictname_key] = r;
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
if r.kind_of?(Proc)
|
193
|
+
flat_params = {}
|
194
|
+
# Convert parameters hash to flat form like "key.subkey"
|
195
|
+
unless params.nil?
|
196
|
+
# Scalar interpreted as { count => scalar, value => scalar }.
|
197
|
+
unless params.kind_of?(Hash)
|
198
|
+
flat_params = {
|
199
|
+
'count' => params,
|
200
|
+
'value' => params,
|
201
|
+
}
|
202
|
+
else
|
203
|
+
_flat_hash_keys( params, '', flat_params )
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
return r.call( flat_params );
|
208
|
+
end
|
209
|
+
return r
|
210
|
+
end
|
211
|
+
|
212
|
+
def t( dictname_key, params = nil, custom_locale = nil )
|
213
|
+
t_or_undef( dictname_key, params, custom_locale ) || "[#{dictname_key}]";
|
214
|
+
end
|
215
|
+
|
216
|
+
def has_any_value( dictname_key, custom_locale = nil )
|
217
|
+
|
218
|
+
# disallow non-ASCII keys
|
219
|
+
raise("wrong dictname_key: #{dictname_key}") if dictname_key =~ /\P{ASCII}/;
|
220
|
+
|
221
|
+
look_for_watchers if watch?
|
222
|
+
|
223
|
+
_locale = custom_locale ? detect_locale( custom_locale ) : self.locale
|
224
|
+
|
225
|
+
return true if dictionaries[_locale].has_key?(dictname_key)
|
226
|
+
|
227
|
+
fallback_cache[_locale] ||= {}
|
228
|
+
return ! fallback_cache[_locale][dictname_key].nil? if fallback_cache[_locale].has_key?(dictname_key)
|
229
|
+
|
230
|
+
fallback_locales = fallbacks[_locale] || []
|
231
|
+
return true if fallback_locales.find do |fallback|
|
232
|
+
! dictionaries[fallback][dictname_key].nil?
|
233
|
+
end
|
234
|
+
|
235
|
+
return false
|
236
|
+
end
|
237
|
+
|
238
|
+
def set_fallback( locale, fallback_locales )
|
239
|
+
return unless fallback_locales && fallback_locales.size
|
240
|
+
|
241
|
+
_locale = detect_locale( locale )
|
242
|
+
|
243
|
+
fallbacks[_locale] = fallback_locales
|
244
|
+
fallback_cache.delete(_locale)
|
245
|
+
|
246
|
+
return true
|
247
|
+
end
|
248
|
+
|
249
|
+
def _flat_hash_keys( hash, prefix, store )
|
250
|
+
hash.each_pair do | key, value |
|
251
|
+
if value.kind_of?(Hash)
|
252
|
+
_flat_hash_keys( value, "#{prefix}#{key}.", store )
|
253
|
+
else
|
254
|
+
store["#{prefix}#{key}"] = value.kind_of?(Symbol) ? value.to_s : value
|
255
|
+
end
|
256
|
+
end
|
257
|
+
return true
|
258
|
+
end
|
259
|
+
|
260
|
+
def addPhrase( locale, phrase, translation, flatten_level = Float::INFINITY)
|
261
|
+
fl = Float::INFINITY
|
262
|
+
case flatten_level
|
263
|
+
when FalseClass
|
264
|
+
fl = 0
|
265
|
+
when TrueClass
|
266
|
+
fl = Float::INFINITY
|
267
|
+
when FixNum, Float
|
268
|
+
fl = flatten_level.to_i
|
269
|
+
fl = 0 if fl < 0
|
270
|
+
else
|
271
|
+
fl = Float::INFINITY;
|
272
|
+
end
|
273
|
+
|
274
|
+
if translation.kind_of?(Hash) && fl > 0
|
275
|
+
translation.each_pair do | key, val |
|
276
|
+
addPhrase( locale, "#{phrase}.#{key}", val, fl - 1 )
|
277
|
+
end
|
278
|
+
return
|
279
|
+
end
|
280
|
+
|
281
|
+
if phrase_need_compilation(translation)
|
282
|
+
dictionaries[locale][phrase] = Babelfish::Phrase::StringToCompile.new(translation)
|
283
|
+
else
|
284
|
+
dictionaries[locale][phrase] = translation
|
285
|
+
end
|
286
|
+
|
287
|
+
self.fallback_cache = {}
|
288
|
+
end
|
289
|
+
end
|