rubi18n 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +166 -0
- data/README +177 -0
- data/Rakefile +95 -0
- data/base/en.yml +15 -0
- data/base/ru.yml +13 -0
- data/lib/rubi18n/formatters.rb +74 -0
- data/lib/rubi18n/locale.rb +124 -0
- data/lib/rubi18n/translated_string.rb +33 -0
- data/lib/rubi18n/translation.rb +269 -0
- data/lib/rubi18n.rb +29 -0
- data/locales/en.yml +13 -0
- data/locales/en_US.yml +5 -0
- data/locales/ru.yml +13 -0
- data/spec/formatters_spec.rb +19 -0
- data/spec/locale_spec.rb +71 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/translation_spec.rb +106 -0
- data/spec/translations/extention/en.yml +2 -0
- data/spec/translations/extention/no_TR.yml +1 -0
- data/spec/translations/general/en.yml +31 -0
- data/spec/translations/general/fr.yml +1 -0
- data/spec/translations/general/no_LC.yml +4 -0
- data/spec/translations/general/ru.yml +5 -0
- metadata +78 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
=begin
|
2
|
+
Translation string for i18n support.
|
3
|
+
|
4
|
+
Copyright (C) 2008 Andrey "A.I." Sitnik <andrey@sitnik.ru>
|
5
|
+
|
6
|
+
This program is free software: you can redistribute it and/or modify
|
7
|
+
it under the terms of the GNU Lesser General Public License as published by
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
9
|
+
(at your option) any later version.
|
10
|
+
|
11
|
+
This program is distributed in the hope that it will be useful,
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
GNU Lesser General Public License for more details.
|
15
|
+
|
16
|
+
You should have received a copy of the GNU Lesser General Public License
|
17
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
=end
|
19
|
+
|
20
|
+
module Rubi18n
|
21
|
+
# String, which is translated to some locale and loading from Translation.
|
22
|
+
class TranslatedString < String
|
23
|
+
# String locale
|
24
|
+
attr_reader :locale
|
25
|
+
|
26
|
+
# Returns a new string object containing a copy of str and translated to
|
27
|
+
# +locale+
|
28
|
+
def initialize(str, locale)
|
29
|
+
super(str)
|
30
|
+
@locale = locale
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,269 @@
|
|
1
|
+
=begin
|
2
|
+
Translation to i18n support.
|
3
|
+
|
4
|
+
Copyright (C) 2008 Andrey “A.I.” Sitnik <andrey@sitnik.ru>
|
5
|
+
|
6
|
+
This program is free software: you can redistribute it and/or modify
|
7
|
+
it under the terms of the GNU Lesser General Public License as published by
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
9
|
+
(at your option) any later version.
|
10
|
+
|
11
|
+
This program is distributed in the hope that it will be useful,
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
GNU Lesser General Public License for more details.
|
15
|
+
|
16
|
+
You should have received a copy of the GNU Lesser General Public License
|
17
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
=end
|
19
|
+
|
20
|
+
require "pathname"
|
21
|
+
require "yaml"
|
22
|
+
|
23
|
+
module Rubi18n
|
24
|
+
# Translation for interface to i18n support.
|
25
|
+
#
|
26
|
+
# Translation files use YAML format and has name CODE.yml, where CODE is a
|
27
|
+
# language/country code (RFC 3066) like en_US. For example: en.yaml is a
|
28
|
+
# English translation, en_US.yml is a translation to USA English dialect.
|
29
|
+
#
|
30
|
+
# Rubi18n contain translations for common words (such as “OK”, “Cancel”, etc)
|
31
|
+
# for most supported locales. See <tt>base/</tt> dir.
|
32
|
+
#
|
33
|
+
# You may load several locales. Also for each locale will be load it
|
34
|
+
# sublocales – languages, which user often know in this locale. For example,
|
35
|
+
# many, who speak on Frensh dialects in Canada can understand original French.
|
36
|
+
# Also many people in Belarus can understand Russian.
|
37
|
+
#
|
38
|
+
# Translated strinsg will have locale methods, which return Locale of locale
|
39
|
+
# code if locale info file isn't exists.
|
40
|
+
#
|
41
|
+
# == Examples
|
42
|
+
# translations/fr.yaml
|
43
|
+
#
|
44
|
+
# one: Un
|
45
|
+
#
|
46
|
+
# translations/ru.yaml
|
47
|
+
#
|
48
|
+
# one: Один
|
49
|
+
# two: Два
|
50
|
+
#
|
51
|
+
# translations/en.yaml
|
52
|
+
#
|
53
|
+
# one: One
|
54
|
+
# two: Two
|
55
|
+
# three: Three
|
56
|
+
#
|
57
|
+
# entry:
|
58
|
+
# between: Between %1 and %2
|
59
|
+
# methods: Is %1 method
|
60
|
+
#
|
61
|
+
# comments: !!pl
|
62
|
+
# 0: no comments
|
63
|
+
# 1: one comment
|
64
|
+
# n: %1 comments
|
65
|
+
#
|
66
|
+
# sum: !!proc |x, y| "is #{x + y}"
|
67
|
+
#
|
68
|
+
# example.rb
|
69
|
+
#
|
70
|
+
# i18n = Rubi18n::Translation.load(["fr", "ru"], "translations/")
|
71
|
+
# i18n.one #=> "Un"
|
72
|
+
# i18n.two #=> "Два"
|
73
|
+
# i18n.three #=> "Three"
|
74
|
+
#
|
75
|
+
# i18n.three.locale["code"] #=> "en"
|
76
|
+
# i18n.three.locale["direction"] #=> "ltr"
|
77
|
+
#
|
78
|
+
# i18n.entry.between(2, 3) #=> "between 2 and 3"
|
79
|
+
# i18n["methods", "object"] #=> "Is object method"
|
80
|
+
#
|
81
|
+
# i18n.comments(0) #=> "no comments"
|
82
|
+
# i18n.comments(10) #=> "10 comments"
|
83
|
+
#
|
84
|
+
# i18n.sum(2, 3) #=> "is 5"
|
85
|
+
#
|
86
|
+
# == Extention translations
|
87
|
+
# You can add dir with translations, which will be used with application
|
88
|
+
# translations. If application translations with same locale isn't exists
|
89
|
+
# extention files willn't be used.
|
90
|
+
#
|
91
|
+
# It's useful for plugins for rubi18n. For example DB plugin may place
|
92
|
+
# translations for error messages in extention dir. Rubi18n contain
|
93
|
+
# translations for base words as extention dir too.
|
94
|
+
class Translation
|
95
|
+
@@default = "en"
|
96
|
+
|
97
|
+
# Set default locale code to use when any user locales willn't be founded.
|
98
|
+
# It should has all translations and locale file.
|
99
|
+
def self.default=(locale)
|
100
|
+
@@default = locale
|
101
|
+
end
|
102
|
+
|
103
|
+
# Get default locale code
|
104
|
+
def self.default
|
105
|
+
@@default
|
106
|
+
end
|
107
|
+
|
108
|
+
@@extension_translations = [
|
109
|
+
Pathname(__FILE__).dirname.expand_path + "../../base"]
|
110
|
+
|
111
|
+
# Get dirs with extention translations. If application translations with
|
112
|
+
# same locale isn't exists extention files willn't be used.
|
113
|
+
def self.extension_translations
|
114
|
+
@@extension_translations
|
115
|
+
end
|
116
|
+
|
117
|
+
# Return available translations in +translations_dir+
|
118
|
+
def self.available(translations_dir)
|
119
|
+
Dir.glob(File.join(translations_dir, "*.yml")).map do |i|
|
120
|
+
File.basename(i, ".yml")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Load locale and translations. +locales+ may be string for one user locale
|
125
|
+
# or array with many.
|
126
|
+
#
|
127
|
+
# It load all available translations in +translations_dir+, which exists in
|
128
|
+
# +locales+. Next it load all translations for +sublocales+ in locale info
|
129
|
+
# for all loaded translations.
|
130
|
+
#
|
131
|
+
# == Example
|
132
|
+
# +locales+ is ["fr", "uk"], translations are available for "fr", "be", "ru"
|
133
|
+
# and "en". Translation will be founding firstly in "fr" next in "be" and
|
134
|
+
# next in "ru" and "en" (because many Belarusians know Russian and "be"
|
135
|
+
# locale contain in +sublocales+ "ru" and "en").
|
136
|
+
def self.load(locales, translations_dir)
|
137
|
+
locales = locales.to_a if String == locales.class
|
138
|
+
locales << @@default
|
139
|
+
|
140
|
+
locales += Locale.find(locales)["sublocales"]
|
141
|
+
locales.each_with_index do |locale, i|
|
142
|
+
# Add language locale for dialects
|
143
|
+
if "_" == locale[2..2]
|
144
|
+
locales.insert(i + 1, locale[0..1])
|
145
|
+
end
|
146
|
+
end
|
147
|
+
locales.uniq!
|
148
|
+
|
149
|
+
locales &= self.available(translations_dir)
|
150
|
+
|
151
|
+
translations = []
|
152
|
+
locales.map! do |locale|
|
153
|
+
locale.delete!("/", "\\")
|
154
|
+
|
155
|
+
translation = {}
|
156
|
+
@@extension_translations.each do |dir|
|
157
|
+
file = File.join(dir, "#{locale}.yml")
|
158
|
+
translation.merge! YAML::load_file(file) if File.exists? file
|
159
|
+
end
|
160
|
+
file = File.join(translations_dir, "#{locale}.yml")
|
161
|
+
translation.merge! YAML::load_file(file)
|
162
|
+
translations << translation
|
163
|
+
|
164
|
+
if Locale.exists? locale
|
165
|
+
Locale.new(locale)
|
166
|
+
else
|
167
|
+
locale
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
self.new(locales, translations)
|
172
|
+
end
|
173
|
+
|
174
|
+
# Default pluralization rule to translation without locale info
|
175
|
+
def self.pluralize(n)
|
176
|
+
n == 0 ? 0 : n == 1 ? 1 : 'n'
|
177
|
+
end
|
178
|
+
|
179
|
+
# Create translation hash with messages in +translations+ for +locales+.
|
180
|
+
#
|
181
|
+
# This is internal contructor to load translation use
|
182
|
+
# Rubi18n::Translation.load(locales, translations_dir).
|
183
|
+
def initialize(locales, translations)
|
184
|
+
@locales = locales
|
185
|
+
@translations = translations
|
186
|
+
end
|
187
|
+
|
188
|
+
# Short and pretty way to get traslation by method name. If translation
|
189
|
+
# has name of object methods ("methods", "strftime") use <tt>[]</tt> method
|
190
|
+
# to access.
|
191
|
+
#
|
192
|
+
# Translation can contain variable part. Just set is as %1, %2 etc in
|
193
|
+
# translations file and set values as methods params.
|
194
|
+
def method_missing(name, *params)
|
195
|
+
self[name.to_s, *params]
|
196
|
+
end
|
197
|
+
|
198
|
+
# Return traslation with special name.
|
199
|
+
#
|
200
|
+
# Translation can contain variable part. Just set is as %1, %2 etc in
|
201
|
+
# translations file and set values in next arguments.
|
202
|
+
def [](name, *params)
|
203
|
+
@translations.each_with_index do |translation, i|
|
204
|
+
result = translation[name]
|
205
|
+
next if result.nil?
|
206
|
+
|
207
|
+
if YAML::PrivateType == result.class
|
208
|
+
case result.type_id
|
209
|
+
when "proc"
|
210
|
+
return eval("proc {#{result.value}}").call(*params)
|
211
|
+
when "pl"
|
212
|
+
pluralizator = @locales[i]
|
213
|
+
pluralizator = self.class if Locale != pluralizator.class
|
214
|
+
|
215
|
+
params.each do |param|
|
216
|
+
type = pluralizator.pluralize(param)
|
217
|
+
type = "n" if not result.value.include? type
|
218
|
+
result = result.value[type]
|
219
|
+
break if YAML::PrivateType != result.class
|
220
|
+
end
|
221
|
+
else
|
222
|
+
return result
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
if String == result.class
|
227
|
+
params.each_with_index do |param, i|
|
228
|
+
result.gsub! "%#{i+1}", param.to_s
|
229
|
+
end
|
230
|
+
return TranslatedString.new(result, @locales[i])
|
231
|
+
elsif Hash == result.class
|
232
|
+
return self.class.new(@locales, @translations.map { |i|
|
233
|
+
i[name] or {}
|
234
|
+
})
|
235
|
+
else
|
236
|
+
return result
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
return nil
|
241
|
+
end
|
242
|
+
|
243
|
+
# Format +time+ according to the directives in the given format string and
|
244
|
+
# translate month, week days and meridian indicator (AM/PM) names (%A, %a,
|
245
|
+
# %B, %b, %p directives).
|
246
|
+
#
|
247
|
+
# See <tt>Time.strftime()</tt> method docs for info about all directives.
|
248
|
+
def strftime(time, format)
|
249
|
+
translated = ""
|
250
|
+
format.scan(/%[EO]?.|./o) do |c|
|
251
|
+
case c.sub(/^%[EO]?(.)$/o, "%\\1")
|
252
|
+
when "%A"
|
253
|
+
translated << self.week.days[time.wday - 1]
|
254
|
+
when "%a"
|
255
|
+
translated << self.week.abbr_days[time.wday - 1]
|
256
|
+
when "%B"
|
257
|
+
translated << self.months.names[time.month - 1]
|
258
|
+
when "%b"
|
259
|
+
translated << self.months.abbr_names[time.month - 1]
|
260
|
+
when "%p"
|
261
|
+
translated << if time.hour < 12 then self.am else self.pm end
|
262
|
+
else
|
263
|
+
translated << c
|
264
|
+
end
|
265
|
+
end
|
266
|
+
time.strftime(translated)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
data/lib/rubi18n.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
=begin
|
2
|
+
Main file to load all neccessary classes for i18n support.
|
3
|
+
|
4
|
+
Copyright (C) 2008 Andrey “A.I.” Sitnik <andrey@sitnik.ru>
|
5
|
+
|
6
|
+
This program is free software: you can redistribute it and/or modify
|
7
|
+
it under the terms of the GNU Lesser General Public License as published by
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
9
|
+
(at your option) any later version.
|
10
|
+
|
11
|
+
This program is distributed in the hope that it will be useful,
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
GNU Lesser General Public License for more details.
|
15
|
+
|
16
|
+
You should have received a copy of the GNU Lesser General Public License
|
17
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
=end
|
19
|
+
|
20
|
+
require "pathname"
|
21
|
+
|
22
|
+
$KCODE = "u"
|
23
|
+
|
24
|
+
dir = Pathname(__FILE__).dirname.expand_path + "rubi18n"
|
25
|
+
|
26
|
+
require dir + "locale"
|
27
|
+
require dir + "translation"
|
28
|
+
require dir + "translated_string"
|
29
|
+
require dir + "formatters"
|
data/locales/en.yml
ADDED
data/locales/en_US.yml
ADDED
data/locales/ru.yml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
title: Русский
|
2
|
+
code: ru
|
3
|
+
sublocales: [en]
|
4
|
+
direction: ltr
|
5
|
+
|
6
|
+
pluralization: "n==0 ? 0 : n%10==1 && n%100!=11 ? 1 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 2 : 'n'"
|
7
|
+
|
8
|
+
week_start: monday
|
9
|
+
|
10
|
+
numbers:
|
11
|
+
separation: classic
|
12
|
+
decimal_separator: ","
|
13
|
+
group_delimiter: " "
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe Rubi18n::Formatters do
|
4
|
+
|
5
|
+
it "should format number in local traditions" do
|
6
|
+
Rubi18n::Locale.current = "en"
|
7
|
+
-123456789.to_ls.should == "−123,456,789"
|
8
|
+
|
9
|
+
-123456789.to_ls(Rubi18n::Locale.new("ru")).should == "−123 456 789"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should format float in local traditions" do
|
13
|
+
Rubi18n::Locale.current = "en"
|
14
|
+
-12345.67.to_ls.should == "−12,345.67"
|
15
|
+
|
16
|
+
-12345.67.to_ls(Rubi18n::Locale.new("ru")).should == "−12 345,67"
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/spec/locale_spec.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe Rubi18n::Locale do
|
4
|
+
|
5
|
+
it "should check is locale exists" do
|
6
|
+
Rubi18n::Locale.exists?("ru").should be_true
|
7
|
+
Rubi18n::Locale.exists?("no_LC").should be_false
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should load locale" do
|
11
|
+
locale = Rubi18n::Locale.new "ru"
|
12
|
+
locale["code"].should == "ru"
|
13
|
+
locale["title"].should == "Русский"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should include locale by 'include' option" do
|
17
|
+
en_US = Rubi18n::Locale.new "en_US"
|
18
|
+
en = Rubi18n::Locale.new "en"
|
19
|
+
en_US["title"].should == "English (US)"
|
20
|
+
en["title"].should == "English"
|
21
|
+
en_US["week"].should == en["week"]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should raise error if locale isn't exists" do
|
25
|
+
lambda {
|
26
|
+
Rubi18n::Locale.new "no_LC"
|
27
|
+
}.should raise_error
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should be equal to another locale with same code" do
|
31
|
+
ru = Rubi18n::Locale.new "ru"
|
32
|
+
en = Rubi18n::Locale.new "en"
|
33
|
+
another = Rubi18n::Locale.new "en"
|
34
|
+
en.should_not == ru
|
35
|
+
en.should == another
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should print human readable representation" do
|
39
|
+
Rubi18n::Locale.new("ru").inspect.should == "Locale ru (Русский)"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should has current locale to use in +to_ls+ methods" do
|
43
|
+
en = Rubi18n::Locale.new "en"
|
44
|
+
Rubi18n::Locale.current = en
|
45
|
+
Rubi18n::Locale.current.should == en
|
46
|
+
Rubi18n::Locale.current = "en"
|
47
|
+
Rubi18n::Locale.current.should == en
|
48
|
+
Rubi18n::Locale.current = "ru"
|
49
|
+
Rubi18n::Locale.current.should_not == en
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should return all available locales" do
|
53
|
+
Rubi18n::Locale.locales.sort.should == ["en", "en_US", "ru"]
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should load first available locale" do
|
57
|
+
Rubi18n::Locale.find(["no_LC", "en", "ru"])["code"].should == "en"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should find a short name of locale" do
|
61
|
+
Rubi18n::Locale.find("ru_RU.UTF-8")["code"].should == "ru"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return pluralization type by elements count" do
|
65
|
+
locale = Rubi18n::Locale.new "en"
|
66
|
+
locale.pluralize(0).should == 0
|
67
|
+
locale.pluralize(1).should == 1
|
68
|
+
locale.pluralize(:n).should == 'n'
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe Rubi18n::Translation do
|
4
|
+
DIR = File.join(File.dirname(__FILE__), "translations", "general")
|
5
|
+
EXT = File.join(File.dirname(__FILE__), "translations", "extention")
|
6
|
+
|
7
|
+
it "should return all available translations" do
|
8
|
+
Rubi18n::Translation.available(DIR).sort.should == ["en", "fr", "no_LC", "ru"]
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should has default locale to use when there aren't any user locales" do
|
12
|
+
Rubi18n::Translation.default = "en"
|
13
|
+
Rubi18n::Translation.default.should == "en"
|
14
|
+
Rubi18n::Translation.load("no_TR", DIR).one.should == "One"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should load translations" do
|
18
|
+
translation = Rubi18n::Translation.load("en", DIR)
|
19
|
+
translation.one.should == "One"
|
20
|
+
translation["one"].should == "One"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should find in subtranslations" do
|
24
|
+
translation = Rubi18n::Translation.load(["fr", "ru"], DIR)
|
25
|
+
translation.one.should == "Un"
|
26
|
+
translation.two.should == "Два"
|
27
|
+
translation.three.should == "Three"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return nil if translation isn't found" do
|
31
|
+
translation = Rubi18n::Translation.load("en", DIR)
|
32
|
+
translation.without_translation.should be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should search language locale for dialect" do
|
36
|
+
translation = Rubi18n::Translation.load("fr_CA", DIR)
|
37
|
+
translation.one.should == "Un"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should can use params in translation" do
|
41
|
+
translation = Rubi18n::Translation.load("en", DIR)
|
42
|
+
translation.params(1, 2).should == "Is 1 between 1 and 2?"
|
43
|
+
translation["params", 1, 2].should == "Is 1 between 1 and 2?"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should load use hierarchical translations" do
|
47
|
+
translation = Rubi18n::Translation.load(["ru", "en"], DIR)
|
48
|
+
translation.in.another.should == "Иерархический"
|
49
|
+
translation["in"]["another"].should == "Иерархический"
|
50
|
+
translation.only.english.should == "Only in English"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return string with locale info" do
|
54
|
+
translation = Rubi18n::Translation.load(["fr", "ru"], DIR)
|
55
|
+
translation.one.locale.should == "fr"
|
56
|
+
translation.two.locale.should == Rubi18n::Locale.new("ru")
|
57
|
+
translation.three.locale.should == Rubi18n::Locale.new("en")
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should use extention translations" do
|
61
|
+
Rubi18n::Translation.extension_translations << EXT
|
62
|
+
|
63
|
+
translation = Rubi18n::Translation.load("en", DIR)
|
64
|
+
translation.ext.should == "Extention"
|
65
|
+
translation.one.should == "One"
|
66
|
+
end
|
67
|
+
|
68
|
+
it "shouldn't use extention without app translations with same locale" do
|
69
|
+
Rubi18n::Translation.extension_translations << EXT
|
70
|
+
|
71
|
+
translation = Rubi18n::Translation.load(["no_TR", "en"], DIR)
|
72
|
+
translation.ext.should == "Extention"
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should translate month, week days and am/pm names in strftime" do
|
76
|
+
translation = Rubi18n::Translation.load("ru", DIR)
|
77
|
+
|
78
|
+
time = Time.at(0).utc
|
79
|
+
translation.strftime(time, "%a %A").should == 'Срд Среда'
|
80
|
+
translation.strftime(time, "%b %B").should == 'Янв Январь'
|
81
|
+
translation.strftime(time, "%H:%M%p").should == '00:00AM'
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should call proc in translation" do
|
85
|
+
translation = Rubi18n::Translation.load("en", DIR)
|
86
|
+
translation.sum(2, 3).should == 5
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should pluralize translation" do
|
90
|
+
translation = Rubi18n::Translation.load("en", DIR)
|
91
|
+
translation.comments(0, "article").should == "no comments for article"
|
92
|
+
translation.comments(1, "article").should == "one comment for article"
|
93
|
+
translation.comments(5, "article").should == "5 comments for article"
|
94
|
+
|
95
|
+
translation.files(0).should == "0 files"
|
96
|
+
|
97
|
+
translation.authors(1, 4).should == "One author with many comments"
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should pluralize translation without locale" do
|
101
|
+
translation = Rubi18n::Translation.load("no_LC", DIR)
|
102
|
+
translation.entries(1).should == "ONE"
|
103
|
+
translation.entries(5).should == "N"
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
ext: NO
|
@@ -0,0 +1,31 @@
|
|
1
|
+
one: One
|
2
|
+
two: Two
|
3
|
+
three: Three
|
4
|
+
|
5
|
+
params: Is %1 between %1 and %2?
|
6
|
+
|
7
|
+
in:
|
8
|
+
another: Hierarchical
|
9
|
+
|
10
|
+
only:
|
11
|
+
english: Only in English
|
12
|
+
|
13
|
+
sum: !!proc |x, y| x + y
|
14
|
+
|
15
|
+
comments: !!pl
|
16
|
+
0: no comments for %2
|
17
|
+
1: one comment for %2
|
18
|
+
n: %1 comments for %2
|
19
|
+
|
20
|
+
files: !!pl
|
21
|
+
1: 1 file
|
22
|
+
n: %1 files
|
23
|
+
|
24
|
+
authors: !!pl
|
25
|
+
0: No authors
|
26
|
+
1: !!pl
|
27
|
+
1: One author with one comment
|
28
|
+
n: One author with many comments
|
29
|
+
n: !!pl
|
30
|
+
1: Many authors with one comment
|
31
|
+
n: Many authors with many comments
|
@@ -0,0 +1 @@
|
|
1
|
+
one: Un
|