grosser-fast_gettext 0.1.0

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.
@@ -0,0 +1,61 @@
1
+ FastGettext
2
+ ===========
3
+ GetText but fast + simple + threadsave!
4
+
5
+ Setup
6
+ =====
7
+ sudo gem install grosser-fast_gettext -s http://gems.github.com/
8
+
9
+ Tell Gettext where your mo-files lie:
10
+ #e.g. for locale/de/LC_MESSAGES/my_app.mo
11
+ FastGettext.add_text_domain('my_app',:path=>'locale')
12
+
13
+ Choose text domain, and locale for translation
14
+ FastGettext.text_domain = 'my_app'
15
+ FastGettext.locale = 'de'
16
+
17
+ Start translating
18
+ include FastGettext
19
+ _('Car') == 'Auto'
20
+ _('not-found') == 'not-found'
21
+ s_('Namespace|no-found') == 'not-found'
22
+ n_('Axis','Axis',3) == 'Achsen' #German plural of Axis
23
+
24
+ Thread-safety
25
+ =============
26
+ locale/text_domain/available_locales are not shared between threads.
27
+ But text_domains is, so that found translations can be reused.
28
+
29
+ Speed
30
+ =====
31
+ FastGettext
32
+ small:
33
+ 1.000000 0.130000 1.130000 ( 1.132578)
34
+ mapped: 8620K writeable/private: 5588K shared: 28K
35
+
36
+ large:
37
+ 1.060000 0.100000 1.160000 ( 1.163962)
38
+ mapped: 8620K writeable/private: 5588K shared: 28K
39
+
40
+
41
+ GetText
42
+ small:
43
+ 3.220000 0.260000 3.480000 ( 3.478093)
44
+ mapped: 9036K writeable/private: 6004K shared: 28K
45
+
46
+ large:
47
+ 3.280000 0.230000 3.510000 ( 3.511891)
48
+ mapped: 9156K writeable/private: 6124K shared: 28K
49
+
50
+
51
+ Updating translations
52
+ =====================
53
+ ATM you have to use the [original GetText](http://github.com/mutoh/gettext) to create and manage your po/mo-files.
54
+
55
+ Author
56
+ ======
57
+ Mofile parsing from Masao Mutoh, see vender/README
58
+
59
+ Michael Grosser
60
+ grosser.michael@gmail.com
61
+ Hereby placed under public domain, do what you want, just do not hold me accountable...
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 1
3
+ :patch: 0
4
+ :major: 0
@@ -0,0 +1,59 @@
1
+ require 'fast_gettext/mo_file'
2
+ require 'fast_gettext/storage'
3
+
4
+ module FastGettext
5
+ include FastGettext::Storage
6
+
7
+ extend self
8
+ def self.included(mod) #:nodoc:
9
+ mod.extend self
10
+ end
11
+
12
+ LOCALE_REX = /^[a-z]{2}$|^[a-z]{2}_[A-Z]{2}$/
13
+ NAMESPACE_SEPERATOR = '|'
14
+
15
+ def _(translate)
16
+ current_mo[translate] || translate
17
+ end
18
+
19
+ #translate pluralized
20
+ def n_(singular,plural,count)
21
+ if translation = current_mo.plural(singular,plural,count)
22
+ translation
23
+ else
24
+ count > 1 ? plural : singular
25
+ end
26
+ end
27
+
28
+ #translate, but discard namespace if nothing was found
29
+ # Car|Tire -> Tire if no translation could be found
30
+ def s_(translate,seperator=nil)
31
+ if translation = current_mo[translate]
32
+ translation
33
+ else
34
+ translate.split(seperator||NAMESPACE_SEPERATOR).last
35
+ end
36
+ end
37
+
38
+ def add_text_domain(name,options)
39
+ self.text_domains ||= {}
40
+ domain = self.text_domains[name] = {:path=>options.delete(:path),:mo_files=>{}}
41
+
42
+ # parse all .mo files with the right name, that sit in locale/LC_MESSAGES folders
43
+ Dir[File.join(domain[:path],'*')].each do |locale_folder|
44
+ next unless File.basename(locale_folder) =~ LOCALE_REX
45
+ mo_file = File.join(locale_folder,'LC_MESSAGES',"#{name}.mo")
46
+ next unless File.exist? mo_file
47
+ locale = File.basename(locale_folder)
48
+ domain[:mo_files][locale] = MoFile.new(mo_file)
49
+ end
50
+ domain
51
+ end
52
+
53
+ private
54
+
55
+ def current_mo
56
+ mo = text_domains[text_domain][:mo_files][locale] rescue nil
57
+ mo || {}
58
+ end
59
+ end
@@ -0,0 +1,48 @@
1
+ require File.join(File.dirname(__FILE__),'..','..','vendor','mofile')
2
+ module FastGettext
3
+ class MoFile
4
+ PLURAL_SEPERATOR = "\000"
5
+
6
+ def initialize(file)
7
+ @data = GetText::MOFile.open(file, "UTF-8")
8
+ make_singular_and_plural_available
9
+ end
10
+
11
+ def [](key)
12
+ @data[key]
13
+ end
14
+
15
+ def plural(singular,plural,count)
16
+ translations = plural_translations(singular,plural)
17
+
18
+ if count > 1
19
+ translations[1] || self[plural]
20
+ else
21
+ translations[0] || self[singular]
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ #(if plural==singular, prefer singular)
28
+ def make_singular_and_plural_available
29
+ @data.each do |key,translation|
30
+ next unless key.include? PLURAL_SEPERATOR
31
+ singular, plural = split_plurals(key)
32
+ translation = split_plurals(translation)
33
+ @data[singular] ||= translation[0]
34
+ @data[plural] ||= translation[1]
35
+ end
36
+ end
37
+
38
+ def split_plurals(singular_plural)
39
+ singular_plural.split(PLURAL_SEPERATOR,2)
40
+ end
41
+
42
+ # Car, Cars => [Auto,Autos] or []
43
+ def plural_translations(singular,plural)
44
+ plurals = self[singular+PLURAL_SEPERATOR+plural]
45
+ if plurals then split_plurals(plurals) else [] end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ module FastGettext
2
+ module Storage
3
+ [:locale,:text_domain,:available_locales].each do |method|
4
+ key = "FastGettext.#{method}"
5
+ define_method method do
6
+ Thread.current[key]
7
+ end
8
+ define_method "#{method}=" do |value|
9
+ Thread.current[key] = value
10
+ end
11
+ end
12
+
13
+ #NOT THREADSAFE, for speed/caching
14
+ @@text_domains = {}
15
+
16
+ def text_domains
17
+ @@text_domains
18
+ end
19
+
20
+ def text_domains=(value)
21
+ @@text_domains=value
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ current_folder = File.dirname(__FILE__)
2
+ require File.join(current_folder,'..','spec_helper')
3
+
4
+ include FastGettext
5
+ de_file = File.join(current_folder,'..','locale','de','LC_MESSAGES','test.mo')
6
+ de = MoFile.new(de_file)
7
+
8
+ describe MoFile do
9
+ before :all do
10
+ File.exist?(de_file).should == true
11
+ end
12
+ it "parses a file" do
13
+ de['car'].should == 'Auto'
14
+ end
15
+ it "stores untranslated values as nil" do
16
+ de['Car|Model'].should == nil
17
+ end
18
+ it "finds pluralized values" do
19
+ de.plural('Axis','Axis',1).should == 'Achse' #singular
20
+ de.plural('Axis','Axis',2).should == 'Achsen' #plurals
21
+ end
22
+ it "can access plurals through []" do
23
+ de['Axis'].should == 'Achse' #singular
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ current_folder = File.dirname(__FILE__)
2
+ require File.join(current_folder,'..','spec_helper')
3
+
4
+ include FastGettext::Storage
5
+
6
+ describe Storage do
7
+ def thread_save(method)
8
+ send("#{method}=",1)
9
+
10
+ # mess around with other threads
11
+ threads = []
12
+ 100.times do |i|
13
+ threads << Thread.new {send("#{method}=",i)}
14
+ end
15
+ threads.each(&:join)
16
+
17
+ send(method) == 1
18
+ end
19
+
20
+ [:locale, :available_locales, :text_domain].each do |method|
21
+ it "stores #{method} thread-save" do
22
+ thread_save(:locale).should == true
23
+ end
24
+ end
25
+
26
+ it "does not store text_domains thread-save" do
27
+ thread_save(:text_domains).should == false
28
+ end
29
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path("spec_helper", File.dirname(__FILE__))
2
+
3
+ include FastGettext
4
+ FastGettext.add_text_domain('test',:path=>File.join(File.dirname(__FILE__),'locale'))
5
+ FastGettext.text_domain = 'test'
6
+ FastGettext.available_locales = ['en','de']
7
+ FastGettext.locale = 'de'
8
+
9
+ include FastGettext
10
+
11
+ describe FastGettext do
12
+ describe :_ do
13
+ it "translates simple text" do
14
+ _('car').should == 'Auto'
15
+ end
16
+ it "returns msgid if not translation was found" do
17
+ _('NOT|FOUND').should == 'NOT|FOUND'
18
+ end
19
+ end
20
+
21
+ describe :n_ do
22
+ it "translates pluralized" do
23
+ n_('Axis','Axis',1).should == 'Achse'
24
+ n_('Axis','Axis',2).should == 'Achsen'
25
+ end
26
+ it "returns the appropriate msgid if no translation was found" do
27
+ n_('NOTFOUND','NOTFOUNDs',1).should == 'NOTFOUND'
28
+ n_('NOTFOUND','NOTFOUNDs',2).should == 'NOTFOUNDs'
29
+ end
30
+ end
31
+
32
+ describe :s_ do
33
+ it "translates simple text" do
34
+ _('car').should == 'Auto'
35
+ end
36
+ it "returns cleaned msgid if a translation was not found" do
37
+ s_("XXX|not found").should == "not found"
38
+ end
39
+ it "can use a custom seperator" do
40
+ s_("XXX/not found",'/').should == "not found"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ # ---- requirements
2
+ $LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
3
+ require 'fast_gettext'
4
+
5
+ # ---- bugfix
6
+ #`exit?': undefined method `run?' for Test::Unit:Module (NoMethodError)
7
+ #can be solved with require test/unit but this will result in extra test-output
8
+ module Test
9
+ module Unit
10
+ def self.run?
11
+ true
12
+ end
13
+ end
14
+ end
15
+
16
+ # ---- Helpers
17
+ def pending_it(text,&block)
18
+ it text do
19
+ pending(&block)
20
+ end
21
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: grosser-fast_gettext
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Grosser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-19 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: grosser.michael@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - VERSION.yml
26
+ - README.markdown
27
+ - lib/fast_gettext.rb
28
+ - lib/fast_gettext
29
+ - lib/fast_gettext/storage.rb
30
+ - lib/fast_gettext/mo_file.rb
31
+ - spec/fast_gettext_spec.rb
32
+ - spec/spec_helper.rb
33
+ - spec/locale
34
+ - spec/locale/en
35
+ - spec/locale/en/LC_MESSAGES
36
+ - spec/locale/en/LC_MESSAGES/test.mo
37
+ - spec/locale/de
38
+ - spec/locale/de/LC_MESSAGES
39
+ - spec/locale/de/LC_MESSAGES/test.mo
40
+ - spec/fast_gettext
41
+ - spec/fast_gettext/storage_spec.rb
42
+ - spec/fast_gettext/mo_file_spec.rb
43
+ has_rdoc: true
44
+ homepage: http://github.com/grosser/fast_gettext
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --inline-source
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.2.0
67
+ signing_key:
68
+ specification_version: 2
69
+ summary: A simple, fast and threadsafe implementation of GetText
70
+ test_files: []
71
+