tater 3.0.4 → 3.0.6
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 +4 -4
- data/{README.org → README.md} +72 -69
- data/lib/tater/utils.rb +14 -1
- data/lib/tater/version.rb +4 -0
- data/lib/tater.rb +52 -49
- metadata +10 -129
- data/test/fixtures/another.yml +0 -2
- data/test/fixtures/fixtures.yml +0 -102
- data/test/fixtures/messages/more.yml +0 -12
- data/test/fixtures/ruby.rb +0 -11
- data/test/tater_test.rb +0 -458
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18944b6a0817574ffa53d289a770dc0d014f7e6cc2a7288bcea2f759ed317aa4
|
4
|
+
data.tar.gz: 0716a6538423a4722bae9929a4fa7668eeace79517680c1e5c30a9e5a9635a28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0690c57c5f348ace3b92d3156efadb40de9256843b20bd8e0ea36be327f48649e70d7c0baf68abe337d0cd4883a9c6c4690c9f54b5017dd3298bc6fa8b4920eb'
|
7
|
+
data.tar.gz: 91b9b6d51ed90b46b27263d6e911bace16959ea21a8da3aa501bf684acac3fada973c3bf48aec3ef6c0cf67567f7dd5f4494ca5312f23573474c9f71272441ce
|
data/{README.org → README.md}
RENAMED
@@ -1,39 +1,40 @@
|
|
1
|
-
|
1
|
+
# Tater
|
2
2
|
|
3
|
-
[[https://badge.fury.io/rb/tater]
|
3
|
+
[](https://badge.fury.io/rb/tater)
|
4
|
+
[](https://github.com/evanleck/tater/actions/workflows/main.yml)
|
4
5
|
|
5
6
|
Tater is an internationalization (i18n) and localization (l10n) library designed
|
6
|
-
for simplicity. It doesn't do everything that other libraries do, but that's
|
7
|
-
design.
|
7
|
+
for simplicity. It doesn't do everything that other libraries do, but that's
|
8
|
+
by design.
|
8
9
|
|
9
|
-
Under the hood, Tater uses a Hash to store the messages, the
|
10
|
-
lookups,
|
10
|
+
Under the hood, Tater uses a Hash to store the messages, the `dig` method
|
11
|
+
for lookups, `strftime` for date and time localizations, and `format` for
|
11
12
|
interpolation. That's probably 90% of what Tater does.
|
12
13
|
|
13
|
-
|
14
|
+
## Installation
|
14
15
|
|
15
|
-
Tater requires Ruby 2.
|
16
|
+
Tater requires Ruby 2.7 or higher. To install Tater, add this line to your
|
16
17
|
application's Gemfile (or gems.rb):
|
17
18
|
|
18
|
-
|
19
|
+
``` ruby
|
19
20
|
gem 'tater'
|
20
|
-
|
21
|
+
```
|
21
22
|
|
22
23
|
And then execute:
|
23
24
|
|
24
|
-
|
25
|
+
``` sh
|
25
26
|
bundle
|
26
|
-
|
27
|
+
```
|
27
28
|
|
28
29
|
Or install it yourself by running:
|
29
30
|
|
30
|
-
|
31
|
+
``` sh
|
31
32
|
gem install tater
|
32
|
-
|
33
|
+
```
|
33
34
|
|
34
|
-
|
35
|
+
## Usage
|
35
36
|
|
36
|
-
|
37
|
+
``` ruby
|
37
38
|
require 'tater'
|
38
39
|
|
39
40
|
messages = {
|
@@ -56,56 +57,56 @@ i18n.translate('some.key') # => 'This here string!'
|
|
56
57
|
|
57
58
|
# Interpolation:
|
58
59
|
i18n.translate('interpolated', you: 'world') # => 'Hello world!'
|
59
|
-
|
60
|
+
```
|
60
61
|
|
61
|
-
|
62
|
+
## Array localization
|
62
63
|
|
63
64
|
Given an array, Tater will do it's best to join the elements of the array into a
|
64
65
|
sentence based on how many elements there are.
|
65
66
|
|
66
|
-
|
67
|
+
``` example
|
67
68
|
en:
|
68
69
|
array:
|
69
70
|
last_word_connector: ", and "
|
70
71
|
two_words_connector: " and "
|
71
72
|
words_connector: ", "
|
72
|
-
|
73
|
+
```
|
73
74
|
|
74
|
-
|
75
|
+
``` ruby
|
75
76
|
i18n.localize(%w[tacos enchiladas burritos]) # => "tacos, enchiladas, and burritos"
|
76
|
-
|
77
|
+
```
|
77
78
|
|
78
|
-
|
79
|
+
## Numeric localization
|
79
80
|
|
80
|
-
Numeric localization (
|
81
|
+
Numeric localization (`Numeric`, `Integer`, `Float`, and `BigDecimal`) require
|
81
82
|
filling in a separator and delimiter. For example:
|
82
83
|
|
83
|
-
|
84
|
+
``` example
|
84
85
|
en:
|
85
86
|
numeric:
|
86
87
|
delimiter: ','
|
87
88
|
separator: '.'
|
88
|
-
|
89
|
+
```
|
89
90
|
|
90
91
|
With that, you can do things like this:
|
91
92
|
|
92
|
-
|
93
|
+
``` ruby
|
93
94
|
i18n.localize(1000.2) # => "1,000.20"
|
94
|
-
|
95
|
+
```
|
95
96
|
|
96
97
|
The separator and delimiter can also be passed in per-call:
|
97
98
|
|
98
|
-
|
99
|
+
``` ruby
|
99
100
|
i18n.localize(1000.2, delimiter: '_', separator: '+') # => "1_000+20"
|
100
|
-
|
101
|
+
```
|
101
102
|
|
102
|
-
|
103
|
+
## Date and time localization
|
103
104
|
|
104
|
-
Date and time localization (
|
105
|
-
all of the needed names and abbreviations for days and months. Here's the
|
105
|
+
Date and time localization (`Date`, `Time`, and `DateTime`) require filling
|
106
|
+
in all of the needed names and abbreviations for days and months. Here's the
|
106
107
|
example for French, which is used in the tests.
|
107
108
|
|
108
|
-
|
109
|
+
``` example
|
109
110
|
fr:
|
110
111
|
time:
|
111
112
|
am: 'am'
|
@@ -168,27 +169,27 @@ fr:
|
|
168
169
|
- oct.
|
169
170
|
- nov.
|
170
171
|
- déc.
|
171
|
-
|
172
|
+
```
|
172
173
|
|
173
|
-
The statically defined keys for dates are
|
174
|
-
and
|
175
|
-
you plan on using the
|
174
|
+
The statically defined keys for dates are `days`, `abbreviated_days`, `months`,
|
175
|
+
and `abbreviated_months`. Only `am` and `pm` are needed for times and only if
|
176
|
+
you plan on using the `%p` or `%P` format strings.
|
176
177
|
|
177
178
|
With all of that, you can do something like:
|
178
179
|
|
179
|
-
|
180
|
+
``` ruby
|
180
181
|
i18n.localize(Date.new(1970, 1, 1), format: '%A') # => 'jeudi'
|
181
182
|
|
182
183
|
# Or, using a key defined in "formats":
|
183
184
|
i18n.localize(Date.new(1970, 1, 1), format: 'day') # => 'jeudi'
|
184
|
-
|
185
|
+
```
|
185
186
|
|
186
|
-
|
187
|
+
## Cascading lookups
|
187
188
|
|
188
189
|
Lookups can be cascaded, i.e. pieces of the scope of the can be lopped off
|
189
190
|
incrementally.
|
190
191
|
|
191
|
-
|
192
|
+
``` ruby
|
192
193
|
messages = {
|
193
194
|
'en' => {
|
194
195
|
'login' => {
|
@@ -207,40 +208,40 @@ i18n.translate('login.special.title') # => 'Special Login'
|
|
207
208
|
i18n.translate('login.special.description') # => 'Tater lookup failed'
|
208
209
|
|
209
210
|
i18n.translate('login.special.description', cascade: true) # => 'Normal description.'
|
210
|
-
|
211
|
+
```
|
211
212
|
|
212
213
|
With cascade, the final key stays the same, but pieces of the scope get lopped
|
213
214
|
off. In this case, lookups will be tried in this order:
|
214
215
|
|
215
|
-
1.
|
216
|
-
2.
|
216
|
+
1. `login.special.description`
|
217
|
+
2. `login.description`
|
217
218
|
|
218
219
|
This can be useful when you want to override some messages but don't want to
|
219
220
|
have to copy all of the other, non-overwritten messages.
|
220
221
|
|
221
222
|
Cascading can also be enabled by default when initializing an instance of Tater.
|
222
223
|
|
223
|
-
|
224
|
+
``` ruby
|
224
225
|
Tater.new(cascade: true)
|
225
|
-
|
226
|
+
```
|
226
227
|
|
227
228
|
Cascading is off by default.
|
228
229
|
|
229
|
-
|
230
|
+
## Defaults
|
230
231
|
|
231
232
|
If you'd like to default to another value in case of a missed lookup, you can
|
232
|
-
provide the
|
233
|
+
provide the `:default` option to `#translate`.
|
233
234
|
|
234
|
-
|
235
|
+
``` ruby
|
235
236
|
Tater.new.translate('nope', default: 'Yep!') # => 'Yep!'
|
236
|
-
|
237
|
+
```
|
237
238
|
|
238
|
-
|
239
|
+
## Procs and messages in Ruby
|
239
240
|
|
240
241
|
Ruby files can be used to store messages in addition to YAML, so long as the
|
241
|
-
Ruby file returns a
|
242
|
+
Ruby file returns a `Hash` when evaluated.
|
242
243
|
|
243
|
-
|
244
|
+
``` ruby
|
244
245
|
{
|
245
246
|
'en' => {
|
246
247
|
ruby: proc do |key, options = {}|
|
@@ -248,15 +249,15 @@ Ruby file returns a =Hash= when evalled.
|
|
248
249
|
end
|
249
250
|
}
|
250
251
|
}
|
251
|
-
|
252
|
+
```
|
252
253
|
|
253
|
-
|
254
|
+
## Multiple locales
|
254
255
|
|
255
256
|
If you would like to check multiple locales and pull the first matching one out,
|
256
|
-
you can pass the
|
257
|
+
you can pass the `:locales` option to initialization or the `translate` method
|
257
258
|
with an array of top-level locale keys.
|
258
259
|
|
259
|
-
|
260
|
+
``` ruby
|
260
261
|
messages = {
|
261
262
|
'en' => {
|
262
263
|
'title' => 'Login',
|
@@ -275,23 +276,25 @@ i18n.translate('description', locales: %w[fr en]) # => 'English description.'
|
|
275
276
|
i18n = Tater.new(messages: messages, locales: %w[fr en])
|
276
277
|
i18n.translate('title') # => 'la connexion'
|
277
278
|
i18n.translate('description') # => 'English description.'
|
278
|
-
|
279
|
+
```
|
279
280
|
|
280
281
|
Locales will be tried in order and whichever one matches first will be returned.
|
281
282
|
|
282
|
-
|
283
|
+
## Limitations
|
283
284
|
|
284
|
-
- It is not
|
285
|
+
- It is not plug-able, it does what it does and that's it.
|
285
286
|
- It doesn't handle pluralization yet, though it may in the future.
|
286
287
|
|
287
|
-
|
288
|
+
## Why?
|
288
289
|
|
289
|
-
Because [
|
290
|
-
|
291
|
-
file that handles the basics of lookup
|
290
|
+
Because [Ruby I18n](https://github.com/ruby-i18n/i18n) is amazing and I wanted
|
291
|
+
to try to create a minimum viable implementation of the bits of I18n that I
|
292
|
+
use 90% of the time. Tater is a single file that handles the basics of lookup
|
293
|
+
and interpolation.
|
292
294
|
|
293
|
-
|
295
|
+
## Trivia
|
294
296
|
|
295
|
-
I was
|
296
|
-
like I18n: "t8r".
|
297
|
-
of "tee-eight-arr" so I
|
297
|
+
I was originally going to call this library "Translator" but with a
|
298
|
+
[numeronym](https://en.wikipedia.org/wiki/Numeronym) like I18n: "t8r". I looked
|
299
|
+
at it for a while but I read it as "tater" instead of "tee-eight-arr" so I
|
300
|
+
figured I'd just name it Tater. Tater the translator.
|
data/lib/tater/utils.rb
CHANGED
@@ -52,7 +52,8 @@ class Tater
|
|
52
52
|
end.freeze
|
53
53
|
end
|
54
54
|
|
55
|
-
# Format values into a string
|
55
|
+
# Format values into a string, conditionally checking the string and options
|
56
|
+
# before interpolating.
|
56
57
|
#
|
57
58
|
# @param string [String]
|
58
59
|
# The target string to interpolate into.
|
@@ -64,6 +65,18 @@ class Tater
|
|
64
65
|
return string if options.empty?
|
65
66
|
return string unless interpolation_string?(string)
|
66
67
|
|
68
|
+
interpolate!(string, options)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Format values into a string unconditionally.
|
72
|
+
#
|
73
|
+
# @param string [String]
|
74
|
+
# The target string to interpolate into.
|
75
|
+
# @param options [Hash]
|
76
|
+
# The values to interpolate into the target string.
|
77
|
+
#
|
78
|
+
# @return [String]
|
79
|
+
def self.interpolate!(string, options)
|
67
80
|
format(string, options)
|
68
81
|
end
|
69
82
|
|
data/lib/tater.rb
CHANGED
@@ -4,8 +4,9 @@ require 'date'
|
|
4
4
|
require 'time'
|
5
5
|
require 'yaml'
|
6
6
|
|
7
|
-
require 'tater/utils'
|
8
7
|
require 'tater/hash' unless Hash.method_defined?(:except)
|
8
|
+
require 'tater/utils'
|
9
|
+
require 'tater/version'
|
9
10
|
|
10
11
|
# Tater is a internationalization (i18n) and localization (l10n) library
|
11
12
|
# designed for speed and simplicity.
|
@@ -22,6 +23,11 @@ class Tater
|
|
22
23
|
# Needed for Ruby < 3.
|
23
24
|
using HashExcept unless Hash.method_defined?(:except)
|
24
25
|
|
26
|
+
# An array of the available locale codes found in loaded messages.
|
27
|
+
#
|
28
|
+
# @return [Array<String>]
|
29
|
+
attr_reader :available
|
30
|
+
|
25
31
|
# @return [String]
|
26
32
|
attr_reader :locale
|
27
33
|
|
@@ -37,6 +43,8 @@ class Tater
|
|
37
43
|
# @param path [String]
|
38
44
|
# A path to search for YAML or Ruby files to load messages from.
|
39
45
|
def initialize(cascade: false, locale: nil, messages: nil, path: nil)
|
46
|
+
@available = []
|
47
|
+
@cache = {}
|
40
48
|
@cascade = cascade
|
41
49
|
@locale = locale
|
42
50
|
@messages = {}
|
@@ -45,6 +53,11 @@ class Tater
|
|
45
53
|
load(messages: messages) if messages
|
46
54
|
end
|
47
55
|
|
56
|
+
# @return [String]
|
57
|
+
def inspect
|
58
|
+
%(#<Tater:#{ object_id } @cascade=#{ @cascade } @locale="#{ @locale }" @available=#{ @available }>)
|
59
|
+
end
|
60
|
+
|
48
61
|
# Do lookups cascade by default?
|
49
62
|
#
|
50
63
|
# @return [Boolean]
|
@@ -52,13 +65,6 @@ class Tater
|
|
52
65
|
@cascade
|
53
66
|
end
|
54
67
|
|
55
|
-
# An array of the available locale codes found in loaded messages.
|
56
|
-
#
|
57
|
-
# @return [Array]
|
58
|
-
def available
|
59
|
-
@available ||= messages.keys
|
60
|
-
end
|
61
|
-
|
62
68
|
# Is this locale available in our current set of messages?
|
63
69
|
#
|
64
70
|
# @return [Boolean]
|
@@ -89,12 +95,12 @@ class Tater
|
|
89
95
|
@messages = Utils.deep_merge(@messages, Utils.deep_stringify_keys(messages)) if messages
|
90
96
|
@messages = Utils.deep_freeze(@messages)
|
91
97
|
|
92
|
-
#
|
93
|
-
|
98
|
+
# Update our available locales.
|
99
|
+
@available.replace(@messages.keys.map(&:to_s).sort)
|
94
100
|
|
95
101
|
# Not only does this clear our cache but it establishes the basic structure
|
96
102
|
# that we rely on in other methods.
|
97
|
-
@cache
|
103
|
+
@cache.clear
|
98
104
|
|
99
105
|
@messages.each_key do |key|
|
100
106
|
@cache[key] = { false => {}, true => {} }
|
@@ -106,7 +112,8 @@ class Tater
|
|
106
112
|
# @param locale [String]
|
107
113
|
# The locale code to set as our default.
|
108
114
|
def locale=(locale)
|
109
|
-
|
115
|
+
str = locale.to_s
|
116
|
+
@locale = str if available?(str)
|
110
117
|
end
|
111
118
|
|
112
119
|
# Localize an Array, Date, Time, DateTime, or Numeric object.
|
@@ -210,24 +217,9 @@ class Tater
|
|
210
217
|
#
|
211
218
|
# @return [Boolean]
|
212
219
|
def includes?(key, options = HASH)
|
213
|
-
if options.empty?
|
214
|
-
!lookup(key).nil?
|
215
|
-
else
|
216
|
-
message =
|
217
|
-
if options.key?(:locales)
|
218
|
-
options[:locales].append(@locale) if @locale && !options[:locales].include?(@locale)
|
220
|
+
return !lookup(key).nil? if options.empty?
|
219
221
|
|
220
|
-
|
221
|
-
found = lookup(key, locale: accept, cascade: options[:cascade])
|
222
|
-
|
223
|
-
break found unless found.nil?
|
224
|
-
end
|
225
|
-
else
|
226
|
-
lookup(key, locale: options[:locale], cascade: options[:cascade])
|
227
|
-
end
|
228
|
-
|
229
|
-
!message.nil?
|
230
|
-
end
|
222
|
+
!lookup_with_options(key, options).nil?
|
231
223
|
end
|
232
224
|
|
233
225
|
# Translate a key path and optional interpolation arguments into a string.
|
@@ -257,33 +249,22 @@ class Tater
|
|
257
249
|
# defined key.
|
258
250
|
def translate(key, options = HASH)
|
259
251
|
if options.empty?
|
260
|
-
message = lookup(key)
|
261
|
-
|
262
|
-
if message.is_a?(Proc) # rubocop:disable Style/CaseLikeIf
|
263
|
-
message.call(key)
|
264
|
-
elsif message.is_a?(String)
|
252
|
+
case (message = lookup(key))
|
253
|
+
when String
|
265
254
|
message
|
255
|
+
when Proc
|
256
|
+
message.call(key)
|
266
257
|
else
|
267
258
|
"Tater lookup failed: #{ locale }.#{ key }"
|
268
259
|
end
|
269
260
|
else
|
270
|
-
message =
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
options[:locales].find do |accept|
|
275
|
-
found = lookup(key, locale: accept, cascade: options[:cascade])
|
276
|
-
|
277
|
-
break found unless found.nil?
|
278
|
-
end
|
279
|
-
else
|
280
|
-
lookup(key, locale: options[:locale], cascade: options[:cascade])
|
281
|
-
end
|
261
|
+
case (message = lookup_with_options(key, options))
|
262
|
+
when String
|
263
|
+
return message unless Utils.interpolation_string?(message)
|
282
264
|
|
283
|
-
|
265
|
+
Utils.interpolate!(message, options.except(:cascade, :default, :locale, :locales))
|
266
|
+
when Proc
|
284
267
|
message.call(key, options.except(:cascade, :default, :locale, :locales))
|
285
|
-
elsif message.is_a?(String)
|
286
|
-
Utils.interpolate(message, options.except(:cascade, :default, :locale, :locales))
|
287
268
|
else
|
288
269
|
options[:default] || "Tater lookup failed: #{ options[:locale] || options[:locales] || locale }.#{ key }"
|
289
270
|
end
|
@@ -292,6 +273,28 @@ class Tater
|
|
292
273
|
|
293
274
|
private
|
294
275
|
|
276
|
+
# @param key [String]
|
277
|
+
# The period-separated key path to look within our messages for.
|
278
|
+
# @param options [Hash]
|
279
|
+
# Options, including values to interpolate to any found string.
|
280
|
+
#
|
281
|
+
# @return [String]
|
282
|
+
# The translated and interpreted string, if found, or any data at the
|
283
|
+
# defined key.
|
284
|
+
def lookup_with_options(key, options)
|
285
|
+
if (locs = options[:locales])
|
286
|
+
locs.append(@locale) if @locale && !locs.include?(@locale)
|
287
|
+
|
288
|
+
locs.find do |accept|
|
289
|
+
found = lookup(key, locale: accept, cascade: options[:cascade])
|
290
|
+
|
291
|
+
break found unless found.nil?
|
292
|
+
end
|
293
|
+
else
|
294
|
+
lookup(key, locale: options[:locale], cascade: options[:cascade])
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
295
298
|
# Localize an Array object.
|
296
299
|
#
|
297
300
|
# @param object [Array<String>]
|
metadata
CHANGED
@@ -1,127 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tater
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Lecklider
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: minitest
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rake
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rubocop
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rubocop-minitest
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rubocop-packaging
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: rubocop-performance
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: rubocop-rake
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
11
|
+
date: 2023-05-26 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
125
13
|
description: Minimal internationalization and localization library.
|
126
14
|
email:
|
127
15
|
- evan@lecklider.com
|
@@ -130,21 +18,19 @@ extensions: []
|
|
130
18
|
extra_rdoc_files: []
|
131
19
|
files:
|
132
20
|
- LICENSE.txt
|
133
|
-
- README.
|
21
|
+
- README.md
|
134
22
|
- lib/tater.rb
|
135
23
|
- lib/tater/aliases.rb
|
136
24
|
- lib/tater/hash.rb
|
137
25
|
- lib/tater/utils.rb
|
138
|
-
-
|
139
|
-
- test/fixtures/fixtures.yml
|
140
|
-
- test/fixtures/messages/more.yml
|
141
|
-
- test/fixtures/ruby.rb
|
142
|
-
- test/tater_test.rb
|
26
|
+
- lib/tater/version.rb
|
143
27
|
homepage: https://github.com/evanleck/tater
|
144
28
|
licenses:
|
145
29
|
- MIT
|
146
30
|
metadata:
|
147
31
|
bug_tracker_uri: https://github.com/evanleck/tater/issues
|
32
|
+
changelog_uri: https://github.com/evanleck/tater/blob/main/CHANGELOG.md
|
33
|
+
homepage_uri: https://github.com/evanleck/tater
|
148
34
|
rubygems_mfa_required: 'true'
|
149
35
|
source_code_uri: https://github.com/evanleck/tater
|
150
36
|
post_install_message:
|
@@ -155,20 +41,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
155
41
|
requirements:
|
156
42
|
- - ">="
|
157
43
|
- !ruby/object:Gem::Version
|
158
|
-
version: 2.
|
44
|
+
version: 2.7.0
|
159
45
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
46
|
requirements:
|
161
47
|
- - ">="
|
162
48
|
- !ruby/object:Gem::Version
|
163
49
|
version: '2.0'
|
164
50
|
requirements: []
|
165
|
-
rubygems_version: 3.
|
51
|
+
rubygems_version: 3.4.10
|
166
52
|
signing_key:
|
167
53
|
specification_version: 4
|
168
54
|
summary: Minimal internationalization and localization library.
|
169
|
-
test_files:
|
170
|
-
- test/fixtures/another.yml
|
171
|
-
- test/fixtures/fixtures.yml
|
172
|
-
- test/fixtures/messages/more.yml
|
173
|
-
- test/fixtures/ruby.rb
|
174
|
-
- test/tater_test.rb
|
55
|
+
test_files: []
|
data/test/fixtures/another.yml
DELETED
data/test/fixtures/fixtures.yml
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
en:
|
2
|
-
english: 'Found in English'
|
3
|
-
|
4
|
-
title: 'This is a title'
|
5
|
-
interpolated: 'This has some %{fancy} text'
|
6
|
-
double: '%{first} %{second}!'
|
7
|
-
|
8
|
-
deep:
|
9
|
-
key: 'This key is deeper'
|
10
|
-
|
11
|
-
array:
|
12
|
-
last_word_connector: ", and "
|
13
|
-
two_words_connector: " and "
|
14
|
-
words_connector: ", "
|
15
|
-
|
16
|
-
date:
|
17
|
-
formats:
|
18
|
-
default: '%Y/%-m/%-d'
|
19
|
-
ohmy: '%-m something %-d oh my %Y'
|
20
|
-
|
21
|
-
time:
|
22
|
-
formats:
|
23
|
-
default: '%Y/%-m/%-d/%H/%M/%S'
|
24
|
-
|
25
|
-
datetime:
|
26
|
-
formats:
|
27
|
-
default: '%Y/%-m/%-d/%H/%M/%S'
|
28
|
-
|
29
|
-
numeric:
|
30
|
-
delimiter: 'TURKEYS'
|
31
|
-
separator: 'NAH'
|
32
|
-
|
33
|
-
cascade:
|
34
|
-
tacos: 'Delicious'
|
35
|
-
|
36
|
-
another:
|
37
|
-
crazy: 'Whoaa'
|
38
|
-
|
39
|
-
fr:
|
40
|
-
french: 'Found in French'
|
41
|
-
|
42
|
-
time:
|
43
|
-
am: 'am'
|
44
|
-
pm: 'pm'
|
45
|
-
|
46
|
-
formats:
|
47
|
-
default: '%I%P'
|
48
|
-
loud: '%I%p'
|
49
|
-
|
50
|
-
date:
|
51
|
-
formats:
|
52
|
-
abbreviated_day: '%a'
|
53
|
-
day: '%A'
|
54
|
-
|
55
|
-
abbreviated_month: '%b'
|
56
|
-
month: '%B'
|
57
|
-
|
58
|
-
days:
|
59
|
-
- dimanche
|
60
|
-
- lundi
|
61
|
-
- mardi
|
62
|
-
- mercredi
|
63
|
-
- jeudi
|
64
|
-
- vendredi
|
65
|
-
- samedi
|
66
|
-
|
67
|
-
abbreviated_days:
|
68
|
-
- dim
|
69
|
-
- lun
|
70
|
-
- mar
|
71
|
-
- mer
|
72
|
-
- jeu
|
73
|
-
- ven
|
74
|
-
- sam
|
75
|
-
|
76
|
-
months:
|
77
|
-
- janvier
|
78
|
-
- février
|
79
|
-
- mars
|
80
|
-
- avril
|
81
|
-
- mai
|
82
|
-
- juin
|
83
|
-
- juillet
|
84
|
-
- août
|
85
|
-
- septembre
|
86
|
-
- octobre
|
87
|
-
- novembre
|
88
|
-
- décembre
|
89
|
-
|
90
|
-
abbreviated_months:
|
91
|
-
- jan.
|
92
|
-
- fév.
|
93
|
-
- mar.
|
94
|
-
- avr.
|
95
|
-
- mai
|
96
|
-
- juin
|
97
|
-
- juil.
|
98
|
-
- août
|
99
|
-
- sept.
|
100
|
-
- oct.
|
101
|
-
- nov.
|
102
|
-
- déc.
|
data/test/fixtures/ruby.rb
DELETED
data/test/tater_test.rb
DELETED
@@ -1,458 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
3
|
-
|
4
|
-
require 'date'
|
5
|
-
require 'minitest/autorun'
|
6
|
-
require 'tater'
|
7
|
-
|
8
|
-
describe Tater do
|
9
|
-
describe Tater::Utils do
|
10
|
-
describe '#deep_merge' do
|
11
|
-
it 'deeply merges two hashes, returning a new one' do
|
12
|
-
first = { 'one' => 'one', 'two' => { 'three' => 'three' } }
|
13
|
-
second = { 'two' => { 'four' => 'four' } }
|
14
|
-
|
15
|
-
third = Tater::Utils.deep_merge(first, second)
|
16
|
-
|
17
|
-
assert_equal({ 'one' => 'one', 'two' => { 'three' => 'three', 'four' => 'four' } }, third)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe '#deep_stringify_keys' do
|
22
|
-
it 'converts all keys into strings, recursively' do
|
23
|
-
start = { en: { login: { title: 'Hello!' } } }
|
24
|
-
finish = Tater::Utils.deep_stringify_keys(start)
|
25
|
-
|
26
|
-
assert_equal({ 'en' => { 'login' => { 'title' => 'Hello!' } } }, finish)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe '#deep_freeze' do
|
31
|
-
it 'freezes the keys and values, recursively' do
|
32
|
-
start = Tater::Utils.deep_stringify_keys({ en: { login: { title: 'Hello!' } } })
|
33
|
-
finish = Tater::Utils.deep_freeze(start)
|
34
|
-
|
35
|
-
assert finish.frozen?
|
36
|
-
assert finish.keys.all?(&:frozen?)
|
37
|
-
assert finish.values.all?(&:frozen?)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
describe '#interpolate' do
|
42
|
-
it 'interpolates a string and hash' do
|
43
|
-
assert_equal 'this thing', Tater::Utils.interpolate('this %{what}', what: 'thing')
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'raises a KeyError when an argument is missing (but options are passed)' do
|
47
|
-
assert_raises(KeyError) do
|
48
|
-
Tater::Utils.interpolate('this %{what}', nope: 'thing')
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'returns the string unchanged when options are empty (does not raise a KeyError)' do
|
53
|
-
assert_equal 'this %{what}', Tater::Utils.interpolate('this %{what}')
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
describe '#string_from_numeric' do
|
58
|
-
it 'converts numerics to decimal-ish strings' do
|
59
|
-
assert_equal '1', Tater::Utils.string_from_numeric(1)
|
60
|
-
assert_equal '1.0', Tater::Utils.string_from_numeric(1.0)
|
61
|
-
assert_equal '1.0', Tater::Utils.string_from_numeric(BigDecimal('1'))
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe '#interpolation_string?' do
|
66
|
-
def is?(arg)
|
67
|
-
Tater::Utils.interpolation_string?(arg)
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'checks whether a string contains interpolation placeholders' do
|
71
|
-
assert is?('Hey %{there}!')
|
72
|
-
assert is?('Hey %<there>s!')
|
73
|
-
refute is?('Nah, this is fine')
|
74
|
-
refute is?("<b>HTML shouldn't count")
|
75
|
-
refute is?("A single % shouldn't count")
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
describe '#available?' do
|
81
|
-
let :i18n do
|
82
|
-
Tater.new(path: File.expand_path('test/fixtures'), locale: 'en')
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'tells you if the locale is available' do
|
86
|
-
assert i18n.available?('en')
|
87
|
-
refute i18n.available?('romulan')
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
describe '#load' do
|
92
|
-
it 'loads from a path on initialization' do
|
93
|
-
i18n = Tater.new(path: File.expand_path('test/fixtures'))
|
94
|
-
|
95
|
-
assert_instance_of(Hash, i18n.messages)
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'loads from a path after initialization' do
|
99
|
-
i18n = Tater.new
|
100
|
-
i18n.load(path: File.expand_path('test/fixtures'))
|
101
|
-
|
102
|
-
assert_instance_of(Hash, i18n.messages)
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'loads from a hash of messages on initialization' do
|
106
|
-
i18n = Tater.new(messages: { 'hey' => 'Oh hi' })
|
107
|
-
|
108
|
-
assert_instance_of(Hash, i18n.messages)
|
109
|
-
end
|
110
|
-
|
111
|
-
it 'loads from a hash of messages after initialization' do
|
112
|
-
i18n = Tater.new
|
113
|
-
i18n.load(messages: { 'hey' => 'Oh hi' })
|
114
|
-
|
115
|
-
assert_instance_of(Hash, i18n.messages)
|
116
|
-
end
|
117
|
-
|
118
|
-
it 'freezes messages after loading' do
|
119
|
-
i18n = Tater.new(messages: { 'hey' => 'Oh hi' })
|
120
|
-
|
121
|
-
assert i18n.messages.frozen?
|
122
|
-
assert i18n.messages.keys.all?(&:frozen?)
|
123
|
-
assert i18n.messages.values.all?(&:frozen?)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
describe '#available' do
|
128
|
-
let :i18n do
|
129
|
-
Tater.new(path: File.expand_path('test/fixtures'))
|
130
|
-
end
|
131
|
-
|
132
|
-
it 'returns an array with the available locales (i.e. the top-level keys in our messages hash)' do
|
133
|
-
assert_equal %w[en delimiter_only separator_only fr].sort, i18n.available.sort
|
134
|
-
end
|
135
|
-
|
136
|
-
it 'updates the available list when new messages are loaded' do
|
137
|
-
i18n.load(messages: { 'added' => { 'hey' => 'yeah' } })
|
138
|
-
|
139
|
-
assert_equal %w[en delimiter_only separator_only fr added].sort, i18n.available.sort
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
describe '#lookup' do
|
144
|
-
let :i18n do
|
145
|
-
Tater.new(path: File.expand_path('test/fixtures'), locale: 'en')
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'returns keys from messages' do
|
149
|
-
assert_equal 'This is a title', i18n.lookup('title')
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'does no interpolation' do
|
153
|
-
assert_equal 'This has some %{fancy} text', i18n.lookup('interpolated')
|
154
|
-
end
|
155
|
-
|
156
|
-
it 'returns nil for missing lookups' do
|
157
|
-
assert_nil i18n.lookup('nope')
|
158
|
-
end
|
159
|
-
|
160
|
-
it 'returns arbitrary data at keys' do
|
161
|
-
assert_equal({ 'key' => 'This key is deeper' }, i18n.lookup('deep'))
|
162
|
-
end
|
163
|
-
|
164
|
-
it 'cascades' do
|
165
|
-
assert_equal 'Delicious', i18n.lookup('cascade.nope.tacos', cascade: true)
|
166
|
-
assert_equal 'Whoaa', i18n.lookup('cascade.another.nope.crazy', cascade: true)
|
167
|
-
assert_nil i18n.lookup('cascade.another.nope.crazy', cascade: false)
|
168
|
-
assert_nil i18n.lookup('cascade.nahhhhhh')
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
describe '#translate' do
|
173
|
-
let :i18n do
|
174
|
-
Tater.new(path: File.expand_path('test/fixtures'), locale: 'en')
|
175
|
-
end
|
176
|
-
|
177
|
-
it 'translates strings' do
|
178
|
-
assert_equal 'This is a title', i18n.translate('title')
|
179
|
-
end
|
180
|
-
|
181
|
-
it 'translates nested strings' do
|
182
|
-
assert_equal 'This key is deeper', i18n.translate('deep.key')
|
183
|
-
end
|
184
|
-
|
185
|
-
it 'does not return a hash for nested keys' do
|
186
|
-
assert_equal 'Tater lookup failed: en.deep', i18n.translate('deep')
|
187
|
-
end
|
188
|
-
|
189
|
-
it 'interpolates additional variables' do
|
190
|
-
assert_equal 'This has some fancy text', i18n.translate('interpolated', fancy: 'fancy')
|
191
|
-
assert_equal 'Double down!', i18n.translate('double', first: 'Double', second: 'down')
|
192
|
-
end
|
193
|
-
|
194
|
-
it 'works with multiple files' do
|
195
|
-
assert_equal 'This is from a different file', i18n.translate('another')
|
196
|
-
assert_equal "Oh there's more!", i18n.translate('more')
|
197
|
-
end
|
198
|
-
|
199
|
-
it 'returns a message for failed translations' do
|
200
|
-
assert_equal 'Tater lookup failed: en.nope', i18n.translate('nope')
|
201
|
-
end
|
202
|
-
|
203
|
-
it 'cascades lookups' do
|
204
|
-
assert_equal 'Tater lookup failed: en.cascade.another.nope.crazy', i18n.translate('cascade.another.nope.crazy', cascade: false)
|
205
|
-
assert_equal 'Tater lookup failed: en.cascade.nope.tacos', i18n.translate('cascade.nope.tacos')
|
206
|
-
assert_equal 'Delicious', i18n.translate('cascade.nope.tacos', cascade: true)
|
207
|
-
end
|
208
|
-
|
209
|
-
it 'defaults lookups' do
|
210
|
-
assert_equal 'Tater lookup failed: en.default.missing', i18n.translate('default.missing')
|
211
|
-
assert_equal 'Nope', i18n.translate('default.missing', default: 'Nope')
|
212
|
-
end
|
213
|
-
|
214
|
-
it 'does lookups across different locales' do
|
215
|
-
assert_equal 'Found in French', i18n.translate('french', locales: %w[fr en])
|
216
|
-
assert_equal 'Found in English', i18n.translate('english', locales: %w[fr en])
|
217
|
-
assert_equal 'Tater lookup failed: ["fr", "en"].neither', i18n.translate('neither', locales: %w[fr en])
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'finds Ruby files' do
|
221
|
-
assert_equal 'Hey ruby!', i18n.translate('ruby')
|
222
|
-
end
|
223
|
-
|
224
|
-
it 'does not interpolate messages returned by procs' do
|
225
|
-
assert_equal 'Hey %{options}!', i18n.translate('options', options: 'options')
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
describe '#localize' do
|
230
|
-
let :i18n do
|
231
|
-
Tater.new(path: File.expand_path('test/fixtures'), locale: 'en')
|
232
|
-
end
|
233
|
-
|
234
|
-
let :fr do
|
235
|
-
Tater.new(path: File.expand_path('test/fixtures'), locale: 'fr')
|
236
|
-
end
|
237
|
-
|
238
|
-
it 'localizes arrays' do
|
239
|
-
assert_equal 'tacos and burritos', i18n.localize(%w[tacos burritos])
|
240
|
-
assert_equal 'tacos', i18n.localize(%w[tacos])
|
241
|
-
assert_equal 'tacos, enchiladas, and burritos', i18n.localize(%w[tacos enchiladas burritos])
|
242
|
-
|
243
|
-
assert_equal 'tacos + enchiladas ++ burritos', fr.localize(%w[tacos enchiladas burritos], words_connector: ' + ', last_word_connector: ' ++ ')
|
244
|
-
assert_equal 'tacostwoburritos', fr.localize(%w[tacos burritos], two_words_connector: 'two')
|
245
|
-
|
246
|
-
assert_raises(Tater::MissingLocalizationFormat) do
|
247
|
-
fr.localize(%w[tacos burritos])
|
248
|
-
end
|
249
|
-
|
250
|
-
assert_raises(Tater::MissingLocalizationFormat) do
|
251
|
-
fr.localize(%w[tacos burritos], last_word_connector: 'last', words_connector: 'words')
|
252
|
-
end
|
253
|
-
|
254
|
-
assert_raises(Tater::MissingLocalizationFormat) do
|
255
|
-
fr.localize(%w[tacos burritos], last_word_connector: 'last')
|
256
|
-
end
|
257
|
-
|
258
|
-
assert_raises(Tater::MissingLocalizationFormat) do
|
259
|
-
fr.localize(%w[tacos burritos], words_connector: 'words')
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
it 'localizes Dates' do
|
264
|
-
assert_equal '1970/1/1', i18n.localize(Date.new(1970, 1, 1))
|
265
|
-
end
|
266
|
-
|
267
|
-
it 'localizes Times' do
|
268
|
-
assert_equal '1970/1/1/00/00/00', i18n.localize(Time.new(1970, 1, 1, 0, 0, 0))
|
269
|
-
end
|
270
|
-
|
271
|
-
it 'localizes DateTimes' do
|
272
|
-
assert_equal '1970/1/1/00/00/00', i18n.localize(DateTime.new(1970, 1, 1, 0, 0, 0))
|
273
|
-
end
|
274
|
-
|
275
|
-
it 'localizes Floats' do
|
276
|
-
assert_equal '10TURKEYS000NAH12', i18n.localize(10_000.12)
|
277
|
-
end
|
278
|
-
|
279
|
-
it 'localizes Integers' do
|
280
|
-
assert_equal '10TURKEYS000', i18n.localize(10_000)
|
281
|
-
end
|
282
|
-
|
283
|
-
it 'localizes BigDecimals' do
|
284
|
-
assert_equal '1NAH12', i18n.localize(BigDecimal('1.12'))
|
285
|
-
end
|
286
|
-
|
287
|
-
describe 'precision option' do
|
288
|
-
it 'defaults to 2' do
|
289
|
-
assert_equal '10NAH00', i18n.localize(BigDecimal('10'))
|
290
|
-
assert_equal '10NAH00', i18n.localize(10.0)
|
291
|
-
end
|
292
|
-
|
293
|
-
it 'defaults to zero for integers' do
|
294
|
-
assert_equal '10', i18n.localize(10)
|
295
|
-
end
|
296
|
-
|
297
|
-
it 'removes fractional pieces when the precision is 0' do
|
298
|
-
assert_equal '10', i18n.localize(BigDecimal('10.123456'), precision: 0)
|
299
|
-
assert_equal '10', i18n.localize(10.123456, precision: 0)
|
300
|
-
|
301
|
-
assert_equal '10', i18n.localize(BigDecimal('10.12'), precision: 0)
|
302
|
-
assert_equal '10', i18n.localize(10.12, precision: 0)
|
303
|
-
end
|
304
|
-
|
305
|
-
it 'truncates long values to the desired precision' do
|
306
|
-
assert_equal '10NAH00', i18n.localize(BigDecimal('10.00234'))
|
307
|
-
assert_equal '10NAH00', i18n.localize(10.00234)
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
it 'allows overriding the delimiter and separator' do
|
312
|
-
assert_equal '10WOO000NAH12', i18n.localize(10_000.12, delimiter: 'WOO')
|
313
|
-
assert_equal '10TURKEYS000YA12', i18n.localize(10_000.12, separator: 'YA')
|
314
|
-
end
|
315
|
-
|
316
|
-
it 'accepts other formats' do
|
317
|
-
assert_equal '1 something 1 oh my 1970', i18n.localize(Date.new(1970, 1, 1), format: 'ohmy')
|
318
|
-
end
|
319
|
-
|
320
|
-
it 'uses the passed in format if the specified class and format are not present' do
|
321
|
-
assert_equal 'not there', i18n.localize(Date.new(1970, 1, 1), format: 'not there')
|
322
|
-
end
|
323
|
-
|
324
|
-
it 'raises a MissingLocalizationFormat if a delimiter is missing' do
|
325
|
-
assert_raises(Tater::MissingLocalizationFormat) do
|
326
|
-
i18n.localize(10, locale: 'separator_only')
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
it 'raises a MissingLocalizationFormat if a separator is missing' do
|
331
|
-
assert_raises(Tater::MissingLocalizationFormat) do
|
332
|
-
i18n.localize(10, locale: 'delimiter_only')
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
describe 'month, day, and AM/PM names' do
|
337
|
-
let :i18n do
|
338
|
-
Tater.new(path: File.expand_path('test/fixtures'), locale: 'fr')
|
339
|
-
end
|
340
|
-
|
341
|
-
it 'localizes day names' do
|
342
|
-
assert_equal 'jeudi', i18n.localize(Date.new(1970, 1, 1), format: 'day')
|
343
|
-
assert_equal 'vendredi', i18n.localize(Date.new(1970, 1, 2), format: 'day')
|
344
|
-
assert_equal 'samedi', i18n.localize(Date.new(1970, 1, 3), format: 'day')
|
345
|
-
assert_equal 'dimanche', i18n.localize(Date.new(1970, 1, 4), format: 'day')
|
346
|
-
assert_equal 'lundi', i18n.localize(Date.new(1970, 1, 5), format: 'day')
|
347
|
-
assert_equal 'mardi', i18n.localize(Date.new(1970, 1, 6), format: 'day')
|
348
|
-
assert_equal 'mercredi', i18n.localize(Date.new(1970, 1, 7), format: 'day')
|
349
|
-
end
|
350
|
-
|
351
|
-
it 'localizes abbreviated day names' do
|
352
|
-
assert_equal 'jeu', i18n.localize(Date.new(1970, 1, 1), format: 'abbreviated_day')
|
353
|
-
assert_equal 'ven', i18n.localize(Date.new(1970, 1, 2), format: 'abbreviated_day')
|
354
|
-
assert_equal 'sam', i18n.localize(Date.new(1970, 1, 3), format: 'abbreviated_day')
|
355
|
-
assert_equal 'dim', i18n.localize(Date.new(1970, 1, 4), format: 'abbreviated_day')
|
356
|
-
assert_equal 'lun', i18n.localize(Date.new(1970, 1, 5), format: 'abbreviated_day')
|
357
|
-
assert_equal 'mar', i18n.localize(Date.new(1970, 1, 6), format: 'abbreviated_day')
|
358
|
-
assert_equal 'mer', i18n.localize(Date.new(1970, 1, 7), format: 'abbreviated_day')
|
359
|
-
end
|
360
|
-
|
361
|
-
it 'localizes months' do
|
362
|
-
assert_equal 'janvier', i18n.localize(Date.new(1970, 1, 1), format: 'month')
|
363
|
-
assert_equal 'février', i18n.localize(Date.new(1970, 2, 1), format: 'month')
|
364
|
-
assert_equal 'mars', i18n.localize(Date.new(1970, 3, 1), format: 'month')
|
365
|
-
assert_equal 'avril', i18n.localize(Date.new(1970, 4, 1), format: 'month')
|
366
|
-
assert_equal 'mai', i18n.localize(Date.new(1970, 5, 1), format: 'month')
|
367
|
-
assert_equal 'juin', i18n.localize(Date.new(1970, 6, 1), format: 'month')
|
368
|
-
assert_equal 'juillet', i18n.localize(Date.new(1970, 7, 1), format: 'month')
|
369
|
-
assert_equal 'août', i18n.localize(Date.new(1970, 8, 1), format: 'month')
|
370
|
-
assert_equal 'septembre', i18n.localize(Date.new(1970, 9, 1), format: 'month')
|
371
|
-
assert_equal 'octobre', i18n.localize(Date.new(1970, 10, 1), format: 'month')
|
372
|
-
assert_equal 'novembre', i18n.localize(Date.new(1970, 11, 1), format: 'month')
|
373
|
-
assert_equal 'décembre', i18n.localize(Date.new(1970, 12, 1), format: 'month')
|
374
|
-
end
|
375
|
-
|
376
|
-
it 'localizes abbreviated months' do
|
377
|
-
assert_equal 'jan.', i18n.localize(Date.new(1970, 1, 1), format: 'abbreviated_month')
|
378
|
-
assert_equal 'fév.', i18n.localize(Date.new(1970, 2, 1), format: 'abbreviated_month')
|
379
|
-
assert_equal 'mar.', i18n.localize(Date.new(1970, 3, 1), format: 'abbreviated_month')
|
380
|
-
assert_equal 'avr.', i18n.localize(Date.new(1970, 4, 1), format: 'abbreviated_month')
|
381
|
-
assert_equal 'mai', i18n.localize(Date.new(1970, 5, 1), format: 'abbreviated_month')
|
382
|
-
assert_equal 'juin', i18n.localize(Date.new(1970, 6, 1), format: 'abbreviated_month')
|
383
|
-
assert_equal 'juil.', i18n.localize(Date.new(1970, 7, 1), format: 'abbreviated_month')
|
384
|
-
assert_equal 'août', i18n.localize(Date.new(1970, 8, 1), format: 'abbreviated_month')
|
385
|
-
assert_equal 'sept.', i18n.localize(Date.new(1970, 9, 1), format: 'abbreviated_month')
|
386
|
-
assert_equal 'oct.', i18n.localize(Date.new(1970, 10, 1), format: 'abbreviated_month')
|
387
|
-
assert_equal 'nov.', i18n.localize(Date.new(1970, 11, 1), format: 'abbreviated_month')
|
388
|
-
assert_equal 'déc.', i18n.localize(Date.new(1970, 12, 1), format: 'abbreviated_month')
|
389
|
-
end
|
390
|
-
|
391
|
-
it 'localizes AM/PM' do
|
392
|
-
assert_equal '05pm', i18n.localize(Time.new(1970, 1, 1, 17))
|
393
|
-
assert_equal '05PM', i18n.localize(Time.new(1970, 1, 1, 17), format: 'loud')
|
394
|
-
assert_equal '05am', i18n.localize(Time.new(1970, 1, 1, 5))
|
395
|
-
assert_equal '05AM', i18n.localize(Time.new(1970, 1, 1, 5), format: 'loud')
|
396
|
-
end
|
397
|
-
end
|
398
|
-
end
|
399
|
-
|
400
|
-
describe '#locale=' do
|
401
|
-
let :i18n do
|
402
|
-
Tater.new(path: File.expand_path('test/fixtures'), locale: 'en')
|
403
|
-
end
|
404
|
-
|
405
|
-
it 'overrides the locale when available' do
|
406
|
-
i18n.locale = 'delimiter_only'
|
407
|
-
assert_equal 'delimiter_only', i18n.locale
|
408
|
-
end
|
409
|
-
|
410
|
-
it 'does not override the locale when not available' do
|
411
|
-
i18n.locale = 'nopeskies'
|
412
|
-
assert_equal 'en', i18n.locale
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
describe '#cascades?' do
|
417
|
-
let :default do
|
418
|
-
Tater.new
|
419
|
-
end
|
420
|
-
|
421
|
-
let :cascade do
|
422
|
-
Tater.new(cascade: true)
|
423
|
-
end
|
424
|
-
|
425
|
-
it 'returns false by default' do
|
426
|
-
refute default.cascades?
|
427
|
-
end
|
428
|
-
|
429
|
-
it 'returns true when passed during initialization' do
|
430
|
-
assert cascade.cascades?
|
431
|
-
end
|
432
|
-
end
|
433
|
-
|
434
|
-
describe '#includes?' do
|
435
|
-
let :i18n do
|
436
|
-
Tater.new(path: File.expand_path('test/fixtures'), locale: 'en')
|
437
|
-
end
|
438
|
-
|
439
|
-
it 'tells you if you have a translation' do
|
440
|
-
assert i18n.includes?('deep')
|
441
|
-
assert i18n.includes?('deep.key')
|
442
|
-
refute i18n.includes?('deep.nope')
|
443
|
-
refute i18n.includes?('nope')
|
444
|
-
end
|
445
|
-
|
446
|
-
it 'allows overriding the locale' do
|
447
|
-
assert i18n.includes?('french', locale: 'fr')
|
448
|
-
assert i18n.includes?('french', locales: %w[en fr])
|
449
|
-
refute i18n.includes?('french', locales: %w[en])
|
450
|
-
refute i18n.includes?('french')
|
451
|
-
end
|
452
|
-
|
453
|
-
it 'allows cascading' do
|
454
|
-
assert i18n.includes?('cascade.nope.tacos', cascade: true)
|
455
|
-
refute i18n.includes?('cascade.nope.tacos', cascade: false)
|
456
|
-
end
|
457
|
-
end
|
458
|
-
end
|