How to use the new internationalization (I18n) API available in Rails 2.2
Not yet released, but you can try it out by first installing the i18n gem:
1 sudo gem install i18n
And then testing the following code:
1 require 'rubygems' 2 require 'i18n' 3 4 I18n.store_translations 'en-US', 5 :yes => "yes", 6 :no => "no", 7 :inbox => { 8 :one => '1 message', 9 :other => '{{count}} messages' 10 } 11 12 I18n.store_translations 'sv', 13 :yes => "ja", 14 :no => "nej", 15 :inbox => { 16 :one => '1 meddelande', 17 :other => '{{count}} meddelanden' 18 } 19 20 I18n.locale = 'en-US' 21 22 puts I18n.translate(:yes) 23 puts I18n.translate(:inbox, :count => 1) 24 puts I18n.translate(:inbox, :count => 2) 25 puts I18n.localize Time.now 26 27 28 I18n.locale = 'sv' 29 30 31 puts I18n.translate(:yes) 32 puts I18n.translate(:inbox, :count => 1) 33 puts I18n.translate(:inbox, :count => 2) 34 puts I18n.localize Time.now
Troubleshooting
Note that the gem doesn’t contain localization data, so you’ll get the following error:
1 translation missing: en-US, time, formats (I18n::MissingTranslationData)
To fix this, simply tell the I18n gem where to find the locales you want to use:
1 I18n.load_translations "#{RAILS_ROOT}/locales/#{locale}.rb"
Creating a shortcut for i18n.translate
I recommend you create a shortcut for I18n.translate to the Symbol and String classes:
1 class Symbol 2 def t(params = {}) 3 I18n.t(self, params) 4 end 5 end 6 7 class String 8 def t(params = {}) 9 I18n.t(self.to_s, params) 10 end 11 end 12
Now instead of this:
1 puts I18n.translate(:yes) 2 puts I18n.translate(:inbox, :count => 1) 3 puts I18n.translate(:inbox, :count => 2)
You can type:
1 puts :yes.t 2 puts :inbox.t(:count => 1) 3 puts :inbox.t(:count => 2)
Handling missing translations
You can use this code to change the default behavior for missing translations, instead of showing “Missing translation” this code allows you to log the missing translation:
1 class Symbol 2 def t(params = {}) 3 params.update({:raise => true}) 4 5 begin 6 I18n.t(self, params) 7 rescue I18n::MissingTranslationData 8 RAILS_DEFAULT_LOGGER.info("Translation for '#{self}' is missing") 9 self 10 end 11 end 12 end 13 14 15 class String 16 def t(params = {}) 17 params.update({:raise => true}) 18 key = self.downcase.to_s 19 20 begin 21 I18n.t(key, params) 22 rescue I18n::MissingTranslationData 23 RAILS_DEFAULT_LOGGER.info("Translation for '#{key}' is missing") 24 self 25 end 26 end 27 end
References
How to fix "Only get, head, post, put, and delete requests are allowed."
I’m getting this once in a while in development mode after changing the routes configuration:
1 ActionController::MethodNotAllowed 2 3 Only get, head, post, put, and delete requests are allowed.
The solution for me has been to restart the server.
How to SEO optimize your Rails URLs and routes
My idea for achieving optimal content crawlability and SEO optimized URLs is to use permalinks instead of ids and the default Rails routes. The permalinks can contain whatever you decide is optimal from a SEO point of view.
As an example, let’s take a recipe site that has a recipe at http://xxx/recipes/asia/china/beijing-duck.html.
First let’s configure the .html extension to be handled by the RecipesController:
1 map.connect 'recipes/*permalink.html', :controller => 'recipes', :action => 'show'
In the code we use the URI , which is the permalink of the recipe, to retrieve the recipe from the database:
1 class RecipesController 2 def show 3 @product = Recipe.find_by_permalink(request.path) 4 end 5 end
To handle the categories and subcategories, we use the following route:
1 map.connect 'recipes/*permalink/', :controller => 'categories', :action => 'show'
And create the CategoriesController:
1 class CategoriesController 2 def show 3 @category = Category.find_by_permalink(request.path) 4 end 5 end
Now what’s left is for you to figure out how to generate the permalinks… I recommend having a look at permalink_fu.
How to localize Rails routes
I forget this all the time:
1 map.resources :products, :as => 'productos', :path_names => { :new => 'nuevo', :edit => 'editar' }
Time ago in words (minutes, hours, days, weeks, months ago in words)
1 def minutes_in_words(timestamp) 2 minutes = (((Time.now - timestamp).abs)/60).round 3 4 return nil if minutes < 0 5 6 case minutes 7 when 0..4 then '< 5 minutes' 8 when 5..14 then '< 15 minutes' 9 when 15..29 then '< 30 minutes' 10 when 30..59 then '> 30 minutes' 11 when 60..119 then '> 1 hour' 12 when 120..239 then '> 2 hours' 13 when 240..479 then '> 4 hours' 14 when 480..719 then '> 8 hours' 15 when 720..1439 then '> 12 hours' 16 when 1440..11519 then '> ' << pluralize((minutes/1440).floor, 'day') 17 when 11520..43199 then '> ' << pluralize((minutes/11520).floor, 'week') 18 when 43200..525599 then '> ' << pluralize((minutes/43200).floor, 'month') 19 else '> ' << pluralize((minutes/525600).floor, 'år') 20 end 21 endThere are also similar implementations:
- http://www.actsasflinn.com/articles/2007/04/10/time-ago-method-for-ruby-on-rails
- http://timeago.yarp.com/