has_translations 0.3.5 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -1
- data/.travis.yml +21 -0
- data/Appraisals +11 -0
- data/Gemfile +1 -2
- data/Gemfile.lock +48 -0
- data/README.md +35 -48
- data/Rakefile +13 -12
- data/gemfiles/3.1.gemfile +7 -0
- data/gemfiles/3.2.gemfile +7 -0
- data/gemfiles/4.0.gemfile +7 -0
- data/has_translations.gemspec +12 -8
- data/lib/generators/templates/migration.rb.erb +19 -0
- data/lib/generators/templates/model.rb.erb +5 -0
- data/lib/generators/translation_for_generator.rb +42 -0
- data/lib/has_translations/model_additions.rb +103 -0
- data/lib/has_translations/railtie.rb +9 -0
- data/lib/has_translations/version.rb +1 -1
- data/lib/has_translations.rb +4 -99
- data/test/has_translations_test.rb +14 -0
- data/test/schema.rb +7 -3
- data/test/test_helper.rb +7 -10
- metadata +102 -77
- data/generators/has_translations/USAGE +0 -8
- data/generators/has_translations/has_translations_generator.rb +0 -8
- data/init.rb +0 -1
- data/install.rb +0 -1
- data/tasks/has_translations_tasks.rake +0 -4
- data/test/.gitignore +0 -2
- data/uninstall.rb +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c6e03b94dfeed7b80f2db6b67d982f0c3a2c43b7
|
4
|
+
data.tar.gz: 993afc8d7892e75345ac2facd51d5b7c3f0c792f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9ec0bc9aba1e8e67bdce71561c5de9e284b601faa0c47fb936c36785aa773f8f98406556c5ddd534d427380f68f05b56f23ff6b7a62c16da3459e32e482257ba
|
7
|
+
data.tar.gz: 635b501602a37de402ca56b8badf2c4c1dbdc608626308c9c9663f9e4c67eed9c0eaf0dfb147dbed99ca83f06194c0ce921d8740973f46b3ecb7107f925d048a
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
rvm:
|
2
|
+
- ree
|
3
|
+
- 1.9.3
|
4
|
+
- 2.0.0
|
5
|
+
|
6
|
+
before_install:
|
7
|
+
- "gem install bundler -v=1.3.0"
|
8
|
+
before_script:
|
9
|
+
- "bundle install"
|
10
|
+
|
11
|
+
script: "bundle exec rake test"
|
12
|
+
|
13
|
+
gemfile:
|
14
|
+
- gemfiles/3.1.gemfile
|
15
|
+
- gemfiles/3.2.gemfile
|
16
|
+
- gemfiles/4.0.gemfile
|
17
|
+
|
18
|
+
matrix:
|
19
|
+
exclude:
|
20
|
+
- rvm: ree
|
21
|
+
gemfile: gemfiles/4.0.gemfile
|
data/Appraisals
ADDED
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
has_translations (1.0.0)
|
5
|
+
activerecord (>= 3.1.0)
|
6
|
+
activesupport (>= 3.1.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activemodel (4.0.0)
|
12
|
+
activesupport (= 4.0.0)
|
13
|
+
builder (~> 3.1.0)
|
14
|
+
activerecord (4.0.0)
|
15
|
+
activemodel (= 4.0.0)
|
16
|
+
activerecord-deprecated_finders (~> 1.0.2)
|
17
|
+
activesupport (= 4.0.0)
|
18
|
+
arel (~> 4.0.0)
|
19
|
+
activerecord-deprecated_finders (1.0.3)
|
20
|
+
activesupport (4.0.0)
|
21
|
+
i18n (~> 0.6, >= 0.6.4)
|
22
|
+
minitest (~> 4.2)
|
23
|
+
multi_json (~> 1.3)
|
24
|
+
thread_safe (~> 0.1)
|
25
|
+
tzinfo (~> 0.3.37)
|
26
|
+
appraisal (0.5.2)
|
27
|
+
bundler
|
28
|
+
rake
|
29
|
+
arel (4.0.0)
|
30
|
+
atomic (1.1.10)
|
31
|
+
builder (3.1.4)
|
32
|
+
i18n (0.6.4)
|
33
|
+
minitest (4.7.5)
|
34
|
+
multi_json (1.7.7)
|
35
|
+
rake (10.1.0)
|
36
|
+
sqlite3 (1.3.7)
|
37
|
+
thread_safe (0.1.2)
|
38
|
+
atomic
|
39
|
+
tzinfo (0.3.37)
|
40
|
+
|
41
|
+
PLATFORMS
|
42
|
+
ruby
|
43
|
+
|
44
|
+
DEPENDENCIES
|
45
|
+
appraisal
|
46
|
+
has_translations!
|
47
|
+
rake
|
48
|
+
sqlite3
|
data/README.md
CHANGED
@@ -1,51 +1,52 @@
|
|
1
|
-
HasTranslations
|
2
|
-
|
1
|
+
HasTranslations v1.0.0
|
2
|
+
==============================
|
3
|
+
|
4
|
+
[![Build Status](https://secure.travis-ci.org/dmitry/has_translations.png?branch=master)](http://travis-ci.org/dmitry/has_translations) [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/dmitry/has_translations/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
|
3
5
|
|
4
6
|
This simple plugin creates translations for your model.
|
5
7
|
Uses delegation pattern: http://en.wikipedia.org/wiki/Delegation_pattern
|
6
8
|
|
7
|
-
Tested with ActiveRecord versions:
|
8
|
-
And tested with ruby 1.8.7
|
9
|
+
Tested with ActiveRecord versions: 3.1.x, 3.2.x, 4.0.x
|
10
|
+
And tested with ruby 1.8.7 (ree), 1.9.3, 2.0.0
|
11
|
+
|
12
|
+
Compatibility
|
13
|
+
=============
|
14
|
+
|
15
|
+
This version only support Rails 4.0.x and 3.x.x. For Rails 2.3.x support please get the 0.3.5 version of this gem.
|
16
|
+
Plugin support is deprecated in Rails and will be removed soon so this version drop plugin support.
|
17
|
+
To prevent method shadowing between "translations" class method and "translations" relation in models the class
|
18
|
+
method has been renamed has_translations.
|
19
|
+
|
20
|
+
class Article < ActiveRecord::Base
|
21
|
+
translations :title, :text
|
22
|
+
end
|
23
|
+
|
24
|
+
become
|
25
|
+
|
26
|
+
class Article < ActiveRecord::Base
|
27
|
+
has_translations :title, :text
|
28
|
+
end
|
9
29
|
|
10
30
|
Installation
|
11
31
|
============
|
12
32
|
|
13
33
|
gem install has_translations
|
14
34
|
|
15
|
-
or as a plugin
|
16
|
-
|
17
|
-
script/plugin install git://github.com/dmitry/has_translations.git
|
18
|
-
|
19
35
|
Example
|
20
36
|
=======
|
21
37
|
|
22
38
|
For example you have Article model and you want to have title and text to be translated.
|
23
39
|
|
24
|
-
|
25
|
-
|
26
|
-
Migration should have `locale` as a string with two letters and `belongs_to associative id`, like:
|
27
|
-
|
28
|
-
class CreateArticleTranslations < ActiveRecord::Migration
|
29
|
-
def self.up
|
30
|
-
create_table :article_translations do |t|
|
31
|
-
t.integer :article_id, :null => false
|
32
|
-
t.string :locale, :null => false, :limit => 2
|
33
|
-
t.string :title, :null => false
|
34
|
-
t.text :text, :null => false
|
35
|
-
end
|
40
|
+
Run in command line:
|
36
41
|
|
37
|
-
|
38
|
-
end
|
42
|
+
rails g translation_for article title:string text:text
|
39
43
|
|
40
|
-
|
41
|
-
drop_table :article_translations
|
42
|
-
end
|
43
|
-
end
|
44
|
+
It will produce ArticleTranslation model and migration.
|
44
45
|
|
45
46
|
Add to article model `translations :value1, :value2`:
|
46
47
|
|
47
48
|
class Article < ActiveRecord::Base
|
48
|
-
|
49
|
+
has_translations :title, :text
|
49
50
|
end
|
50
51
|
|
51
52
|
And that's it. Now you can add your translations using:
|
@@ -71,10 +72,11 @@ You can use text filtering plugins, like acts_as_sanitiled and validations, and
|
|
71
72
|
|
72
73
|
Options:
|
73
74
|
|
74
|
-
*
|
75
|
-
*
|
76
|
-
*
|
77
|
-
*
|
75
|
+
* `:fallback => true` [default: false] - fallback 1) default locale; 2) first from translations;
|
76
|
+
* `:reader => false` [default: true] - add reader to the model object
|
77
|
+
* `:writer => true` [default: false] - add writer to the model object
|
78
|
+
* `:autosave => true` [default: false] - use [autosave option](http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many) for the ActiveRecord translations relation
|
79
|
+
* `:nil => nil` [default: ''] - if no model found by default returns empty string, you can set it for example to `nil` (no `lambda` supported)
|
78
80
|
|
79
81
|
It's better to use translations with `accepts_nested_attributes_for`:
|
80
82
|
|
@@ -110,18 +112,9 @@ those models that is translated only to specific locale. For example if you will
|
|
110
112
|
have 2 models, one is translated to english and the second one isn't, then it
|
111
113
|
`Article.translated(:en)` will find only first one.
|
112
114
|
|
113
|
-
PS
|
114
|
-
==
|
115
|
-
|
116
|
-
I suggest you to use latest i18n gem, include it in your rails 2 environment:
|
117
|
-
|
118
|
-
config.gem 'i18n', :version => '0.4.1' # change version to the latest
|
119
|
-
|
120
115
|
TODO
|
121
116
|
====
|
122
117
|
|
123
|
-
* add installation description to readme
|
124
|
-
* model and migration generators
|
125
118
|
* caching
|
126
119
|
* write more examples: fallback feature
|
127
120
|
* write blog post about comparison and benefits of this plugin between another translation model plugins
|
@@ -132,16 +125,10 @@ Alternatives
|
|
132
125
|
|
133
126
|
I know three of them:
|
134
127
|
|
128
|
+
* [globalize3](https://github.com/svenfuchs/globalize3) - Globalize3 is the successor of Globalize for Rails.
|
135
129
|
* [puret](http://github.com/jo/puret) - special for Rails 3 and almost the same as this project.
|
136
|
-
* [globalite2](http://github.com/joshmh/globalize2) - a lot of magic.
|
137
130
|
* [model_translations](http://github.com/janne/model_translations) - almost the same as this project, but more with more code in lib.
|
138
131
|
* [translatable_columns](http://github.com/iain/translatable_columns) - different approach: every column have own postfix "_#{locale}" in the same table (sometimes it could be fine).
|
139
132
|
|
140
133
|
|
141
|
-
|
142
|
-
=======
|
143
|
-
|
144
|
-
[noch.es](http://noch.es/), [eten.es](http://www.eten.es), [sem.ee](http://sem.ee/)
|
145
|
-
|
146
|
-
|
147
|
-
Copyright (c) 2009-2010 [Dmitry Polushkin], released under the MIT license
|
134
|
+
Copyright (c) 2009-2013 [Dmitry Polushkin], released under the MIT license
|
data/Rakefile
CHANGED
@@ -1,17 +1,18 @@
|
|
1
|
-
require '
|
1
|
+
require 'bundler/gem_tasks'
|
2
2
|
require 'rake/testtask'
|
3
|
-
require '
|
3
|
+
require 'appraisal'
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
Rake::TestTask.new do |t|
|
6
|
+
t.libs = %w(lib test)
|
7
|
+
t.test_files = Dir.glob('test/**/*_test.rb').sort
|
8
|
+
t.verbose = true
|
9
|
+
end
|
7
10
|
|
8
|
-
desc 'Default: run unit tests.'
|
9
11
|
task :default => :test
|
10
12
|
|
11
|
-
desc '
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
13
|
+
desc 'Setup Appraisal.'
|
14
|
+
task 'appraisal:setup' do
|
15
|
+
Rake::Task['appraisal:cleanup'].invoke
|
16
|
+
Rake::Task['appraisal:gemfiles'].invoke
|
17
|
+
Rake::Task['appraisal:install'].invoke
|
18
|
+
end
|
data/has_translations.gemspec
CHANGED
@@ -3,22 +3,26 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
require "has_translations/version"
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
6
|
+
s.name = 'has_translations'
|
7
7
|
s.version = HasTranslations::VERSION
|
8
|
-
s.authors = [
|
9
|
-
s.email =
|
10
|
-
s.homepage =
|
8
|
+
s.authors = ['Dmitry Polushkin']
|
9
|
+
s.email = %w(dmitry.polushkin@gmail.com)
|
10
|
+
s.homepage = 'http://github.com/dmitry/has_translations'
|
11
11
|
s.summary = %q{Create translations for your ActiveRecord models.}
|
12
12
|
s.description = %q{Create translations for your ActiveRecord models. Uses delegate pattern. Fully tested and used in a several production sites.}
|
13
13
|
|
14
|
-
s.rubyforge_project =
|
14
|
+
s.rubyforge_project = 'has_translations'
|
15
15
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
-
s.require_paths =
|
19
|
+
s.require_paths = %w(lib)
|
20
20
|
|
21
21
|
s.license = 'MIT'
|
22
|
-
|
23
|
-
s.add_dependency '
|
22
|
+
|
23
|
+
s.add_dependency 'activesupport', '>= 3.1.0'
|
24
|
+
s.add_dependency 'activerecord', '>= 3.1.0'
|
25
|
+
s.add_development_dependency 'sqlite3'
|
26
|
+
s.add_development_dependency 'appraisal'
|
27
|
+
s.add_development_dependency 'rake'
|
24
28
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Create<%= table_name.camelcase %> < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def <%= old_active_record? ? "self.up" : "change" %>
|
4
|
+
create_table :<%= table_name %> do |t|
|
5
|
+
t.integer :<%= foreign_key_name %>, :null => false
|
6
|
+
t.string :locale, :null => false, :limit => 2
|
7
|
+
<%- attributes.each do |attribute| -%>
|
8
|
+
t.<%= attribute.type %> :<%= attribute.name %>, :null => false
|
9
|
+
<%- end -%>
|
10
|
+
end
|
11
|
+
|
12
|
+
add_index :<%= table_name %>, [:<%= foreign_key_name %>, :locale], :unique => true
|
13
|
+
end
|
14
|
+
<% if old_active_record? %>
|
15
|
+
def self.down
|
16
|
+
drop_table :<%= table_name %>
|
17
|
+
end
|
18
|
+
<% end %>
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
class TranslationForGenerator < ActiveRecord::Generators::Base
|
4
|
+
|
5
|
+
desc "Description:\n Generate translation for ActiveRecord model"
|
6
|
+
source_root File.expand_path("../templates", __FILE__)
|
7
|
+
|
8
|
+
argument :attributes, :type => :array, :default => [], :banner => "field_1:text field_2:string field_3:another_type"
|
9
|
+
|
10
|
+
def check_attributes
|
11
|
+
puts table_name
|
12
|
+
if attributes.blank?
|
13
|
+
puts "Define at least one translated attribute"
|
14
|
+
exit
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_model
|
19
|
+
template 'model.rb.erb', File.join('app/models', class_path, "#{file_name}.rb")
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_migration
|
23
|
+
migration_template 'migration.rb.erb', "db/migrate/create_#{table_name}"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def name_with_translation
|
29
|
+
"#{name_without_translation.underscore}_translation"
|
30
|
+
end
|
31
|
+
|
32
|
+
alias_method_chain :name, :translation
|
33
|
+
|
34
|
+
def old_active_record?
|
35
|
+
(ActiveRecord::VERSION::MAJOR < 3) || (ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0)
|
36
|
+
end
|
37
|
+
|
38
|
+
def foreign_key_name
|
39
|
+
"#{name_without_translation.underscore}_id"
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module HasTranslations
|
2
|
+
module ModelAdditions
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def translated(locale)
|
7
|
+
where(["#{self.has_translations_options[:translation_class].table_name}.locale = ?", locale.to_s]).joins(:translations)
|
8
|
+
end
|
9
|
+
|
10
|
+
def has_translations(*attrs)
|
11
|
+
new_options = attrs.extract_options!
|
12
|
+
options = {
|
13
|
+
:fallback => false,
|
14
|
+
:reader => true,
|
15
|
+
:writer => false,
|
16
|
+
:nil => '',
|
17
|
+
#:inverse_of => self.model_name.singular.to_sym,
|
18
|
+
:autosave => new_options[:writer],
|
19
|
+
:translation_class => nil
|
20
|
+
}.merge(new_options)
|
21
|
+
|
22
|
+
translation_class_name = options[:translation_class].try(:name) || "#{self.model_name}Translation"
|
23
|
+
options[:translation_class] ||= translation_class_name.constantize
|
24
|
+
|
25
|
+
options.assert_valid_keys([:fallback, :reader, :writer, :nil, :inverse_of, :autosave, :translation_class])
|
26
|
+
|
27
|
+
belongs_to = self.model_name.to_s.demodulize.underscore.to_sym
|
28
|
+
|
29
|
+
class_attribute :has_translations_options
|
30
|
+
self.has_translations_options = options
|
31
|
+
|
32
|
+
# associations, validations and scope definitions
|
33
|
+
has_many :translations, :class_name => translation_class_name, :dependent => :destroy, :autosave => options[:autosave], :inverse_of => options[:inverse_of]
|
34
|
+
options[:translation_class].belongs_to belongs_to
|
35
|
+
options[:translation_class].validates_presence_of :locale
|
36
|
+
options[:translation_class].validates_uniqueness_of :locale, :scope => :"#{belongs_to}_id"
|
37
|
+
|
38
|
+
# Optionals delegated readers
|
39
|
+
if options[:reader]
|
40
|
+
attrs.each do |name|
|
41
|
+
send :define_method, name do |*args|
|
42
|
+
locale = args.first || I18n.locale
|
43
|
+
translation = self.translation(locale)
|
44
|
+
translation.try(name) || has_translations_options[:nil]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Optionals delegated writers
|
50
|
+
if options[:writer]
|
51
|
+
attrs.each do |name|
|
52
|
+
send :define_method, "#{name}_before_type_cast" do
|
53
|
+
translation = self.translation(I18n.locale, false)
|
54
|
+
translation.try(name)
|
55
|
+
end
|
56
|
+
|
57
|
+
send :define_method, "#{name}=" do |value|
|
58
|
+
translation = find_or_build_translation(I18n.locale)
|
59
|
+
translation.send(:"#{name}=", value)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_or_create_translation(locale)
|
68
|
+
locale = locale.to_s
|
69
|
+
(find_translation(locale) || self.has_translations_options[:translation_class].new).tap do |t|
|
70
|
+
t.locale = locale
|
71
|
+
t.send(:"#{self.class.model_name.to_s.demodulize.underscore.to_sym}_id=", self.id)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def find_or_build_translation(locale)
|
76
|
+
locale = locale.to_s
|
77
|
+
(find_translation(locale) || self.translations.build).tap do |t|
|
78
|
+
t.locale = locale
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def translation(locale, fallback=has_translations_options[:fallback])
|
83
|
+
locale = locale.to_s
|
84
|
+
find_translation(locale) || (fallback && !translations.blank? ? translations.detect { |t| t.locale == I18n.default_locale.to_s } || translations.first : nil)
|
85
|
+
end
|
86
|
+
|
87
|
+
def all_translations
|
88
|
+
t = I18n.available_locales.map do |locale|
|
89
|
+
[locale, find_or_create_translation(locale)]
|
90
|
+
end
|
91
|
+
ActiveSupport::OrderedHash[t]
|
92
|
+
end
|
93
|
+
|
94
|
+
def has_translation?(locale)
|
95
|
+
find_translation(locale).present?
|
96
|
+
end
|
97
|
+
|
98
|
+
def find_translation(locale)
|
99
|
+
locale = locale.to_s
|
100
|
+
translations.detect { |t| t.locale == locale }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/has_translations.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
# Provides ability to add the translations for the model using delegate pattern.
|
1
|
+
# Provides ability to add the translations for the model using delegate pattern.
|
3
2
|
# Uses has_many association to the ModelNameTranslation.
|
4
3
|
#
|
5
4
|
# For example you have model Article with attributes title and text.
|
@@ -27,9 +26,6 @@ class ActiveRecord::Base
|
|
27
26
|
# Notice: if you want to have validates_presence_of :article, you should use :inverse_of.
|
28
27
|
# Support this by yourself. Better is always to use artile.translations.build() method.
|
29
28
|
#
|
30
|
-
# For more information please read API. Feel free to write me an email to:
|
31
|
-
# dmitry.polushkin@gmail.com.
|
32
|
-
#
|
33
29
|
# ===
|
34
30
|
#
|
35
31
|
# You also can pass attributes and options to the translations class method:
|
@@ -77,101 +73,10 @@ class ActiveRecord::Base
|
|
77
73
|
#
|
78
74
|
# <tt>all_translations</tt> method that returns all possible translations in
|
79
75
|
# ordered hash (useful when creating forms with nested attributes).
|
80
|
-
def self.translations(*attrs)
|
81
|
-
new_options = attrs.extract_options!
|
82
|
-
options = {
|
83
|
-
:fallback => false,
|
84
|
-
:reader => true,
|
85
|
-
:writer => false,
|
86
|
-
:nil => '',
|
87
|
-
:autosave => new_options[:writer]
|
88
|
-
}.merge(new_options)
|
89
|
-
|
90
|
-
options.assert_valid_keys([:fallback, :reader, :writer, :nil, :autosave])
|
91
|
-
|
92
|
-
translation_class_name = "#{self.model_name}Translation"
|
93
|
-
translation_class = translation_class_name.constantize
|
94
|
-
belongs_to = self.model_name.demodulize.underscore.to_sym
|
95
|
-
|
96
|
-
if ActiveRecord::VERSION::MAJOR < 3
|
97
|
-
write_inheritable_attribute :has_translations_options, options
|
98
|
-
class_inheritable_reader :has_translations_options
|
99
|
-
|
100
|
-
scope_method = :named_scope
|
101
|
-
else
|
102
|
-
class_attribute :has_translations_options
|
103
|
-
self.has_translations_options = options
|
104
|
-
|
105
|
-
scope_method = :scope
|
106
|
-
end
|
107
|
-
|
108
|
-
# associations, validations and scope definitions
|
109
|
-
has_many :translations, :class_name => translation_class_name, :dependent => :destroy, :autosave => options[:autosave]
|
110
|
-
translation_class.belongs_to belongs_to
|
111
|
-
translation_class.validates_presence_of :locale
|
112
|
-
translation_class.validates_uniqueness_of :locale, :scope => :"#{belongs_to}_id"
|
113
|
-
send scope_method, :translated, lambda { |locale| {:conditions => ["#{translation_class.table_name}.locale = ?", locale.to_s], :joins => :translations} }
|
114
|
-
|
115
|
-
public
|
116
|
-
|
117
|
-
def find_or_create_translation(locale)
|
118
|
-
locale = locale.to_s
|
119
|
-
(find_translation(locale) || self.translations.new).tap do |t|
|
120
|
-
t.locale = locale
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def find_or_build_translation(locale)
|
125
|
-
locale = locale.to_s
|
126
|
-
(find_translation(locale) || self.translations.build).tap do |t|
|
127
|
-
t.locale = locale
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def translation(locale, fallback=has_translations_options[:fallback])
|
132
|
-
locale = locale.to_s
|
133
|
-
find_translation(locale) || (fallback && !translations.blank? ? translations.detect { |t| t.locale == I18n.default_locale.to_s } || translations.first : nil)
|
134
|
-
end
|
135
|
-
|
136
|
-
def all_translations
|
137
|
-
t = I18n.available_locales.map do |locale|
|
138
|
-
[locale, find_or_create_translation(locale)]
|
139
|
-
end
|
140
|
-
ActiveSupport::OrderedHash[t]
|
141
|
-
end
|
142
|
-
|
143
|
-
def has_translation?(locale)
|
144
|
-
find_translation(locale).present?
|
145
|
-
end
|
146
|
-
|
147
|
-
if options[:reader]
|
148
|
-
attrs.each do |name|
|
149
|
-
send :define_method, name do
|
150
|
-
translation = self.translation(I18n.locale)
|
151
|
-
translation.try(name) || has_translations_options[:nil]
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
if options[:writer]
|
157
|
-
attrs.each do |name|
|
158
|
-
send :define_method, "#{name}_before_type_cast" do
|
159
|
-
translation = self.translation(I18n.locale, false)
|
160
|
-
translation.try(name)
|
161
|
-
end
|
162
76
|
|
163
|
-
|
164
|
-
|
165
|
-
translation.send(:"#{name}=", value)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
77
|
+
require "has_translations/model_additions"
|
78
|
+
require "has_translations/railtie" if defined? Rails
|
169
79
|
|
170
|
-
|
80
|
+
module HasTranslations
|
171
81
|
|
172
|
-
def find_translation(locale)
|
173
|
-
locale = locale.to_s
|
174
|
-
translations.detect { |t| t.locale == locale }
|
175
|
-
end
|
176
|
-
end
|
177
82
|
end
|
@@ -34,6 +34,19 @@ class HasTranslationsTest < Test::Unit::TestCase
|
|
34
34
|
assert_equal article.text, article_translation.text
|
35
35
|
end
|
36
36
|
|
37
|
+
def test_reader_for_single_column
|
38
|
+
article = Article.create!
|
39
|
+
%w{en ru wu}.each do |locale|
|
40
|
+
translation = article.translations.build(:description=>"description in #{locale}", :text=>"text in #{locale}")
|
41
|
+
translation.locale=locale
|
42
|
+
translation.save!
|
43
|
+
end
|
44
|
+
I18n.locale = :ru
|
45
|
+
assert_equal article.description(:en), "description in en"
|
46
|
+
assert_equal article.text(:wu), "text in wu"
|
47
|
+
assert_equal article.text, "text in ru"
|
48
|
+
end
|
49
|
+
|
37
50
|
def test_writer_text_for_a_given_locale
|
38
51
|
article = Article.create!
|
39
52
|
assert_equal '', article.text
|
@@ -104,6 +117,7 @@ class HasTranslationsTest < Test::Unit::TestCase
|
|
104
117
|
assert_equal 'ru', team.all_translations[:ru].locale
|
105
118
|
team_translation_new = team.translations.build(:locale => :ru)
|
106
119
|
assert_equal team_translation_new.locale.to_s, team.all_translations[:ru].locale
|
120
|
+
assert_equal team.all_translations[:ru].team_id, team.id
|
107
121
|
end
|
108
122
|
|
109
123
|
def test_all_translations_should_not_have_build_translations
|
data/test/schema.rb
CHANGED
@@ -22,14 +22,18 @@ ActiveRecord::Schema.define(:version => 0) do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
class ArticleTranslation < ActiveRecord::Base
|
25
|
-
attr_accessible :description, :text
|
25
|
+
#attr_accessible :description, :text
|
26
26
|
end
|
27
27
|
class Article < ActiveRecord::Base
|
28
|
-
|
28
|
+
include HasTranslations::ModelAdditions
|
29
|
+
|
30
|
+
has_translations :description, :text, :writer => true
|
29
31
|
end
|
30
32
|
|
31
33
|
class TeamTranslation < ActiveRecord::Base
|
32
34
|
end
|
33
35
|
class Team < ActiveRecord::Base
|
34
|
-
|
36
|
+
include HasTranslations::ModelAdditions
|
37
|
+
|
38
|
+
has_translations :text, :fallback => true, :nil => nil
|
35
39
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'test/unit'
|
3
3
|
|
4
|
-
rails_version = "~> #{ENV['RAILS_VERSION'] || '3.1.0'}"
|
5
|
-
|
6
|
-
gem 'activerecord', rails_version
|
7
|
-
gem 'activesupport', rails_version
|
8
|
-
|
9
4
|
require 'active_record'
|
10
5
|
require 'logger'
|
11
6
|
|
@@ -14,16 +9,18 @@ require 'has_translations'
|
|
14
9
|
begin
|
15
10
|
I18n.available_locales = :ru, :en, :es
|
16
11
|
rescue
|
17
|
-
p
|
12
|
+
p '[WARNING]: This test should have the I18n.available_locales= method, which were included in versions ~> 0.3.0'
|
18
13
|
end
|
19
14
|
|
20
|
-
#ActiveRecord::
|
21
|
-
|
22
|
-
ActiveRecord::Base.
|
15
|
+
puts "Using Rails version: #{ActiveRecord::VERSION::STRING}"
|
16
|
+
|
17
|
+
ActiveRecord::Base.logger = Logger.new('test.log')
|
18
|
+
#ActiveRecord::Base.logger = nil
|
19
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
23
20
|
|
24
21
|
def setup_db
|
25
22
|
ActiveRecord::Migration.verbose = false
|
26
|
-
load
|
23
|
+
load 'schema.rb'
|
27
24
|
end
|
28
25
|
|
29
26
|
def teardown_db
|
metadata
CHANGED
@@ -1,112 +1,137 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_translations
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 3
|
9
|
-
- 5
|
10
|
-
version: 0.3.5
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Dmitry Polushkin
|
14
8
|
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2013-07-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
21
14
|
name: activesupport
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
hash: 5
|
29
|
-
segments:
|
30
|
-
- 2
|
31
|
-
- 3
|
32
|
-
version: "2.3"
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.1.0
|
33
20
|
type: :runtime
|
34
|
-
version_requirements: *id001
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: activerecord
|
37
21
|
prerelease: false
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.1.0
|
48
34
|
type: :runtime
|
49
|
-
|
50
|
-
|
51
|
-
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.1.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: appraisal
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Create translations for your ActiveRecord models. Uses delegate pattern.
|
84
|
+
Fully tested and used in a several production sites.
|
85
|
+
email:
|
52
86
|
- dmitry.polushkin@gmail.com
|
53
87
|
executables: []
|
54
|
-
|
55
88
|
extensions: []
|
56
|
-
|
57
89
|
extra_rdoc_files: []
|
58
|
-
|
59
|
-
files:
|
90
|
+
files:
|
60
91
|
- .gitignore
|
92
|
+
- .travis.yml
|
93
|
+
- Appraisals
|
61
94
|
- Gemfile
|
95
|
+
- Gemfile.lock
|
62
96
|
- MIT-LICENSE
|
63
97
|
- README.md
|
64
98
|
- Rakefile
|
65
|
-
-
|
66
|
-
-
|
99
|
+
- gemfiles/3.1.gemfile
|
100
|
+
- gemfiles/3.2.gemfile
|
101
|
+
- gemfiles/4.0.gemfile
|
67
102
|
- has_translations.gemspec
|
68
|
-
-
|
69
|
-
-
|
103
|
+
- lib/generators/templates/migration.rb.erb
|
104
|
+
- lib/generators/templates/model.rb.erb
|
105
|
+
- lib/generators/translation_for_generator.rb
|
70
106
|
- lib/has_translations.rb
|
107
|
+
- lib/has_translations/model_additions.rb
|
108
|
+
- lib/has_translations/railtie.rb
|
71
109
|
- lib/has_translations/version.rb
|
72
|
-
- tasks/has_translations_tasks.rake
|
73
|
-
- test/.gitignore
|
74
110
|
- test/has_translations_test.rb
|
75
111
|
- test/schema.rb
|
76
112
|
- test/test_helper.rb
|
77
|
-
- uninstall.rb
|
78
113
|
homepage: http://github.com/dmitry/has_translations
|
79
|
-
licenses:
|
114
|
+
licenses:
|
80
115
|
- MIT
|
116
|
+
metadata: {}
|
81
117
|
post_install_message:
|
82
118
|
rdoc_options: []
|
83
|
-
|
84
|
-
require_paths:
|
119
|
+
require_paths:
|
85
120
|
- lib
|
86
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
none: false
|
97
|
-
requirements:
|
98
|
-
- - ">="
|
99
|
-
- !ruby/object:Gem::Version
|
100
|
-
hash: 3
|
101
|
-
segments:
|
102
|
-
- 0
|
103
|
-
version: "0"
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
104
131
|
requirements: []
|
105
|
-
|
106
132
|
rubyforge_project: has_translations
|
107
|
-
rubygems_version:
|
133
|
+
rubygems_version: 2.0.3
|
108
134
|
signing_key:
|
109
|
-
specification_version:
|
135
|
+
specification_version: 4
|
110
136
|
summary: Create translations for your ActiveRecord models.
|
111
137
|
test_files: []
|
112
|
-
|
data/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'has_translations'
|
data/install.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
# Install hook code here
|
data/test/.gitignore
DELETED
data/uninstall.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
# Uninstall hook code here
|