fast_gettext 1.6.0 → 2.1.0
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 +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
|
-
[](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
|