grosser-fast_gettext 0.4.7 → 0.4.8

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.
@@ -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