Skip to content
Datamapper support for localization of content in multilanguage applications http://quasipartikel.at
Ruby
Find file
Latest commit ee46a7b @snusnu Merge pull request #4 from shingara/patch-1
Don't freeze the VERSION constant
Failed to load latest commit information.
lib Don't freeze the VERSION constant
spec Remove the explicit auto_migrate_spec
tasks Fix the rake changelog task and update the CHANGELOG
.document Initial commit to dm-is-localizable.
.gitignore Add Gemifle.lock to .gitignore
CHANGELOG Fix the rake changelog task and update the CHANGELOG
Gemfile Work with latest DM sources and nuke jeweler
LICENSE updated LICENSE information
README.textile Minor README fixes
Rakefile
TODO added passing specs for unique language translations
dm-is-localizable.gemspec Work with latest DM sources and nuke jeweler

README.textile

dm-is-localizable

Datamapper support for localization of (user entered) content in multilanguage applications

Schema

  • one xxx_translations table for every translatable resource
  • xxx_translations belongs_to the resource to translate
  • xxx_translations belongs_to a locale
  • properties to be translated are defined in xxx_translations

Advantages

  • Proper normalization and referential integrity
  • Easy to add a new language (add row to xxx_translations)
  • Easy to query
  • Columns keep their names

Disadvantages (not really if you think about it)

  • One extra table for every resource that needs translations

Example definition of a localizable model

The plugin comes with a Locale model that already got required for you. This means that the underlying storage will be created automatically when you run auto_migrate! or auto_upgrade!.


class Item

  include DataMapper::Resource

  property :id, Serial

  translatable do
    property :name, String
    property :desc, String
  end

end

The above Item model will define and thus be able to DataMapper.auto_migrate! the ItemTranslation model. The naming convention used here is "#{ClassToBeLocalized.name}Translation".

Preliminary support for changing this is available by using the :model option like so (note that this isn’t specced yet).


DataMapper::Model.translatable, :model => 'ItemLocalization' do
  # ...
end

Furthermore, the above Item will automatically have the following instance methods defined.


#item_translations_attributes
#item_translations_attributes=

# and handy aliases for the above

#translations_attributes
#translations_attributes=

These are generated by dm-accepts_nested_attributes and allow for easy manipulation of the translatable properties from say forms in a web application. For more information on working with nested attributes, have a look at the documentation at the README for dm-accepts_nested_attributes

Of course you can turn this behavior off by specifying the translatable, :accept_nested_attributes => false do .. end

The resulting model you get when calling Item.translatable { ... } looks like this:


class ItemTranslation

  include DataMapper::Resource

  property :id,         Serial

  property :item_id,    Integer, :required => true, :unique_index => :unique_locales
  property :locale_tag, String,  :required => true, :unique_index => :unique_locales

  property :name,       String
  property :desc,       String

  validates_is_unique :locale_tag, :scope => :item_id

  belongs_to :item
  belongs_to :locale

end

Furthermore, the following API gets defined on the Item class:


class Item

  include DataMapper::Resource

  property :id, Serial

  translatable do
    property :name,        String
    property :description, String
  end

  # -------------------------
  #   added by .translatable
  # -------------------------

  has n, :item_translations
  has n, :locales, :through => :item_translations

  # and a handy alias
  alias :translations :item_translations

  # method to access the i18n proxy for this model
  def self.i18n
    @i18n
  end

  # the proxy instance to delegate api calls to
  def i18n
    @i18n ||= I18n::Resource::Proxy.new(self)
  end

  # translates the :name property to the given locale
  def name(locale_tag = DataMapper::I18n.default_locale_tag)
    i18n.translate(:name, locale_tag)
  end

  # translates the :desc property to the given locale
  def desc(locale_tag = DataMapper::I18n.default_locale_tag)
    i18n.translate(:desc, locale_tag)
  end

  # ----------------------------------------
  #   added by dm-accepts_nested_attributes
  # ----------------------------------------


  def item_translations_attributes
    # ...
  end

  def item_translations_attributes=(attributes_or_attributes_collection)
    # ...
  end

  # and handy aliases for the above

  alias :translations_attributes  :item_translations_attributes
  alias :translations_attributes= :item_translations_attributes
end

# ---------------------------------------------
#   methods accessible via the Item.i18n proxy
# ---------------------------------------------

# helper method to get at ItemTranslation
Item.i18n.translation_model

# list all available locales for the translatable model
Item.i18n.available_locales

# returns all translatable properties of this resource
Item.i18n.translatable_properties

# ---------------------------------------------
#   methods accessible via the Item#i18n proxy
# ---------------------------------------------

# list all available locales for this instance
item.i18n.available_locales

# translates the given attribute to the locale identified by the given locale_code
item.i18n.translate(attribute, locale_tag)

Inspired by (thx guys!)

Copyright

Copyright © 2009 Martin Gamsjaeger (snusnu). See LICENSE for details.

Something went wrong with that request. Please try again.