grosser-fast_gettext 0.4.7 → 0.4.8
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +32 -29
- data/VERSION.yml +1 -1
- data/lib/fast_gettext/storage.rb +8 -1
- data/lib/fast_gettext/translation.rb +3 -3
- data/spec/fast_gettext/storage_spec.rb +25 -0
- data/spec/fast_gettext/translation_spec.rb +15 -0
- data/spec/vendor/string_spec.rb +16 -4
- data/vendor/string.rb +17 -11
- metadata +2 -2
data/README.markdown
CHANGED
@@ -2,57 +2,66 @@ FastGettext
|
|
2
2
|
===========
|
3
3
|
GetText but 3.5 x faster, 560 x less memory, simple, clean namespace (7 vs 34) and threadsave!
|
4
4
|
|
5
|
-
It supports multiple backends (atm: .mo files, .po files,
|
5
|
+
It supports multiple backends (atm: .mo files, .po files, Database(ActiveRecor + 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
|
Setup
|
10
10
|
=====
|
11
|
+
### 1. Install
|
11
12
|
sudo gem install grosser-fast_gettext -s http://gems.github.com/
|
12
13
|
|
13
14
|
Or from source:
|
14
15
|
git clone git://github.com/grosser/fast_gettext.git
|
15
16
|
cd fast_gettext && rake install
|
16
17
|
|
17
|
-
|
18
|
+
### 2. Add a translation repository
|
19
|
+
|
20
|
+
#### From mo files (traditional/default)
|
21
|
+
FastGettext.add_text_domain('my_app',:path=>'locale')
|
22
|
+
|
23
|
+
#### po files (less maintenacnce than mo)
|
24
|
+
FastGettext.add_text_domain('my_app',:path=>'locale', :type=>:po)
|
25
|
+
|
26
|
+
#### Database (odern/scaleable)
|
27
|
+
include FastGettext::TranslationRepository::Db.require_models #load and include default models
|
28
|
+
FastGettext.add_text_domain('my_app', :type=>:db, :model=>TranslationKey)
|
29
|
+
|
30
|
+
### 3. Choose text domain and locale for translation
|
31
|
+
Do this once in every Thread. (e.g. Rails -> ApplicationController)
|
18
32
|
FastGettext.text_domain = 'my_app'
|
19
33
|
FastGettext.available_locales = ['de','en','fr','en_US','en_UK'] # only allow these locales to be set (optional)
|
20
34
|
FastGettext.locale = 'de'
|
21
35
|
|
22
|
-
Start translating
|
36
|
+
### 4. Start translating
|
23
37
|
include FastGettext::Translation
|
24
38
|
_('Car') == 'Auto'
|
25
39
|
_('not-found') == 'not-found'
|
26
40
|
s_('Namespace|no-found') == 'not-found'
|
27
41
|
n_('Axis','Axis',3) == 'Achsen' #German plural of Axis
|
28
42
|
|
29
|
-
|
30
|
-
FastGettext.silence_errors
|
31
|
-
|
32
|
-
Translations
|
43
|
+
Managing translations
|
33
44
|
============
|
34
|
-
###
|
45
|
+
### mo/po-files
|
35
46
|
Generate .po or .mo files using GetText parser (example tasks at [gettext_i18n_rails](http://github.com/grosser/gettext_i18n_rails))
|
36
47
|
|
37
48
|
Tell Gettext where your .mo or .po files lie:
|
38
49
|
#e.g. for locale/de/my_app.po and locale/de/LC_MESSAGES/my_app.mo
|
39
|
-
#add :type=>:po and it will read directly from po files (not recommended for production since po-parsing can crash!)
|
40
50
|
FastGettext.add_text_domain('my_app',:path=>'locale')
|
41
51
|
|
42
|
-
|
43
|
-
|
52
|
+
Use the [original GetText](http://github.com/mutoh/gettext) to create and manage po/mo-files.
|
53
|
+
(Work on a po/mo parser & reader that is easier to use has started, contributions welcome @ [pomo](http://github.com/grosser/pomo) )
|
44
54
|
|
45
55
|
###Database
|
46
56
|
!!!new/only short time in production, please report back any ideas/suggestions you have!!!
|
47
|
-
Easy to maintain especially with many translations and multiple locales.
|
48
57
|
[Example migration for ActiveRecord](http://github.com/grosser/fast_gettext/blob/master/examples/db/migration.rb)
|
49
|
-
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.
|
50
58
|
The default plural seperator is `||||` but you may overwrite it (or suggest a better one..).
|
51
|
-
include FastGettext::TranslationRepository::Db.require_models #load and include default models
|
52
|
-
FastGettext.add_text_domain('my_app', :type=>:db, :model=>TranslationKey)
|
53
59
|
|
60
|
+
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.
|
54
61
|
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.
|
55
62
|
|
63
|
+
To manage translations via a Web GUI, use a [Rails application and the translation_db_engine](http://github.com/grosser/translation_db_engine)
|
64
|
+
|
56
65
|
Performance
|
57
66
|
===========
|
58
67
|
50_000 translations speed / memory
|
@@ -73,18 +82,16 @@ small translation file <-> large translation file
|
|
73
82
|
ActiveSupport I18n::Backend::Simple :
|
74
83
|
21.770000s / 10100K <->
|
75
84
|
|
76
|
-
|
85
|
+
Rails
|
77
86
|
=======================
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
###Rails
|
82
|
-
Try the [gettext_i18n_rails plugin](http://github.com/grosser/gettext_i18n_rails), it simplifies the setup.
|
87
|
+
Try the [gettext_i18n_rails plugin](http://github.com/grosser/gettext_i18n_rails), it simplifies the setup.
|
88
|
+
Try the [translation_db_engine](http://github.com/grosser/translation_db_engine), to manage your translations in a db.
|
83
89
|
|
84
|
-
Setting `available_locales`,`text_domain` or `locale` will not work inside the `evironment.rb`,
|
85
|
-
then e.g. controllers, so set them inside your application_controller.
|
90
|
+
Setting `available_locales`,`text_domain` or `locale` will not work inside the `evironment.rb`,
|
91
|
+
since it runs in a different thread then e.g. controllers, so set them inside your application_controller.
|
86
92
|
|
87
93
|
#environment.rb after initializers
|
94
|
+
Object.send(:include,FastGettext::Translation)
|
88
95
|
FastGettext.add_text_domain('accounting',:path=>'locale')
|
89
96
|
FastGettext.add_text_domain('frontend',:path=>'locale')
|
90
97
|
...
|
@@ -99,11 +106,6 @@ then e.g. controllers, so set them inside your application_controller.
|
|
99
106
|
session[:locale] = I18n.locale = FastGettext.set_locale(params[:locale] || session[:locale] || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en')
|
100
107
|
end
|
101
108
|
|
102
|
-
#application_helper.rb
|
103
|
-
module ApplicationHelper
|
104
|
-
include FastGettext::Translation
|
105
|
-
...
|
106
|
-
|
107
109
|
Advanced features
|
108
110
|
=================
|
109
111
|
###Abnormal pluralisation
|
@@ -156,8 +158,9 @@ FAQ
|
|
156
158
|
|
157
159
|
TODO
|
158
160
|
====
|
161
|
+
- add caching to untranslateable calls
|
162
|
+
- break with gettext naming-tradition, convert msgid => key, msgstr => translation
|
159
163
|
- some cleanup required, repositories should not have locale
|
160
|
-
- DbModel::TranslationKey responds_to? :available_locales should be false when it is not defined, maybe testing bug
|
161
164
|
- use `default_locale=(x)` internally, atm the default is available_locales.first || 'en'
|
162
165
|
- use `default_text_domain=(x)` internally, atm default is nil...
|
163
166
|
|
data/VERSION.yml
CHANGED
data/lib/fast_gettext/storage.rb
CHANGED
@@ -6,7 +6,7 @@ module FastGettext
|
|
6
6
|
module Storage
|
7
7
|
class NoTextDomainConfigured < RuntimeError
|
8
8
|
def to_s
|
9
|
-
"Current textdomain (#{FastGettext.text_domain.inspect}) was not added, use FastGettext.add_text_domain!"
|
9
|
+
"Current textdomain (#{FastGettext.text_domain.inspect}) was not added, use FastGettext.add_text_domain !"
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -67,6 +67,13 @@ module FastGettext
|
|
67
67
|
translation_repositories[text_domain] || raise(NoTextDomainConfigured)
|
68
68
|
end
|
69
69
|
|
70
|
+
def key_exist?(key)
|
71
|
+
false
|
72
|
+
translation = current_repository[key]
|
73
|
+
current_cache[key] ||= translation
|
74
|
+
!!translation
|
75
|
+
end
|
76
|
+
|
70
77
|
def locale
|
71
78
|
_locale || ( default_locale || (available_locales||[]).first || 'en' )
|
72
79
|
end
|
@@ -38,11 +38,11 @@ module FastGettext
|
|
38
38
|
|
39
39
|
#translate, but discard namespace if nothing was found
|
40
40
|
# Car|Tire -> Tire if no translation could be found
|
41
|
-
def s_(
|
42
|
-
if translation = FastGettext.current_repository[
|
41
|
+
def s_(key,seperator=nil)
|
42
|
+
if translation = FastGettext.current_cache[key] || FastGettext.current_repository[key]
|
43
43
|
translation
|
44
44
|
else
|
45
|
-
|
45
|
+
key.split(seperator||NAMESPACE_SEPERATOR).last
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -214,6 +214,31 @@ describe 'Storage' do
|
|
214
214
|
end
|
215
215
|
end
|
216
216
|
|
217
|
+
describe :key_exist? do
|
218
|
+
it "does not find default keys" do
|
219
|
+
_('abcde')
|
220
|
+
key_exist?('abcde').should be_false
|
221
|
+
end
|
222
|
+
|
223
|
+
it "finds using the current repository" do
|
224
|
+
should_receive(:current_repository).and_return 'xxx'=>'1'
|
225
|
+
key_exist?('xxx').should == true
|
226
|
+
end
|
227
|
+
|
228
|
+
it "sets the current cache with a found result" do
|
229
|
+
should_receive(:current_repository).and_return 'xxx'=>'1'
|
230
|
+
key_exist?('xxx')
|
231
|
+
current_cache['xxx'].should == '1'
|
232
|
+
end
|
233
|
+
|
234
|
+
it "does not overwrite an existing cache value" do
|
235
|
+
current_cache['xxx']='xxx'
|
236
|
+
should_receive(:current_repository).and_return 'xxx'=>'1'
|
237
|
+
key_exist?('xxx')
|
238
|
+
current_cache['xxx'].should == 'xxx'
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
217
242
|
describe NoTextDomainConfigured do
|
218
243
|
it "shows what to do" do
|
219
244
|
NoTextDomainConfigured.new.to_s.should =~ /FastGettext\.add_text_domain/
|
@@ -96,6 +96,21 @@ describe FastGettext::Translation do
|
|
96
96
|
end
|
97
97
|
|
98
98
|
describe :caching do
|
99
|
+
describe :cache_hit do
|
100
|
+
before do
|
101
|
+
FastGettext.translation_repositories.replace({})
|
102
|
+
current_cache['xxx'] = '1'
|
103
|
+
end
|
104
|
+
|
105
|
+
it "uses the cache when translating with _" do
|
106
|
+
_('xxx').should == '1'
|
107
|
+
end
|
108
|
+
|
109
|
+
it "uses the cache when translating with s_" do
|
110
|
+
s_('xxx').should == '1'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
99
114
|
it "caches different locales seperatly" do
|
100
115
|
FastGettext.locale = 'en'
|
101
116
|
_('car').should == 'car'
|
data/spec/vendor/string_spec.rb
CHANGED
@@ -3,8 +3,18 @@ require File.join(current_folder,'..','spec_helper')
|
|
3
3
|
|
4
4
|
#just to make sure we did not mess up while copying...
|
5
5
|
describe String do
|
6
|
-
it "
|
7
|
-
"
|
6
|
+
it "does not translate twice" do
|
7
|
+
("%{a} %{b}" % {:a=>'%{b}',:b=>'c'}).should == '%{b} c'
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "old % style replacement" do
|
11
|
+
it "substitudes using % + Hash" do
|
12
|
+
"x%{name}y" %{:name=>'a'}.should == 'xay'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "does not substitute after %%" do
|
16
|
+
("%%{num} oops" % {:num => 1}).should == '%{num} oops'
|
17
|
+
end
|
8
18
|
end
|
9
19
|
|
10
20
|
describe 'old sprintf style' do
|
@@ -22,6 +32,10 @@ describe String do
|
|
22
32
|
end
|
23
33
|
|
24
34
|
describe 'ruby 1.9 style %< replacement' do
|
35
|
+
it "does not substitute after %%" do
|
36
|
+
("%%<num> oops" % {:num => 1}).should == '%<num> oops'
|
37
|
+
end
|
38
|
+
|
25
39
|
it "subsitutes %<something>d" do
|
26
40
|
("x%<hello>dy" % {:hello=>1}).should == 'x1y'
|
27
41
|
end
|
@@ -29,7 +43,5 @@ describe String do
|
|
29
43
|
it "substitutes #b" do
|
30
44
|
("%<num>#b" % {:num => 1}).should == "0b1"
|
31
45
|
end
|
32
|
-
|
33
|
-
|
34
46
|
end
|
35
47
|
end
|
data/vendor/string.rb
CHANGED
@@ -15,6 +15,12 @@ rescue ArgumentError
|
|
15
15
|
class String
|
16
16
|
alias :_fast_gettext_old_format_m :% # :nodoc:
|
17
17
|
|
18
|
+
PERCENT_MATCH_RE = Regexp.union(
|
19
|
+
/%%/,
|
20
|
+
/%\{(\w+)\}/,
|
21
|
+
/%<(\w+)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/
|
22
|
+
)
|
23
|
+
|
18
24
|
# call-seq:
|
19
25
|
# %(hash)
|
20
26
|
#
|
@@ -28,17 +34,17 @@ rescue ArgumentError
|
|
28
34
|
def %(args)
|
29
35
|
if args.kind_of? Hash
|
30
36
|
ret = dup
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
ret.gsub!(PERCENT_MATCH_RE) do |match|
|
38
|
+
if match == '%%'
|
39
|
+
'%'
|
40
|
+
elsif $1
|
41
|
+
key = $1.to_sym
|
42
|
+
args.has_key?(key) ? args[key] : match
|
43
|
+
elsif $2
|
44
|
+
key = $2.to_sym
|
45
|
+
args.has_key?(key) ? sprintf("%#{$3}", args[key]) : match
|
46
|
+
end
|
47
|
+
end
|
42
48
|
else
|
43
49
|
ret = gsub(/%([{<])/, '%%\1')
|
44
50
|
ret._fast_gettext_old_format_m(args)
|
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.8
|
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-10 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|