Skip to content

Commit

Permalink
--Adding bidi support to internal storage mechanism.
Browse files Browse the repository at this point in the history
--Adding rdoc mentioning bidi support in Globalize and how to 
  de/activate it via facet options.
--Add support for hebrew in internal storage mechanism testing to allow testing of bidi.
--Fixed rdoc references to old 'localizes' method.
  • Loading branch information
saimonmoore committed Jan 26, 2007
1 parent bf8fea9 commit 5f76371
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 14 deletions.
86 changes: 73 additions & 13 deletions lib/globalize/localization/db_translate.rb
Expand Up @@ -57,7 +57,32 @@ class Product < ActiveRecord::Base
translates :name, :description, {:some_option => true}
The available options are described below.
The available options are described below:
==== Option for Bidrectional text (bidi)
Globalize fully supports Bidirectional text. By default all attributes
that have been passed to 'translates' will have bidi active.
If for some reason, you wish do disactivate bidi for a particular attribute
then you may specify this in the options hash. e.g.
translates :name, :description, {:name => {:bidi_embed => false}}
In this example bidi will be active for the 'description' attribute but
not for the 'name' attribute.
With 'bidi_embed' active the direction of the string is determined in the
following manner:
* If an attribute has no translation for the current locale then the
direction will be that of the base locale.
* If an attribute has a translation for the currently active locale then
the direction of it's value will be that of the active locale.
Note: This feature is valid for both of the currently supported storage mechanisms
== Storage Mechanisms
Expand Down Expand Up @@ -87,7 +112,7 @@ class Product < ActiveRecord::Base
class Product < ActiveRecord::Base
self.keep_translations_in_model = true
localizes :name, :description, :specs
translates :name, :description, :specs
end
Expand Down Expand Up @@ -344,6 +369,7 @@ def translates_preload(*facets)
def translate_internal(facets, options)
facets_string = "[" + facets.map {|facet| ":#{facet}"}.join(", ") + "]"
class_eval %{
@@facet_options = {}
@@globalize_facets = #{facets_string}
def self.globalize_facets
Expand All @@ -365,10 +391,10 @@ def non_localized_fields
#Returns true if translated
#Warning! Depends on Locale.switch_locale
def translated?(facet, locale_code = nil)
localized_method = "\#{facet}_\#{Locale.active.language.code}"
localized_method = "\#{facet}_\#{Locale.language.code}"
Locale.switch_locale(locale_code) do
localized_method = "\#{facet}_\#{Locale.active.language.code}"
localized_method = "\#{facet}_\#{Locale.language.code}"
end if locale_code
value = send(localized_method.to_sym) if respond_to?(localized_method.to_sym)
Expand All @@ -377,34 +403,43 @@ def translated?(facet, locale_code = nil)
}

facets.each do |facet|
bidi = (!(options[facet] && !options[facet][:bidi_embed])).to_s
class_eval %{
#Handle facet-specific options (.e.g a bidirectional setting)
@@facet_options[:#{facet}] ||= {}
@@facet_options[:#{facet}][:bidi] = #{bidi}
#Accessor that proxies to the right accessor for the current locale
def #{facet}
value = nil
unless Locale.base?
localized_method = "#{facet}_\#{Locale.active.language.code}"
localized_method = "#{facet}_\#{Locale.language.code}"
value = send(localized_method.to_sym) if respond_to?(localized_method.to_sym)
value = value ? value : read_attribute(:#{facet}) if #{options[:base_as_default]}
return value
else
value = read_attribute(:#{facet})
end
read_attribute(:#{facet})
value.nil? ? nil : add_bidi(value, :#{facet})
end
#Accessor before typecasting that proxies to the right accessor for the current locale
def #{facet}_before_type_cast
unless Locale.base?
localized_method = "#{facet}_\#{Locale.active.language.code}_before_type_cast"
localized_method = "#{facet}_\#{Locale.language.code}_before_type_cast"
value = send(localized_method.to_sym) if respond_to?(localized_method.to_sym)
value = value ? value : read_attribute_before_type_cast('#{facet}') if #{options[:base_as_default]}
return value
else
value = read_attribute_before_type_cast('#{facet}')
end
read_attribute_before_type_cast('#{facet}')
value.nil? ? nil : add_bidi(value, :#{facet})
end
#Write to appropriate localized attribute
def #{facet}=(value)
unless Locale.base?
localized_method = "#{facet}_\#{Locale.active.language.code}"
localized_method = "#{facet}_\#{Locale.language.code}"
write_attribute(localized_method.to_sym, value) if respond_to?(localized_method.to_sym)
else
write_attribute(:#{facet}, value)
Expand All @@ -414,14 +449,15 @@ def #{facet}=(value)
#Is field translated?
#Returns true if untranslated
def #{facet}_is_base?
localized_method = "#{facet}_\#{Locale.active.language.code}"
localized_method = "#{facet}_\#{Locale.language.code}"
value = send(localized_method.to_sym) if respond_to?(localized_method.to_sym)
return value.nil?
end
#Read base language attribute directly
def _#{facet}
read_attribute(:#{facet})
value = read_attribute(:#{facet})
value.nil? ? nil : add_bidi(value, :#{facet})
end
#Read base language attribute directly without typecasting
Expand All @@ -433,6 +469,30 @@ def _#{facet}_before_type_cast
def _#{facet}=(value)
write_attribute(:#{facet}, value)
end
def add_bidi(value, facet)
return value unless Locale.active?
value.direction = self.send("\#{facet}_is_base?") ?
(Locale.base_language ? Locale.base_language.direction : nil) :
(Locale.active ? Locale.language.direction : nil)
# insert bidi embedding characters, if necessary
if @@facet_options[facet][:bidi] &&
Locale.language && Locale.language.direction && value.direction
if Locale.language.direction == 'ltr' && value.direction == 'rtl'
bidi_str = "\xe2\x80\xab" + value + "\xe2\x80\xac"
bidi_str.direction = value.direction
return bidi_str
elsif Locale.language.direction == 'rtl' && value.direction == 'ltr'
bidi_str = "\xe2\x80\xaa" + value + "\xe2\x80\xac"
bidi_str.direction = value.direction
return bidi_str
end
end
return value
end
protected :add_bidi
}
end

Expand All @@ -446,7 +506,7 @@ def _#{facet}=(value)
# Note: <i>Used when Globalize::DbTranslate.keep_translations_in_model is true</i>
def localized_facet(facet)
unless Locale.base?
"#{facet}_#{Locale.active.language.code}"
"#{facet}_#{Locale.language.code}"
else
facet.to_s
end
Expand Down
9 changes: 8 additions & 1 deletion test/db/schema.rb
Expand Up @@ -3,19 +3,24 @@
create_table :globalize_simples, :force => true do |t|
t.column :name, :string
t.column :name_es, :string
t.column :name_he, :string
t.column :description, :string
t.column :description_es, :string
t.column :description_he, :string
end

create_table :globalize_products, :force => true do |t|
t.column :code, :string
t.column :manufacturer_id, :integer
t.column :name, :string
t.column :name_es, :string
t.column :name_he, :string
t.column :description, :string
t.column :description_es, :string
t.column :description_he, :string
t.column :specs, :string
t.column :specs_es, :string
t.column :specs_he, :string
end

add_index :globalize_products, :code, :unique
Expand All @@ -25,6 +30,7 @@
t.column :code, :string
t.column :name, :string
t.column :name_es, :string
t.column :name_he, :string
end

add_index :globalize_manufacturers, :code, :unique
Expand All @@ -33,6 +39,7 @@
t.column :code, :string
t.column :name, :string
t.column :name_es, :string
t.column :name_he, :string
end

add_index :globalize_categories, :code, :unique
Expand Down Expand Up @@ -100,4 +107,4 @@
end

add_index :globalize_unlocalized_classes, :code, :unique
end
end
37 changes: 37 additions & 0 deletions test/db_localizes_translates_test.rb
Expand Up @@ -446,4 +446,41 @@ def test_association_create
assert prod.translated?(:description, 'es-ES')
assert prod.translated?(:specs, 'es-ES')
end

def test_returned_base
Product.class_eval %{
self.keep_translations_in_model = true
translates :name, :description, :specs, {
:base_as_default => true,
:name => { :bidi_embed => false }, :specs => { :bidi_embed => false }
}
}

Globalize::Locale.set("he-IL")
prod = Product.find(1)
assert_equal "first-product", prod.code
assert_equal "these are the specs for the first product", prod.specs
assert_equal "זהו תיאור המוצר הראשון", prod.description

assert prod.specs_is_base?
assert !prod.description_is_base?

assert_equal 'ltr', prod.specs.direction
assert_equal 'rtl', prod.description.direction
end

def test_bidi_embed
Product.class_eval %{
self.keep_translations_in_model = true
translates :name, :description, :specs, {
:base_as_default => true,
:name => { :bidi_embed => false }, :specs => { :bidi_embed => false }
}
}

Globalize::Locale.set("he-IL")
prod = Product.find(2)
assert_equal "\xe2\x80\xaaThis is a description of the second product\xe2\x80\xac",
prod.description
end
end
1 change: 1 addition & 0 deletions test/fixtures/globalize_manufacturers.yml
Expand Up @@ -4,3 +4,4 @@ first_manufacturer:
code: first-mfr
name: Reverend
name_es: Reverendo
name_he: רברנד
4 changes: 4 additions & 0 deletions test/fixtures/globalize_products.yml
Expand Up @@ -7,6 +7,7 @@ first_product:
manufacturer_id: 1
description: This is a description of the first product
description_es: Esta es una descripcion del primer producto
description_he: זהו תיאור המוצר הראשון
specs: these are the specs for the first product
specs_es: estas son las especificaciones del primer producto
second_product:
Expand All @@ -23,15 +24,18 @@ third:
manufacturer_id: 1
name: efe
name_es: efes
name_he: סקר
fourth:
id: 4
code: fourth-product
manufacturer_id: 1
name: eff
name_es: effes
name_he: סארט
fifth:
id: 5
code: fifth-product
manufacturer_id: 1
name: ear
name_es: oreja
name_he: סארי
2 changes: 2 additions & 0 deletions test/fixtures/globalize_simples.yml
Expand Up @@ -3,5 +3,7 @@ first_simple:
id: 1
name: first
name_es: primer
name_he: זהו השם הראשון
description: This is a description of the first simple
description_es: Esta es una descripcion del primer simple
description_he: זהו התיאור הראשון

0 comments on commit 5f76371

Please sign in to comment.