Generación dinámica de librerías Javascript internacionalizadas con GetText

La internacionalización es uno de los requisitos del proyecto que estamos desarrollando actualmente en Trabe Soluciones con Ruby on Rails. Para cumplirlo estamos utilizando GetText y Ruby GetText para la internacionalización de cadenas y código propio para internacionalizar ActiveRecord (un enfoque habitual cuando uno se enfrenta a este problema).

La aplicación además, cuenta con una adminsitración que, por su interfaz, utiliza una cantidad considerable de Javascript. Dicho Javascript también debe estar internacionalizado. Lo primero que se nos puede pasar por la cabeza es separar las cadenas que requieran traducción a unos ficheros separados y que nuestro layout enlace uno u otro en función del idioma de la petición (o el idioma preferido del usuario). Si lo hacemos así, estamos desaprovechando todas las ventajas que nos aporta el uso de GetText, en especial las facilidades para gestionar la traducción de cadenas (utilizando herramientas como poEdit).

Lo que vamos a hacer es generar los Javascripts dinámicamente utilizando Ruby embebido, como un rhtml cualquiera, con lo que podremos incrustar nuestras llamadas a GetText con total impunidad. Resumiendo, que lo que queremos es utilizar algo como ésto en nuestro layout:

<%= javascript_include_tag "/dyn_javascripts/#{Locale.get}/application" %>

Para ello necesitamos un poco de código.

Creamos un controlador que responda a las peticiones y que simplemente delegue en la vista correspondiente. Estas vistas estarán en la carpeta app/views/dyn_javascripts y tendrán la extensión .djs (por ejemplo).

class DynJavascriptsController < ApplicationController                

  layout false                

  def method_missing(symbol, *args)
    if symbol.to_s =~ /(.*)\.js$/ 
      render :action => $1
    end
  end  
end

Añadimos la ruta correspondiente al fichero de rutas (routes.rb). En ella pasamos el idioma como parametro porque nuestros filtros de GetText lo buscan en la URL, no por vicio.

map.connect 'dyn_javascripts/:language/:action.js', :controller => 'dyn_javascripts'

Ahora creamos un fichero que requeriremos al iniciar la aplicación (en el fichero environment.rb). Este fichero incluye una clase que procesa nuestras plantillas .djs y que debemos registrar con el métodod register_template_handler de ActionView::Base::. Además incluimos el código necesario para que la aplicación encuentre el controlador que hemos definido previamente (la última línea de código) de tal modo que se recargue con cada petición en modo desarrollo.

require 'erb'

module DynJavascripts  
  class View

    def initialize(action_view) #:nodoc:
      @action_view = action_view
    end

    def render(template, local_assigns={})
      @action_view.controller.headers["Content-Type"] = 'text/javascript'      
      @action_view.instance_eval { ERB.new(template).result(binding) }      
    end    

  end 

end

ActionView::Base::register_template_handler 'r_js', DynJavascripts::View

# Nuestro controladoe está situado en 
# lib/common/dyn_js/dyn_javascripts_controller.rb
Dependencies.load_paths << "#{RAILS_ROOT}/lib/common/dyn_js" 

Hecho todo esto ya podemos escribir código simpático como el siguiente en nuestra carpeta app/view/dyn_javasctripts:

# Archivo app/views/dyn_javascripts/application.djs
function changeALink(whichLink) {
    var the_link = document.getElementById(whichLink);
    the_link.href =  "<%= url_for :controller => 'a_controller'  %>"; 
    the_link.innerHTML = "_('Some text')";
}

El último detalle es conseguir que Ruby-GetText extraiga las cadenas de nuestros ficheros .djs. Para ello, vamos a indicarle al parser de rhtml que “sabe” procesar nuestros ficheros djs. La tarea “Rake”: de actualización de los ficheros .po quedaría tal que así:

desc "Update pot/po files."
task :updatepo do
  require 'gettext/utils'

  # 
  # ¡¡¡ Abracadabra!!!
  # 
  GetText::ErbParser.instance_variable_set(
      '@config', :extnames => ['.rhtml', '.r_js'])

   GetText.update_pofiles("app_domain",
   Dir.glob("{app,lib,bin}/**/*.{rb,rhtml,rjs,r_js}"), "App 1.0.0"")
end

Sencillo, ¿no?

Instalando Fedora (nunca más Core) 7 en un Dell Dimension C521 o el infierno de la ATI X1300

Hace menos de una semana hemos renovado el parque de equipos de Trabe. Nos hemos decantado por unos Dell Dimension C521 con la siguiente configuración:

  • AMD Athlon X2 64 4400+
  • 300GB de disco duro
  • 2GB de memoria
  • Tarjeta gráfica ATI X1300 256MB
  • TFT 22” (1680×1050) + TFT 17” (1280×1024)

Los equipos, en cuanto que “electrodomésticos”, son una maravilla: pequeños (dento de un orden), silenciosos, e incluso, si se me apura, bonitos (aunque esto es para gustos, claro). Pero el problema de los ordenadores es, precisamente, que no son electrodomésticos (me estoy desviando del tema, así que lo dejo para otro post).

A lo que iba. Los equipos traen un Windows Vista Bussiness preinstalado. Un operativo como otro cualquiera, que tarda mucho en arrancar y en cerrarse. Y poco más puedo decir sobre el Vista, porque lo primero que hemos hecho ha sido instalar una distribución linux, una Fedora 7 para ser más concretos. Obviando los pasos básicos de la instalación, y dejando a un lado algún que otro problema puntual con aplicaciones concretas (léase Firefox, léase Adobe Acrobat Reader, léase Eclipse), sí me gustaría destacar lo complicado que resultó poner a funcionar el escritorio (KDE algunos, GNOME otros) en los dos monitores a las resoluciones adecuadas. Por si alguien se encuentra con el problema, aquí queda enlazada una solución, que pasa por parchear el driver cambiando unos cuantos bits aquí y allí… algo muy natural, evidente y nada complicado ¬¬. Tras seguir los pasos indicados en el post citado, el escritorio funciona perfectamente (si dejamos a un lado unos extraños parpadeos o flashes que se producen cada n minutos), extendido a ambos monitores, como debe ser.

Conferencias Rails 2007 en camino

Por segundo año se va a celebrar en España la Conferencia Rails, que pretende ser un punto de encuentro para los desarrolladores y entusiastas de Rails de la comunidad hispana. La cita es en Madrid durante el mes de noviembre (la fecha y lugar definitivos no están confirmados).

Asís y yo participamos como ponenetes en la edición 2006 en representación de Trabe Soluciones con una charla acerca de Internacionalización en Rails. Este año hemos presentado dos propuestas de ponencia y estamos a la espera de que nos confirmen nuestra presencia. Os seguiremos informando de todas las novedades que vayan surgiendo.

Microsoft Office 2003 Professional Edition Adobe Creative Suite 2 Premium Macromedia Dreamweaver 8 [Mac] Microsoft Office Visio Professional 2007 Microsoft Windows XP Professional SP3 Adobe Flash Media Server 3.0 Adobe Font Folio 11 Microsoft Office 2008 [Mac] Adobe Acrobat 8 Professional [Mac] Adobe InDesign CS3 [Mac]