Rails I18n scopes

Geplaatst door Remco van 't Veer vr, 17 okt 2008 18:19:00 GMT

Op dit moment ben ik in een team druk aan het bouwen aan een site voor een startup. Een vereiste voor deze applicatie is dat deze meertalig uitgevoerd moet worden. Gelukkig wordt er hard gewerkt om Rails 2.2 uit te rusten met I18N en zijn we dus op edge gedoken om van deze goodies gebruik te kunnen maken.

Een aardige eigenschap van de i18n api is het gebruik van scopes. Hiermee kan je je vertalingen netjes georganiseerd houden. Waar ik echter al snel tegenaan liep is dat ik in m’n templates steeds weer dezelfde scope aan het doorgeven was;

<%= t.label :user_name %>
<%= t.text_field :user_name %>
<div class="help">
  <%= t(:user_name, :scope => [:user, :register, :help]) %>
</div>

<%= t.label :password %>
<%= t.text_field :password %>
<div class="help">
  <%= t(:password, :scope => [:user, :register, :help]) %>
</div>

Natuurlijk had ik ook het volgende kunnen schrijven:

  <%= t('user:register:help:user_name')

Maar eigenlijk wil ik:

  <%= t('user_name', :subscope => :help) %>

of:

  <%= t('help:user_name') %>

schrijven.

Gelukkig is dat helemaal niet moeilijk! We hebben nu het volgende in onze application helper staan:

# Override translate method to consider translate_scope.
def t(text, options = {})
  scope = (translate_scope.dup << options.delete(:subscope)).compact
  super(text, {:scope => scope}.merge(options))
end

# Append scopes to the current translation scope.
def with_translate_scope(*scopes)
  translate_scope.concat(scopes)
  yield
  scopes.size.times{translate_scope.pop}
end

# The current translation scope, default to current controller name.
def translate_scope
  @translate_scope ||= [controller.controller_name]
end

De translate_scope methode beheert de huidige scope. Als basis scope wordt de controller naam gebruikt. De with_translate_scope verwacht een scope en een blok waarin deze scope actief zal zijn. Ten slotte wordt de t methode overschreven om deze scopes te gebruiken en om een extra optie subscope te accepteren.

Hiermee kan het eerdere voorbeeld herschreven worden tot:

<% with_translate_scope [:user, :register] do %>
  <%= t.label :user_name %>
  <%= t.text_field :user_name %>
  <div class="help">
    <%= t(:user_name, :subscope => :help) %>
  </div>

  <%= t.label :password %>
  <%= t.text_field :password %>
  <div class="help">
    <%= t(:password, :subscope => :help) %>
  </div>
<% end %>

Beter? Toch?

Geplaatst in ,  | 2 reacties

Reacties

  1. Edwin Vlieg zei 29 dagen later:

    Hi Remco,

    Omdat 2.2 snel dichtbij komt, ben ik vandaag ook eens wat aan het spelen geweest met de I18n implementatie van Rails. Ziet er heel netjes en bruikbaar uit.

    Ik loop eigenlijk tegen hetzelfde probleem aan als jou, namelijk dat je telkens weer de scope moet opgeven. Ik vind het een handig truucje om de controller naam je standaard scope te laten zijn, maar in de praktijk zie ik ook veel woorden die dan in elke scope gaan voorkomen. Denk aan ‘Annuleren’, ‘Opslaan’ en ‘of’. Nu zit ik na te denken over een soort fallback in de bouwen, zodat hij eerst in de huidige scope een vertaling zoekt en vervolgens steeds iets breder gaat zoeken in een bovenliggende scope.

    Ben jij al tegen dit probleem aangelopen en misschien ook al eens over een oplossing nagedacht?

  2. Remco zei 30 dagen later:

    Edwin, voor al die algemene knoppen heb ik helpers gemaakt welke wel een scope (“button”) hebben. Voordeel is dat ik dan meteen op bijv. alle annuleer knoppen de zelfde html class kan zetten.

(Laat url/e-mail achter »)

   Voorvertoning