fast_gettext 1.6.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG +4 -3
- data/Readme.md +146 -51
- data/lib/fast_gettext/cache.rb +4 -2
- data/lib/fast_gettext/mo_file.rb +29 -19
- data/lib/fast_gettext/po_file.rb +17 -14
- data/lib/fast_gettext/storage.rb +38 -32
- data/lib/fast_gettext/translation.rb +81 -107
- data/lib/fast_gettext/translation_repository/base.rb +9 -6
- data/lib/fast_gettext/translation_repository/chain.rb +11 -5
- data/lib/fast_gettext/translation_repository/db.rb +12 -13
- data/lib/fast_gettext/translation_repository/db_models/translation_key.rb +11 -8
- data/lib/fast_gettext/translation_repository/db_models/translation_text.rb +4 -2
- data/lib/fast_gettext/translation_repository/logger.rb +4 -2
- data/lib/fast_gettext/translation_repository/merge.rb +9 -4
- data/lib/fast_gettext/translation_repository/mo.rb +8 -4
- data/lib/fast_gettext/translation_repository/po.rb +5 -2
- data/lib/fast_gettext/translation_repository/yaml.rb +16 -6
- data/lib/fast_gettext/translation_repository.rb +5 -5
- data/lib/fast_gettext/version.rb +3 -1
- data/lib/fast_gettext.rb +16 -16
- metadata +33 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 91bc0d49ead2bfbfad8065858e52255dfcd9938cb547f0b20984bb12cc202380
|
4
|
+
data.tar.gz: 45c2e546d2041e36b82a4d82593d4b1c014d46da561996037a76d6e911ed2cdb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1120024578b173fb99e2bf879b22654723efede889a98d7d950c8201aef11261566f6c70a6247f8ce937fef9f7ec88fe1a6dc9a874331e6cc41fbed55cc651f2
|
7
|
+
data.tar.gz: 6cdbf2dcec813b6fb0c0da4b87af33c372a2f87ea177fdafd0203cf3f45f565a5fe64b4e41fe4fedcd4450ec1a7196d4c5a015df35470b4cfdb8b21e4037b137
|
data/CHANGELOG
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
+
2.0.0 -- Changed p_ separator to \0004 https://github.com/grosser/fast_gettext/pull/107 add np and add gettext aliases
|
1
2
|
1.6.0 -- Remove restrictions around yaml file names
|
2
3
|
1.1.0 -- translations are no longer eager loaded for improved startup performance, pass `eager_load: true` to preload for example in preforked web server
|
3
4
|
1.0.0 -- do not enforce attr_accessible unless ProtectedAttributes are loaded
|
4
|
-
0.9.0 -- reworked internals of caching to be
|
5
|
+
0.9.0 -- reworked internals of caching to be pluggable
|
5
6
|
0.7.0 -- set_locale resets to default locale if none of the available locales was tried to set
|
6
|
-
0.6.0 -- plurals use singular translations as
|
7
|
+
0.6.0 -- plurals use singular translations as fallback e.g. you translated 'Axis' then n_('Axis','Axis',1) would return the translation for 'Axis' if no plural translation was found
|
7
8
|
0.4.14 -- "" is translated as "", not as gettext meta information
|
8
|
-
0.4.0 -- pluralisation_rules is no longer stored in each repository, only
|
9
|
+
0.4.0 -- pluralisation_rules is no longer stored in each repository, only retrieved. Added Chain and Logger repository.
|
9
10
|
0.3.6 -- FastGettext.default_locale=
|
10
11
|
0.3.5 -- FastGettext.default_text_domain=
|
11
12
|
0.3.4 -- Exceptions are thrown, not returned when translating without text domain
|
data/Readme.md
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
FastGettext
|
2
2
|
===========
|
3
|
-
GetText but
|
3
|
+
GetText but 12 x faster, 530 x less garbage, clean namespace (8 vs 26), simple and threadsafe!
|
4
4
|
|
5
5
|
It supports multiple backends (.mo, .po, .yml files, Database(ActiveRecord + any other), Chain, Loggers) and can easily be extended.
|
6
6
|
|
7
7
|
[Example Rails application](https://github.com/grosser/gettext_i18n_rails_example)
|
8
8
|
|
9
|
+
|
9
10
|
Comparison
|
10
11
|
==========
|
11
12
|
<table>
|
@@ -18,17 +19,17 @@ Comparison
|
|
18
19
|
</tr>
|
19
20
|
<tr>
|
20
21
|
<td>Speed*</td>
|
21
|
-
<td>0.
|
22
|
-
<td>
|
23
|
-
<td>
|
24
|
-
<td>
|
22
|
+
<td>0.08s</td>
|
23
|
+
<td>0.14s</td>
|
24
|
+
<td>1.75s</td>
|
25
|
+
<td>3.75s</td>
|
25
26
|
</tr>
|
26
27
|
<tr>
|
27
|
-
<td>
|
28
|
-
<td>
|
29
|
-
<td>
|
30
|
-
<td>
|
31
|
-
<td>
|
28
|
+
<td>Objects*</td>
|
29
|
+
<td>11K</td>
|
30
|
+
<td>15K</td>
|
31
|
+
<td>8017K</td>
|
32
|
+
<td>7107K</td>
|
32
33
|
</tr>
|
33
34
|
<tr>
|
34
35
|
<td>Included backends</td>
|
@@ -38,10 +39,12 @@ Comparison
|
|
38
39
|
<td>yml (db/key-value/po/chain in other I18n backends)</td>
|
39
40
|
</tr>
|
40
41
|
</table>
|
41
|
-
<small>*
|
42
|
+
<small>*500.000 translations with ruby 2.5.3 through `bundle exec rake benchmark`</small>
|
43
|
+
|
42
44
|
|
43
45
|
Setup
|
44
46
|
=====
|
47
|
+
|
45
48
|
### 1. Install
|
46
49
|
|
47
50
|
```Bash
|
@@ -60,13 +63,15 @@ Or po files (less maintenance than mo)
|
|
60
63
|
|
61
64
|
```Ruby
|
62
65
|
FastGettext.add_text_domain('my_app', path: 'locale', type: :po)
|
63
|
-
# :
|
64
|
-
# :
|
66
|
+
# ignore_fuzzy: true to not use fuzzy translations
|
67
|
+
# report_warning: false to hide warnings about obsolete/fuzzy translations
|
65
68
|
```
|
66
69
|
|
67
70
|
Or yaml files (use I18n syntax/indentation)
|
68
71
|
|
69
72
|
```Ruby
|
73
|
+
# A single locale can be segmented in multiple yaml files but they all should be
|
74
|
+
# named with a `qq.yml` suffix, where `qq` is the locale name.
|
70
75
|
FastGettext.add_text_domain('my_app', path: 'config/locales', type: :yaml)
|
71
76
|
```
|
72
77
|
|
@@ -75,7 +80,7 @@ Or database (scaleable, good for many locales/translators)
|
|
75
80
|
```Ruby
|
76
81
|
# db access is cached <-> only first lookup hits the db
|
77
82
|
require "fast_gettext/translation_repository/db"
|
78
|
-
FastGettext::TranslationRepository::Db.require_models #load and include default models
|
83
|
+
FastGettext::TranslationRepository::Db.require_models # load and include default models
|
79
84
|
FastGettext.add_text_domain('my_app', type: :db, model: TranslationKey)
|
80
85
|
```
|
81
86
|
|
@@ -84,24 +89,83 @@ Do this once in every Thread. (e.g. Rails -> ApplicationController)
|
|
84
89
|
|
85
90
|
```Ruby
|
86
91
|
FastGettext.text_domain = 'my_app'
|
87
|
-
FastGettext.available_locales = ['de','en','fr','en_US','en_UK'] # only allow these locales to be set (optional)
|
92
|
+
FastGettext.available_locales = ['de', 'en', 'fr', 'en_US', 'en_UK'] # only allow these locales to be set (optional)
|
88
93
|
FastGettext.locale = 'de'
|
89
94
|
```
|
90
95
|
|
91
96
|
### 4. Start translating
|
92
97
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
_(
|
97
|
-
|
98
|
-
|
99
|
-
|
98
|
+
FastGettext supports all the translation methods of [ruby-gettext](http://github.com/ruby-gettext/gettext) with added support for block defaults.
|
99
|
+
(to get `*gettext` methods, use `FastGettext::TranslationAliased`)
|
100
|
+
|
101
|
+
#### `_()` or `gettext()`: basic translation
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
extend FastGettext::Translation
|
105
|
+
_('Car') == 'Auto' # found translation for 'Car'
|
106
|
+
_('not-found') == 'not-found' # The msgid is returned by default
|
107
|
+
```
|
108
|
+
|
109
|
+
#### `n_()` or `ngettext()`: pluralization
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
n_('Car', 'Cars', 1) == 'Auto'
|
113
|
+
n_('Car', 'Cars', 2) == 'Autos' # German plural of Cars
|
114
|
+
```
|
115
|
+
|
116
|
+
You'll often want to interpolate the results of `n_()` using ruby builtin `%` operator.
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
n_('Car', '%{n} Cars', 2) % { n: count } == '2 Autos'
|
120
|
+
```
|
121
|
+
|
122
|
+
#### `p_()` or `pgettext()`: translation with context
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
p_('File', 'Open') == _("File\004Open") == "öffnen"
|
126
|
+
p_('Context', 'not-found') == 'not-found'
|
127
|
+
```
|
128
|
+
|
129
|
+
#### `s_()` or `sgettext()`: translation with namespace
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
s_('File|Open') == _('File|Open') == "öffnen"
|
133
|
+
s_('Context|not-found') == 'not-found'
|
134
|
+
```
|
135
|
+
|
136
|
+
The difference between `s_()` and `p_()` is largely based on how the translations
|
137
|
+
are stored. Your preference will be based on your workflow and translation editing
|
138
|
+
tools.
|
139
|
+
|
140
|
+
#### `pn_()` or `pngettext()`: context-aware pluralized
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
pn_('Fruit', 'Apple', 'Apples', 3) == 'Äpfel'
|
144
|
+
pn_('Fruit', 'Apple', 'Apples', 1) == 'Apfel'
|
145
|
+
```
|
146
|
+
|
147
|
+
#### `sn_()` or `sngettext()`: without context pluralized
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
sn_('Fruit|Apple', 'Apples', 3) == 'Äpfel'
|
151
|
+
sn_('Fruit|Apple', 'Apples', 1) == 'Apfel'
|
152
|
+
```
|
153
|
+
|
154
|
+
#### `N_()` and `Nn_()`: make dynamic translations available to the parser.
|
155
|
+
|
156
|
+
In many instances, your strings will not be found by the ruby parsing. These methods
|
157
|
+
allow for those strings to be discovered.
|
158
|
+
|
159
|
+
```
|
160
|
+
N_("active"); N_("inactive"); N_("paused") # possible value of status for parser to find.
|
161
|
+
Nn_("active", "inactive", "paused") # alternative method
|
162
|
+
_("Your account is %{account_state}.") % { account_state: _(status) }
|
100
163
|
```
|
101
164
|
|
102
165
|
|
103
166
|
Managing translations
|
104
|
-
|
167
|
+
=====================
|
168
|
+
|
105
169
|
### mo/po-files
|
106
170
|
Generate .po or .mo files using GetText parser (example tasks at [gettext_i18n_rails](http://github.com/grosser/gettext_i18n_rails))
|
107
171
|
|
@@ -111,12 +175,12 @@ Tell Gettext where your .mo or .po files lie, e.g. for locale/de/my_app.po and l
|
|
111
175
|
FastGettext.add_text_domain('my_app', path: 'locale')
|
112
176
|
```
|
113
177
|
|
114
|
-
Use the [original GetText](http://github.com/
|
178
|
+
Use the [original GetText](http://github.com/ruby-gettext/gettext) to create and manage po/mo-files.
|
115
179
|
(Work on a po/mo parser & reader that is easier to use has started, contributions welcome @ [get_pomo](http://github.com/grosser/get_pomo) )
|
116
180
|
|
117
181
|
### Database
|
118
182
|
[Example migration for ActiveRecord](http://github.com/grosser/fast_gettext/blob/master/examples/db/migration.rb)<br/>
|
119
|
-
The default plural
|
183
|
+
The default plural separator is `||||` but you may overwrite it (or suggest a better one...).
|
120
184
|
|
121
185
|
This is usable with any model DataMapper/Sequel or any other(non-database) backend, the only thing you need to do is respond to the self.translation(key, locale) call.
|
122
186
|
If you want to use your own models, have a look at the [default models](http://github.com/grosser/fast_gettext/tree/master/lib/fast_gettext/translation_repository/db_models) to see what you want/need to implement.
|
@@ -128,7 +192,7 @@ Rails
|
|
128
192
|
Try the [gettext_i18n_rails plugin](http://github.com/grosser/gettext_i18n_rails), it simplifies the setup.<br/>
|
129
193
|
Try the [translation_db_engine](http://github.com/grosser/translation_db_engine), to manage your translations in a db.
|
130
194
|
|
131
|
-
Setting `available_locales`,`text_domain` or `locale` will not work inside the `
|
195
|
+
Setting `available_locales`,`text_domain` or `locale` will not work inside the `environment.rb`,
|
132
196
|
since it runs in a different thread then e.g. controllers, so set them inside your application_controller.
|
133
197
|
|
134
198
|
```Ruby
|
@@ -143,7 +207,7 @@ class ApplicationController ...
|
|
143
207
|
include FastGettext::Translation
|
144
208
|
before_filter :set_locale
|
145
209
|
def set_locale
|
146
|
-
FastGettext.available_locales = ['de','en'
|
210
|
+
FastGettext.available_locales = ['de', 'en', ...]
|
147
211
|
FastGettext.text_domain = 'frontend'
|
148
212
|
FastGettext.set_locale(params[:locale] || session[:locale] || request.env['HTTP_ACCEPT_LANGUAGE'])
|
149
213
|
session[:locale] = I18n.locale = FastGettext.locale
|
@@ -153,6 +217,7 @@ class ApplicationController ...
|
|
153
217
|
|
154
218
|
Advanced features
|
155
219
|
=================
|
220
|
+
|
156
221
|
### Abnormal pluralisation
|
157
222
|
Plurals are selected by index, think of it as `['car', 'cars'][index]`<br/>
|
158
223
|
A pluralisation rule decides which form to use e.g. in english its `count == 1 ? 0 : 1`.<br/>
|
@@ -161,7 +226,7 @@ If you have any languages that do not fit this rule, you have to add a custom pl
|
|
161
226
|
Via Ruby:
|
162
227
|
|
163
228
|
```Ruby
|
164
|
-
FastGettext.pluralisation_rule =
|
229
|
+
FastGettext.pluralisation_rule = ->(count){ count > 5 ? 1 : (count > 2 ? 0 : 2)}
|
165
230
|
```
|
166
231
|
|
167
232
|
Via mo/pofile:
|
@@ -177,7 +242,7 @@ If you only use one text domain, setting `FastGettext.default_text_domain = 'app
|
|
177
242
|
is sufficient and no more `text_domain=` is needed
|
178
243
|
|
179
244
|
### default_locale
|
180
|
-
If the simple rule of "first `
|
245
|
+
If the simple rule of "first `available_locale` or 'en'" is not sufficient for you, set `FastGettext.default_locale = 'de'`.
|
181
246
|
|
182
247
|
### default_available_locales
|
183
248
|
Fallback when no available_locales are set
|
@@ -201,7 +266,7 @@ repos = [
|
|
201
266
|
FastGettext::TranslationRepository.build('new', path: '....'),
|
202
267
|
FastGettext::TranslationRepository.build('old', path: '....')
|
203
268
|
]
|
204
|
-
FastGettext.add_text_domain 'combined', type: :chain,
|
269
|
+
FastGettext.add_text_domain 'combined', type: :chain, chain: repos
|
205
270
|
```
|
206
271
|
|
207
272
|
### Merge
|
@@ -211,8 +276,8 @@ a subordinate repository is added. This puts the burden on the load phase and sp
|
|
211
276
|
|
212
277
|
```Ruby
|
213
278
|
repos = [
|
214
|
-
FastGettext::TranslationRepository.build('new',
|
215
|
-
FastGettext::TranslationRepository.build('old',
|
279
|
+
FastGettext::TranslationRepository.build('new', path: '....'),
|
280
|
+
FastGettext::TranslationRepository.build('old', path: '....')
|
216
281
|
]
|
217
282
|
domain = FastGettext.add_text_domain 'combined', type: :merge, chain: repos
|
218
283
|
```
|
@@ -230,7 +295,7 @@ When you want to know which keys could not be translated or were used, add a Log
|
|
230
295
|
```Ruby
|
231
296
|
repos = [
|
232
297
|
FastGettext::TranslationRepository.build('app', path: '....')
|
233
|
-
FastGettext::TranslationRepository.build('logger', type: :logger, callback:
|
298
|
+
FastGettext::TranslationRepository.build('logger', type: :logger, callback: ->(key_or_array_of_ids) { ... }),
|
234
299
|
}
|
235
300
|
FastGettext.add_text_domain 'combined', type: :chain, chain: repos
|
236
301
|
```
|
@@ -240,11 +305,11 @@ Unfound may not always mean missing, if you choose not to translate a word becau
|
|
240
305
|
A lambda or anything that responds to `call` will do as callback. A good starting point may be `examples/missing_translations_logger.rb`.
|
241
306
|
|
242
307
|
### Plugins
|
243
|
-
Want
|
308
|
+
Want an xml version?
|
244
309
|
Write your own TranslationRepository!
|
245
310
|
|
246
311
|
```Ruby
|
247
|
-
# fast_gettext/translation_repository/
|
312
|
+
# fast_gettext/translation_repository/wtf.rb
|
248
313
|
module FastGettext
|
249
314
|
module TranslationRepository
|
250
315
|
class Wtf
|
@@ -261,33 +326,65 @@ If you have more than one gettext domain, there are two sets of functions
|
|
261
326
|
available:
|
262
327
|
|
263
328
|
```Ruby
|
264
|
-
|
329
|
+
extend FastGettext::TranslationMultidomain
|
265
330
|
|
266
331
|
d_("domainname", "string") # finds 'string' in domain domainname
|
267
332
|
dn_("domainname", "string", "strings", 1) # ditto
|
268
|
-
|
333
|
+
dp_("domainname", "context", "key")
|
334
|
+
ds_("domainname", "context|key")
|
335
|
+
dnp_("domainname", "context", "string", "strings")
|
336
|
+
dns_("domainname", "context|string", "strings")
|
269
337
|
```
|
270
338
|
|
271
339
|
These are helper methods so you don't need to write:
|
272
340
|
|
273
341
|
```Ruby
|
274
|
-
FastGettext.
|
275
|
-
_("string")
|
342
|
+
FastGettext.with_domain("domainname") { _("string") }
|
276
343
|
```
|
277
344
|
|
278
345
|
It is useful in Rails plugins in the views for example. The second set of
|
279
346
|
functions are D functions which search for string in _all_ domains. If there
|
280
347
|
are multiple translations in different domains, it returns them in random
|
281
|
-
order (depends on the Ruby hash implementation)
|
348
|
+
order (depends on the Ruby hash implementation).
|
282
349
|
|
283
350
|
```Ruby
|
284
|
-
|
351
|
+
extend FastGettext::TranslationMultidomain
|
285
352
|
|
286
353
|
D_("string") # finds 'string' in any domain
|
287
|
-
#
|
354
|
+
Dn_("string", "strings", 1) # ditto
|
355
|
+
Dp_("context", "key")
|
356
|
+
Ds_("context|key")
|
357
|
+
Dnp_("context", "string", "strings")
|
358
|
+
Dns_("context|string", "strings")
|
359
|
+
```
|
360
|
+
|
361
|
+
Alternatively you can use [merge repository](https://github.com/grosser/fast_gettext#merge) to achieve the same behavior.
|
362
|
+
|
363
|
+
#### Block defaults
|
364
|
+
|
365
|
+
All the translation methods (including MultiDomain) support a block default, a feature not provided by ruby-gettext. When a translation is
|
366
|
+
not found, if a block is provided the block is always returned. Otherwise, a key is returned. Methods doing pluralization will attempt a simple translation of alternate keys.
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
_('not-found'){ "alternative default" } == alternate default
|
370
|
+
```
|
371
|
+
|
372
|
+
This block default is useful when the default is a very long passage of text that wouldn't make a useful key. You can also instrument logging not found keys.
|
373
|
+
|
374
|
+
```ruby
|
375
|
+
_('terms-and-conditions'){
|
376
|
+
load_terms_and_conditions
|
377
|
+
request_terms_and_conditions_translation_from_legal
|
378
|
+
}
|
379
|
+
|
380
|
+
# Override _ with logging
|
381
|
+
def _(key, &block)
|
382
|
+
result = gettext(key){ nil } # nil returned when not found
|
383
|
+
log_missing_translation_key(key) if result.nil?
|
384
|
+
result || (block ? block.call : key)
|
385
|
+
end
|
288
386
|
```
|
289
387
|
|
290
|
-
Alternatively you can use [merge repository](https://github.com/grosser/fast_gettext#merge) to achieve the same behaviour.
|
291
388
|
|
292
389
|
FAQ
|
293
390
|
===
|
@@ -295,13 +392,8 @@ FAQ
|
|
295
392
|
- [Iconv require error in 1.9.2](http://exceptionz.wordpress.com/2010/02/03/how-to-fix-the-iconv-require-error-in-ruby-1-9)
|
296
393
|
|
297
394
|
|
298
|
-
|
299
|
-
|
300
|
-
- Add a fallback for Iconv.conv in ruby 1.9.4 -> lib/fast_gettext/vendor/iconv
|
301
|
-
- YML backend that reads ActiveSupport::I18n files
|
302
|
-
|
303
|
-
Author
|
304
|
-
======
|
395
|
+
Authors
|
396
|
+
=======
|
305
397
|
Mo/Po-file parsing from Masao Mutoh, see vendor/README
|
306
398
|
|
307
399
|
### [Contributors](http://github.com/grosser/fast_gettext/contributors)
|
@@ -323,8 +415,11 @@ Mo/Po-file parsing from Masao Mutoh, see vendor/README
|
|
323
415
|
- [Dominic Cleal](https://github.com/domcleal)
|
324
416
|
- [Tomas Strachota](https://github.com/tstrachota)
|
325
417
|
- [Martin Meier](https://github.com/mameier)
|
418
|
+
- [morcoteg](https://github.com/morcoteg)
|
419
|
+
- [Daniel Schepers](https://github.com/tall-dan)
|
420
|
+
- [Robert Graff](https://github.com/rgraff)
|
326
421
|
|
327
422
|
[Michael Grosser](http://grosser.it)<br/>
|
328
423
|
michael@grosser.it<br/>
|
329
424
|
License: MIT, some vendor parts under the same license terms as Ruby (see headers)<br/>
|
330
|
-
[![
|
425
|
+
[![CI](https://github.com/grosser/fast_gettext/actions/workflows/actions.yml/badge.svg)](https://github.com/grosser/fast_gettext/actions/workflows/actions.yml)
|
data/lib/fast_gettext/cache.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module FastGettext
|
2
4
|
class Cache
|
3
5
|
def initialize
|
@@ -8,13 +10,13 @@ module FastGettext
|
|
8
10
|
def fetch(key)
|
9
11
|
translation = @current[key]
|
10
12
|
if translation.nil? # uncached
|
11
|
-
@current[key] = yield || false # TODO get rid of this false hack and cache :missing
|
13
|
+
@current[key] = yield || false # TODO: get rid of this false hack and cache :missing
|
12
14
|
else
|
13
15
|
translation
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
17
|
-
# TODO only used for tests, maybe if-else around it ...
|
19
|
+
# TODO: only used for tests, maybe if-else around it ...
|
18
20
|
def []=(key, value)
|
19
21
|
@current[key] = value
|
20
22
|
end
|
data/lib/fast_gettext/mo_file.rb
CHANGED
@@ -1,13 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fast_gettext/vendor/mofile'
|
2
4
|
module FastGettext
|
3
5
|
# Responsibility:
|
4
6
|
# - abstract mo files for Mo Repository
|
5
7
|
class MoFile
|
6
|
-
|
8
|
+
PLURAL_SEPARATOR = "\000"
|
9
|
+
CONTEXT_SEPARATOR = "\004"
|
7
10
|
|
8
11
|
# file => path or FastGettext::GetText::MOFile
|
9
|
-
def initialize(file, options={})
|
12
|
+
def initialize(file, options = {})
|
10
13
|
@filename = file
|
14
|
+
@data = nil
|
11
15
|
load_data if options[:eager_load]
|
12
16
|
end
|
13
17
|
|
@@ -15,17 +19,21 @@ module FastGettext
|
|
15
19
|
data[key]
|
16
20
|
end
|
17
21
|
|
18
|
-
#returns the plural forms or all singular translations that where found
|
22
|
+
# returns the plural forms or all singular translations that where found
|
19
23
|
# Car, Cars => [Auto,Autos] or []
|
20
24
|
def plural(*msgids)
|
21
|
-
split_plurals(self[msgids*
|
25
|
+
split_plurals(self[msgids * PLURAL_SEPARATOR].to_s)
|
22
26
|
end
|
23
27
|
|
24
28
|
def pluralisation_rule
|
25
|
-
#gettext uses 0 as default rule, which would turn off all pluralisation, very clever...
|
26
|
-
#additionally parsing fails when directly accessing po files, so this line was taken from gettext/mofile
|
27
|
-
(data['']||'').split("\n").each do |line|
|
28
|
-
|
29
|
+
# gettext uses 0 as default rule, which would turn off all pluralisation, very clever...
|
30
|
+
# additionally parsing fails when directly accessing po files, so this line was taken from gettext/mofile
|
31
|
+
(data[''] || '').split("\n").each do |line|
|
32
|
+
if /^Plural-Forms:\s*nplurals\s*\=\s*(\d*);\s*plural\s*\=\s*([^;]*)\n?/ =~ line
|
33
|
+
return ->(n) do # rubocop:disable Lint/UnusedBlockArgument
|
34
|
+
eval($2) # rubocop:disable Security/Eval
|
35
|
+
end
|
36
|
+
end
|
29
37
|
end
|
30
38
|
nil
|
31
39
|
end
|
@@ -36,35 +44,37 @@ module FastGettext
|
|
36
44
|
end
|
37
45
|
|
38
46
|
def self.empty
|
39
|
-
MoFile.new(File.join(File.dirname(__FILE__),'vendor','empty.mo'))
|
47
|
+
MoFile.new(File.join(File.dirname(__FILE__), 'vendor', 'empty.mo'))
|
40
48
|
end
|
41
49
|
|
42
50
|
private
|
43
51
|
|
44
52
|
def load_data
|
45
|
-
@data =
|
46
|
-
@filename
|
47
|
-
|
48
|
-
|
49
|
-
|
53
|
+
@data =
|
54
|
+
if @filename.is_a? FastGettext::GetText::MOFile
|
55
|
+
@filename
|
56
|
+
else
|
57
|
+
FastGettext::GetText::MOFile.open(@filename, "UTF-8")
|
58
|
+
end
|
50
59
|
make_singular_and_plural_available
|
51
60
|
end
|
52
61
|
|
53
|
-
#(if plural==singular, prefer singular)
|
62
|
+
# (if plural==singular, prefer singular)
|
54
63
|
def make_singular_and_plural_available
|
55
64
|
data = {}
|
56
|
-
@data.each do |key,translation|
|
57
|
-
next unless key.include?
|
65
|
+
@data.each do |key, translation|
|
66
|
+
next unless key.include? PLURAL_SEPARATOR
|
67
|
+
|
58
68
|
singular, plural = split_plurals(key)
|
59
69
|
translation = split_plurals(translation)
|
60
70
|
data[singular] ||= translation[0]
|
61
71
|
data[plural] ||= translation[1]
|
62
72
|
end
|
63
|
-
@data.merge!(data){|
|
73
|
+
@data.merge!(data) { |_key, old, _new| old }
|
64
74
|
end
|
65
75
|
|
66
76
|
def split_plurals(singular_plural)
|
67
|
-
singular_plural.split(
|
77
|
+
singular_plural.split(PLURAL_SEPARATOR)
|
68
78
|
end
|
69
79
|
end
|
70
80
|
end
|