📄 db_translate.rb
字号:
module Globalize # :nodoc:
class WrongLanguageError < ActiveRecord::ActiveRecordError
attr_reader :original_language, :active_language
def initialize(orig_lang, active_lang)
@original_language = orig_lang
@active_language = active_lang
end
end
class TranslationTrampleError < ActiveRecord::ActiveRecordError; end
module DbTranslate # :nodoc:
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
=begin rdoc
Specifies fields that can be translated. These are normal ActiveRecord
fields, with corresponding database columns, but they are shadowed
by translations in a special translation table. All the translation
stuff is done behind the scenes.
=== Example:
==== In your model:
class Product < ActiveRecord::Base
translates :name, :description
end
==== In your controller:
Locale.set("en_US")
product.name -> guitar
Locale.set("es_ES")
product.name -> guitarra
=end
def translates(*facets)
# parse out options hash
options = facets.pop if facets.last.kind_of? Hash
options ||= {}
facets_string = "[" + facets.map {|facet| ":#{facet}"}.join(", ") + "]"
class_eval <<-HERE
@@facet_options = {}
attr_writer :fully_loaded
def fully_loaded?; @fully_loaded; end
@@globalize_facets = #{facets_string}
@@preload_facets ||= @@globalize_facets
class << self
def sqlite?; connection.kind_of? ActiveRecord::ConnectionAdapters::SQLiteAdapter end
def globalize_facets
@@globalize_facets
end
def globalize_facets_hash
@@globalize_facets_hash ||= globalize_facets.inject({}) {|hash, facet|
hash[facet.to_s] = true; hash
}
end
def untranslated_fields
@@untranslated_fields ||=
column_names.map {|cn| cn.intern } - globalize_facets
end
def preload_facets; @@preload_facets; end
def postload_facets
@@postload_facets ||= @@globalize_facets - @@preload_facets
end
alias_method :globalize_old_find, :find unless
respond_to? :globalize_old_find
end
alias_method :globalize_old_reload, :reload
alias_method :globalize_old_destroy, :destroy
alias_method :globalize_old_create_or_update, :create_or_update
include Globalize::DbTranslate::TranslateObjectMethods
extend Globalize::DbTranslate::TranslateClassMethods
HERE
facets.each do |facet|
bidi = (!(options[facet] && !options[facet][:bidi_embed])).to_s
class_eval <<-HERE
@@facet_options[:#{facet}] ||= {}
@@facet_options[:#{facet}][:bidi] = #{bidi}
def #{facet}
if not_original_language
raise WrongLanguageError.new(@original_language, Locale.language)
end
load_other_translations if
!fully_loaded? && !self.class.preload_facets.include?(:#{facet})
result = read_attribute(:#{facet})
return nil if result.nil?
result.direction = #{facet}_is_base? ?
(Locale.base_language ? Locale.base_language.direction : nil) :
(@original_language ? @original_language.direction : nil)
# insert bidi embedding characters, if necessary
if @@facet_options[:#{facet}][:bidi] &&
Locale.language && Locale.language.direction && result.direction
if Locale.language.direction == 'ltr' && result.direction == 'rtl'
bidi_str = "\xe2\x80\xab" + result + "\xe2\x80\xac"
bidi_str.direction = result.direction
return bidi_str
elsif Locale.language.direction == 'rtl' && result.direction == 'ltr'
bidi_str = "\xe2\x80\xaa" + result + "\xe2\x80\xac"
bidi_str.direction = result.direction
return bidi_str
end
end
return result
end
def #{facet}=(arg)
raise WrongLanguageError.new(@original_language, Locale.language) if
not_original_language
write_attribute(:#{facet}, arg)
end
def #{facet}_is_base?
self['#{facet}_not_base'].nil?
end
HERE
end
end
=begin rdoc
Optionally specifies translated fields to be preloaded on <tt>find</tt>. For instance,
in a product catalog, you may want to do a <tt>find</tt> of the first 10 products:
Product.find(:all, :limit => 10, :order => "name")
But you wouldn't want to load the complete descriptions and specs of all the
products, just the names and summaries. So you'd specify:
class Product < ActiveRecord::Base
translates :name, :summary, :description, :specs
translates_preload :name, :summary
...
end
By default (if no translates_preload is specified), Globalize will preload
the first field given to <tt>translates</tt>. It will also fully load on
a <tt>find(:first)</tt> or when <tt>:translate_all => true</tt> is given as a find option.
=end
def translates_preload(*facets)
module_eval <<-HERE
@@preload_facets = facets
HERE
end
end
module TranslateObjectMethods # :nodoc: all
module_eval <<-HERE
def not_original_language
return false if @original_language.nil?
return @original_language != Locale.language
end
def set_original_language
@original_language = Locale.language
end
HERE
def load_other_translations
postload_facets = self.class.postload_facets
return if postload_facets.empty? || new_record?
table_name = self.class.table_name
facet_selection = postload_facets.join(", ")
base = connection.select_one("SELECT #{facet_selection} " +
" FROM #{table_name} WHERE #{self.class.primary_key} = #{id}",
"loading base for load_other_translations")
base.each {|key, val| write_attribute( key, val ) }
unless Locale.base?
trs = ModelTranslation.find(:all,
:conditions => [ "table_name = ? AND item_id = ? AND language_id = ? AND " +
"facet IN (#{[ '?' ] * postload_facets.size * ', '})", table_name,
self.id, Locale.active.language.id ] + postload_facets.map {|facet| facet.to_s} )
trs ||= []
trs.each do |tr|
attr = tr.text || base[tr.facet.to_s]
write_attribute( tr.facet, attr )
end
end
self.fully_loaded = true
end
def destroy
globalize_old_destroy
ModelTranslation.delete_all( [ "table_name = ? AND item_id = ?",
self.class.table_name, id ])
end
def reload
globalize_old_reload
set_original_language
end
private
# Returns copy of the attributes hash where all the values have been safely quoted for use in
# an SQL statement.
# REDEFINED to include only untranslated fields. We don't want to overwrite the
# base translation with other translations.
def attributes_with_quotes(include_primary_key = true)
if Locale.base?
attributes.inject({}) do |quoted, (name, value)|
if column = column_for_attribute(name)
quoted[name] = quote(value, column) unless !include_primary_key && column.primary
end
quoted
end
else
attributes.inject({}) do |quoted, (name, value)|
if !self.class.globalize_facets_hash.has_key?(name) &&
column = column_for_attribute(name)
quoted[name] = quote(value, column) unless !include_primary_key && column.primary
end
quoted
end
end
end
def create_or_update
globalize_old_create_or_update
update_translation if Locale.active
end
def update_translation
raise WrongLanguageError.new(@original_language, Locale.language) if
not_original_language
set_original_language
# nothing to do, facets updated in main model
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -