grosser-fast_gettext 0.4.8 → 0.4.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +18 -14
- data/VERSION.yml +1 -1
- data/lib/fast_gettext/storage.rb +14 -4
- data/lib/fast_gettext/translation.rb +10 -16
- data/lib/fast_gettext/translation_repository/base.rb +2 -4
- data/lib/fast_gettext/translation_repository/chain.rb +2 -2
- data/lib/fast_gettext/translation_repository/logger.rb +2 -2
- data/spec/fast_gettext/storage_spec.rb +14 -6
- data/spec/fast_gettext/translation_repository/base_spec.rb +3 -2
- data/spec/fast_gettext/translation_spec.rb +19 -6
- data/vendor/string.rb +1 -1
- metadata +2 -2
data/README.markdown
CHANGED
@@ -6,6 +6,7 @@ It supports multiple backends (atm: .mo files, .po files, Database(ActiveRecor +
|
|
6
6
|
|
7
7
|
[Example Rails application](https://github.com/grosser/gettext_i18n_rails_example)
|
8
8
|
|
9
|
+
|
9
10
|
Setup
|
10
11
|
=====
|
11
12
|
### 1. Install
|
@@ -17,13 +18,14 @@ Or from source:
|
|
17
18
|
|
18
19
|
### 2. Add a translation repository
|
19
20
|
|
20
|
-
|
21
|
+
From mo files (traditional/default)
|
21
22
|
FastGettext.add_text_domain('my_app',:path=>'locale')
|
22
23
|
|
23
|
-
|
24
|
+
Or po files (less maintenacnce than mo)
|
24
25
|
FastGettext.add_text_domain('my_app',:path=>'locale', :type=>:po)
|
25
26
|
|
26
|
-
|
27
|
+
Or database (scaleable, great for many locales/translators)
|
28
|
+
require "fast_gettext/translation_repository/db"
|
27
29
|
include FastGettext::TranslationRepository::Db.require_models #load and include default models
|
28
30
|
FastGettext.add_text_domain('my_app', :type=>:db, :model=>TranslationKey)
|
29
31
|
|
@@ -40,13 +42,13 @@ Do this once in every Thread. (e.g. Rails -> ApplicationController)
|
|
40
42
|
s_('Namespace|no-found') == 'not-found'
|
41
43
|
n_('Axis','Axis',3) == 'Achsen' #German plural of Axis
|
42
44
|
|
45
|
+
|
43
46
|
Managing translations
|
44
47
|
============
|
45
48
|
### mo/po-files
|
46
49
|
Generate .po or .mo files using GetText parser (example tasks at [gettext_i18n_rails](http://github.com/grosser/gettext_i18n_rails))
|
47
50
|
|
48
|
-
Tell Gettext where your .mo or .po files lie
|
49
|
-
#e.g. for locale/de/my_app.po and locale/de/LC_MESSAGES/my_app.mo
|
51
|
+
Tell Gettext where your .mo or .po files lie, e.g. for locale/de/my_app.po and locale/de/LC_MESSAGES/my_app.mo
|
50
52
|
FastGettext.add_text_domain('my_app',:path=>'locale')
|
51
53
|
|
52
54
|
Use the [original GetText](http://github.com/mutoh/gettext) to create and manage po/mo-files.
|
@@ -62,6 +64,7 @@ If you want to use your own models, have a look at the [default models](http://g
|
|
62
64
|
|
63
65
|
To manage translations via a Web GUI, use a [Rails application and the translation_db_engine](http://github.com/grosser/translation_db_engine)
|
64
66
|
|
67
|
+
|
65
68
|
Performance
|
66
69
|
===========
|
67
70
|
50_000 translations speed / memory
|
@@ -82,6 +85,7 @@ small translation file <-> large translation file
|
|
82
85
|
ActiveSupport I18n::Backend::Simple :
|
83
86
|
21.770000s / 10100K <->
|
84
87
|
|
88
|
+
|
85
89
|
Rails
|
86
90
|
=======================
|
87
91
|
Try the [gettext_i18n_rails plugin](http://github.com/grosser/gettext_i18n_rails), it simplifies the setup.
|
@@ -106,6 +110,7 @@ since it runs in a different thread then e.g. controllers, so set them inside yo
|
|
106
110
|
session[:locale] = I18n.locale = FastGettext.set_locale(params[:locale] || session[:locale] || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en')
|
107
111
|
end
|
108
112
|
|
113
|
+
|
109
114
|
Advanced features
|
110
115
|
=================
|
111
116
|
###Abnormal pluralisation
|
@@ -121,7 +126,7 @@ If the simple rule of "first `availble_locale` or 'en'" is not suficcient for yo
|
|
121
126
|
|
122
127
|
###Chains
|
123
128
|
You can use any number of repositories to find a translation. Simply add them to a chain and when
|
124
|
-
the first cannot translate a given
|
129
|
+
the first cannot translate a given key, the next is asked and so forth.
|
125
130
|
repos = [
|
126
131
|
FastGettext::TranslationRepository.build('new', :path=>'....'),
|
127
132
|
FastGettext::TranslationRepository.build('old', :path=>'....')
|
@@ -132,11 +137,11 @@ the first cannot translate a given msgid, the next is asked and so forth.
|
|
132
137
|
When you want to know which keys could not be translated or were used, add a Logger to a Chain:
|
133
138
|
repos = [
|
134
139
|
FastGettext::TranslationRepository.build('app', :path=>'....')
|
135
|
-
FastGettext::TranslationRepository.build('logger', :type=>:logger, :callback=>lamda{|
|
140
|
+
FastGettext::TranslationRepository.build('logger', :type=>:logger, :callback=>lamda{|key_or_array_of_ids| ... }),
|
136
141
|
}
|
137
142
|
FastGettext.add_text_domain 'combined', :type=>:chain, :chain=>repos
|
138
143
|
If the Logger is in position #1 it will see all translations, if it is in position #2 it will only see the unfound.
|
139
|
-
Unfound may not always mean missing, if you chose not to translate a word because the
|
144
|
+
Unfound may not always mean missing, if you chose not to translate a word because the key is a good translation, it will appear nevertheless.
|
140
145
|
A lambda or anything that responds to `call` will do as callback. A good starting point may be `examples/missing_translations_logger.rb`.
|
141
146
|
|
142
147
|
###Plugins
|
@@ -146,23 +151,22 @@ Write your own TranslationRepository!
|
|
146
151
|
module FastGettext
|
147
152
|
module TranslationRepository
|
148
153
|
class Wtf
|
149
|
-
define initialize(name,options), [key], plural(*
|
154
|
+
define initialize(name,options), [key], plural(*keys) and
|
150
155
|
either inherit from TranslationRepository::Base or define available_locales and pluralisation_rule
|
151
156
|
end
|
152
157
|
end
|
153
158
|
end
|
154
159
|
|
160
|
+
|
155
161
|
FAQ
|
156
162
|
===
|
157
163
|
- [Problems with ActiveRecord messages?](http://wiki.github.com/grosser/fast_gettext/activerecord)
|
158
164
|
|
165
|
+
|
159
166
|
TODO
|
160
167
|
====
|
161
|
-
-
|
162
|
-
-
|
163
|
-
- some cleanup required, repositories should not have locale
|
164
|
-
- use `default_locale=(x)` internally, atm the default is available_locales.first || 'en'
|
165
|
-
- use `default_text_domain=(x)` internally, atm default is nil...
|
168
|
+
- YML backend that reads ActiveSupport::I18n files
|
169
|
+
- any ideas ? :D
|
166
170
|
|
167
171
|
Author
|
168
172
|
======
|
data/VERSION.yml
CHANGED
data/lib/fast_gettext/storage.rb
CHANGED
@@ -68,10 +68,20 @@ module FastGettext
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def key_exist?(key)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
71
|
+
!!(cached_find key)
|
72
|
+
end
|
73
|
+
|
74
|
+
def cached_find(key)
|
75
|
+
translation = current_cache[key]
|
76
|
+
return translation if translation or translation == false #found or was not found before
|
77
|
+
current_cache[key] = current_repository[key] || false
|
78
|
+
end
|
79
|
+
|
80
|
+
def cached_plural_find(*keys)
|
81
|
+
key = '||||' + keys * '||||'
|
82
|
+
translation = current_cache[key]
|
83
|
+
return translation if translation or translation == false #found or was not found before
|
84
|
+
current_cache[key] = current_repository.plural(*keys) || false
|
75
85
|
end
|
76
86
|
|
77
87
|
def locale
|
@@ -17,33 +17,27 @@ module FastGettext
|
|
17
17
|
klas.extend self
|
18
18
|
end
|
19
19
|
|
20
|
-
def _(
|
21
|
-
|
22
|
-
FastGettext.current_cache[translate] = FastGettext.current_repository[translate] || translate
|
20
|
+
def _(key)
|
21
|
+
FastGettext.cached_find(key) or key
|
23
22
|
end
|
24
23
|
|
25
24
|
#translate pluralized
|
26
25
|
# some languages have up to 4 plural forms...
|
27
26
|
# n_(singular, plural, plural form 2, ..., count)
|
28
27
|
# n_('apple','apples',3)
|
29
|
-
def n_(*
|
30
|
-
count =
|
31
|
-
|
32
|
-
|
33
|
-
translations = repo.plural(*msgids)
|
28
|
+
def n_(*keys)
|
29
|
+
count = keys.pop
|
30
|
+
translations = FastGettext.cached_plural_find *keys
|
34
31
|
selected = FastGettext.pluralisation_rule.call(count)
|
35
32
|
selected = selected ? 1 : 0 unless selected.is_a? Numeric #convert booleans to numbers
|
36
|
-
translations[selected] ||
|
33
|
+
translations[selected] || keys[selected] || keys.last
|
37
34
|
end
|
38
35
|
|
39
36
|
#translate, but discard namespace if nothing was found
|
40
37
|
# Car|Tire -> Tire if no translation could be found
|
41
38
|
def s_(key,seperator=nil)
|
42
|
-
|
43
|
-
|
44
|
-
else
|
45
|
-
key.split(seperator||NAMESPACE_SEPERATOR).last
|
46
|
-
end
|
39
|
+
translation = FastGettext.cached_find(key) and return translation
|
40
|
+
key.split(seperator||NAMESPACE_SEPERATOR).last
|
47
41
|
end
|
48
42
|
|
49
43
|
#tell gettext: this string need translation (will be found during parsing)
|
@@ -52,8 +46,8 @@ module FastGettext
|
|
52
46
|
end
|
53
47
|
|
54
48
|
#tell gettext: this string need translation (will be found during parsing)
|
55
|
-
def Nn_(*
|
56
|
-
|
49
|
+
def Nn_(*keys)
|
50
|
+
keys
|
57
51
|
end
|
58
52
|
end
|
59
53
|
end
|
@@ -4,8 +4,6 @@ module FastGettext
|
|
4
4
|
# - base for all repositories
|
5
5
|
# - fallback as empty repository, that cannot translate anything but does not crash
|
6
6
|
class Base
|
7
|
-
attr_accessor :locale
|
8
|
-
|
9
7
|
def initialize(name,options={})
|
10
8
|
@name = name
|
11
9
|
@options = options
|
@@ -23,8 +21,8 @@ module FastGettext
|
|
23
21
|
current_translations[key]
|
24
22
|
end
|
25
23
|
|
26
|
-
def plural(*
|
27
|
-
current_translations.plural(*
|
24
|
+
def plural(*keys)
|
25
|
+
current_translations.plural(*keys)
|
28
26
|
end
|
29
27
|
|
30
28
|
protected
|
@@ -180,7 +180,10 @@ describe 'Storage' do
|
|
180
180
|
FastGettext.text_domain = 'xxx'
|
181
181
|
FastGettext.available_locales = ['de','en']
|
182
182
|
FastGettext.locale = 'de'
|
183
|
+
FastGettext.current_repository.stub!(:"[]").with('abc').and_return 'old'
|
184
|
+
FastGettext.current_repository.stub!(:"[]").with('unfound').and_return nil
|
183
185
|
FastGettext._('abc')
|
186
|
+
FastGettext._('unfound')
|
184
187
|
FastGettext.locale = 'en'
|
185
188
|
end
|
186
189
|
|
@@ -198,19 +201,24 @@ describe 'Storage' do
|
|
198
201
|
FastGettext.locale = 'de'
|
199
202
|
FastGettext.text_domain = nil
|
200
203
|
FastGettext.default_text_domain = 'xxx'
|
201
|
-
FastGettext.current_cache['abc'].should == '
|
204
|
+
FastGettext.current_cache['abc'].should == 'old'
|
202
205
|
end
|
203
206
|
|
204
207
|
it "cache is restored through setting of default_locale" do
|
205
208
|
FastGettext.send(:_locale=,nil)#reset locale to nil
|
206
209
|
FastGettext.default_locale = 'de'
|
207
210
|
FastGettext.locale.should == 'de'
|
208
|
-
FastGettext.current_cache['abc'].should == '
|
211
|
+
FastGettext.current_cache['abc'].should == 'old'
|
209
212
|
end
|
210
213
|
|
211
214
|
it "stores a translation permanently" do
|
212
215
|
FastGettext.locale = 'de'
|
213
|
-
FastGettext.current_cache['abc'].should == '
|
216
|
+
FastGettext.current_cache['abc'].should == 'old'
|
217
|
+
end
|
218
|
+
|
219
|
+
it "stores a unfound translation permanently" do
|
220
|
+
FastGettext.locale = 'de'
|
221
|
+
FastGettext.current_cache['unfound'].should == false
|
214
222
|
end
|
215
223
|
end
|
216
224
|
|
@@ -221,8 +229,8 @@ describe 'Storage' do
|
|
221
229
|
end
|
222
230
|
|
223
231
|
it "finds using the current repository" do
|
224
|
-
should_receive(:current_repository).and_return '
|
225
|
-
key_exist?('
|
232
|
+
should_receive(:current_repository).and_return '1234'=>'1'
|
233
|
+
key_exist?('1234').should == true
|
226
234
|
end
|
227
235
|
|
228
236
|
it "sets the current cache with a found result" do
|
@@ -233,7 +241,7 @@ describe 'Storage' do
|
|
233
241
|
|
234
242
|
it "does not overwrite an existing cache value" do
|
235
243
|
current_cache['xxx']='xxx'
|
236
|
-
|
244
|
+
stub!(:current_repository).and_return 'xxx'=>'1'
|
237
245
|
key_exist?('xxx')
|
238
246
|
current_cache['xxx'].should == 'xxx'
|
239
247
|
end
|
@@ -6,15 +6,16 @@ describe 'FastGettext::TranslationRepository::Base' do
|
|
6
6
|
before do
|
7
7
|
@rep = FastGettext::TranslationRepository::Base.new('x')
|
8
8
|
end
|
9
|
+
|
9
10
|
it "can be built" do
|
10
11
|
@rep.available_locales.should == []
|
11
12
|
end
|
13
|
+
|
12
14
|
it "cannot translate" do
|
13
|
-
@rep.locale = 'de'
|
14
15
|
@rep['car'].should == nil
|
15
16
|
end
|
17
|
+
|
16
18
|
it "cannot pluralize" do
|
17
|
-
@rep.locale = 'de'
|
18
19
|
@rep.plural('Axis','Axis').should == ['Axis','Axis']
|
19
20
|
end
|
20
21
|
end
|
@@ -27,7 +27,7 @@ describe FastGettext::Translation do
|
|
27
27
|
it "translates simple text" do
|
28
28
|
_('car').should == 'Auto'
|
29
29
|
end
|
30
|
-
it "returns
|
30
|
+
it "returns key if not translation was found" do
|
31
31
|
_('NOT|FOUND').should == 'NOT|FOUND'
|
32
32
|
end
|
33
33
|
end
|
@@ -60,12 +60,12 @@ describe FastGettext::Translation do
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
it "returns the appropriate
|
63
|
+
it "returns the appropriate key if no translation was found" do
|
64
64
|
n_('NOTFOUND','NOTFOUNDs',1).should == 'NOTFOUND'
|
65
65
|
n_('NOTFOUND','NOTFOUNDs',2).should == 'NOTFOUNDs'
|
66
66
|
end
|
67
67
|
|
68
|
-
it "returns the last
|
68
|
+
it "returns the last key when no translation was found and keys where to short" do
|
69
69
|
FastGettext.pluralisation_rule = lambda{|x|4}
|
70
70
|
n_('Apple','Apples',2).should == 'Apples'
|
71
71
|
end
|
@@ -75,7 +75,7 @@ describe FastGettext::Translation do
|
|
75
75
|
it "translates simple text" do
|
76
76
|
_('car').should == 'Auto'
|
77
77
|
end
|
78
|
-
it "returns cleaned
|
78
|
+
it "returns cleaned key if a translation was not found" do
|
79
79
|
s_("XXX|not found").should == "not found"
|
80
80
|
end
|
81
81
|
it "can use a custom seperator" do
|
@@ -84,13 +84,13 @@ describe FastGettext::Translation do
|
|
84
84
|
end
|
85
85
|
|
86
86
|
describe :N_ do
|
87
|
-
it "returns the
|
87
|
+
it "returns the key" do
|
88
88
|
N_('XXXXX').should == 'XXXXX'
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
92
|
describe :Nn_ do
|
93
|
-
it "returns the
|
93
|
+
it "returns the keys as array" do
|
94
94
|
Nn_('X','Y').should == ['X','Y']
|
95
95
|
end
|
96
96
|
end
|
@@ -99,7 +99,12 @@ describe FastGettext::Translation do
|
|
99
99
|
describe :cache_hit do
|
100
100
|
before do
|
101
101
|
FastGettext.translation_repositories.replace({})
|
102
|
+
#singular cache keys
|
102
103
|
current_cache['xxx'] = '1'
|
104
|
+
|
105
|
+
#plural cache keys
|
106
|
+
current_cache['||||xxx'] = ['1','2']
|
107
|
+
current_cache['||||xxx||||yyy'] = ['1','2']
|
103
108
|
end
|
104
109
|
|
105
110
|
it "uses the cache when translating with _" do
|
@@ -109,6 +114,14 @@ describe FastGettext::Translation do
|
|
109
114
|
it "uses the cache when translating with s_" do
|
110
115
|
s_('xxx').should == '1'
|
111
116
|
end
|
117
|
+
|
118
|
+
it "uses the cache when translating with n_" do
|
119
|
+
n_('xxx','yyy',1).should == '1'
|
120
|
+
end
|
121
|
+
|
122
|
+
it "uses the cache when translating with n_ and single argument" do
|
123
|
+
n_('xxx',1).should == '1'
|
124
|
+
end
|
112
125
|
end
|
113
126
|
|
114
127
|
it "caches different locales seperatly" do
|
data/vendor/string.rb
CHANGED
@@ -30,7 +30,7 @@ rescue ArgumentError
|
|
30
30
|
# with field type such as d(decimal), f(float), ...
|
31
31
|
# "%<age>d, %<weight>.1f" % {:age => 10, :weight => 43.4} == "10 43.4"
|
32
32
|
# This is the recommanded way for Ruby-GetText
|
33
|
-
# because the translators can understand the meanings of the
|
33
|
+
# because the translators can understand the meanings of the keys easily.
|
34
34
|
def %(args)
|
35
35
|
if args.kind_of? Hash
|
36
36
|
ret = dup
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grosser-fast_gettext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Grosser
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-05-
|
12
|
+
date: 2009-05-15 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|