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.
@@ -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, ActiveRecord, Chain) and can easily be extended.
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
- Choose text domain and locale for translation
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
- Disable translation errors(like no text domain setup) while doing e.g. console session / testing
30
- FastGettext.silence_errors
31
-
32
- Translations
43
+ Managing translations
33
44
  ============
34
- ### Default: .mo-files
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
- ATM you have to use the [original GetText](http://github.com/mutoh/gettext) to create and manage your po/mo-files.
43
- I already started work on a po/mo parser & reader that is easier to use, contributions welcome @ [pomo](http://github.com/grosser/pomo)
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
- Thread Safety and Rails
85
+ Rails
77
86
  =======================
78
- Parsed `text_domains` are not stored thread-save, so that they can be added inside the `environment.rb`,
79
- and do not need to be readded for every thread (parsing takes time...).
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`, since it runs in a different thread
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
 
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 4
4
- :patch: 7
4
+ :patch: 8
@@ -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_(translate,seperator=nil)
42
- if translation = FastGettext.current_repository[translate]
41
+ def s_(key,seperator=nil)
42
+ if translation = FastGettext.current_cache[key] || FastGettext.current_repository[key]
43
43
  translation
44
44
  else
45
- translate.split(seperator||NAMESPACE_SEPERATOR).last
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'
@@ -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 "substitudes using % + Hash" do
7
- "x%{name}y" %{:name=>'a'}.should == 'xay'
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
@@ -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
- # %{something} type
32
- args.each {|key, value| ret.gsub!(/\%\{#{key}\}/, value.to_s)}
33
-
34
- # %<..>d type
35
- args.each {|key, value|
36
- ret.gsub!(/\%<#{key}>([ #\+-0\*]?\d*\.?\d*[bBdiouxXeEfgGcps])/){
37
- sprintf("%#{$1}", value)
38
- }
39
- }
40
- ret.gsub(/%%/, "%")
41
- ret
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.7
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-01 00:00:00 -07:00
12
+ date: 2009-05-10 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15