<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>i18n « Plataformatec Blog</title>
	<atom:link href="/tag/i18n/feed/" rel="self" type="application/rss+xml" />
	<link>/</link>
	<description>Plataformatec&#039;s place to talk about Ruby, Ruby on Rails, Elixir, and software engineering</description>
	<lastBuildDate>Tue, 08 May 2012 18:13:37 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.2</generator>
	<item>
		<title>I18n Alchemy &#8211; localization and parsing</title>
		<link>/2012/05/i18n-alchemy-localization-and-parsing/</link>
		
		<dc:creator><![CDATA[Carlos Antônio]]></dc:creator>
		<pubDate>Tue, 08 May 2012 17:23:20 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[localization]]></category>
		<category><![CDATA[number]]></category>
		<category><![CDATA[parsing]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[time]]></category>
		<guid isPermaLink="false">/?p=2328</guid>

					<description><![CDATA[<p>Today I want to show you a project I&#8217;ve started over a year ago, during Mendicant University core skills course. For those who don&#8217;t know, Mendicant University is a group of skilled software developers that offer courses, mentoring, and help out the community, started by Gregory Brown, and that nowadays counts with some other awesome ... <a class="read-more-link" href="/2012/05/i18n-alchemy-localization-and-parsing/">»</a></p>
<p>The post <a href="/2012/05/i18n-alchemy-localization-and-parsing/">I18n Alchemy – localization and parsing</a> first appeared on <a href="/">Plataformatec Blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Today I want to show you a project I&#8217;ve started over a year ago, during <a href="http://mendicantuniversity.org/" title="Mendicant University" target="_blank">Mendicant University</a> core skills course. For those who don&#8217;t know, Mendicant University is a group of skilled software developers that offer courses, mentoring, and help out the community, started by <a href="http://majesticseacreature.com/" target="_blank" title="Gregory Brown">Gregory Brown</a>, and that nowadays counts with some other awesome folks as part of the staff. I highly recommend taking a look at and enrolling.</p>
<p>Back to I18n, during Mendicant University we were supposed to create a project in Ruby, not specifically with Rails, and I decided to scratch my own itch by trying to solve a problem we usually have in Brazil: receiving date/time/numeric input from user interface. I know and have already used the <a href="https://github.com/clemens/delocalize" title="delocalized">delocalized gem</a>, and it works quite nice, but sometimes I felt a bit uncomfortable about how it handled some parts of localization/parsing. This is mainly due to the need to monkey patch both ActiveRecord to handle input, and ActionView to handle output. Besides that, and most important, I had to come up with some project and I thought that&#8217;d be a good challenge :D.</p>
<p>The main goal of this project is to provide a proxy object to use with your ORM (currently ActiveRecord only) that will be responsible for localizing and parsing the date/time/numeric attributes when getting or setting their values, respectively. Lets see some quick examples:</p>
<pre lang="ruby">
# Include the proxy in your model
class Product < ActiveRecord::Base
  include I18n::Alchemy
end

# Grab your object from the database
@product   = Product.first
# Instantiate the localized proxy
@localized = @product.localized
</pre>
<p>Now that we have a localized proxy for the <code>@product</code> object, we can get/set numeric attributes with localized values, such as:</p>
<pre lang="ruby">
@localized.price = "1.99"

@product.price   # => 1.99
@localized.price # => "1.99"

I18n.with_locale :pt do
  @localized.price = "1,88"

  @product.price   # => 1.88
  @localized.price # => "1,88"
end
</pre>
<p>And also date/time attributes, for instance:</p>
<pre lang="ruby">
@localized.released_at = "12/31/2011"

@product.released_at   # => Date.new(2011, 12, 31)
@localized.released_at # => "12/31/2011"

I18n.with_locale :pt do
  @localized.released_at = "31/12/2011"

  @product.released_at   # => Date.new(2011, 12, 31)
  @localized.released_at # => "31/12/2011"
end
</pre>
<p>I18n Alchemy can also receive a hash of attributes, the same way you use with your models when calling <code>new</code>. That means you can use it like this:</p>
<pre lang="ruby">
# You could be using params[:product] for instance.
I18n.with_locale :pt do
  @localized = @product.localized(:price => "1,88") 

  @product.price   # => 1.88
  @localized.price # => "1,88"
end
</pre>
<p>The parsing/localization formats are basically the same ones you already use in your Rails application. You can check the basic locale configuration for <a href="https://github.com/carlosantoniodasilva/i18n_alchemy" title="I18n Alchemy - date/number parsing/localization">I18n Alchemy in its README on github</a>.</p>
<h2>Wrapping up</h2>
<p>I18n Alchemy is a small and new project which solves most of the problems we commonly face when dealing with localization and parsing of date/time/numeric values. It is tested with Rails 3.0, 3.1 and 3.2 and works with all the basic methods, such as <code>attributes=</code>, <code>assign_attributes</code>, <code>update_attributes</code> and nested attributes as well.</p>
<p>It was a really fun time creating it during Mendicant University, and it took a long time until I decided to release it as a gem. There is still a bunch of things to do, but I wanted to ask you to give it a try and let me know about any feedback you have.</p>
<p>As a side note, if you are interested in knowing more about the design decisions that led this project, you may want to take a look at <a href="http://blog.rubybestpractices.com/posts/gregory/055-issue-23-solid-design.html" title="Ruby Best Practices: Issue #23: SOLID Design Principles">Gregory Brown's post on Ruby Best Practices, entitled "Issue #23: SOLID Design Principles"</a>, more specifically in the Open/closed principle topic.</p>
<p>I'm releasing the first 0.0.1 version today, and I hope you find it useful. Have any comments? Let us know!</p><p>The post <a href="/2012/05/i18n-alchemy-localization-and-parsing/">I18n Alchemy – localization and parsing</a> first appeared on <a href="/">Plataformatec Blog</a>.</p>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Best Ruby Open Source Test Suites Awards</title>
		<link>/2010/04/best-ruby-open-source-test-suites-awards/</link>
					<comments>/2010/04/best-ruby-open-source-test-suites-awards/#comments</comments>
		
		<dc:creator><![CDATA[José Valim]]></dc:creator>
		<pubDate>Thu, 29 Apr 2010 15:40:37 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[capybara]]></category>
		<category><![CDATA[euruko]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[rails 3]]></category>
		<category><![CDATA[railties]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tests]]></category>
		<guid isPermaLink="false">/?p=974</guid>

					<description><![CDATA[<p>One of the beauties in the Open Source world is the possibility of reading other people source code and learn new things. However, lately I found out that not only the library code, but the test suite of several open source projects are full lessons for us. In this post, I want to tell you ... <a class="read-more-link" href="/2010/04/best-ruby-open-source-test-suites-awards/">»</a></p>
<p>The post <a href="/2010/04/best-ruby-open-source-test-suites-awards/">Best Ruby Open Source Test Suites Awards</a> first appeared on <a href="/">Plataformatec Blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>One of the beauties in the Open Source world is the possibility of reading other people source code and learn new things. However, lately I found out that not only the library code, but the test suite of several open source projects are full lessons for us.</p>
<p>In this post, I want to tell you which are the three test suites that I admire the most and why.</p>
<h3>Integration award: Railties</h3>
<p><a href="http://github.com/rails/rails" target="_blank">Rails 3</a> has several improvements and not all of them may be visible to the application developer. One of the hidden unicorns is Railties test suite. As Yehuda stated <a href="http://yehudakatz.com/2009/07/01/new-rails-isolation-testing/" target="_blank">in a blog post</a> during the refactoring of version 2.3 to 3.0:</p>
<blockquote><p>&#8220;Although the Rails initializer tests covered a fair amount of area, successfully getting the tests to pass did not guarantee that Rails booted.&#8221;</p></blockquote>
<p>This happened because, in order to have fast tests, Rails 2.3 suite stubbed and mocked a significant part of the booting process. The new test suite is able to create a new application using the application generator, change configuration options, add plugins and engines, boot it and even make HTTP requests using Rack::Test.</p>
<p>For instance, take a look at this test which ensures that app/metals inside plugins are successfully added to the application middleware stack:</p>
<pre lang='ruby'>def test_plugin_metals_added_to_middleware_stack
  @plugin.write 'app/metal/foo_metal.rb', <<-RUBY
    class FooMetal
      def self.call(env)
        [200, { "Content-Type" => "text/html"}, ["FooMetal"]]
      end
    end
  RUBY

  boot_rails
  require 'rack/test'
  extend Rack::Test::Methods

  get "/not/slash"
  assert_equal 200, last_response.status
  assert_equal "FooMetal", last_response.body
end</pre>
<p>The most important lesson here is: whenever mocking or stubbing in our tests, we still need to add tests without the mocks and stubs to ensure all API contracts are respected.</p>
<h3>Readability award: Capybara</h3>
<p><a href="http://github.com/jnicklas/capybara" target="_blank">Capybara</a> is a tool to aid writing acceptance tests for web applications. <a href="http://github.com/jnicklas/capybara" target="_blank">Capybara</a> can use several drivers to interact with a web application, as Selenium, Celerity or even Rack::Test. Each driver needs a different setup and has different features. For instance, both Selenium and Celerity can handle javascript, but not Rack::Test.</p>
<p>As you may imagine, all these different drivers can make a test suite become a real spaghetti. However, <a href="http://twitter.com/jncoward" target="_blank">Jonas Nicklas</a> was able to transform a potential problem into a very elegant and readable test suite with Rspec help. Here is, for instance, the tests for selenium:</p>
<pre lang="ruby">describe Capybara::Driver::Selenium do
  before do
    @driver = Capybara::Driver::Selenium.new(TestApp)
  end

  it_should_behave_like "driver"
  it_should_behave_like "driver with javascript support"
end
</pre>
<p>Each behavior group above (&#8220;driver&#8221; and &#8220;driver with javascript support&#8221;) is inside <a href="http://github.com/jnicklas/capybara" target="_blank">Capybara</a> library allowing everyone to develop its own extensions using a shared suite. For instance, if a driver has javascript support, it means the following tests should pass:</p>
<pre lang="ruby">shared_examples_for "driver with javascript support" do
  before { @driver.visit('/with_js') }

  describe '#find' do
    it "should find dynamically changed nodes" do
      @driver.find('//p').first.text.should == 'I changed it'
    end
  end

  describe '#drag_to' do
    it "should drag and drop an object" do
      draggable = @driver.find('//div[@id="drag"]').first
      droppable = @driver.find('//div[@id="drop"]').first
      draggable.drag_to(droppable)
      @driver.find('//div[contains(., "Dropped!")]').should_not be_nil
    end
  end

  describe "#evaluate_script" do
    it "should return the value of the executed script" do
      @driver.evaluate_script('1+1').should == 2
    end
  end
end</pre>
<p><a href="http://github.com/jnicklas/capybara" target="_blank">Capybara</a> test suite is one of the best examples of using tests as documentation. By skimming the test suite you can easily know which features are supported by each driver! Sweet, isn&#8217;t it?</p>
<h3>Friendliness award: I18n</h3>
<p>When you are a big Open Source project, your test suite needs to be easy to run in order to new developers can create patches without hassle. The <a href="http://github.com/svenfuchs/i18n" target="_blank">I18n</a> library for Ruby definitely meets the big Open Source project requirement since it&#8217;s widely used and provides several extensions.</p>
<p>However, some of these extensions depends on <strong>ActiveRecord</strong>, some in <strong>ruby2ruby</strong>, others in <strong>ruby-cldr</strong>&#8230; and <a href="http://gist.github.com/381892" target="_blank">soon it will even support a few Key-Value stores</a>, as Tokyo and Redis. Due to all these dependencies, you would probably imagine that running I18n test suite would require several trials and a lot of configuration before it finally works, right?</p>
<p>WRONG! If you don&#8217;t have ActiveRecord, <a href="http://github.com/svenfuchs/i18n" target="_blank">I18n</a> will say: &#8220;hey, you don&#8217;t have ActiveRecord&#8221; but still run the part of test suite that does not depend on it. So if a developer wants to fix or add something trivial, he doesn&#8217;t need to worry with installing all sorts of dependencies.</p>
<p>Besides, as mentioned a couple months ago, <a href="/2009/12/run-i18n-run/">the I18n library allows you to create several combinations of backends</a>. In other words, the I18n test suite needs to ensure that all these different combinations work as expected.</p>
<p>This problem is quite similar to the one in <a href="http://github.com/jnicklas/capybara" target="_blank">Capybara</a> which needs to test different drivers. However, <a href="http://github.com/svenfuchs/i18n" target="_blank">I18n</a> uses Test::Unit thus it cannot use shared examples groups as in Rspec. So how were I18n developers able to solve this issue? Using Ruby modules!</p>
<p>Here are the tests for the upcoming KeyValue backend:</p>
<pre lang="ruby">require 'test_helper'
require 'api'

class I18nKeyValueApiTest < Test::Unit::TestCase
  include Tests::Api::Basics
  include Tests::Api::Defaults
  include Tests::Api::Interpolation
  include Tests::Api::Link
  include Tests::Api::Lookup
  include Tests::Api::Pluralization
  # include Tests::Api::Procs
  include Tests::Api::Localization::Date
  include Tests::Api::Localization::DateTime
  include Tests::Api::Localization::Time
  # include Tests::Api::Localization::Procs

  STORE = Rufus::Tokyo::Cabinet.new('*')

  def setup
    I18n.backend = I18n::Backend::KeyValue.new(STORE)
    super
  end

  test "make sure we use the KeyValue backend" do
    assert_equal I18n::Backend::KeyValue, I18n.backend.class
  end
end</pre>
<p>Each included module above adds a series of tests to the backend. Since key-value backends cannot store procs, we don't include any test related to procs.</p>
<h3>Wrapping up</h3>
<p>These three are my favorite test suites and also part of my favorite open source projects!</p>
<p>We've adopted <a href="http://github.com/jnicklas/capybara" target="_blank">Capybara</a> as the official testing tool at PlataformaTec for some time already and I18n is one of the subjects of my upcoming book about Rails 3. In one specific chapter, we will build a tool that stores <a href="http://github.com/svenfuchs/i18n" target="_blank">I18n</a> translations into TokyoCabinet, which allows us to create and update translations through a web interface, similarly to ActiveRecord. The only difference is that <a href="http://gist.github.com/381892" target="_blank">TokyoCabinet is waaaay faster</a>.</p>
<p>Finally, the fact you can mimic several of Rspec features using simple Ruby (like <a href="http://github.com/jnicklas/capybara" target="_blank">Capybara</a> using shared example groups and <a href="http://github.com/svenfuchs/i18n" target="_blank">I18n</a> simply using modules) will be part of my talk in <a href="http://euruko2010.org/" target="_blank">Euruko 2010</a> entitled <strong>DSL or NoDSL: The power is in the middle</strong>. The talk will show cases where DSLs mimics much of the behavior provided by Ruby and discuss what we are winning and/or losing in such cases.</p>
<p>Keep following us and, until the next blog post is out, we would love to hear in the comments which are your favorite test suites!</p><p>The post <a href="/2010/04/best-ruby-open-source-test-suites-awards/">Best Ruby Open Source Test Suites Awards</a> first appeared on <a href="/">Plataformatec Blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>/2010/04/best-ruby-open-source-test-suites-awards/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>Rails 3 I18n changes</title>
		<link>/2010/02/rails-3-i18n-changes/</link>
					<comments>/2010/02/rails-3-i18n-changes/#comments</comments>
		
		<dc:creator><![CDATA[José Valim]]></dc:creator>
		<pubDate>Tue, 02 Feb 2010 13:23:41 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[rails]]></category>
		<guid isPermaLink="false">/?p=669</guid>

					<description><![CDATA[<p>As we already know, in Rails 3 all dependencies will be bundled. This means you will be able to use latest I18n version which includes several improvements by itself. Besides that, a couple things changed on Rails 3 I18n, some features were added and others were deprecated. This post is a quick walkthrough it: 1) ... <a class="read-more-link" href="/2010/02/rails-3-i18n-changes/">»</a></p>
<p>The post <a href="/2010/02/rails-3-i18n-changes/">Rails 3 I18n changes</a> first appeared on <a href="/">Plataformatec Blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>As we already know, in Rails 3 all dependencies will be bundled. This means you will be able to use latest I18n version which <a href="/2009/12/run-i18n-run/">includes several improvements</a> by itself.</p>
<p>Besides that, a couple things changed on Rails 3 I18n, some features were added and others were deprecated. This post is a quick walkthrough it:</p>
<h3>1) Error messages defaults</h3>
<p>With the addition of ActiveModel, it&#8217;s easy to add I18n behavior to any object by simply including <code>ActiveModel::Translation</code> and <code>ActiveModel::Validations</code>. As side effect, if we followed the same translation pattern as in Rails 2.3, each ORM would have to specify its default error messages at <code>#{ORM.name}.errors.messages</code>. This means that if you are using two ORMs in your app, you would have to translate the same messages twice.</p>
<p>To handle this situation, error messages now has <code>errors.attributes</code> and <code>errors.messages</code> as fallbacks in case a message cannot be found for an specific ORM. Notice that this also allows you to customize a message for an specific attribute used by models in different ORMs. So if you have several models with title attribute, you can customize the blank message for them all by simply placing it at <code>errors.attributes.title.blank</code>.</p>
<h3>2) Attributes default</h3>
<p>In the same line as above, you can now specify default attributes across different models and ORMs as well. For example, if you are exposing <code>created_at</code> and <code>updated_at</code> in your views, until Rails 2.3 you needed to specify the same translation for each model. In Rails 3, you can simply do:</p>
<pre lang="yml">en:
  attributes:
    created_at: "Created at"
    updated_at: "Updated at"</pre>
<h3>3) f.submit</h3>
<p><code>f.submit</code> in forms now can be called without arguments and it will inspect the form object to set the proper label. Imagine the following form:</p>
<pre lang="erb">
<% form_for @post do |f| %>
  <%= f.submit %>
<% end %>
</pre>
<p>If @post is a new record, it will use &#8220;Create Post&#8221; as submit button label, otherwise, it uses &#8220;Update Post&#8221;. You can customize those labels with I18n under the following keys:</p>
<pre lang="yml">en:
  helpers:
    submit:
      create: "Create a {{model}}"
      update: "Confirm changes to {{model}}"</pre>
<p>Nonetheless, it also searches for keys under the object name key as well:</p>
<pre lang="yml">en:
  helpers:
    submit:
      post:
        create: "Add {{model}}"</pre>
<h3>4) Labels with I18n</h3>
<p>Labels were also updated to use I18n. Imagine the following form:</p>
<pre lang="erb">
<% form_for @post do |f| %>
  <%= f.label :title %>
  <%= f.text_field :title %>
  <%= f.submit %>
<% end %>
</pre>
<p>It will search for a label value at <code>helpers.label.post.title</code>, falling back to the value returned by <code>Post.human_attribute_name(:title)</code>. This is useful in case you want more personalized labels instead of just &#8220;Title&#8221;.</p>
<h3>5) Deprecation</h3>
<p>Besides those improvements, I18n has two deprecations: the first is the key <code>support.select</code> should now be <code>helpers.select</code> and the other is that AV error messages are now agnostic, so <code>activerecord.errors.template</code> should now be <code>errors.template</code>.</p>
<p>That&#8217;s all, enjoy!</p><p>The post <a href="/2010/02/rails-3-i18n-changes/">Rails 3 I18n changes</a> first appeared on <a href="/">Plataformatec Blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>/2010/02/rails-3-i18n-changes/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title>Run, I18n, run!</title>
		<link>/2009/12/run-i18n-run/</link>
					<comments>/2009/12/run-i18n-run/#comments</comments>
		
		<dc:creator><![CDATA[José Valim]]></dc:creator>
		<pubDate>Tue, 29 Dec 2009 22:11:42 +0000</pubDate>
				<category><![CDATA[English]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[rails]]></category>
		<guid isPermaLink="false">/?p=538</guid>

					<description><![CDATA[<p>A new I18n gem just got released and it comes with two new backends extensions: Fast and InterpolationCompiler. First, what is a backend? I18n.t, I18n.translate, I18n.l and I18n.localize methods are actually just wrappers to I18n.backend, which is actually who does all the heavy lifting. This means that you can change your backend to other stuff, ... <a class="read-more-link" href="/2009/12/run-i18n-run/">»</a></p>
<p>The post <a href="/2009/12/run-i18n-run/">Run, I18n, run!</a> first appeared on <a href="/">Plataformatec Blog</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>A new <a href="http://github.com/svenfuchs/i18n">I18n gem</a> <a href="http://twitter.com/svenfuchs/status/7160682325" target="_blank">just got released</a> and it comes with two new backends extensions: <a href="http://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/fast.rb" target="_blank">Fast</a> and <a href="http://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/interpolation_compiler.rb" target="_blank">InterpolationCompiler</a>.</p>
<h3>First, what is a backend?</h3>
<p><code>I18n.t</code>, <code>I18n.translate</code>, <code>I18n.l</code> and <code>I18n.localize</code> methods are actually just wrappers to <code>I18n.backend</code>, which is actually who does all the heavy lifting. This means that you can change your backend to other stuff, as long as it respects the required API.</p>
<p>By default, I18n comes with the <a href="http://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/simple.rb" target="_blank">Simple backend</a>, but others are available. For example, I18n has an <a href="http://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/active_record.rb" target="_blank">ActiveRecord</a>, which stores translations in the database. This is useful in cases someone needs to change translations through a web interface. To use it, you just need to do:</p>
<pre lang="ruby">  I18n.backend = I18n::Backend::ActiveRecord</pre>
<p>There are a couple other backends, like <a href="http://github.com/svenfuchs/i18n/tree/master/lib/i18n/backend/fallbacks.rb" target="_blank">a backend which implements fallbacks</a>, so if something cannot be found in a specified language, like german (:de), it can fallback to english (:en). You can check <a href="http://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/" target="_blank">the whole list</a>, but for this while, we are going to focus on the two new backends extensions.</p>
<h3>Fast</h3>
<p>Fast, means fast. And oh, boy, this one is fast. This extension flattens translations to speed up the look up. For example, the following hash <code>{ :a =&gt; { :b =&gt; { :c =&gt; :foo } } }</code>, gets flattened to <code>{ :"a.b.c" =&gt; "foo" }</code>, so instead of recursively looking into hashes, it looks just once. The obvious expense is that whenever you are storing translations, you need to flatten the translation hash, and it takes more time than usual.</p>
<p>In order to measure different backend implementations, I <a href="http://github.com/svenfuchs/i18n/blob/master/benchmark/run.rb">pushed some benchmark setup</a> to the I18n repository. The current setup measures the storage time, the time it takes to translate a key (the depth of the key means how many nested hashes it takes), the time to translate a key falling back to the default key and the time translate a key (at depth 5) and interpolate. The results comparing the Simple backend without and with Fast extension are showed below:</p>
<p><a href="/wp-content/uploads/2009/12/Screen-shot-2009-12-29-at-4.50.45-PM.png"><img fetchpriority="high" decoding="async" class="aligncenter size-full wp-image-542" title="Simple vs. Fast" src="/wp-content/uploads/2009/12/Screen-shot-2009-12-29-at-4.50.45-PM.png" alt="Simple vs. Fast" width="523" height="269" /></a></p>
<p>In other words, a simple lookup using the Fast extension is 3 to 4 times faster than the Simple one. Besides, configuring your application to use it is very simple:</p>
<pre lang="ruby">
  I18n::Backend::Simple.send :include, I18n::Backend::Fast
</pre>
<p>Nice!</p>
<h3>Interpolation compiler</h3>
<p>The <a href="http://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/interpolation_compiler.rb" target="_blank">InterpolationCompiler</a> is a backend extension which extracts all required interpolation keys from a string, leaving just the minimum required to runtime. Imagine the following string: <code>"This is a custom blank message for {{model}}: {{attribute}}"</code>. This extension annotates the string so it knows that it needs to interpolate both model and attribute, and points exactly where the interpolation should happen. We can compare the Simple backend without and with the InterpolationCompiler below:</p>
<p><a href="/wp-content/uploads/2009/12/Screen-shot-2009-12-29-at-5.03.25-PM.png"><img decoding="async" src="/wp-content/uploads/2009/12/Screen-shot-2009-12-29-at-5.03.25-PM.png" alt="Simple vs. Interpol" title="Simple vs. Interpol" width="517" height="260" class="aligncenter size-full wp-image-544" /></a></p>
<p>The InterpolationCompiler just changes the time taken when we have interpolation keys, without affecting too much the other translations. You can add it to your app as easy as the Fast backend:</p>
<pre lang="ruby">
  I18n::Backend::Simple.send :include, I18n::Backend::InterpolationCompiler
</pre>
<h3>Run, I18n, run!</h3>
<p>But the best is still coming! <strong>Fast and InterpolationCompiler can actually be used together</strong>, to achieve unseen performance in I18n. The benchmark speaks for itself:</p>
<p><a href="/wp-content/uploads/2009/12/Screen-shot-2009-12-29-at-5.07.37-PM.png"><img decoding="async" src="/wp-content/uploads/2009/12/Screen-shot-2009-12-29-at-5.07.37-PM.png" alt="Simple vs. FastInterpol" title="Simple vs. FastInterpol" width="511" height="262" class="aligncenter size-full wp-image-545" /></a></p>
<p>While we speed up the performance in around four times in simple lookups, <a href="http://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/fast.rb" target="_blank">Fast</a> and <a href="http://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/interpolation_compiler.rb" target="_blank">InterpolationCompiler</a> improvements get combined whenever we need to use interpolation, becoming around six times faster!</p>
<p>As said previously, both extensions increase the time taken to store translations as side-effect. Such can be viewed below:</p>
<p><a href="/wp-content/uploads/2009/12/Screen-shot-2009-12-29-at-5.26.00-PM.png"><img loading="lazy" decoding="async" src="/wp-content/uploads/2009/12/Screen-shot-2009-12-29-at-5.26.00-PM.png" alt="Store" title="Store" width="388" height="239" class="aligncenter size-full wp-image-546" /></a></p>
<p>The yaml hash used in for the benchmark, is relatively slow, but it shows how the time taken to store translations grows with such extensions. But remember, you are constantly storing translations only in development (before each request is processed). In production, the translations are stored at startup and that is it.</p>
<h3>Using within Rails</h3>
<p>You should be able to use such features today in Rails 2.3.5 and it will also be possible in Rails 3. You just need to install the <a href="http://github.com/svenfuchs/i18n">I18n</a> gem and configure it in your environment.</p>
<h3>Why care?</h3>
<p>All the times shown are in miliseconds. In other words, why care? If you are building a simple application, using just one language, those improvements likely won&#8217;t change anything. But in an application which relies on I18n, during a request/response lifecycle, I18n is invoked many times: error messages for models, flash messages, page titles, e-mail subjects, page content, date and time localization, pluralization rules and even in many of ActionView helpers. So in such cases, it&#8217;s worth to give such extensions a try.</p>
<h3>Running benchmarks on your own</h3>
<p>If you want to run benchmarks on your own, it&#8217;s quite simple. You just need to do:</p>
<pre lang="bash">git clone git://github.com/svenfuchs/i18n.git
cd i18n
ruby benchmark/run.rb</pre>
<h3>Credits</h3>
<p>The possibility to have backends and such extensions is due to <a href="http://github.com/svenfuchs" target="_blank">Sven Fuchs</a>, which leads the I18n group quite well.</p>
<p>Many of the backends were added by I18n community, and the <a href="http://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/fast.rb" target="_blank">Fast</a> and <a href="http://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/interpolation_compiler.rb" target="_blank">InterpolationCompiler</a> were created by <a href="http://github.com/thedarkone" target="_blank">thedarkone</a>.</p>
<p>Guys, I owe you a beer! <img src="https://s.w.org/images/core/emoji/14.0.0/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Enjoy!</p><p>The post <a href="/2009/12/run-i18n-run/">Run, I18n, run!</a> first appeared on <a href="/">Plataformatec Blog</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>/2009/12/run-i18n-run/feed/</wfw:commentRss>
			<slash:comments>16</slash:comments>
		
		
			</item>
	</channel>
</rss>
