Unit tested example

Here’s a Unit Test (you do know how to test your Rails app, right?) which shows a way to work with the Globalize plugin. Far easier than playing around in the console to see if you can get it to work.

Ensure compatability

Globalize uses its own models – e.g. Language, Country and Translation. If you have models or database tables with these names, they might conflict with testing later on. Better now create a migration to rename these tables and then rename the models, and you’ll be fine.

Install Globalize

In your RAILS_ROOT, execute the following to install the Globalize plugin.

script/plugin install http://svn.globalize-rails.org/svn/globalize/globalize/trunk

Create the model

The test assumes the presence of a model called Newsitem. So go ahead and generate the model and modify it like so:

class Newsitem < ActiveRecord::Base
  translates    :title, :excerpt, :body
end

See the Globalize API docs for translates. Basically, it means Globalize will give the specified columns special treatment.

Create the table

The following migration might help you create the table:

class AddNewsTable < ActiveRecord::Migration
  def self.up
    create_table :newsitems do |t|
      t.column :title, :string
      t.column :excerpt, :string
      t.column :body, :text
      t.column :lock_version, :integer, :default => 0
      t.column :user_id, :integer
      t.column :updated_at, :datetime
      t.column :created_at, :datetime
    end
  end
  def self.down
    drop_table :newsitems
  end
end

You’re ready to migrate the table into your database by running rake migrate. Of course, not all columns are needed for this example, but it might be an incentive to find the meaning of one or two things in the Rails API.

Globalize it

script/generate globalize tiny
rake migrate

This will take a while. You have been warned.

Setup the test fixtures

You need to tell globalize which languages/countries it should know about. The previous migration made sure to fill up the globalize tables with a large number of preconfigured languages and countries all ready for you to use in your development database.

However as we are using the test database, you’ll need to create fixtures for the globalize tables. You can either create them from scratch (Have a look at the globalize tables in your dev tables) or copy over the fixtures used in globalize’s own test which are located in the test directory


vendor/plugins/globalize/test/fixtures/globalize_languages.yml
#You only really need the languages fixtures but chances are
#you'll want to copy over these two as well for more tests
vendor/plugins/globalize/test/fixtures/globalize_countries.yml
vendor/plugins/globalize/test/fixtures/globalize_translations.yml

The globalize test fixtures do not include dutch so you’ll have to add it in for the newsitem_test (or you could just modify the test to use any of the languages in the fixtures):


#globalize_languages.yml
...
dutch:
  id: 7
  iso_639_1: nl
  iso_639_2: nld
  english_name: Dutch
  native_name: Nederlands
  scope: L
  macro_language: false
  pluralization: 'c == 1 ? 1 : 2'
#globalize_countries.yml
...
holland:
  id: 6
  code: NL
  english_name: Netherlands
  currency_format: '€ %n'
  currency_code: EUR
  thousands_sep: '.'
  decimal_sep: ','
  currency_decimal_sep: '.'

The Unit Test

First of all, this is not a real unit test. It’s just an easy way to show you how to work with Globalize.

When you generated your model, the rails command was smart enough to create a test for it. You can find the test in RAILS_ROOT/test/unit/newsitem_test.rb. Just copy the paste below and replace the content of the original file with it.

require File.dirname(__FILE__) + '/../test_helper'
class NewsitemTest < Test::Unit::TestCase
  def test_add_content_translations
    Newsitem.delete_all
    Globalize::Locale.set_base_language('en-US')
    # create a row in the base language
    Globalize::Locale.set('en-US')
    assert_nothing_raised() do
      assert_kind_of Newsitem, Newsitem.create!(:title => 'US Title',
                                                :excerpt => 'US excerpt',
                                                :body => 'US body copy')
    end
    assert_equal 1, Newsitem.find(:all).size
    # retrieve row
    newsitem = Newsitem.find(:first)
    assert_kind_of Newsitem, newsitem
    assert_equal 'US Title', newsitem.title
    # create a translation by switching the locale and updating attributes
    Globalize::Locale.set('nl-NL')
    # newsitem.title = 'NL Titel'
    # newsitem.excerpt = 'NL samenvatting.'
    # newsitem.body = 'NL Broodtekst.'
    # assert_nothing_raised() {newsitem.save!}
    # either use the commented out code above or the line below
    # You cannot fetch a row in one language and save it in another.
    # So just switch language, fetch again, and then update_attributes
    newsitem = Newsitem.find(:first)
    newsitem.update_attributes(:title => 'NL Titel',
                                :excerpt => 'NL samenvatting.',
                                :body => 'NL broodtekst')
    # check if the translated row has been saved
    assert_equal 'NL Titel', newsitem.title
    # check if the base language row still exists
    Globalize::Locale.set('en-US')
    # now see if the example from the wiki gives the expected result
    newsitem = Newsitem.find(:first)
    assert_equal 'US Title', newsitem.title
    Globalize::Locale.set('nl-NL')
    newsitem = Newsitem.find(newsitem.id)
    assert_equal 'NL Titel', newsitem.title
  end
  def test_add_string_translations
    Globalize::Locale.set_base_language('en-US')
    Globalize::Locale.set('en-US')
    language = Globalize::Language.pick 'nl-NL'
    Globalize::Locale.set_translation(
      "This is written in English",
      language,
      "Dit is geschreven in het Nederlands" 
    )
    assert_equal 'This is written in English', "This is written in English".t
    Globalize::Locale.set('nl-NL')
    assert_equal 'Dit is geschreven in het Nederlands', "This is written in English".t
  end
end

Run the test

From your RAILS_ROOT, run the test. The expected result should be something like shown below.

aluminum:~/dev/projects/my_app/trunk charles$ ruby test/unit/newsitem_test.rb 
Loaded suite test/unit/newsitem_test
Started
..
Finished in 1.986655 seconds.
2 tests, 10 assertions, 0 failures, 0 errors
aluminum:~/dev/projects/my_app/trunk charles$

Help!

If you have more questions, you can find us in #globalize on Freenode or on the Rails mailing list. Make sure the first word of your subject line is Globalize, so your message is easier to spot.

revision 1 · 02.06.09 16:27 · by: Marko Seppä