fast_gettext 1.8.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af7af45d00211da2791e03bf1f4f7c611d8c557a10f339189ebdf2a72008ff05
4
- data.tar.gz: 23040ab7524d7eb95b0e11fcc22a05a1ddf54eeeb88babade01c9876620447c5
3
+ metadata.gz: 3b7df1ae6f9c9acae6fe82a22b0ce3efd1d545c9d814447070ebb59652a7fd71
4
+ data.tar.gz: 05af6efd5f93f5ea8bf2f8be7314566d0238781f7d809799823223ec01866ce4
5
5
  SHA512:
6
- metadata.gz: c9152caffa285a723a4681e23db5d0710465a5b47f2c2251f863026cf91da316cdd36155097038896d77cb1c5562af619e73cf29f69be70bebec28ac8bf6d272
7
- data.tar.gz: c59623e1c15a293922cfcdd457634a2cb5f082900ee0948d14d7d37c4ddac5533f1fa6437f8e9bc200cc391e9be4a8c6d416e72568017905f0be930fbd65bb00
6
+ metadata.gz: b0df4b37e9837b4661cf7c0cbef1c75144c3c2804b2da4110a4850c08eb3084a91cd419ffb5c796eff30ee96860d87cb555a3cb2bd3e99e25db64731868a08ff
7
+ data.tar.gz: dc6f882c3c3fa4ea1c3fc2399077d149c3e981124de8f9da99e0ee7bdf2fd248ac74131cc92f9167d05ef15a04eb2ba4e25780ea1f8bc9ecfe04795776704310
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 plugable
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 fallack e.g. you translated 'Axis' then n_('Axis','Axis',1) would return the translation for 'Axis' if no plural translation was found
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 retrived. Added Chain and Logger repository.
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.5 x faster, 560 x less memory, simple, clean namespace (7 vs 34) and threadsafe!
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.82s</td>
22
- <td>1.36s</td>
23
- <td>4.88s</td>
24
- <td>21.77s</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>RAM*</td>
28
- <td>4K</td>
29
- <td>8K</td>
30
- <td>4480K</td>
31
- <td>10100K</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>*50.000 translations with ruby enterprise 1.8.6 through `rake benchmark`</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,8 +63,8 @@ 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
- # :ignore_fuzzy => true to not use fuzzy translations
64
- # :report_warning => false to hide warnings about obsolete/fuzzy translations
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)
@@ -77,7 +80,7 @@ Or database (scaleable, good for many locales/translators)
77
80
  ```Ruby
78
81
  # db access is cached <-> only first lookup hits the db
79
82
  require "fast_gettext/translation_repository/db"
80
- FastGettext::TranslationRepository::Db.require_models #load and include default models
83
+ FastGettext::TranslationRepository::Db.require_models # load and include default models
81
84
  FastGettext.add_text_domain('my_app', type: :db, model: TranslationKey)
82
85
  ```
83
86
 
@@ -86,24 +89,83 @@ Do this once in every Thread. (e.g. Rails -> ApplicationController)
86
89
 
87
90
  ```Ruby
88
91
  FastGettext.text_domain = 'my_app'
89
- 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)
90
93
  FastGettext.locale = 'de'
91
94
  ```
92
95
 
93
96
  ### 4. Start translating
94
97
 
95
- ```Ruby
96
- include FastGettext::Translation
97
- _('Car') == 'Auto'
98
- _('not-found') == 'not-found'
99
- s_('Namespace|not-found') == 'not-found'
100
- n_('Axis','Axis',3) == 'Achsen' #German plural of Axis
101
- _('Hello %{name}!') % {name: "Pete"} == 'Hello Pete!'
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 `sgetext()`: 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 the by the ruby-parse. 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 }
102
163
  ```
103
164
 
104
165
 
105
166
  Managing translations
106
- ============
167
+ =====================
168
+
107
169
  ### mo/po-files
108
170
  Generate .po or .mo files using GetText parser (example tasks at [gettext_i18n_rails](http://github.com/grosser/gettext_i18n_rails))
109
171
 
@@ -113,12 +175,12 @@ Tell Gettext where your .mo or .po files lie, e.g. for locale/de/my_app.po and l
113
175
  FastGettext.add_text_domain('my_app', path: 'locale')
114
176
  ```
115
177
 
116
- Use the [original GetText](http://github.com/mutoh/gettext) to create and manage po/mo-files.
178
+ Use the [original GetText](http://github.com/ruby-gettext/gettext) to create and manage po/mo-files.
117
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) )
118
180
 
119
181
  ### Database
120
182
  [Example migration for ActiveRecord](http://github.com/grosser/fast_gettext/blob/master/examples/db/migration.rb)<br/>
121
- The default plural seperator is `||||` but you may overwrite it (or suggest a better one..).
183
+ The default plural separator is `||||` but you may overwrite it (or suggest a better one..).
122
184
 
123
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.
124
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.
@@ -130,7 +192,7 @@ Rails
130
192
  Try the [gettext_i18n_rails plugin](http://github.com/grosser/gettext_i18n_rails), it simplifies the setup.<br/>
131
193
  Try the [translation_db_engine](http://github.com/grosser/translation_db_engine), to manage your translations in a db.
132
194
 
133
- Setting `available_locales`,`text_domain` or `locale` will not work inside the `evironment.rb`,
195
+ Setting `available_locales`,`text_domain` or `locale` will not work inside the `environment.rb`,
134
196
  since it runs in a different thread then e.g. controllers, so set them inside your application_controller.
135
197
 
136
198
  ```Ruby
@@ -145,7 +207,7 @@ class ApplicationController ...
145
207
  include FastGettext::Translation
146
208
  before_filter :set_locale
147
209
  def set_locale
148
- FastGettext.available_locales = ['de','en',...]
210
+ FastGettext.available_locales = ['de', 'en', ...]
149
211
  FastGettext.text_domain = 'frontend'
150
212
  FastGettext.set_locale(params[:locale] || session[:locale] || request.env['HTTP_ACCEPT_LANGUAGE'])
151
213
  session[:locale] = I18n.locale = FastGettext.locale
@@ -155,6 +217,7 @@ class ApplicationController ...
155
217
 
156
218
  Advanced features
157
219
  =================
220
+
158
221
  ### Abnormal pluralisation
159
222
  Plurals are selected by index, think of it as `['car', 'cars'][index]`<br/>
160
223
  A pluralisation rule decides which form to use e.g. in english its `count == 1 ? 0 : 1`.<br/>
@@ -163,7 +226,7 @@ If you have any languages that do not fit this rule, you have to add a custom pl
163
226
  Via Ruby:
164
227
 
165
228
  ```Ruby
166
- FastGettext.pluralisation_rule = lambda{|count| count > 5 ? 1 : (count > 2 ? 0 : 2)}
229
+ FastGettext.pluralisation_rule = ->(count){ count > 5 ? 1 : (count > 2 ? 0 : 2)}
167
230
  ```
168
231
 
169
232
  Via mo/pofile:
@@ -179,7 +242,7 @@ If you only use one text domain, setting `FastGettext.default_text_domain = 'app
179
242
  is sufficient and no more `text_domain=` is needed
180
243
 
181
244
  ### default_locale
182
- If the simple rule of "first `availble_locale` or 'en'" is not suficcient for you, set `FastGettext.default_locale = 'de'`.
245
+ If the simple rule of "first `available_locale` or 'en'" is not sufficient for you, set `FastGettext.default_locale = 'de'`.
183
246
 
184
247
  ### default_available_locales
185
248
  Fallback when no available_locales are set
@@ -203,7 +266,7 @@ repos = [
203
266
  FastGettext::TranslationRepository.build('new', path: '....'),
204
267
  FastGettext::TranslationRepository.build('old', path: '....')
205
268
  ]
206
- FastGettext.add_text_domain 'combined', type: :chain, :chain: repos
269
+ FastGettext.add_text_domain 'combined', type: :chain, chain: repos
207
270
  ```
208
271
 
209
272
  ### Merge
@@ -213,8 +276,8 @@ a subordinate repository is added. This puts the burden on the load phase and sp
213
276
 
214
277
  ```Ruby
215
278
  repos = [
216
- FastGettext::TranslationRepository.build('new', :path: '....'),
217
- FastGettext::TranslationRepository.build('old', :path: '....')
279
+ FastGettext::TranslationRepository.build('new', path: '....'),
280
+ FastGettext::TranslationRepository.build('old', path: '....')
218
281
  ]
219
282
  domain = FastGettext.add_text_domain 'combined', type: :merge, chain: repos
220
283
  ```
@@ -232,7 +295,7 @@ When you want to know which keys could not be translated or were used, add a Log
232
295
  ```Ruby
233
296
  repos = [
234
297
  FastGettext::TranslationRepository.build('app', path: '....')
235
- FastGettext::TranslationRepository.build('logger', type: :logger, callback: lambda{|key_or_array_of_ids| ... }),
298
+ FastGettext::TranslationRepository.build('logger', type: :logger, callback: ->(key_or_array_of_ids) { ... }),
236
299
  }
237
300
  FastGettext.add_text_domain 'combined', type: :chain, chain: repos
238
301
  ```
@@ -246,7 +309,7 @@ Want a xml version ?
246
309
  Write your own TranslationRepository!
247
310
 
248
311
  ```Ruby
249
- # fast_gettext/translation_repository/xxx.rb
312
+ # fast_gettext/translation_repository/wtf.rb
250
313
  module FastGettext
251
314
  module TranslationRepository
252
315
  class Wtf
@@ -263,33 +326,65 @@ If you have more than one gettext domain, there are two sets of functions
263
326
  available:
264
327
 
265
328
  ```Ruby
266
- include FastGettext::TranslationMultidomain
329
+ extend FastGettext::TranslationMultidomain
267
330
 
268
331
  d_("domainname", "string") # finds 'string' in domain domainname
269
332
  dn_("domainname", "string", "strings", 1) # ditto
270
- # etc.
333
+ dp_("domainname", "context", "key")
334
+ ds_("domainname", "context|key")
335
+ dnp_("domainname", "context", "string", "strings")
336
+ dns_("domainname", "context|string", "strings")
271
337
  ```
272
338
 
273
339
  These are helper methods so you don't need to write:
274
340
 
275
341
  ```Ruby
276
- FastGettext.text_domain = "domainname"
277
- _("string")
342
+ FastGettext.with_domain("domainname") { _("string") }
278
343
  ```
279
344
 
280
345
  It is useful in Rails plugins in the views for example. The second set of
281
346
  functions are D functions which search for string in _all_ domains. If there
282
347
  are multiple translations in different domains, it returns them in random
283
- order (depends on the Ruby hash implementation):
348
+ order (depends on the Ruby hash implementation).
284
349
 
285
350
  ```Ruby
286
- include FastGettext::TranslationMultidomain
351
+ extend FastGettext::TranslationMultidomain
287
352
 
288
353
  D_("string") # finds 'string' in any domain
289
- # etc.
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 (includ 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
290
386
  ```
291
387
 
292
- Alternatively you can use [merge repository](https://github.com/grosser/fast_gettext#merge) to achieve the same behaviour.
293
388
 
294
389
  FAQ
295
390
  ===
@@ -297,13 +392,8 @@ FAQ
297
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)
298
393
 
299
394
 
300
- TODO
301
- ====
302
- - Add a fallback for Iconv.conv in ruby 1.9.4 -> lib/fast_gettext/vendor/iconv
303
- - YML backend that reads ActiveSupport::I18n files
304
-
305
- Author
306
- ======
395
+ Authors
396
+ =======
307
397
  Mo/Po-file parsing from Masao Mutoh, see vendor/README
308
398
 
309
399
  ### [Contributors](http://github.com/grosser/fast_gettext/contributors)
@@ -327,6 +417,7 @@ Mo/Po-file parsing from Masao Mutoh, see vendor/README
327
417
  - [Martin Meier](https://github.com/mameier)
328
418
  - [morcoteg](https://github.com/morcoteg)
329
419
  - [Daniel Schepers](https://github.com/tall-dan)
420
+ - [Robert Graff](https://github.com/rgraff)
330
421
 
331
422
  [Michael Grosser](http://grosser.it)<br/>
332
423
  michael@grosser.it<br/>
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fast_gettext/mo_file'
2
4
  require 'fast_gettext/storage'
3
5
  require 'fast_gettext/translation'
@@ -6,30 +8,28 @@ require 'fast_gettext/vendor/string'
6
8
  require 'fast_gettext/version'
7
9
 
8
10
  module FastGettext
9
- include FastGettext::Storage
10
- extend self
11
+ extend FastGettext::Storage
12
+ extend FastGettext::Translation
11
13
 
12
- LOCALE_REX = /^[a-z]{2,3}$|^[a-z]{2,3}_[A-Z]{2,3}$/
14
+ LOCALE_REX = /^[a-z]{2,3}$|^[a-z]{2,3}_[A-Z]{2,3}$/.freeze
13
15
  NAMESPACE_SEPARATOR = '|'
16
+ CONTEXT_SEPARATOR = "\004"
14
17
 
15
- # users should not include FastGettext, since this would contaminate their namespace
16
- # rather use
17
- # FastGettext.locale = ..
18
- # FastGettext.text_domain = ..
19
- # and
20
- # include FastGettext::Translation
21
- FastGettext::Translation.public_instance_methods.each do |method|
22
- define_method method do |*args|
23
- Translation.send(method,*args)
24
- end
18
+ # helper block for changing domains
19
+ def self.with_domain(domain)
20
+ old_domain = FastGettext.text_domain
21
+ FastGettext.text_domain = domain
22
+ yield
23
+ ensure
24
+ FastGettext.text_domain = old_domain
25
25
  end
26
26
 
27
- def add_text_domain(name,options)
28
- translation_repositories[name] = TranslationRepository.build(name,options)
27
+ def self.add_text_domain(name, options)
28
+ translation_repositories[name] = TranslationRepository.build(name, options)
29
29
  end
30
30
 
31
31
  # some repositories know where to store their locales
32
- def locale_path
32
+ def self.locale_path
33
33
  translation_repositories[text_domain].instance_variable_get(:@options)[:path]
34
34
  end
35
35
  end
@@ -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