Ruby on Rails 2.2 staat voor de deur
17 November 2008 17:22 · Iain Hecker · Ruby
De eerste release candidate van Ruby on Rails 2.2 is een paar dagen uit. Het kon daarom ook niet uitblijven dat er ook op het blog van Finalist wat over deze bijzondere release geschreven werd. Deze release is een van de belangrijkste releases, aangezien het twee grote tekortkomingen van Rails oplost. Het gaat dan natuurlijk over thread-safety en internationalisatie (i18n). Er zijn er natuurlijk nog veel meer nieuwe features dan de twee die ik hier uitlicht. Een complete lijst is hier te vinden.
Thread Safety
Wat betreft thread-safety verandert er weinig voor de gemiddelde programmeur. Het is een mooie aanwinst voor mensen die met JRuby bezig zijn of gebruik moeten maken van Neverblock. Thread safety maakt connection pools mogelijk met de database bijvoorbeeld. Ook met het gebruik van static variables moet je even opletten. Maar, zoals gezegd, zijn dat geen dingen waar je dagelijks mee te maken hebt.
Internationalisatie
Iets wat een veel grotere impact op de programmeur heeft is het hele i18n verhaal. Om fatsoenlijk een Rails applicatie te vertalen naar het Nederlands waren tot op heden vele hacks nodig, omdat Rails daar domweg niet op berekend was. Het was een chaos aan losse plugins en gems die allemaal een stukje van de puzzel oploste. Vertalingen voor de voorkant waren gemakkelijk te realiseren, mits je er vanaf het begin rekening mee hield, maar Rails barst ook van de standaard meldingen. Deze zaten hard gecodeerd, diep in code van het framework zelf. Gelukkig is dat nu anders.
De i18n module van Rails ondersteund de belangrijkste kernfuncties. Dit zijn nog lang niet alle functies die er in een volwassen i18n module moeten zitten. Er zijn veel complexe talen in de wereld. Gelukkig is Nederlands niet zo complex, en kan er prima gewerkt worden met de standaardimplementatie. Er wordt gebruikt gemaakt van scoping om vertalingen onder te verdelen, pluralization om op basis van een variabele het enkelvoud of meervoud te pakken en interpolating om waarden, zoals een naam, midden in een vertaling te zetten. Mocht je een site vertalen naar een complexere taal, zul je echter nog steeds naar extra plugins moeten grijpen. De i18n module is echter zo opgebouwd dat de ‘backend’ verwisselbaar is, om makkelijk plaats te maken voor ingewikkeldere implementaties. De standaard backend die geleverd wordt bij Rails is de SimpleBackend, die vertalingen uit ruby-files en yaml haalt.
Installatie
sudo gem install rails -v 2.2.0 -s http://gems.rubyonrails.org
Hoe te implementeren?
Als je de code van Rails er op na slaat vind je nu een aantal locale.yml files, verspreid over de verschillende modules van Rails. Deze bevatten de standaard mededelingen, zoals validatie-errors en dag- en maandnamen. In een paar simpele stappen krijg je deze meldingen vertaald naar het Nederlands.
We beginnen met het maken van een directory waar de vertalingen van de applicatie terecht kunnen. Een voorbeeld is app/locales, maar je bent uiteraard geheel vrij in het kiezen van deze locatie. In deze directory kun je per taal een subdirectory maken, of niet, dat is geheel aan de programmeur. Het voelt wat overbodig aan voor een applicatie die enkel Nederlands is om daar een complete structuur voor neer te zetten. Enfin, maak ergens in deze directory dus yml bestand aan. De Nederlandstalige inhoud kan je hier vinden. Je mag zoveel yml bestanden maken als je wilt en je vertalingen indelen zoals je wilt. Elke vertaling moet wel beginnen met de naam van de locale (bij Nederlands dus nl-NL).
De volgende stap is Rails vertellen waar deze vertalingen staan. De ideale plaats is in een initializer, een ruby-bestand in de config/initializers/-directory. Maak daar een i18n.rb bestand aan en voeg daar deze code aan toe:
I18n.load_path += Dir.glob("#{RAILS_ROOT}/app/locales/*.yml") I18n.load_path += Dir.glob("#{RAILS_ROOT}/app/locales/**/*.yml") I18n.default_locale = 'nl-NL'
Je kan regel 1 of 2 weghalen, afhankelijk of je subdirectories gebruikt of niet. Met de laatste regel geef je aan dat de standaard locale Nederlands is. Dat is alles.
Wil je een meertalige website? Dan moet je per request de juiste locale te zien achterhalen, uit bijvoorbeeld de URL parameters of een gebruiksprofiel. Maak daarvoor een before_filter in de ApplicationController
class ApplicationController < ActionController::Base before_filter :set_locale private def set_locale I18n.locale = params[:locale] if params[:locale] end end
Vertaal mij!
Handmatig vertalen is erg eenvoudig. De methode I18n.translate biedt de interface om vertalingen op te halen. Vanuit de view kan je de modulenaam weg laten en de methode is ook af te korten tot de letter t. Daarin kan je op verschillende manieren door de scope heen gaan. Dat kan door de optie :scope of door de key door punten te verdelen, of een combinatie daarvan. De volgende drie regels doen exact hetzelfde:
I18n.translate(:hello, :scope => [:messages, :users]) I18n.translate(:"users.hello", :scope => :messages) I18n.translate(:"messages.users.hello")
Je kan de hoeveelheid opgeven om gebruik te maken van de pluralization:
I18n.translate(:number_of_posts, :count => @posts.size)
Je kan defaults opgeven, voor als de vertaling nog niet opgegeven is. Je kan zelfs meerdere opgeven in een Array om een lijst af te gaan tot de juiste gevonden is. Alleen symbols worden opgezocht:
I18n.translate(:special_hello, :default => [:regular_hello, "Hallo"])
Als je van errors houdt, kan je translate ook een exceptie laten gooien als er geen vertaling gevonden werd:
I18n.translate(:untranslatable, :raise => true)
En je kan zelfs de locale on-the-fly veranderen:
I18n.translate(:hello, :locale => 'en-US')
Elke andere optie die je meegeeft kan je gebruiken voor interpolatie. Een vertaling als deze:
nl-NL:
welcome: "Welkom {{name}}!"Maakt de volgende code mogelijk:
I18n.translate(:welcome, :name => @user.name) # => "Welkom Iain!"
En al deze opties zijn natuurlijk in elke samenstelling te gebruiken, maar dat moge duidelijk zijn.
En mijn database?
De namen van je modellen en diens attributen zijn op een elegante manier te vertalen. Rails levert daarvoor de klasse-methoden: human_name en human_attribute_name. Deze geven een vertaalde naam voor respectievelijk het model en het attribuut. Om aan te duiden hoe dat gaat, hier een klein voorbeeld van hoe je yml-bestand er dan uit ziet:
nl-NL:
activerecord:
models:
user:
one: gebruiker
other: gebruikers
attributes:
user:
login: inlognaamJe kan hier direct zien hoe pluralization werkt. Enkelvoud heeft de key one en meervoud de key other. Andere talen hebben speciale meervoudsvormen voor 2 of maximaal 5. Deze heten dan few en many. Dit is een voorbeeld van een functie die verder niet ondersteund wordt door de SimpleBackend, maar iets wat je met een eigen backend wel kan toevoegen.
Goed, om terug te komen op de modellen. De methode User.human_name geeft de string “gebruiker” terug, de methode User.human_attribute_name("login") geeft de string “inlognaam” terug. Let bij de laatste methode wel op dat je de attribuutnaam als string moet opgeven en niet als symbol. De methode error_messages_for en consorten gebruiken deze methodes ook, zodat je validatiemededelingen ook automatisch vertaald zijn.
Dat is eigenlijk het belangrijkste van i18n. Een (redelijk) complete lijst met tutorials en plugins voor i18n zijn hier te vinden.
Conclusie
Rails maakt met deze twee nieuwe features een grote stap in de goede richting. Met name op het gebied van i18n zijn we er nog niet. Rails 2.2 moet uitwijzen wat gebruikers het meest gaan missen en wat er nog in Rails zelf verwerkt moet worden. Ga nou echter niet direct zeuren. Het is ook de bedoeling dat Rails zelf niet volledige i18n gaat ondersteunen voor alle mogelijke talen en omstandigheden. De doelstelling was om Rails vertaalbaar te maken zonder hacks te hoeven toepassen. Een geslaagde poging en weer twee argumenten minder voor de mensen die nog steeds twijfelen over Rails.













En vergeet niet: transactional migrations!! Ik vroeg me altijd al af waarom deze niet transactional waren.
Remco - November 17, 2008 18:08
Rails 2.2.1 is uit. Updaten kan met: sudo gem install rails -s http://gems.rubyonrails.org
@remco: Ik heb me geconcentreerd op wat er in het programmeren verandert. transactional migrations zijn super, maar vergen geen verandering voor de programmeur.
Iain Hecker - November 18, 2008 10:51
2.2.2 is uit!!
Remco - November 22, 2008 11:38
Eigenlijk is de titel van deze blogpost niet zo sterk… je zou het beter Internationalisatie in Rails 2.2 kunnen noemen of zo… volgens mij zijn er namelijk nog wel meer dingen veranderd (ook voor de programmeur
). Maar wel leuk artikel desalniettemin
Martin Sturm - December 13, 2008 17:04
Eigenlijk is de titel van deze blogpost niet zo sterk… je zou het beter Internationalisatie in Rails 2.2 kunnen noemen of zo… volgens mij zijn er namelijk nog wel meer dingen veranderd (ook voor de programmeur
). Maar wel leuk artikel desalniettemin
Martin Sturm - December 13, 2008 17:04