tater 2.0.1 → 2.0.2
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.md → README.org} +66 -84
- data/lib/tater.rb +11 -6
- data/test/tater_test.rb +23 -5
- metadata +45 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb7166fcdf9b548f8837e4411bfe5d83712f202e1de27c299fa0e5694b50bc2b
|
4
|
+
data.tar.gz: ab3f53e56fa8538f39ce59ba9f2e42496e5bea116a880fc26e23ad2091e5e93c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ceb821ff34a086711feb0df9e21a7aa4c7891a3e84fc52a9cf62d5972462c6ab0a5f81eef2ab820ef95df7211dda82e2a56299a1ced017e468c50358b6e537db
|
7
|
+
data.tar.gz: 2ad3f4c078bb63e39b5650254f92cb3859c39c73f4eaf2dfae18320e60712bf2c632e42c38770c39a456ee62f13fbf6262e1fef527846c17c53d7ebd859fa6de
|
data/{README.md → README.org}
RENAMED
@@ -1,42 +1,39 @@
|
|
1
|
-
|
1
|
+
* Tater
|
2
2
|
|
3
|
-
[
|
4
|
-
[](https://travis-ci.com/evanleck/tater)
|
3
|
+
[[https://badge.fury.io/rb/tater][https://badge.fury.io/rb/tater.svg]]
|
5
4
|
|
6
5
|
Tater is an internationalization (i18n) and localization (l10n) library designed
|
7
6
|
for simplicity. It doesn't do everything that other libraries do, but that's by
|
8
7
|
design.
|
9
8
|
|
10
|
-
Under the hood, Tater uses a Hash to store the messages, the
|
11
|
-
lookups,
|
9
|
+
Under the hood, Tater uses a Hash to store the messages, the =dig= method for
|
10
|
+
lookups, =strftime= for date and time localizations, and =format= for
|
12
11
|
interpolation. That's probably 90% of what Tater does.
|
13
12
|
|
14
|
-
|
15
|
-
## Installation
|
13
|
+
** Installation
|
16
14
|
|
17
15
|
Tater requires Ruby 2.5 or higher. To install Tater, add this line to your
|
18
16
|
application's Gemfile (or gems.rb):
|
19
17
|
|
20
|
-
|
18
|
+
#+begin_src ruby
|
21
19
|
gem 'tater'
|
22
|
-
|
20
|
+
#+end_src
|
23
21
|
|
24
22
|
And then execute:
|
25
23
|
|
26
|
-
|
24
|
+
#+begin_src sh
|
27
25
|
bundle
|
28
|
-
|
26
|
+
#+end_src
|
29
27
|
|
30
28
|
Or install it yourself by running:
|
31
29
|
|
32
|
-
|
30
|
+
#+begin_src sh
|
33
31
|
gem install tater
|
34
|
-
|
35
|
-
|
32
|
+
#+end_src
|
36
33
|
|
37
|
-
|
34
|
+
** Usage
|
38
35
|
|
39
|
-
|
36
|
+
#+begin_src ruby
|
40
37
|
require 'tater'
|
41
38
|
|
42
39
|
messages = {
|
@@ -59,59 +56,56 @@ i18n.translate('some.key') # => 'This here string!'
|
|
59
56
|
|
60
57
|
# Interpolation:
|
61
58
|
i18n.translate('interpolated', you: 'world') # => 'Hello world!'
|
62
|
-
|
59
|
+
#+end_src
|
63
60
|
|
64
|
-
|
65
|
-
## Array localization
|
61
|
+
** Array localization
|
66
62
|
|
67
63
|
Given an array, Tater will do it's best to join the elements of the array into a
|
68
64
|
sentence based on how many elements there are.
|
69
65
|
|
70
|
-
|
66
|
+
#+begin_example
|
71
67
|
en:
|
72
68
|
array:
|
73
69
|
last_word_connector: ", and "
|
74
70
|
two_words_connector: " and "
|
75
71
|
words_connector: ", "
|
76
|
-
|
72
|
+
#+end_example
|
77
73
|
|
78
|
-
|
74
|
+
#+begin_src ruby
|
79
75
|
i18n.localize(%w[tacos enchiladas burritos]) # => "tacos, enchiladas, and burritos"
|
80
|
-
|
81
|
-
|
76
|
+
#+end_src
|
82
77
|
|
83
|
-
|
78
|
+
** Numeric localization
|
84
79
|
|
85
|
-
Numeric localization (
|
80
|
+
Numeric localization (=Numeric=, =Integer=, =Float=, and =BigDecimal=) require
|
86
81
|
filling in a separator and delimiter. For example:
|
87
82
|
|
88
|
-
|
83
|
+
#+begin_example
|
89
84
|
en:
|
90
85
|
numeric:
|
91
86
|
delimiter: ','
|
92
87
|
separator: '.'
|
93
|
-
|
88
|
+
#+end_example
|
94
89
|
|
95
90
|
With that, you can do things like this:
|
96
91
|
|
97
|
-
|
92
|
+
#+begin_src ruby
|
98
93
|
i18n.localize(1000.2) # => "1,000.20"
|
99
|
-
|
94
|
+
#+end_src
|
100
95
|
|
101
96
|
The separator and delimiter can also be passed in per-call:
|
102
97
|
|
103
|
-
|
98
|
+
#+begin_src ruby
|
104
99
|
i18n.localize(1000.2, delimiter: '_', separator: '+') # => "1_000+20"
|
105
|
-
|
100
|
+
#+end_src
|
106
101
|
|
102
|
+
** Date and time localization
|
107
103
|
|
108
|
-
|
109
|
-
|
110
|
-
Date and time localization (`Date`, `Time`, and `DateTime`) require filling in
|
104
|
+
Date and time localization (=Date=, =Time=, and =DateTime=) require filling in
|
111
105
|
all of the needed names and abbreviations for days and months. Here's the
|
112
106
|
example for French, which is used in the tests.
|
113
107
|
|
114
|
-
|
108
|
+
#+begin_example
|
115
109
|
fr:
|
116
110
|
time:
|
117
111
|
am: 'am'
|
@@ -174,28 +168,27 @@ fr:
|
|
174
168
|
- oct.
|
175
169
|
- nov.
|
176
170
|
- déc.
|
177
|
-
|
171
|
+
#+end_example
|
178
172
|
|
179
|
-
The statically defined keys for dates are
|
180
|
-
and
|
181
|
-
you plan on using the
|
173
|
+
The statically defined keys for dates are =days=, =abbreviated_days=, =months=,
|
174
|
+
and =abbreviated_months=. Only =am= and =pm= are needed for times and only if
|
175
|
+
you plan on using the =%p= or =%P= format strings.
|
182
176
|
|
183
177
|
With all of that, you can do something like:
|
184
178
|
|
185
|
-
|
179
|
+
#+begin_src ruby
|
186
180
|
i18n.localize(Date.new(1970, 1, 1), format: '%A') # => 'jeudi'
|
187
181
|
|
188
182
|
# Or, using a key defined in "formats":
|
189
183
|
i18n.localize(Date.new(1970, 1, 1), format: 'day') # => 'jeudi'
|
190
|
-
|
191
|
-
|
184
|
+
#+end_src
|
192
185
|
|
193
|
-
|
186
|
+
** Cascading lookups
|
194
187
|
|
195
|
-
Lookups can be cascaded, i.e.
|
188
|
+
Lookups can be cascaded, i.e. pieces of the scope of the can be lopped off
|
196
189
|
incrementally.
|
197
190
|
|
198
|
-
|
191
|
+
#+begin_src ruby
|
199
192
|
messages = {
|
200
193
|
'en' => {
|
201
194
|
'login' => {
|
@@ -214,42 +207,40 @@ i18n.translate('login.special.title') # => 'Special Login'
|
|
214
207
|
i18n.translate('login.special.description') # => 'Tater lookup failed'
|
215
208
|
|
216
209
|
i18n.translate('login.special.description', cascade: true) # => 'Normal description.'
|
217
|
-
|
210
|
+
#+end_src
|
218
211
|
|
219
212
|
With cascade, the final key stays the same, but pieces of the scope get lopped
|
220
213
|
off. In this case, lookups will be tried in this order:
|
221
214
|
|
222
|
-
1.
|
223
|
-
2.
|
215
|
+
1. ='login.special.description'=
|
216
|
+
2. ='login.description'=
|
224
217
|
|
225
218
|
This can be useful when you want to override some messages but don't want to
|
226
219
|
have to copy all of the other, non-overwritten messages.
|
227
220
|
|
228
221
|
Cascading can also be enabled by default when initializing an instance of Tater.
|
229
222
|
|
230
|
-
|
223
|
+
#+begin_src ruby
|
231
224
|
Tater.new(cascade: true)
|
232
|
-
|
225
|
+
#+end_src
|
233
226
|
|
234
227
|
Cascading is off by default.
|
235
228
|
|
236
|
-
|
237
|
-
## Defaults
|
229
|
+
** Defaults
|
238
230
|
|
239
231
|
If you'd like to default to another value in case of a missed lookup, you can
|
240
|
-
provide the
|
232
|
+
provide the =:default= option to =#translate=.
|
241
233
|
|
242
|
-
|
234
|
+
#+begin_src ruby
|
243
235
|
Tater.new.translate('nope', default: 'Yep!') # => 'Yep!'
|
244
|
-
|
236
|
+
#+end_src
|
245
237
|
|
246
|
-
|
247
|
-
## Procs and messages in Ruby
|
238
|
+
** Procs and messages in Ruby
|
248
239
|
|
249
240
|
Ruby files can be used to store messages in addition to YAML, so long as the
|
250
|
-
Ruby file returns a
|
241
|
+
Ruby file returns a =Hash= when evalled.
|
251
242
|
|
252
|
-
|
243
|
+
#+begin_src ruby
|
253
244
|
{
|
254
245
|
'en' => {
|
255
246
|
ruby: proc do |key, options = {}|
|
@@ -257,16 +248,15 @@ Ruby file returns a `Hash` when evalled.
|
|
257
248
|
end
|
258
249
|
}
|
259
250
|
}
|
260
|
-
|
261
|
-
|
251
|
+
#+end_src
|
262
252
|
|
263
|
-
|
253
|
+
** Multiple locales
|
264
254
|
|
265
255
|
If you would like to check multiple locales and pull the first matching one out,
|
266
|
-
you can pass the
|
256
|
+
you can pass the =:locales= option to initialization or the =translate= method
|
267
257
|
with an array of top-level locale keys.
|
268
258
|
|
269
|
-
|
259
|
+
#+begin_src ruby
|
270
260
|
messages = {
|
271
261
|
'en' => {
|
272
262
|
'title' => 'Login',
|
@@ -285,31 +275,23 @@ i18n.translate('description', locales: %w[fr en]) # => 'English description.'
|
|
285
275
|
i18n = Tater.new(messages: messages, locales: %w[fr en])
|
286
276
|
i18n.translate('title') # => 'la connexion'
|
287
277
|
i18n.translate('description') # => 'English description.'
|
288
|
-
|
278
|
+
#+end_src
|
289
279
|
|
290
280
|
Locales will be tried in order and whichever one matches first will be returned.
|
291
281
|
|
282
|
+
** Limitations
|
292
283
|
|
293
|
-
|
294
|
-
|
295
|
-
- It is not "pluggable", it does what it does and that's it.
|
284
|
+
- It is not pluggable, it does what it does and that's it.
|
296
285
|
- It doesn't handle pluralization yet, though it may in the future.
|
297
|
-
- It doesn't cache anything, that's up to you.
|
298
|
-
|
299
|
-
|
300
|
-
## Why?
|
301
|
-
|
302
|
-
Because [Ruby I18n][rubyi18n] is amazing and I wanted to try to create a minimum
|
303
|
-
viable implementation of the bits of I18n that I use 90% of the time. Tater is a
|
304
|
-
single file that handles the basics of lookup and interpolation.
|
305
286
|
|
287
|
+
** Why?
|
306
288
|
|
307
|
-
|
289
|
+
Because [[https://github.com/ruby-i18n/i18n][Ruby I18n]] is amazing and I wanted to try to create a minimum viable
|
290
|
+
implementation of the bits of I18n that I use 90% of the time. Tater is a single
|
291
|
+
file that handles the basics of lookup and interpolation.
|
308
292
|
|
309
|
-
|
310
|
-
[numeronym][numeronym] like I18n: "t8r". I looked at it for a while but I read
|
311
|
-
it as "tater" instead of "tee-eight-arr" so I figured I'd just name it Tater.
|
312
|
-
Tater the translator.
|
293
|
+
** Trivia
|
313
294
|
|
314
|
-
[
|
315
|
-
|
295
|
+
I was orininally going to call this library "Translator" but with a [[https://en.wikipedia.org/wiki/Numeronym][numeronym]]
|
296
|
+
like I18n: "t8r". I looked at it for a while but I read it as "tater" instead
|
297
|
+
of "tee-eight-arr" so I figured I'd just name it Tater. Tater the translator.
|
data/lib/tater.rb
CHANGED
@@ -6,6 +6,7 @@ require 'yaml'
|
|
6
6
|
# designed for speed and simplicity.
|
7
7
|
class Tater
|
8
8
|
class MissingLocalizationFormat < ArgumentError; end
|
9
|
+
|
9
10
|
class UnLocalizableObject < ArgumentError; end
|
10
11
|
|
11
12
|
module Utils # :nodoc:
|
@@ -214,16 +215,20 @@ class Tater
|
|
214
215
|
raise(MissingLocalizationFormat, "Numeric localization delimiter ('numeric.delimiter') missing or not passed as option :delimiter") unless delimiter
|
215
216
|
raise(MissingLocalizationFormat, "Numeric localization separator ('numeric.separator') missing or not passed as option :separator") unless separator
|
216
217
|
|
217
|
-
#
|
218
|
-
integer
|
219
|
-
integer.
|
220
|
-
|
218
|
+
# Break the number up into integer and fraction parts.
|
219
|
+
integer = Utils.string_from_numeric(object)
|
220
|
+
integer, fraction = integer.split('.') unless object.is_a?(Integer)
|
221
|
+
|
222
|
+
if integer.length > 3
|
223
|
+
integer.gsub!(DELIMITING_REGEX) do |number|
|
224
|
+
"#{ number }#{ delimiter }"
|
225
|
+
end
|
221
226
|
end
|
222
227
|
|
223
|
-
if precision.zero?
|
228
|
+
if precision.zero? || fraction.nil?
|
224
229
|
integer
|
225
230
|
else
|
226
|
-
|
231
|
+
"#{ integer }#{ separator }#{ fraction.ljust(precision, '0').slice(0, precision) }"
|
227
232
|
end
|
228
233
|
when Date, Time, DateTime
|
229
234
|
format = lookup("#{ object.class.to_s.downcase }.formats.#{ options[:format] || DEFAULT }", locale: options[:locale]) || options[:format] || DEFAULT
|
data/test/tater_test.rb
CHANGED
@@ -118,7 +118,7 @@ describe Tater do
|
|
118
118
|
end
|
119
119
|
|
120
120
|
it 'updates the available list when new messages are loaded' do
|
121
|
-
i18n.load(messages: { 'added' => { 'hey' => 'yeah' }})
|
121
|
+
i18n.load(messages: { 'added' => { 'hey' => 'yeah' } })
|
122
122
|
|
123
123
|
assert_equal %w[en delimiter_only separator_only fr added].sort, i18n.available.sort
|
124
124
|
end
|
@@ -265,10 +265,28 @@ describe Tater do
|
|
265
265
|
assert_equal '1NAH12', i18n.localize(BigDecimal('1.12'))
|
266
266
|
end
|
267
267
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
268
|
+
describe 'precision option' do
|
269
|
+
it 'defaults to 2' do
|
270
|
+
assert_equal '10NAH00', i18n.localize(BigDecimal('10'))
|
271
|
+
assert_equal '10NAH00', i18n.localize(10.0)
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'defaults to zero for integers' do
|
275
|
+
assert_equal '10', i18n.localize(10)
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'removes fractional pieces when the precision is 0' do
|
279
|
+
assert_equal '10', i18n.localize(BigDecimal('10.123456'), precision: 0)
|
280
|
+
assert_equal '10', i18n.localize(10.123456, precision: 0)
|
281
|
+
|
282
|
+
assert_equal '10', i18n.localize(BigDecimal('10.12'), precision: 0)
|
283
|
+
assert_equal '10', i18n.localize(10.12, precision: 0)
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'truncates long values to the desired precision' do
|
287
|
+
assert_equal '10NAH00', i18n.localize(BigDecimal('10.00234'))
|
288
|
+
assert_equal '10NAH00', i18n.localize(10.00234)
|
289
|
+
end
|
272
290
|
end
|
273
291
|
|
274
292
|
it 'allows overriding the delimiter and separator' do
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tater
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Lecklider
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-21 00:00:00.000000000 Z
|
12
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'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: minitest
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +66,20 @@ dependencies:
|
|
52
66
|
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
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'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: rubocop-performance
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +94,20 @@ dependencies:
|
|
66
94
|
- - ">="
|
67
95
|
- !ruby/object:Gem::Version
|
68
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-rake
|
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'
|
69
111
|
description: Minimal internationalization and localization library.
|
70
112
|
email:
|
71
113
|
- evan@lecklider.com
|
@@ -74,7 +116,7 @@ extensions: []
|
|
74
116
|
extra_rdoc_files: []
|
75
117
|
files:
|
76
118
|
- LICENSE.txt
|
77
|
-
- README.
|
119
|
+
- README.org
|
78
120
|
- lib/tater.rb
|
79
121
|
- test/fixtures/another.yml
|
80
122
|
- test/fixtures/fixtures.yml
|