rails-translate-models 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
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "activerecord", ">= 3.0"
4
+
5
+ # Add dependencies to develop your gem here.
6
+ # Include everything needed to run rake, tests, features, etc.
7
+ group :development do
8
+ gem "shoulda", ">= 0"
9
+ gem "bundler", "~> 1.0.0"
10
+ gem "jeweler", "~> 1.6.4"
11
+ gem "rcov", ">= 0"
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,37 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.1.3)
5
+ activesupport (= 3.1.3)
6
+ builder (~> 3.0.0)
7
+ i18n (~> 0.6)
8
+ activerecord (3.1.3)
9
+ activemodel (= 3.1.3)
10
+ activesupport (= 3.1.3)
11
+ arel (~> 2.2.1)
12
+ tzinfo (~> 0.3.29)
13
+ activesupport (3.1.3)
14
+ multi_json (~> 1.0)
15
+ arel (2.2.1)
16
+ builder (3.0.0)
17
+ git (1.2.5)
18
+ i18n (0.6.0)
19
+ jeweler (1.6.4)
20
+ bundler (~> 1.0)
21
+ git (>= 1.2.5)
22
+ rake
23
+ multi_json (1.0.4)
24
+ rake (0.9.2.2)
25
+ rcov (0.9.11)
26
+ shoulda (2.11.3)
27
+ tzinfo (0.3.31)
28
+
29
+ PLATFORMS
30
+ ruby
31
+
32
+ DEPENDENCIES
33
+ activerecord (>= 3.0)
34
+ bundler (~> 1.0.0)
35
+ jeweler (~> 1.6.4)
36
+ rcov
37
+ shoulda
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Francesc Pla
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,101 @@
1
+ = rails-translate-models
2
+
3
+ Minimal implementation of model translations for Rails 3.x having a translations table for each model, based on translated_attributes.
4
+
5
+ == Installation
6
+
7
+ Add it to your Gemfile:
8
+
9
+ gem 'rails-translate-models'
10
+
11
+ == Setting up
12
+
13
+ All examples provided will be based on an article model with title and body as translated attributes.
14
+
15
+ <b>Migration</b>
16
+
17
+ For each model you have to create a table for the translations, you can do it on model migration, for example:
18
+
19
+ class CreateArticles < ActiveRecord::Migration
20
+ def change
21
+ create_table :articles do |t|
22
+ t.timestamps
23
+ end
24
+
25
+ create_table :article_translations do |t|
26
+ t.integer :article_id
27
+ t.string :language_code
28
+ t.string :title
29
+ t.text :body
30
+ t.timestamps
31
+ end
32
+
33
+ add_index :pages_translations, :page_id
34
+ add_index :pages_translations, [:page_id, :language_code]
35
+ end
36
+ end
37
+
38
+ <b>Specify translated attributes in model</b>
39
+
40
+ class Article < ActiveRecord::Base
41
+ has_translations :title, :body
42
+ end
43
+
44
+ == Usage
45
+
46
+ Self-explained usage given an article with two translations (en / es)
47
+
48
+ Retrieve data, english as current language:
49
+
50
+ a = Article.first
51
+ a.title
52
+ => "example title"
53
+
54
+ Change language and you'll get in spanish
55
+
56
+ I18n.locale = :es
57
+ a.title
58
+ => "título ejemplo"
59
+
60
+ Or you can also get any other language using in_language_code for each attribute
61
+
62
+ a.title_in_en
63
+ => "example title"
64
+
65
+ Note that if the current language doesn't have a translation it always tries to fallback to english then returns nil if it's also not available.
66
+
67
+ To create a new object.
68
+
69
+ a = Article.new
70
+ a.title = "example title"
71
+ a.title_in_es = "título ejemplo"
72
+ a.save
73
+
74
+ When translation associated record is destroyed all translations are destroyed as well
75
+
76
+ ==
77
+
78
+ == Scopes
79
+
80
+ All models with 'has_translations' have 'has_many :model_translations' and 'default_scope :include => :model_translations' so you can take advantage of it and make use of some scopes, for example:
81
+
82
+ class Article < ActiveRecord::Base
83
+ has_translations :title, :body
84
+
85
+ scope :ordered_by_title, :order => 'article_translations.title'
86
+ scope :with_title, lambda { |title| { where("article_translations.title = ?", title) } }
87
+ end
88
+
89
+ == TODO
90
+
91
+ It's an initial implementation for a work in progress project, it's just an initial release but does the basic stuff I need. Help is welcome ;)
92
+
93
+ * make tests
94
+ * translations models generators
95
+
96
+
97
+
98
+
99
+
100
+
101
+
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "rails-translate-models"
18
+ gem.homepage = "http://github.com/francesc/rails-translate-models"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Simple gem to translate multi-lingual content in Rails models}
21
+ gem.description = %Q{Simple gem to translate multi-lingual content in Rails models in separate tables for each model (modelname_translations)}
22
+ gem.email = "francesc@francesc.net"
23
+ gem.authors = ["Francesc Pla"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ test.rcov_opts << '--exclude "gems/*"'
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "rails-translate-models #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,143 @@
1
+ module RailsTranslateModels
2
+ def has_translations(*args)
3
+ # store options
4
+ cattr_accessor :has_translations_options
5
+ self.has_translations_options = args
6
+
7
+ # create translations class
8
+ type = self.to_s.underscore
9
+ translations_klass_name = "#{self}_translation".classify
10
+ translations_table_name = translations_klass_name.pluralize.tableize.to_sym
11
+
12
+ translations_klass = Class.new(ActiveRecord::Base) do
13
+ set_table_name translations_table_name
14
+ belongs_to type.to_sym
15
+ end
16
+
17
+ Object.const_set(translations_klass_name, translations_klass)
18
+
19
+ # set translations association, scoping, and after_save
20
+ has_many :translations, :class_name => translations_klass_name, :dependent => :destroy
21
+ default_scope :include => :translations
22
+
23
+ after_save :store_translated_attributes
24
+
25
+ # include methods
26
+ include InstanceMethods
27
+ end
28
+
29
+ module InstanceMethods
30
+ def translatable?
31
+ true
32
+ end
33
+
34
+ def self.included(base)
35
+ attributes = base.has_translations_options
36
+
37
+ attributes.each do |attribute|
38
+ base.class_eval <<-GETTER_AND_SETTER
39
+ def get_#{attribute}(locale=nil)
40
+ get_translated_attribute(locale, :#{attribute})
41
+ end
42
+
43
+ def set_#{attribute}(value, locale=I18n.locale)
44
+ set_translated_attribute(locale, :#{attribute}, value)
45
+ end
46
+
47
+ alias #{attribute} get_#{attribute}
48
+ alias #{attribute}= set_#{attribute}
49
+ GETTER_AND_SETTER
50
+ end
51
+ end
52
+
53
+ def get_translated_attribute(locale, attribute)
54
+ translated_value = if locale
55
+ translated_attributes_for(locale)[attribute]
56
+ else
57
+ # find translated attribute, first try current locale, then english
58
+ text = translated_attributes_for(I18n.locale)[attribute] || translated_attributes_for("en")[attribute]
59
+ end
60
+ end
61
+
62
+ def set_translated_attribute(locale, attribute, value)
63
+ old_value = translated_attributes_for(locale)[attribute]
64
+ return if old_value.to_s == value.to_s
65
+ changed_attributes.merge!("#{attribute}_in_#{locale}" => old_value)
66
+ translated_attributes_for(locale)[attribute] = value
67
+ @translated_attributes_changed = true
68
+ # self.translations_attributes.merge!({ :language_code => locale, attribute.to_sym => value })
69
+ # raise self.translations.inspect
70
+ end
71
+
72
+ def translated_attributes
73
+ return @translated_attributes if @translated_attributes
74
+ merge_db_translations_with_instance_variable
75
+ @translated_attributes ||= {}.with_indifferent_access
76
+ end
77
+
78
+ def translated_attributes= hash
79
+ @db_translations_merged = true
80
+ @translated_attributes_changed = true
81
+ @translated_attributes = hash.with_indifferent_access
82
+ end
83
+
84
+ def respond_to?(name, *args)
85
+ return true if parse_translated_attribute_method(name)
86
+ super
87
+ end
88
+
89
+ def method_missing(name, *args)
90
+ attribute, locale = parse_translated_attribute_method(name)
91
+ return super unless attribute
92
+ if name.to_s.include? '='
93
+ send("set_#{attribute}", args[0], locale)
94
+ else
95
+ send("get_#{attribute}", locale)
96
+ end
97
+ end
98
+
99
+ protected
100
+
101
+ def store_translated_attributes
102
+ return true unless @translated_attributes_changed
103
+ translations.delete_all
104
+ @translated_attributes.each do |locale, attributes|
105
+ translations.create!(attributes.merge(:language_code => locale))
106
+ end
107
+ @translated_attributes_changed = false
108
+ true
109
+ end
110
+
111
+ private
112
+
113
+ def merge_db_translations_with_instance_variable
114
+ return if new_record? or @db_translations_merged
115
+ @db_translations_merged = true
116
+
117
+ translations.each do |t|
118
+ has_translations_options.each do |attribute|
119
+ translated_attributes_for(t.language_code)[attribute] = eval("t.#{attribute.to_s}")
120
+ end
121
+ end
122
+ end
123
+
124
+ def translated_attributes_for(locale)
125
+ translated_attributes[locale] ||= {}.with_indifferent_access
126
+ translated_attributes[locale]
127
+ end
128
+
129
+ def parse_translated_attribute_method(name)
130
+ return false if name.to_s !~ /^([a-zA-Z_]+)_in_([a-z]{2})[=]?$/
131
+ attribute = $1; locale = $2
132
+ return false unless is_translated_attribute?(attribute)
133
+ return attribute, locale
134
+ end
135
+
136
+ def is_translated_attribute?(method_name)
137
+ attributes = self.class.has_translations_options
138
+ attributes.include? method_name.sub('=','').to_sym
139
+ end
140
+ end
141
+ end
142
+
143
+ ActiveRecord::Base.extend RailsTranslateModels
@@ -0,0 +1,62 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "rails-translate-models"
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 = ["Francesc Pla"]
12
+ s.date = "2011-12-29"
13
+ s.description = "Simple gem to translate multi-lingual content in Rails models in separate tables for each model (modelname_translations)"
14
+ s.email = "francesc@francesc.net"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "LICENSE.txt",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "lib/rails-translate-models.rb",
28
+ "rails-translate-models.gemspec",
29
+ "test/helper.rb",
30
+ "test/test_rails-translate-models.rb"
31
+ ]
32
+ s.homepage = "http://github.com/francesc/rails-translate-models"
33
+ s.licenses = ["MIT"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = "1.8.10"
36
+ s.summary = "Simple gem to translate multi-lingual content in Rails models"
37
+
38
+ if s.respond_to? :specification_version then
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
42
+ s.add_runtime_dependency(%q<activerecord>, [">= 3.0"])
43
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
44
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
45
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
46
+ s.add_development_dependency(%q<rcov>, [">= 0"])
47
+ else
48
+ s.add_dependency(%q<activerecord>, [">= 3.0"])
49
+ s.add_dependency(%q<shoulda>, [">= 0"])
50
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
51
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
52
+ s.add_dependency(%q<rcov>, [">= 0"])
53
+ end
54
+ else
55
+ s.add_dependency(%q<activerecord>, [">= 3.0"])
56
+ s.add_dependency(%q<shoulda>, [">= 0"])
57
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
58
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
59
+ s.add_dependency(%q<rcov>, [">= 0"])
60
+ end
61
+ end
62
+
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'rails-translate-models'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestRailsTranslateModels < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-translate-models
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Francesc Pla
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: &70186038307120 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70186038307120
25
+ - !ruby/object:Gem::Dependency
26
+ name: shoulda
27
+ requirement: &70186038309020 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70186038309020
36
+ - !ruby/object:Gem::Dependency
37
+ name: bundler
38
+ requirement: &70186038310860 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70186038310860
47
+ - !ruby/object:Gem::Dependency
48
+ name: jeweler
49
+ requirement: &70186038312320 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.6.4
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70186038312320
58
+ - !ruby/object:Gem::Dependency
59
+ name: rcov
60
+ requirement: &70186038313780 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70186038313780
69
+ description: Simple gem to translate multi-lingual content in Rails models in separate
70
+ tables for each model (modelname_translations)
71
+ email: francesc@francesc.net
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files:
75
+ - LICENSE.txt
76
+ - README.rdoc
77
+ files:
78
+ - .document
79
+ - Gemfile
80
+ - Gemfile.lock
81
+ - LICENSE.txt
82
+ - README.rdoc
83
+ - Rakefile
84
+ - VERSION
85
+ - lib/rails-translate-models.rb
86
+ - rails-translate-models.gemspec
87
+ - test/helper.rb
88
+ - test/test_rails-translate-models.rb
89
+ homepage: http://github.com/francesc/rails-translate-models
90
+ licenses:
91
+ - MIT
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ segments:
103
+ - 0
104
+ hash: -3390267926304446438
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 1.8.10
114
+ signing_key:
115
+ specification_version: 3
116
+ summary: Simple gem to translate multi-lingual content in Rails models
117
+ test_files: []