embedded_localization 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +23 -25
- data/embedded_localization.gemspec +1 -3
- data/lib/embedded_localization/active_record/act_macro.rb +27 -8
- data/lib/embedded_localization/active_record/class_methods.rb +11 -2
- data/lib/embedded_localization/active_record/instance_methods.rb +11 -8
- data/lib/embedded_localization/version.rb +1 -1
- data/lib/embedded_localization.rb +23 -8
- metadata +3 -6
data/README.textile
CHANGED
@@ -50,25 +50,6 @@ g.name # => "공상 과학 소설"
|
|
50
50
|
|
51
51
|
No extra tables needed for this!
|
52
52
|
|
53
|
-
h3. Rails 3.0
|
54
|
-
|
55
|
-
<pre><code>
|
56
|
-
class CreateGenres < ActiveRecord::Migration
|
57
|
-
def self.up
|
58
|
-
create_table :genres do |t|
|
59
|
-
t.string :name
|
60
|
-
t.text :description
|
61
|
-
t.timestamps
|
62
|
-
end
|
63
|
-
end
|
64
|
-
def self.down
|
65
|
-
drop_table :posts
|
66
|
-
end
|
67
|
-
end
|
68
|
-
</code></pre>
|
69
|
-
|
70
|
-
Note that the ActiveRecord model @Genre@ must already exist and have a @translates@ directive listing the translated fields.
|
71
|
-
|
72
53
|
h3. Rails 3.0 + Embedded_Localization version < 0.2.0
|
73
54
|
|
74
55
|
<pre><code>
|
@@ -87,19 +68,23 @@ end
|
|
87
68
|
|
88
69
|
Please note, if you use Embedded_Localization with version < 0.2.0, that you should not define the translated attributes in the migrations -- instead define one text attribute with the name :i18n -- this will change in version 0.2.0
|
89
70
|
|
71
|
+
Note that the ActiveRecord model @Genre@ must already exist and have a @translates@ directive listing the translated fields.
|
72
|
+
|
73
|
+
|
90
74
|
h2. I18n fallbacks for empty translations
|
91
75
|
|
92
|
-
It is possible to enable fallbacks for empty translations. It will depend on the configuration setting you have set for I18n translations in your Rails config.
|
76
|
+
It is possible to enable fallbacks for empty translations. It will depend on the configuration setting you have set for I18n translations in your Rails config, or you can enable fallback when you define the translation fields. Currently we only support fallback to @I18n.default_locale@
|
93
77
|
|
94
78
|
You can enable them by adding the next line to @config/application.rb@ (or only @config/environments/production.rb@ if you only want them in production)
|
95
79
|
|
96
|
-
<pre><code>config.i18n.fallbacks = true
|
80
|
+
<pre><code>config.i18n.fallbacks = true # falls back to I18n.default_locale
|
81
|
+
</code></pre>
|
97
82
|
|
98
83
|
By default, Embedded_Localization will only use fallbacks when the translation value for the item you've requested is @nil@.
|
99
84
|
|
100
85
|
<pre><code>
|
101
86
|
class Genre < ActiveRecord::Base
|
102
|
-
translates :name, :description
|
87
|
+
translates :name, :description # , :fallbacks => true
|
103
88
|
end
|
104
89
|
|
105
90
|
I18n.locale = :en
|
@@ -129,7 +114,7 @@ Each class which uses Embedded_Localization will have these additional methods d
|
|
129
114
|
<ul>
|
130
115
|
<li>Klass.translated_attributes
|
131
116
|
<li>Klass.translated?
|
132
|
-
<li>Klass.
|
117
|
+
<li>Klass.fallbacks?
|
133
118
|
</ul>
|
134
119
|
|
135
120
|
e.g.:
|
@@ -137,7 +122,7 @@ e.g.:
|
|
137
122
|
<pre><code>
|
138
123
|
Genre.translated_attributes # => [:name,:description]
|
139
124
|
Genre.translated? # => true
|
140
|
-
Genre.
|
125
|
+
Genre.fallbacks? # => false
|
141
126
|
|
142
127
|
</code></pre>
|
143
128
|
|
@@ -188,10 +173,23 @@ e.g.:
|
|
188
173
|
|
189
174
|
</code></pre>
|
190
175
|
|
176
|
+
h2. Motivation
|
177
|
+
|
178
|
+
A recent project needed some localization support for ActiveRecord model data, but I did not want to clutter the schema with one additional table for each translated model, as globalization3 requires. A second requirement was to allow SQL queries of the fields using the default locale.
|
179
|
+
|
180
|
+
The advantage of EmbeddedLocalization is that it does not need extra tables, and therefore no joins or additional table lookups to get to the translated data.
|
181
|
+
|
182
|
+
If your requirements are different, my approach might not work for you. In that case, I recommend to look at the alternative solutions listed below.
|
191
183
|
|
192
184
|
h2. Changes
|
193
185
|
|
194
|
-
|
186
|
+
h3. 0.1.4 (2012-01-31)
|
187
|
+
* fixed bug with dirty tracking of serialized i18n attribute
|
188
|
+
* renamed #fallback? to #fallbacks?
|
189
|
+
|
190
|
+
|
191
|
+
h3. 0.1.3 Initial Version (2012-01-27)
|
192
|
+
|
195
193
|
|
196
194
|
h2. Alternative Solutions
|
197
195
|
|
@@ -9,9 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.email = ["tilo.sloboda@gmail.com"]
|
10
10
|
s.homepage = "http://www.unixgods.org/~tilo/Ruby/embedded_localization"
|
11
11
|
s.summary = %q{Rails I18n: library for embedded ActiveRecord 3 model/data translation}
|
12
|
-
s.description = %q{Rails I18n: Embedded_Localization for ActiveRecord 3 is very lightweight, and allows you to
|
13
|
-
transparently store translations of attributes right inside each record -- no extra database tables needed to store \
|
14
|
-
the localization data!}
|
12
|
+
s.description = %q{Rails I18n: Embedded_Localization for ActiveRecord 3 is very lightweight, and allows you to transparently store translations of attributes right inside each record -- no extra database tables needed to store the localization data!}
|
15
13
|
|
16
14
|
# s.rubyforge_project = "embedded_localization"
|
17
15
|
s.rubyforge_project = "[none]"
|
@@ -4,8 +4,12 @@ module EmbeddedLocalization
|
|
4
4
|
def translates(*attr_names)
|
5
5
|
return if translates? # cludge to make sure we don't set this up twice..
|
6
6
|
|
7
|
+
# for details about I18n fallbacks, check the source:
|
8
|
+
# i18n-0.6.0/lib/i18n/backend/fallbacks.rb
|
9
|
+
# i18n-0.6.0/lib/i18n/locale/fallbacks.rb
|
10
|
+
|
11
|
+
# options[:fallbacks] => true or false # not used at this time
|
7
12
|
options = attr_names.extract_options!
|
8
|
-
# options[:fallback] => true or false
|
9
13
|
|
10
14
|
class_attribute :translated_attribute_names, :translation_options
|
11
15
|
self.translated_attribute_names = attr_names.map(&:to_sym).sort.uniq
|
@@ -14,10 +18,17 @@ module EmbeddedLocalization
|
|
14
18
|
include InstanceMethods
|
15
19
|
extend ClassMethods
|
16
20
|
|
21
|
+
#-
|
17
22
|
# if ActiveRecord::Base is in the parent-chain of the class where we are included into:
|
23
|
+
# ::Rails::Railtie.subclasses.map(&:to_s).include?("ActiveRecord::Railtie")
|
24
|
+
#+
|
25
|
+
|
18
26
|
serialize :i18n # we should also protect it from direct assignment by the user
|
19
27
|
|
28
|
+
#-
|
20
29
|
# if Mongoid::Document is in the list of classes which extends the class we are included into:
|
30
|
+
# ::Rails::Railtie.subclasses.map(&:to_s).include?("Rails::Mongoid::Railtie")
|
31
|
+
|
21
32
|
# field :i18n, type: Hash
|
22
33
|
# but on the other hand, Mongoid now supports "localized fields" -- so we don't need to re-implement this.
|
23
34
|
# Yay! Durran Jordan is awesome! :-) See: http://mongoid.org/docs/documents/localized.html
|
@@ -30,32 +41,40 @@ module EmbeddedLocalization
|
|
30
41
|
# - we can easily hide the internal hash by re-defining the attr-accessors for doing the I18n
|
31
42
|
# - we can better add the per-attribute versioning, which is planned
|
32
43
|
# -
|
44
|
+
#+
|
33
45
|
|
34
46
|
after_initialize :initialize_i18n_hashes
|
35
47
|
|
36
|
-
|
37
48
|
# dynamically define the accessors for the translated attributes:
|
38
49
|
|
39
50
|
translated_attribute_names.each do |attr_name|
|
40
51
|
class_eval do
|
41
52
|
# define the getter method
|
53
|
+
#
|
42
54
|
define_method(attr_name) do |locale = I18n.locale|
|
43
|
-
if
|
44
|
-
|
45
|
-
|
55
|
+
if self.i18n.has_key?(locale)
|
56
|
+
self.i18n[ locale ][attr_name]
|
57
|
+
else
|
58
|
+
# fallback to the I18n.default_locale if we do fallbacks:
|
59
|
+
if self.class.fallbacks? && self.i18n[ I18n.default_locale ]
|
60
|
+
return self.i18n[ I18n.default_locale ][attr_name]
|
61
|
+
else
|
62
|
+
return nil
|
63
|
+
end
|
46
64
|
end
|
47
|
-
self.i18n[ locale ][attr_name]
|
48
65
|
end
|
49
66
|
|
50
|
-
|
67
|
+
# define the setter method
|
68
|
+
#
|
51
69
|
define_method(attr_name.to_s+ '=') do |new_translation|
|
70
|
+
self.i18n_will_change! # for ActiveModel Dirty tracking
|
52
71
|
self.i18n[I18n.locale] ||= HashWithIndifferentAccess.new
|
53
72
|
self.i18n[I18n.locale][attr_name] = new_translation
|
54
73
|
end
|
55
74
|
end
|
56
75
|
end
|
57
76
|
end
|
58
|
-
|
77
|
+
|
59
78
|
def translates?
|
60
79
|
included_modules.include?(InstanceMethods)
|
61
80
|
end
|
@@ -16,9 +16,18 @@ module EmbeddedLocalization
|
|
16
16
|
translated_attribute_names.include?(name.to_sym)
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
# # determine if we are using fallbacks
|
20
|
+
def fallbacks?
|
21
|
+
i18n_fallbacks = I18n.backend.class.included_modules.map(&:to_s).include?('I18n::Backend::Fallbacks') # will be true if config.i18n.fallbacks => true in config
|
22
|
+
i18n_fallbacks || translation_options[:fallbacks] == true
|
21
23
|
end
|
24
|
+
|
25
|
+
#-
|
26
|
+
# # fetch the fallbacks from the i18n backend
|
27
|
+
# def fallbacks
|
28
|
+
# fallbacks? ? I18n.fallbacks : nil
|
29
|
+
# end
|
30
|
+
|
22
31
|
end
|
23
32
|
end
|
24
33
|
end
|
@@ -2,19 +2,22 @@ module EmbeddedLocalization
|
|
2
2
|
module ActiveRecord
|
3
3
|
module InstanceMethods
|
4
4
|
|
5
|
-
#
|
6
|
-
#
|
7
|
-
|
5
|
+
# we only support fallbacks to I18n.default_locale for now
|
6
|
+
#
|
8
7
|
def get_localized_attribute(attr_name, locale)
|
9
|
-
if
|
10
|
-
return self.i18n[ I18n.default_locale ][attr_name] if ActsAsI18n.fallback?
|
11
|
-
return nil
|
12
|
-
else
|
8
|
+
if self.i18n.has_key?(locale)
|
13
9
|
self.i18n[locale][attr_name]
|
10
|
+
else
|
11
|
+
if self.class.fallbacks? && self.i18n[ I18n.default_locale ]
|
12
|
+
return self.i18n[ I18n.default_locale ][attr_name]
|
13
|
+
else
|
14
|
+
return nil
|
15
|
+
end
|
14
16
|
end
|
15
17
|
end
|
16
|
-
|
18
|
+
|
17
19
|
def set_localized_attribute(attr_name, locale, new_translation)
|
20
|
+
self.i18n_will_change! # for ActiveModel Dirty tracking
|
18
21
|
self.i18n[locale] ||= HashWithIndifferentAccess.new
|
19
22
|
self.i18n[locale][attr_name] = new_translation
|
20
23
|
end
|
@@ -3,15 +3,30 @@ require 'extensions/hash'
|
|
3
3
|
|
4
4
|
module EmbeddedLocalization
|
5
5
|
autoload :ActiveRecord, 'embedded_localization/active_record'
|
6
|
-
|
7
|
-
class << self
|
8
|
-
class_attribute :fallback
|
9
|
-
|
10
|
-
def fallback?
|
11
|
-
fallback == true
|
12
|
-
end
|
13
|
-
end
|
14
6
|
end
|
15
7
|
|
16
8
|
# we're assuming for now only to be used with ActiveRecord 3, which is auto-required above
|
17
9
|
ActiveRecord::Base.extend(EmbeddedLocalization::ActiveRecord::ActMacro)
|
10
|
+
|
11
|
+
#-
|
12
|
+
# ------------------------------------------------------------------------------------------------------
|
13
|
+
# probably a good idea to keep our own implementation of fallbacks,
|
14
|
+
# because we only want to fallback to I18n.default_locale .. nothing more complicated for now.
|
15
|
+
# ------------------------------------------------------------------------------------------------------
|
16
|
+
#
|
17
|
+
# Fallbacks: https://github.com/svenfuchs/i18n/wiki/Fallbacks
|
18
|
+
#
|
19
|
+
# The problem is that the I18n backends are meant for static strings in the views, helpers, etc.; not for model data.
|
20
|
+
# Switching on the current I18n backend's fallbacks will allow us to use that backend's mappings from one locale to the fallbacks,
|
21
|
+
# but we still need to search for the translated module data in our serialized i18n attribute hash ourselves.
|
22
|
+
|
23
|
+
# to enable I18n fallbacks:
|
24
|
+
# require "i18n/backend/fallbacks"
|
25
|
+
# I18n.backend.class.send(:include, I18n::Backend::Fallbacks)
|
26
|
+
|
27
|
+
# Thread.current[:i18n_config].backend
|
28
|
+
# ?? I18n.fallbacks.map('es' => 'en') ?? doesn't seem to work as expected..
|
29
|
+
|
30
|
+
# not as general:
|
31
|
+
# I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
|
32
|
+
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: embedded_localization
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.1.
|
5
|
+
version: 0.1.4
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Tilo Sloboda
|
@@ -10,13 +10,10 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-01-
|
13
|
+
date: 2012-01-31 00:00:00 Z
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description:
|
17
|
-
Rails I18n: Embedded_Localization for ActiveRecord 3 is very lightweight, and allows you to \
|
18
|
-
transparently store translations of attributes right inside each record -- no extra database tables needed to store \
|
19
|
-
the localization data!
|
16
|
+
description: "Rails I18n: Embedded_Localization for ActiveRecord 3 is very lightweight, and allows you to transparently store translations of attributes right inside each record -- no extra database tables needed to store the localization data!"
|
20
17
|
email:
|
21
18
|
- tilo.sloboda@gmail.com
|
22
19
|
executables: []
|