i18n_backend_sequel 0.0.1

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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010-2010 Corin Langosch
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
+
data/README.rdoc ADDED
@@ -0,0 +1,55 @@
1
+ =About
2
+
3
+ I18n backend which allows to store/get the translations from a database using a sequel.
4
+
5
+ ==Install
6
+
7
+ Simply install it as any other gem:
8
+
9
+ gem install i18n_backend_sequel
10
+
11
+ Or when using bundler, add it got your Gemfile:
12
+
13
+ gem i18n_backend_sequel
14
+
15
+ This should also install the geokit gem.
16
+
17
+ ==Quick Start
18
+
19
+ Create the table used to store i18n translations:
20
+
21
+ create_table :i18n_translations do |t|
22
+ String :locale, :null => false
23
+ String :key, :null => false
24
+ String :value, :text => true
25
+ String :interpolations, :text => true
26
+ TrueClass :is_proc, :null => false, :default => false
27
+ primary_key [:locale, :key]
28
+ end
29
+
30
+ Make I18n use it as its backend:
31
+
32
+ I18n.backend = I18n::Backend::Sequel.new
33
+
34
+ If you want sequel to add missing translations to the database prepend this too:
35
+
36
+ I18n::Backend::Sequel.send(:include, I18n::Backend::Sequel::Missing)
37
+
38
+ ==Todo
39
+
40
+ * Source documentation (rdoc)
41
+ * Tests
42
+
43
+ ==Contributing
44
+
45
+ If you'd like to contribute a feature or bugfix: Thanks! To make sure your
46
+ fix/feature has a high chance of being included, please read the following
47
+ guidelines:
48
+
49
+ 1. Fork the project.
50
+ 2. Make your feature addition or bug fix.
51
+ 3. Add tests for it. This is important so we don’t break anything in a future version unintentionally.
52
+ 4. Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
53
+ 5. Send me a pull request. Bonus points for topic branches.
54
+
55
+
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = 'i18n_backend_sequel'
8
+ gem.authors = ['Corin Langosch']
9
+ gem.date = Date.today.to_s
10
+ gem.email = 'info@netskin.com'
11
+ gem.homepage = 'http://github.com/gucki/i18n_backend_sequel'
12
+ gem.summary = 'I18n backend which uses a Sequel Model'
13
+ gem.description = 'I18n backend which allows to store/get the translations from a database using a sequel.'
14
+ gem.add_dependency "sequel", ">= 3.0.0"
15
+ gem.add_development_dependency "rspec", ">= 1.2.9"
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ require 'spec/rake/spectask'
24
+ Spec::Rake::SpecTask.new(:spec) do |spec|
25
+ spec.libs << 'lib' << 'spec'
26
+ spec.spec_files = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
30
+ spec.libs << 'lib' << 'spec'
31
+ spec.pattern = 'spec/**/*_spec.rb'
32
+ spec.rcov = true
33
+ end
34
+
35
+ task :spec => :check_dependencies
36
+
37
+ task :default => :spec
38
+
39
+ require 'rake/rdoctask'
40
+ Rake::RDocTask.new do |rdoc|
41
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "i18n_backend_sequel #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,61 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{i18n_backend_sequel}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Corin Langosch"]
12
+ s.date = %q{2010-09-21}
13
+ s.description = %q{I18n backend which allows to store/get the translations from a database using a sequel.}
14
+ s.email = %q{info@netskin.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "i18n_backend_sequel.gemspec",
27
+ "lib/i18n_backend_sequel.rb",
28
+ "lib/i18n_backend_sequel/missing.rb",
29
+ "lib/i18n_backend_sequel/store_procs.rb",
30
+ "lib/i18n_backend_sequel/translation.rb",
31
+ "spec/i18n_backend_sequel_spec.rb",
32
+ "spec/spec.opts",
33
+ "spec/spec_helper.rb"
34
+ ]
35
+ s.homepage = %q{http://github.com/gucki/i18n_backend_sequel}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.7}
39
+ s.summary = %q{I18n backend which uses a Sequel Model}
40
+ s.test_files = [
41
+ "spec/spec_helper.rb",
42
+ "spec/i18n_backend_sequel_spec.rb"
43
+ ]
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ s.add_runtime_dependency(%q<sequel>, [">= 3.0.0"])
51
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
52
+ else
53
+ s.add_dependency(%q<sequel>, [">= 3.0.0"])
54
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<sequel>, [">= 3.0.0"])
58
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
59
+ end
60
+ end
61
+
@@ -0,0 +1,65 @@
1
+ # This extension stores translation stub records for missing translations to
2
+ # the database.
3
+ #
4
+ # This is useful if you have a web based translation tool. It will populate
5
+ # the database with untranslated keys as the application is being used. A
6
+ # translator can then go through these and add missing translations.
7
+ #
8
+ # Example usage:
9
+ #
10
+ # I18n::Backend::Chain.send(:include, I18n::Backend::Sequel::Missing)
11
+ # I18n.backend = I18n::Backend::Chain.new(I18n::Backend::Sequel.new, I18n::Backend::Simple.new)
12
+ #
13
+ # Stub records for pluralizations will also be created for each key defined
14
+ # in i18n.plural.keys.
15
+ #
16
+ # For example:
17
+ #
18
+ # # en.yml
19
+ # en:
20
+ # i18n:
21
+ # plural:
22
+ # keys: [:zero, :one, :other]
23
+ #
24
+ # # pl.yml
25
+ # pl:
26
+ # i18n:
27
+ # plural:
28
+ # keys: [:zero, :one, :few, :other]
29
+ #
30
+ # It will also persist interpolation keys in Translation#interpolations so
31
+ # translators will be able to review and use them.
32
+ module I18n
33
+ module Backend
34
+ class Sequel
35
+ module Missing
36
+ include Flatten
37
+
38
+ def store_default_translations(locale, key, options = {})
39
+ count, scope, default, separator = options.values_at(:count, :scope, :default, :separator)
40
+ separator ||= I18n.default_separator
41
+ key = normalize_flat_keys(locale, key, scope, separator)
42
+
43
+ if Sequel::Translation.locale(locale).lookup(key).empty?
44
+ interpolations = options.keys - Base::RESERVED_KEYS
45
+ keys = count ? I18n.t('i18n.plural.keys', :locale => locale).map { |k| [key, k].join(FLATTEN_SEPARATOR) } : [key]
46
+ keys.each { |key| store_default_translation(locale, key, interpolations) }
47
+ end
48
+ end
49
+
50
+ def store_default_translation(locale, key, interpolations)
51
+ translation = Sequel::Translation.new(:locale => locale.to_s, :key => key)
52
+ translation.interpolations = interpolations
53
+ translation.save(:validate => false)
54
+ end
55
+
56
+ def translate(locale, key, options = {})
57
+ super
58
+ rescue I18n::MissingTranslationData => e
59
+ self.store_default_translations(locale, key, options)
60
+ raise e
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,38 @@
1
+ # This module is intended to be mixed into the Sequel backend to allow
2
+ # storing Ruby Procs as translation values in the database.
3
+ #
4
+ # I18n.backend = I18n::Backend::Sequel.new
5
+ # I18n::Backend::Sequel::Translation.send(:include, I18n::Backend::Sequel::StoreProcs)
6
+ #
7
+ # The StoreProcs module requires the ParseTree and ruby2ruby gems and therefor
8
+ # was extracted from the original backend.
9
+ #
10
+ # ParseTree is not compatible with Ruby 1.9.
11
+
12
+ begin
13
+ require 'ruby2ruby'
14
+ require 'parse_tree'
15
+ require 'parse_tree_extensions'
16
+ rescue LoadError => e
17
+ puts "can't use StoreProcs because: #{e.message}"
18
+ end
19
+
20
+ module I18n
21
+ module Backend
22
+ class Sequel
23
+ module StoreProcs
24
+ def value=(v)
25
+ case v
26
+ when Proc
27
+ write_attribute(:value, v.to_ruby)
28
+ write_attribute(:is_proc, true)
29
+ else
30
+ write_attribute(:value, v)
31
+ end
32
+ end
33
+
34
+ Translation.send(:include, self) if method(:to_s).respond_to?(:to_ruby)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,110 @@
1
+ require 'sequel'
2
+ require 'json'
3
+
4
+ module I18n
5
+ module Backend
6
+ # Sequel model used to store actual translations to the database.
7
+ #
8
+ # This model expects a table like the following to be already set up in
9
+ # your the database:
10
+ #
11
+ # create_table :i18n_translations do |t|
12
+ # String :locale, :null => false
13
+ # String :key, :null => false
14
+ # String :value, :text => true
15
+ # String :interpolations, :text => true
16
+ # TrueClass :is_proc, :null => false, :default => false
17
+ # primary_key [:locale, :key]
18
+ # end
19
+ #
20
+ # This model supports to named scopes :locale and :lookup. The :locale
21
+ # scope simply adds a condition for a given locale:
22
+ #
23
+ # I18n::Backend::Sequel::Translation.locale(:en).all
24
+ # # => all translation records that belong to the :en locale
25
+ #
26
+ # The :lookup scope adds a condition for looking up all translations
27
+ # that either start with the given keys (joined by an optionally given
28
+ # separator or I18n.default_separator) or that exactly have this key.
29
+ #
30
+ # # with translations present for :"foo.bar" and :"foo.baz"
31
+ # I18n::Backend::Sequel::Translation.lookup(:foo)
32
+ # # => an array with both translation records :"foo.bar" and :"foo.baz"
33
+ #
34
+ # I18n::Backend::Sequel::Translation.lookup([:foo, :bar])
35
+ # I18n::Backend::Sequel::Translation.lookup(:"foo.bar")
36
+ # # => an array with the translation record :"foo.bar"
37
+ #
38
+ # When the StoreProcs module was mixed into this model then Procs will
39
+ # be stored to the database as Ruby code and evaluated when :value is
40
+ # called.
41
+ #
42
+ # Translation = I18n::Backend::Sequel::Translation
43
+ # Translation.create \
44
+ # :locale => 'en'
45
+ # :key => 'foo'
46
+ # :value => lambda { |key, options| 'FOO' }
47
+ # Translation.locale('en').lookup('foo').value
48
+ # # => 'FOO'
49
+ class Sequel
50
+ class Translation < ::Sequel::Model(:i18n_translations)
51
+ TRUTHY_CHAR = "\001"
52
+ FALSY_CHAR = "\002"
53
+
54
+ unrestrict_primary_key
55
+ set_restricted_columns :is_proc, :interpolations
56
+
57
+ def_dataset_method(:locale) do |locale|
58
+ filter(:locale => locale.to_s)
59
+ end
60
+
61
+ def_dataset_method(:lookup) do |keys, *separator|
62
+ keys = Array(keys).map! { |key| key.to_s }
63
+
64
+ unless separator.empty?
65
+ warn "[DEPRECATION] Giving a separator to Translation.lookup is deprecated. " <<
66
+ "You can change the internal separator by overwriting FLATTEN_SEPARATOR."
67
+ end
68
+
69
+ namespace = "#{keys.last}#{I18n::Backend::Flatten::FLATTEN_SEPARATOR}%"
70
+ filter(:key => keys).or(:key.like(namespace))
71
+ end
72
+
73
+ plugin :serialization, :json, :value, :interpolations
74
+
75
+ class << self
76
+ def available_locales
77
+ Translation.distinct.select(:locale).all.map { |t| t.locale.to_sym }
78
+ end
79
+ end
80
+
81
+ def interpolates?(key)
82
+ self.interpolations.include?(key) if self.interpolations
83
+ end
84
+
85
+ def value
86
+ value = self[:value]
87
+ if is_proc
88
+ Kernel.eval(value)
89
+ elsif value == FALSY_CHAR
90
+ false
91
+ elsif value == TRUTHY_CHAR
92
+ true
93
+ else
94
+ value
95
+ end
96
+ end
97
+
98
+ def value=(value)
99
+ if value === false
100
+ value = FALSY_CHAR
101
+ elsif value === true
102
+ value = TRUTHY_CHAR
103
+ end
104
+
105
+ write_attribute(:value, value)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,54 @@
1
+ module I18n
2
+ module Backend
3
+ class Sequel
4
+ autoload :Missing, 'i18n_backend_sequel/missing'
5
+ autoload :StoreProcs, 'i18n_backend_sequel/store_procs'
6
+ autoload :Translation, 'i18n_backend_sequel/translation'
7
+
8
+ module Implementation
9
+ include Base, Flatten
10
+
11
+ def available_locales
12
+ Translation.available_locales
13
+ end
14
+
15
+ def store_translations(locale, data, options = {})
16
+ escape = options.fetch(:escape, true)
17
+ flatten_translations(locale, data, escape, false).each do |key, value|
18
+ Translation.locale(locale).lookup(expand_keys(key)).delete_all
19
+ Translation.create(:locale => locale.to_s, :key => key.to_s, :value => value)
20
+ end
21
+ end
22
+
23
+ protected
24
+
25
+ def lookup(locale, key, scope = [], options = {})
26
+ key = normalize_flat_keys(locale, key, scope, options[:separator])
27
+ result = Translation.locale(locale).lookup(key).all
28
+
29
+ if result.empty?
30
+ nil
31
+ elsif result.first.key == key
32
+ result.first.value
33
+ else
34
+ chop_range = (key.size + FLATTEN_SEPARATOR.size)..-1
35
+ result = result.inject({}) do |hash, r|
36
+ hash[r.key.slice(chop_range)] = r.value
37
+ hash
38
+ end
39
+ result.deep_symbolize_keys
40
+ end
41
+ end
42
+
43
+ # For a key :'foo.bar.baz' return ['foo', 'foo.bar', 'foo.bar.baz']
44
+ def expand_keys(key)
45
+ key.to_s.split(FLATTEN_SEPARATOR).inject([]) do |keys, key|
46
+ keys << [keys.last, key].compact.join(FLATTEN_SEPARATOR)
47
+ end
48
+ end
49
+ end
50
+
51
+ include Implementation
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "I18nBackendSequel" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'sequel_mappable'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: i18n_backend_sequel
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Corin Langosch
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-09-21 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: sequel
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 3
30
+ - 0
31
+ - 0
32
+ version: 3.0.0
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 1
45
+ - 2
46
+ - 9
47
+ version: 1.2.9
48
+ type: :development
49
+ version_requirements: *id002
50
+ description: I18n backend which allows to store/get the translations from a database using a sequel.
51
+ email: info@netskin.com
52
+ executables: []
53
+
54
+ extensions: []
55
+
56
+ extra_rdoc_files:
57
+ - LICENSE
58
+ - README.rdoc
59
+ files:
60
+ - .document
61
+ - .gitignore
62
+ - LICENSE
63
+ - README.rdoc
64
+ - Rakefile
65
+ - VERSION
66
+ - i18n_backend_sequel.gemspec
67
+ - lib/i18n_backend_sequel.rb
68
+ - lib/i18n_backend_sequel/missing.rb
69
+ - lib/i18n_backend_sequel/store_procs.rb
70
+ - lib/i18n_backend_sequel/translation.rb
71
+ - spec/i18n_backend_sequel_spec.rb
72
+ - spec/spec.opts
73
+ - spec/spec_helper.rb
74
+ has_rdoc: true
75
+ homepage: http://github.com/gucki/i18n_backend_sequel
76
+ licenses: []
77
+
78
+ post_install_message:
79
+ rdoc_options:
80
+ - --charset=UTF-8
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ segments:
97
+ - 0
98
+ version: "0"
99
+ requirements: []
100
+
101
+ rubyforge_project:
102
+ rubygems_version: 1.3.7
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: I18n backend which uses a Sequel Model
106
+ test_files:
107
+ - spec/spec_helper.rb
108
+ - spec/i18n_backend_sequel_spec.rb