globalize2 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/README.textile +27 -143
- data/VERSION +1 -1
- data/generators/templates/db_backend_migration.rb +3 -3
- data/globalize2.gemspec +30 -49
- data/init.rb +1 -8
- data/lib/globalize.rb +15 -0
- data/lib/globalize/active_record.rb +195 -0
- data/lib/globalize/active_record/adapter.rb +80 -0
- data/lib/globalize/active_record/attributes.rb +25 -0
- data/lib/globalize/active_record/migration.rb +40 -0
- data/lib/{globalize/i18n → i18n}/missing_translations_log_handler.rb +8 -8
- data/lib/{globalize/i18n → i18n}/missing_translations_raise_handler.rb +3 -5
- data/test/active_record/fallbacks_test.rb +102 -0
- data/test/{model/active_record → active_record}/migration_test.rb +21 -26
- data/test/{model/active_record → active_record}/sti_translated_test.rb +4 -30
- data/test/active_record/translates_test.rb +87 -0
- data/test/active_record/translation_class_test.rb +30 -0
- data/test/active_record/validation_tests.rb +75 -0
- data/test/active_record_test.rb +451 -0
- data/test/data/models.rb +16 -0
- data/test/data/schema.rb +23 -7
- data/test/i18n/missing_translations_test.rb +6 -6
- data/test/test_helper.rb +55 -15
- metadata +33 -46
- data/lib/globalize/backend/chain.rb +0 -102
- data/lib/globalize/backend/pluralizing.rb +0 -37
- data/lib/globalize/backend/static.rb +0 -61
- data/lib/globalize/load_path.rb +0 -63
- data/lib/globalize/locale/fallbacks.rb +0 -63
- data/lib/globalize/locale/language_tag.rb +0 -81
- data/lib/globalize/model/active_record.rb +0 -56
- data/lib/globalize/model/active_record/adapter.rb +0 -100
- data/lib/globalize/model/active_record/translated.rb +0 -174
- data/lib/globalize/translation.rb +0 -32
- data/lib/locale/root.yml +0 -3
- data/lib/rails_edge_load_path_patch.rb +0 -40
- data/notes.textile +0 -51
- data/test/backends/chained_test.rb +0 -175
- data/test/backends/pluralizing_test.rb +0 -63
- data/test/backends/static_test.rb +0 -147
- data/test/data/locale/all.yml +0 -2
- data/test/data/locale/de-DE.yml +0 -2
- data/test/data/locale/en-US.yml +0 -2
- data/test/data/locale/en-US/module.yml +0 -2
- data/test/data/locale/fi-FI/module.yml +0 -2
- data/test/data/locale/root.yml +0 -0
- data/test/load_path_test.rb +0 -49
- data/test/locale/fallbacks_test.rb +0 -154
- data/test/locale/language_tag_test.rb +0 -130
- data/test/model/active_record/translated_test.rb +0 -487
- data/test/translation_test.rb +0 -54
@@ -1,61 +0,0 @@
|
|
1
|
-
require 'globalize/backend/pluralizing'
|
2
|
-
require 'globalize/locale/fallbacks'
|
3
|
-
require 'globalize/translation'
|
4
|
-
|
5
|
-
module Globalize
|
6
|
-
module Backend
|
7
|
-
class Static < Pluralizing
|
8
|
-
def initialize(*args)
|
9
|
-
add(*args) unless args.empty?
|
10
|
-
end
|
11
|
-
|
12
|
-
def translate(locale, key, options = {})
|
13
|
-
result, default, fallback = nil, options.delete(:default), nil
|
14
|
-
I18n.fallbacks[locale].each do |fallback|
|
15
|
-
begin
|
16
|
-
result = super(fallback, key, options) and break
|
17
|
-
rescue I18n::MissingTranslationData
|
18
|
-
end
|
19
|
-
end
|
20
|
-
result ||= default locale, default, options
|
21
|
-
|
22
|
-
attrs = {:requested_locale => locale, :locale => fallback, :key => key, :options => options}
|
23
|
-
translation(result, attrs)
|
24
|
-
# translation(result, attrs) || raise(I18n::MissingTranslationData.new(locale, key, options))
|
25
|
-
end
|
26
|
-
|
27
|
-
protected
|
28
|
-
|
29
|
-
alias :orig_interpolate :interpolate unless method_defined? :orig_interpolate
|
30
|
-
def interpolate(locale, string, values = {})
|
31
|
-
result = orig_interpolate(locale, string, values)
|
32
|
-
translation = translation(string)
|
33
|
-
translation.nil? ? result : translation.replace(result)
|
34
|
-
end
|
35
|
-
|
36
|
-
def translation(result, meta = nil)
|
37
|
-
return unless result
|
38
|
-
|
39
|
-
case result
|
40
|
-
when Numeric
|
41
|
-
result
|
42
|
-
when String
|
43
|
-
result = Translation::Static.new(result) unless result.is_a? Translation::Static
|
44
|
-
result.set_meta meta
|
45
|
-
result
|
46
|
-
when Hash
|
47
|
-
Hash[*result.map do |key, value|
|
48
|
-
[key, translation(value, meta)]
|
49
|
-
end.flatten]
|
50
|
-
when Array
|
51
|
-
result.map do |value|
|
52
|
-
translation(value, meta)
|
53
|
-
end
|
54
|
-
else
|
55
|
-
result
|
56
|
-
# raise "unexpected translation type: #{result.inspect}"
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
data/lib/globalize/load_path.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
# Locale load_path and Locale loading support.
|
2
|
-
#
|
3
|
-
# To use this include the Globalize::LoadPath::I18n module to I18n like this:
|
4
|
-
#
|
5
|
-
# I18n.send :include, Globalize::LoadPath::I18n
|
6
|
-
#
|
7
|
-
# Clients can add load_paths using:
|
8
|
-
#
|
9
|
-
# I18n.load_path.add load_path, 'rb', 'yml' # pass any number of extensions like this
|
10
|
-
# I18n.load_path << 'path/to/dir' # usage without an extension, defaults to 'yml'
|
11
|
-
#
|
12
|
-
# And load locale data using either of:
|
13
|
-
#
|
14
|
-
# I18n.load_locales 'en-US', 'de-DE'
|
15
|
-
# I18n.load_locale 'en-US'
|
16
|
-
#
|
17
|
-
# This will lookup all files named like:
|
18
|
-
#
|
19
|
-
# 'path/to/dir/all.yml'
|
20
|
-
# 'path/to/dir/en-US.yml'
|
21
|
-
# 'path/to/dir/en-US/*.yml'
|
22
|
-
#
|
23
|
-
# The filenames will be passed to I18n.load_translations which delegates to
|
24
|
-
# the backend. So the actual behaviour depends on the implementation of the
|
25
|
-
# backend. I18n::Backend::Simple will be able to read YAML and plain Ruby
|
26
|
-
# files. See the documentation for I18n.load_translations for details.
|
27
|
-
|
28
|
-
module Globalize
|
29
|
-
class LoadPath < Array
|
30
|
-
def extensions
|
31
|
-
@extensions ||= ['rb', 'yml']
|
32
|
-
end
|
33
|
-
attr_writer :extensions
|
34
|
-
|
35
|
-
def locales
|
36
|
-
@locales ||= ['*']
|
37
|
-
end
|
38
|
-
attr_writer :locales
|
39
|
-
|
40
|
-
def <<(path)
|
41
|
-
push path
|
42
|
-
end
|
43
|
-
|
44
|
-
def push(*paths)
|
45
|
-
super(*paths.map{|path| filenames(path) }.flatten.uniq.sort)
|
46
|
-
end
|
47
|
-
|
48
|
-
protected
|
49
|
-
|
50
|
-
def filenames(path)
|
51
|
-
return [path] if File.file? path
|
52
|
-
patterns(path).map{|pattern| Dir[pattern] }
|
53
|
-
end
|
54
|
-
|
55
|
-
def patterns(path)
|
56
|
-
locales.map do |locale|
|
57
|
-
extensions.map do |extension|
|
58
|
-
%W(#{path}/all.#{extension} #{path}/#{locale}.#{extension} #{path}/#{locale}/**/*.#{extension})
|
59
|
-
end
|
60
|
-
end.flatten.uniq
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'globalize/locale/language_tag'
|
2
|
-
|
3
|
-
module I18n
|
4
|
-
@@fallbacks = nil
|
5
|
-
|
6
|
-
class << self
|
7
|
-
# Returns the current fallbacks. Defaults to +Globalize::Locale::Fallbacks+.
|
8
|
-
def fallbacks
|
9
|
-
@@fallbacks ||= Globalize::Locale::Fallbacks.new
|
10
|
-
end
|
11
|
-
|
12
|
-
# Sets the current fallbacks. Used to set a custom fallbacks instance.
|
13
|
-
def fallbacks=(fallbacks)
|
14
|
-
@@fallbacks = fallbacks
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
module Globalize
|
20
|
-
module Locale
|
21
|
-
class Fallbacks < Hash
|
22
|
-
def initialize(*defaults)
|
23
|
-
@map = {}
|
24
|
-
map defaults.pop if defaults.last.is_a?(Hash)
|
25
|
-
|
26
|
-
defaults = [I18n.default_locale.to_sym] if defaults.empty?
|
27
|
-
self.defaults = defaults
|
28
|
-
end
|
29
|
-
|
30
|
-
def defaults=(defaults)
|
31
|
-
@defaults = defaults.map{|default| compute(default, false) }.flatten << :root
|
32
|
-
end
|
33
|
-
attr_reader :defaults
|
34
|
-
|
35
|
-
def [](tag)
|
36
|
-
tag = tag.to_sym
|
37
|
-
has_key?(tag) ? fetch(tag) : store(tag, compute(tag))
|
38
|
-
end
|
39
|
-
|
40
|
-
def map(mappings)
|
41
|
-
mappings.each do |from, to|
|
42
|
-
from, to = from.to_sym, Array(to)
|
43
|
-
to.each do |to|
|
44
|
-
@map[from] ||= []
|
45
|
-
@map[from] << to.to_sym
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
protected
|
51
|
-
|
52
|
-
def compute(tags, include_defaults = true)
|
53
|
-
result = Array(tags).collect do |tag|
|
54
|
-
tags = LanguageTag::tag(tag.to_sym).parents(true).map! {|t| t.to_sym }
|
55
|
-
tags.each{|tag| tags += compute(@map[tag]) if @map[tag] }
|
56
|
-
tags
|
57
|
-
end.flatten
|
58
|
-
result.push *defaults if include_defaults
|
59
|
-
result.uniq
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
# for specifications see http://en.wikipedia.org/wiki/IETF_language_tag
|
2
|
-
#
|
3
|
-
# SimpleParser does not implement advanced usages such as grandfathered tags
|
4
|
-
|
5
|
-
module Globalize
|
6
|
-
module Locale
|
7
|
-
module Rfc4646
|
8
|
-
SUBTAGS = [:language, :script, :region, :variant, :extension, :privateuse, :grandfathered]
|
9
|
-
FORMATS = {:language => :downcase, :script => :capitalize, :region => :upcase, :variant => :downcase}
|
10
|
-
end
|
11
|
-
|
12
|
-
class LanguageTag < Struct.new(*Rfc4646::SUBTAGS)
|
13
|
-
class << self
|
14
|
-
def parser
|
15
|
-
@@parser ||= SimpleParser
|
16
|
-
end
|
17
|
-
|
18
|
-
def parser=(parser)
|
19
|
-
@@parser = parser
|
20
|
-
end
|
21
|
-
|
22
|
-
def tag(tag)
|
23
|
-
matches = parser.match(tag)
|
24
|
-
new *matches if matches
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
Rfc4646::FORMATS.each do |name, format|
|
29
|
-
define_method(name) { self[name].send(format) unless self[name].nil? }
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_sym
|
33
|
-
to_s.to_sym
|
34
|
-
end
|
35
|
-
|
36
|
-
def to_s
|
37
|
-
@tag ||= to_a.compact.join("-")
|
38
|
-
end
|
39
|
-
|
40
|
-
def to_a
|
41
|
-
members.collect {|attr| self.send(attr) }
|
42
|
-
end
|
43
|
-
|
44
|
-
def parent
|
45
|
-
segs = to_a.compact
|
46
|
-
segs.length < 2 ? nil : LanguageTag.tag(segs[0..(segs.length-2)].join('-'))
|
47
|
-
end
|
48
|
-
|
49
|
-
def parents(include_self = true)
|
50
|
-
result, parent = [], self.dup
|
51
|
-
result << parent if include_self
|
52
|
-
while parent = parent.parent
|
53
|
-
result << parent
|
54
|
-
end
|
55
|
-
result
|
56
|
-
end
|
57
|
-
|
58
|
-
module SimpleParser
|
59
|
-
PATTERN = %r{\A(?:
|
60
|
-
([a-z]{2,3}(?:(?:-[a-z]{3}){0,3})?|[a-z]{4}|[a-z]{5,8}) # language
|
61
|
-
(?:-([a-z]{4}))? # script
|
62
|
-
(?:-([a-z]{2}|\d{3}))? # region
|
63
|
-
(?:-([0-9a-z]{5,8}|\d[0-9a-z]{3}))* # variant
|
64
|
-
(?:-([0-9a-wyz](?:-[0-9a-z]{2,8})+))* # extension
|
65
|
-
(?:-(x(?:-[0-9a-z]{1,8})+))?| # privateuse subtag
|
66
|
-
(x(?:-[0-9a-z]{1,8})+)| # privateuse tag
|
67
|
-
/* ([a-z]{1,3}(?:-[0-9a-z]{2,8}){1,2}) */ # grandfathered
|
68
|
-
)\z}xi
|
69
|
-
|
70
|
-
class << self
|
71
|
-
def match(tag)
|
72
|
-
c = PATTERN.match(tag.to_s).captures
|
73
|
-
c[0..4] << (c[5].nil? ? c[6] : c[5]) << c[7] # TODO c[7] is grandfathered, throw a NotImplemented exception here?
|
74
|
-
rescue
|
75
|
-
false
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
require 'globalize/translation'
|
2
|
-
require 'globalize/locale/fallbacks'
|
3
|
-
require 'globalize/model/active_record/adapter'
|
4
|
-
require 'globalize/model/active_record/translated'
|
5
|
-
|
6
|
-
module Globalize
|
7
|
-
module Model
|
8
|
-
module ActiveRecord
|
9
|
-
class << self
|
10
|
-
def create_proxy_class(klass)
|
11
|
-
module_names = klass.name.split('::')
|
12
|
-
klass_name = module_names.pop
|
13
|
-
target = module_names.empty? ? Object : module_names.join('::').constantize
|
14
|
-
|
15
|
-
proxy_class_name = "#{klass_name}Translation"
|
16
|
-
proxy_class = nil
|
17
|
-
begin
|
18
|
-
proxy_class = proxy_class_name.constantize
|
19
|
-
rescue NameError
|
20
|
-
proxy_class = target.const_set proxy_class_name, Class.new(::ActiveRecord::Base)
|
21
|
-
end
|
22
|
-
|
23
|
-
proxy_class.instance_eval do
|
24
|
-
belongs_to "#{klass.name.underscore.gsub('/', '_')}".intern
|
25
|
-
end
|
26
|
-
proxy_class.class_eval do
|
27
|
-
def locale
|
28
|
-
read_attribute(:locale).to_sym
|
29
|
-
end
|
30
|
-
|
31
|
-
def locale=(locale)
|
32
|
-
write_attribute(:locale, locale.to_s)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
return proxy_class
|
37
|
-
end
|
38
|
-
|
39
|
-
def define_accessors(klass, attr_names)
|
40
|
-
attr_names.each do |attr_name|
|
41
|
-
klass.send :define_method, attr_name, lambda {
|
42
|
-
globalize.fetch self.class.locale, attr_name
|
43
|
-
}
|
44
|
-
klass.send :define_method, "#{attr_name}_before_type_cast", lambda {
|
45
|
-
globalize.fetch self.class.locale, attr_name
|
46
|
-
}
|
47
|
-
klass.send :define_method, "#{attr_name}=", lambda {|val|
|
48
|
-
globalize.stash self.class.locale, attr_name, val
|
49
|
-
self[attr_name] = val
|
50
|
-
}
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,100 +0,0 @@
|
|
1
|
-
module Globalize
|
2
|
-
module Model
|
3
|
-
class AttributeStash < Hash
|
4
|
-
def contains?(locale, attr_name)
|
5
|
-
locale = locale.to_sym
|
6
|
-
self[locale] ||= {}
|
7
|
-
self[locale].has_key? attr_name
|
8
|
-
end
|
9
|
-
|
10
|
-
def read(locale, attr_name)
|
11
|
-
locale = locale.to_sym
|
12
|
-
self[locale] ||= {}
|
13
|
-
self[locale][attr_name]
|
14
|
-
end
|
15
|
-
|
16
|
-
def write(locale, attr_name, value)
|
17
|
-
locale = locale.to_sym
|
18
|
-
self[locale] ||= {}
|
19
|
-
self[locale][attr_name] = value
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class Adapter
|
24
|
-
def initialize(record)
|
25
|
-
@record = record
|
26
|
-
|
27
|
-
# TODO what exactly are the roles of cache and stash
|
28
|
-
@cache = AttributeStash.new
|
29
|
-
@stash = AttributeStash.new
|
30
|
-
end
|
31
|
-
|
32
|
-
def fetch(locale, attr_name)
|
33
|
-
# locale = I18n.locale
|
34
|
-
is_cached = @cache.contains?(locale, attr_name)
|
35
|
-
is_cached ? @cache.read(locale, attr_name) : begin
|
36
|
-
value = fetch_attribute locale, attr_name
|
37
|
-
@cache.write locale, attr_name, value if value && value.locale == locale
|
38
|
-
value
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def stash(locale, attr_name, value)
|
43
|
-
@stash.write locale, attr_name, value
|
44
|
-
@cache.write locale, attr_name, value
|
45
|
-
end
|
46
|
-
|
47
|
-
def update_translations!
|
48
|
-
@stash.each do |locale, attrs|
|
49
|
-
translation = @record.globalize_translations.find_or_initialize_by_locale(locale.to_s)
|
50
|
-
attrs.each{|attr_name, value| translation[attr_name] = value }
|
51
|
-
translation.save!
|
52
|
-
end
|
53
|
-
@stash.clear
|
54
|
-
end
|
55
|
-
|
56
|
-
# Clears the cache
|
57
|
-
def clear
|
58
|
-
@cache.clear
|
59
|
-
@stash.clear
|
60
|
-
end
|
61
|
-
|
62
|
-
def clear_cache
|
63
|
-
@cache.clear
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def fetch_attribute(locale, attr_name)
|
69
|
-
fallbacks = I18n.fallbacks[locale].map{|tag| tag.to_s}.map(&:to_sym)
|
70
|
-
|
71
|
-
# If the translations were included with
|
72
|
-
# :include => globalize_translations
|
73
|
-
# there is no need to query them again.
|
74
|
-
unless @record.globalize_translations.loaded?
|
75
|
-
translations = @record.globalize_translations.by_locales(fallbacks)
|
76
|
-
else
|
77
|
-
translations = @record.globalize_translations
|
78
|
-
end
|
79
|
-
result, requested_locale = nil, locale
|
80
|
-
|
81
|
-
# Walk through the fallbacks, starting with the current locale itself, and moving
|
82
|
-
# to the next best choice, until we find a match.
|
83
|
-
# Check the @globalize_set_translations cache first to see if we've just changed the
|
84
|
-
# attribute and not saved yet.
|
85
|
-
fallbacks.each do |fallback|
|
86
|
-
# TODO should we be checking stash or just cache?
|
87
|
-
result = @cache.read(fallback, attr_name) || begin
|
88
|
-
translation = translations.detect {|tr| tr.locale == fallback }
|
89
|
-
translation && translation.send(attr_name)
|
90
|
-
end
|
91
|
-
if result
|
92
|
-
locale = fallback
|
93
|
-
break
|
94
|
-
end
|
95
|
-
end
|
96
|
-
result && Translation::Attribute.new(result, :locale => locale, :requested_locale => requested_locale)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
@@ -1,174 +0,0 @@
|
|
1
|
-
require 'digest/sha1'
|
2
|
-
|
3
|
-
module Globalize
|
4
|
-
module Model
|
5
|
-
class MigrationError < StandardError; end
|
6
|
-
class MigrationMissingTranslatedField < MigrationError; end
|
7
|
-
class BadMigrationFieldType < MigrationError; end
|
8
|
-
|
9
|
-
module ActiveRecord
|
10
|
-
module Translated
|
11
|
-
def self.included(base)
|
12
|
-
base.extend ActMethods
|
13
|
-
end
|
14
|
-
|
15
|
-
module ActMethods
|
16
|
-
def translates(*attr_names)
|
17
|
-
options = attr_names.extract_options!
|
18
|
-
options[:translated_attributes] = attr_names
|
19
|
-
|
20
|
-
# Only set up once per class
|
21
|
-
unless included_modules.include? InstanceMethods
|
22
|
-
class_inheritable_accessor :globalize_options, :globalize_proxy
|
23
|
-
|
24
|
-
include InstanceMethods
|
25
|
-
extend ClassMethods
|
26
|
-
|
27
|
-
self.globalize_proxy = Globalize::Model::ActiveRecord.create_proxy_class(self)
|
28
|
-
has_many(
|
29
|
-
:globalize_translations,
|
30
|
-
:class_name => globalize_proxy.name,
|
31
|
-
:extend => Extensions,
|
32
|
-
:dependent => :delete_all,
|
33
|
-
:foreign_key => class_name.foreign_key
|
34
|
-
)
|
35
|
-
|
36
|
-
after_save :update_globalize_record
|
37
|
-
end
|
38
|
-
|
39
|
-
self.globalize_options = options
|
40
|
-
Globalize::Model::ActiveRecord.define_accessors(self, attr_names)
|
41
|
-
|
42
|
-
# Import any callbacks that have been defined by extensions to Globalize2
|
43
|
-
# and run them.
|
44
|
-
extend Callbacks
|
45
|
-
Callbacks.instance_methods.each { |callback| send(callback) }
|
46
|
-
end
|
47
|
-
|
48
|
-
def locale=(locale)
|
49
|
-
@@locale = locale
|
50
|
-
end
|
51
|
-
|
52
|
-
def locale
|
53
|
-
(defined?(@@locale) && @@locale) || I18n.locale
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# Dummy Callbacks module. Extensions to Globalize2 can insert methods into here
|
58
|
-
# and they'll be called at the end of the translates class method.
|
59
|
-
module Callbacks
|
60
|
-
end
|
61
|
-
|
62
|
-
# Extension to the has_many :globalize_translations association
|
63
|
-
module Extensions
|
64
|
-
def by_locales(locales)
|
65
|
-
find :all, :conditions => { :locale => locales.map(&:to_s) }
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
module ClassMethods
|
70
|
-
def method_missing(method, *args)
|
71
|
-
if method.to_s =~ /^find_by_(\w+)$/ && globalize_options[:translated_attributes].include?($1.to_sym)
|
72
|
-
find(:first, :joins => :globalize_translations,
|
73
|
-
:conditions => [ "#{i18n_attr($1)} = ? AND #{i18n_attr('locale')} IN (?)",
|
74
|
-
args.first,I18n.fallbacks[I18n.locale].map{|tag| tag.to_s}])
|
75
|
-
else
|
76
|
-
super
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def create_translation_table!(fields)
|
81
|
-
translated_fields = self.globalize_options[:translated_attributes]
|
82
|
-
translated_fields.each do |f|
|
83
|
-
raise MigrationMissingTranslatedField, "Missing translated field #{f}" unless fields[f]
|
84
|
-
end
|
85
|
-
|
86
|
-
fields.each do |name, type|
|
87
|
-
if translated_fields.include?(name) && ![:string, :text].include?(type)
|
88
|
-
raise BadMigrationFieldType, "Bad field type for #{name}, should be :string or :text"
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
self.connection.create_table(translation_table_name) do |t|
|
93
|
-
t.references self.table_name.singularize
|
94
|
-
t.string :locale
|
95
|
-
fields.each do |name, type|
|
96
|
-
t.column name, type
|
97
|
-
end
|
98
|
-
t.timestamps
|
99
|
-
end
|
100
|
-
|
101
|
-
self.connection.add_index(translation_table_name, "#{self.table_name.singularize}_id", :name => translation_index_name)
|
102
|
-
end
|
103
|
-
|
104
|
-
def set_translation_table_name(table_name)
|
105
|
-
globalize_proxy.set_table_name(table_name)
|
106
|
-
end
|
107
|
-
|
108
|
-
def translation_table_name
|
109
|
-
globalize_proxy.table_name
|
110
|
-
end
|
111
|
-
|
112
|
-
def translation_index_name
|
113
|
-
# FIXME what's the max size of an index name?
|
114
|
-
index_name = "index_#{translation_table_name}_on_#{self.table_name.singularize}_id"
|
115
|
-
index_name.size < 50 ? index_name : "index_#{Digest::SHA1.hexdigest(index_name)}"
|
116
|
-
end
|
117
|
-
|
118
|
-
def drop_translation_table!
|
119
|
-
self.connection.remove_index(translation_table_name, :name => translation_index_name)
|
120
|
-
self.connection.drop_table translation_table_name
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
|
125
|
-
def i18n_attr(attribute_name)
|
126
|
-
self.base_class.name.underscore.gsub('/', '_') + "_translations.#{attribute_name}"
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
module InstanceMethods
|
131
|
-
def reload(options = nil)
|
132
|
-
globalize.clear_cache
|
133
|
-
|
134
|
-
# clear all globalized attributes
|
135
|
-
# TODO what's the best way to handle this?
|
136
|
-
self.class.globalize_options[:translated_attributes].each do |attr|
|
137
|
-
@attributes.delete(attr.to_s)
|
138
|
-
end
|
139
|
-
|
140
|
-
super(options)
|
141
|
-
end
|
142
|
-
|
143
|
-
def translated_attributes
|
144
|
-
self.class.globalize_options[:translated_attributes].inject({}) {|h, tf| h[tf] = send(tf); h }
|
145
|
-
end
|
146
|
-
|
147
|
-
def globalize
|
148
|
-
@globalize ||= Adapter.new self
|
149
|
-
end
|
150
|
-
|
151
|
-
def update_globalize_record
|
152
|
-
globalize.update_translations!
|
153
|
-
end
|
154
|
-
|
155
|
-
def translated_locales
|
156
|
-
globalize_translations.scoped(:select => 'DISTINCT locale').map do |translation|
|
157
|
-
translation.locale.to_sym
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
def set_translations(options)
|
162
|
-
options.keys.each do |key|
|
163
|
-
translation = globalize_translations.find_by_locale(key.to_s) ||
|
164
|
-
globalize_translations.build(:locale => key.to_s)
|
165
|
-
translation.update_attributes!(options[key])
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
ActiveRecord::Base.send(:include, Globalize::Model::ActiveRecord::Translated)
|