Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

first commit

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