Reverse URL translation with Globalize - Rails




Globalize is one of possible way(see the comparison) to translate a Rails app, you are forced to use a database to do this but It's really a powerful method to localize  an application because this plugin adds a method .t to every String.

Unfortunatly the method .t is just for English-to-otherLanguage translation so you have to hack it a bit to have reverse translation.

Here's the method I used to translate the URL:

  • Name of the controller statically translated in routes.rb
  • Translation of each chunk after in the controller


So I'll be able to manage, at the same way, url like:

http://x.com/ristorante/ricette/insalata.html
http://x.com/restaurant/recipes/salad.html

# config/environment.rb
# [...]

include Globalize
Locale.set_base_language 'en'


# enables reverse translation and redefine String#t
class String

alias :old_t :t

def t
if self.old_t == self.to_s
q = Translation.find_by_sql("SELECT tr_key FROM globalize_translations g where text='#{self.to_s}'")

if q.empty? # there's no translation
return self
else
return q[0].tr_key
end
else
self.old_t
end
end

end

Restart /script/server 

# config/routes.rb
# [...]

  map.connect 'ristorante/*url' ,
:controller => 'restaurant', :action=>'translate', :language => 'it'

  map.connect 'restaurant/*url' ,
:controller => 'restaurant', :action=>'translate', :language => 'en'
# app/controllers/restaurant_controller.rb
# [...]

def translate
if params[:url].nil? or params[:url].empty?
@url = []

url_join=url.join('/')

case url_join

# url empty
when ''
render :text => 'main'

# restaurant/ + recipes/pizza.html
when /^\w+\/+\w+\.html$/ then

# try to search 'pizza'.t in the db, without '.html'
@recipe= Recipe.find(:first, :conditions=> ["name = ?",@url[1].split('.')[0].t])

if @url[0] == 'recipes'.t
render :partial => 'view_recipe'
# if the same regexp match to some other subaction
elsif @url[0] == 'ingredients'.t
render :view_ingredients => 'view_ingredients'
else
render :text => 'Error 404' --> '+url_join
end


end

Probably this solution isn't very scalable, because it does to many queries, so if you adopt an url like http://site.com/ristorante/ricette/23/pollo.htm instead of http://site.com/ristorante/ricette/pollo.htm, you will save the reverse query, because the id is already present.