Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Localizzazione e internazionalizzazione con Rails 2.2

Sfruttare le API di Rails 2.2 per la creare applicazioni multilingua
Sfruttare le API di Rails 2.2 per la creare applicazioni multilingua
Link copiato negli appunti

Le applicazioni multiligua devono anche essere in grado di adattarsi al particolare modo rappresentare i dati di reioni dverse, non solo traducendo i messaggi di testo, ma anche cambiando la formattazione delle date o dei numeri decimali.

Se da tempo sono disponibili plugin per il framework Rails che permettono di affrontare il problema dell'internazionalizzazione, la versione 2.2 di Rails espone un set di API che permette la costruzioni di funzionalità dedicate alla localizzazione, incorporando un backend semplificato che espone le funzionalità più comuni.

Con questa strategia Rails raggiunge il duplice scopo di includere nel framework gli strumenti minimi per applicazioni multiligua e di offrire la base per lo sviluppo di soluzioni differenti che sostituiscano quella di base.

Con ogni probabilità questa impostazione sarà adottata con insistenza delle prossime major release di Rails.

In questo articolo esploriamo le funzionalità disponibili nel backend per l'internazionalizzazione di Rails 2.2, chiamato Simple Backend per sottolineare l'intento di offrire un set minimo di funzionalità. Utilizzeremo come esempio l'applicazione creata per l'articolo dedicato ai filtri in Rails, che può essere generata ex novo con i seguenti comandi:

rails int_notes
cd int_notes
ruby script/generate scaffold Note title:string content:text username:string password:string
rake db:migrate

Prime configurazioni

Come prima cosa impostiamo la lingua (e tutto il contesto culturale locale) di default per l'applicazione, modificando il file config/environment.rb. L'istruzione riportata sotto dovrebbe essere già presente nel file di configurazione ma commentata:

...
config.i18n.default_locale = :en
...

Questa istruzione impone all'applicazione di utilizzare il contesto locale identificato dal simbolo en tutte le volte che non è richiesto l'utilizzo di un contesto specifico. La configurazione del contesto locale corrispondente al simbolo en risiede nel file config/locales/en.yml, dove il nome del file corrisponde al simbolo utilizzato per identificare la lingua.

Seguendo questa regola creiamo il file config/locales/it.yml che conterrà la configurazione locale in italiano, identificata dal simbolo it.

Questi file di configurazione sono di tipo Yaml, lo stesso formato utilizzato per la configurazione del database (file config/database.yml), è possibile specificare i file anche come script Ruby con estensione rb ma è meno consueto.

Nei file Yaml le impostazioni sono espresse in modo gerarchico; ad esempio:

en: # simbolo che identifica il locale
  lorem:
    ipsum: "foo"
    dolor: "bar"
  sit: "foobar"

definisce proprietà che rispondono a:

lorem.ipsum con valore foo
lorem.dolor con valore bar
sit con valore foobar

Localizzazione delle viste

Avviamo il server e accediamo alla pagina di creazione di una nuova istanza del modello Note puntando il browser all'indirizzo http://localhost:3000/notes/new.

Figura 1. Creazione nuova nota in inglese
Creazione nuova nota in inglese

Sulla pagina individuiamo le stringhe "New note", "Title", "Content", ... "Back" che devono essere tradotte nelle differenti lingue; definiamo nel file config/locales/en.yml una serie di coppie chiave/valore per le stringhe che abbiamo individuato:

en:
  new_note: "Create a new note"
  title: "Title"
  content: "Content"
  username: "Username"
  password: "Password"
  create: "Create"
  back: "Back"

Modifichiamo anche il file config/locales/it.yml così che a fronte delle stesse chiavi siano presenti le stringhe tradotte in italiano:

it:
  new_note: "Crea una nuova nota"
  title: "Titolo"
  content: "Contenuto"
  username: "Nome utente"
  password: "Password"
  create: "Crea"
  back: "Indietro"

Ora possiamo modificare la vista app/views/notes/new.html.erb per richiedere la visualizzazione delle stringhe per il locale selezionato; ricordando di avere il valore di default del locale impostato nel file config/environment.rb non dobbiamo fare altro che richiedere la visualizzazione della stringa per quel localo utilizzando il metodo t() e come parametro la chiave di accesso utilizzato nei precedenti file di configurazione:

<h1><%= t(:new_note) %></h1>

<% form_for(@note) do |f| %>
 <%= f.error_messages %>

 <p><%= f.label t(:title) %>    <br /> <%= f.text_field :title %> </p>
 <p><%= f.label t(:content) %>  <br /> <%= f.text_area :content %> </p>
 <p><%= f.label t(:username) %> <br /> <%= f.text_field :username %> </p>
 <p><%= f.label t(:password) %> <br /> <%= f.text_field :password %> </p>
 <p><%= f.submit t(:create) %> </p>
<% end %>

<%= link_to t(:back), notes_path %>

Ricaricando la pagina non si dovrebbe avvertire alcun cambiamento, poiché le stringhe per l'inglese sono identiche alle precedenti. Proviamo a modificare la lingua di default nel file config/environment.rb:

...
config.i18n.default_locale = :it
...

Riavviando il server e accedendo alla stessa pagina vedremo cambiare le stringhe nelle corrispondenti in italiano.

Figura 2. Creazione nuova nota in italiano
Creazione nuova nota in italiano

Scelta della lingua e del contesto locale

Per cambiare lingua, la nostra applicazione richiede quindi la modifica di un file di configurazione e il riavvio, ma dovremmo dare la possibilità ad ogni utente di scegliere la lingua che preferisce. Inseriamo allora un link sulla pagina da utilizzare per indicare il contesto locale da attivare:

<p>
  <%= link_to "it", :locale => "it" %> |
  <%= link_to "en", :locale => "en" %>
</p>

L'helper link_to produce due link con i parametri controller e action (ed eventuali altri parametri utilizzati per la richiesta) aventi gli stessi valori della richiesta corrente, ed aggiunge ai parametri già presente il parametro locale valorizzato a it e en; per la richiesta http://localhost:3000/notes/new saranno quindi generati i link:

http://localhost:3000/notes/new?locale=it
http://localhost:3000/notes/new?locale=en

Inseriamo ora un filtro applicato a tutte le action del controller NotesController:

class NotesController < ApplicationController
  before_filter :set_locale
  # GET /notes
  ...
private

  def set_locale
    I18n.locale = params[:locale] 
  end
end

Il metodo set_locale imposta la lingua in accordo con il valore del parametro params[:locale]. Se il parametro è nullo viene assegnato il valore di default definito nel file di configurazione.

È possibile evolvere il metodo set_locale così da salvare la preferenza dell'utente nella sua sessione ed utilizzare la sua lingua preferita anche in assenza del parametro della richiesta (in caso contrario sarebbe necessario esplicitare il parametro locale per ogni richiesta).

Se l'applicazione contempla una gestione utenti (ad esempio utilizzando il plugin Restful Authentication, si può dare agli utenti la possibilità di scegliere la lingua direttamente dal pannello di gestione del proprio account, e modificare il filtro così che estragga questo dato prima di ogni richiesta.

Se, per una particolare stringa, si vuole utilizzare un linguaggio differente rispetto a quello utilizzato per tutte le altre, è possibile scrivere:

t(:title, :locale => :'en')

In questo caso il singolo messaggio è impostato a en: questa scelta prevale sull'impostazione locale per la singola action determinato dal filtro, che a sua volta prevale sulla impostazione locale di default, scritta nel file di configurazione.

Messaggi flash e validazione ActiveRecord

Non tutte le stringhe da tradurre sono presenti nelle viste; nel caso dei messaggi flash (utilizzati per segnalare un messaggio relativo ad una action nella vista della action successiva), questi sono definiti nel controller, mentre nel caso dei messaggi di errore della validazione ActiveRecord sono definiti nei modelli.

Per i messaggi flash poco cambia rispetto a quanto fatto per le viste; ricordando che il metodo t() restituisce una stringa è possibile ad esempio scrivere all'interno della action create per il controller NotesController:

...
  def create
    @note = Note.new(params[:note])

    respond_to do |format|
      if @note.save
        flash[:notice] = t(:note_created)
...

aggiungendo al file en.yml

note_created: "Your note has been successfully created"

e al file it.yml

note_created: "La nota è stata creata con successo"

per definire la stringa da utilizzare nelle due lingue.

Per i messaggi di errore di validazione di ActiveRecord l'unica attenzione particolare va riposte nell'utilizzo del namespace riservato a questi messaggi.

Come accennato in precedenza le impostazioni di configurazione per le diverse lingue, possono avere un'organizzazione gerarchica; con questa gerarchia è possibile definire namespace personalizzati e alcuni sono stati adibiti ad usi particolari come quello che stiamo per utilizzare.

Il messaggio di errore abbinato alla validazione validates_presence_of corrisponde a activerecord.errors.messages.blank; proviamo a personalizzarlo nel file it.yml:

activerecord:
  errors:
    blank: "non può essere non compilato"

È possibile personalizzare ulteriormente i messaggi indicando un testo particolare per un errore di validazione di un modello o addirittura di un attributo. Per specificare un errore da abbinare a validates_presence_of per un modello ma indipendente dall'attributo:

activerecord.errors.models.note.blank

In questo modo si identificano tutti i messaggi di errore relativi alla validazione validates_presence_of per il modello Note. Per indicare invece l'attributo a cui applicare il messaggio:

activerecord.errors.models.note.attributes.title.blank

In questo modo viene identificato il messaggio di errore relativo alla validazione validates_presence_of per il modello Notes per il solo attributo title.

Sia per le stringhe "ordinarie" che per i messaggi di errore di ActiveRecord è possibile configurare dei messaggi parametrici, ad esempio il messaggio di benvenuto per un utente che ha appena eseguito il login si potrebbe definire:

it:
  welcome: "Benvenuto {{user_firstname}}!"

ed essere richiamato in questo modo:

t(:welcome, :user_firstname => "Joe")

Il risultato è l'inserimento di "Joe" all'interno della stringa prodotta.

Conclusioni

Il set di API messe a disposizione da Rails 2.2 permette di sviluppare diversi backend dedicati all'internalizzazione. Abbiamo analizzato SimpleBackend, incluso nell'installazione standard di Rails, ma nulla impedirà lo svilupparsi di soluzioni alternative, come dimostra la nuova versione del plugin Globalize.

Ti consigliamo anche