sábado, 26 de abril de 2008

Recursos para viajes en Internet

En octubre del año pasado Nayda y yo hicimos un viaje a Europa. La primera vez que yo fui, en el año 2000 (podría decir que en una época "preinternáutica"), sólo me valí del correo electrónico para contactar a las personas que quería visitar, sin mucha planificación por adelantado. En este segundo viaje prácticamente no hubo detalle que no hubiese estado relacionado a algún recurso de Internet. Dónde ir, qué hacer, cómo llegar allí, dónde conseguir los mejores pasajes y alojamientos, etc.: todo fue minuciosamente escarbado en Internet (con la ayuda de Google y de numerosos tips de mis amigos en Europa). Esto nos permitió reducir bastante los costos, y aprovechar al máximo el tiempo de viaje y disfrute, sobretodo tomando en cuenta el poco tiempo de planificación que tuvimos.

Cómo llegar

Fueron muchos los sitios que me recomendaron, y que revisé, para conseguir buenas ofertas en pasajes aéreos, pero, sin duda alguna, el mejor de todos es Kayak. Kayak no vende los pasajes, sino que reune en un sólo sitio web los resultados de todas las aerolíneas y operadores de vuelos. Una vez que se selecciona el pasaje que nos gusta, la web lo lleva a uno directamente a la página de compra de la aerolínea seleccionada.

La página de búsqueda es bastante sencilla: origen, destino, fechas de salida y retorno y número de pasajeros; tiene opciones adicionales para vuelos sólo de ida, ida y vuelta, múltiples ciudades, y fechas flexibles (por si hay mejores ofertas en un período cercano al que escogimos). Y hay una casilla muy importante, debajo del origen y destino, que dice "show nearby airports" (mostrar aeropuertos cercanos) para el caso de vuelos a ciudades con aeropuertos pequeños cercanos, que permiten vuelos más baratos.

La página de resultados puede intimidar un poco al principio, porque hay mucha información, pero creo que la gente de Kayak ha hecho un muy buen trabajo de diseño para poder concentrar tantas posibilidades juntas, y aun hacerla legible (luego del susto inicial). Allí podemos filtrar los resultados de acuerdo a numerosos parámetros: rango de precios, fechas (si escogimos fechas flexibles en la búsqueda), cantidad de escalas en el vuelo, líneas aéreas preferidas, horas de salida y llegada, duración del vuelo, duración de las escales (si las hay); podemos ver los resultados en forma de lista, matriz, o gráfico de tendencias; podemos ordenar la lista de diferentes maneras, ver más información de un vuelo en específico, enviarlo por correo, imprimirlo, o marcarlo como favorito (para futuras referencias y búsquedas)

Otro detalle muy importante es que el precio que se muestra en los resultados tiene todos los impuestos requeridos en el aeropuerto, así que no hay sorpresas a la hora de planificar los costos del viaje. Con todas estas opciones, se puede uno armar el mejor plan de vuelo, dependiendo de lo que queramos y nuestra posibilidades.

Trenes

Algunos de los traslados eran más económicos por tren. Lamentablemente no encontré un sitio web como Kayak para pasajes de tren, así que tuve que recurrir a los diferentes sitios web de los servicios de trenes: SNCF (Francia), DB Bahn (Alemania; hay unos trenes nocturnos que salen bastante económicos), SBB (Suiza), SNCB (Bélgica). Cada web tiene sus particularidades, y no todas están en español (o inglés).

Libreta de pasajes

Todos los pasajes electrónicos comprados en Internet (incluyendo las reservaciones de hotel), los encuaderné juntos en una sola libreta. De esta manera no había enredos posibles, ni problemas por olvido de pasajes en ningún punto del viaje. Hice varias copias de esta libreta, una que llevaba a la mano en todo momento, y otras guardadas en diferentes sitios del equipaje. Esto resultó ser una práctica muy útil, ya que en un apuro en Alemania, comprando un pasaje de metro, la dejé olvidada en la taquilla. Kein Stress: saqué una copia de la maleta, y a continuar el viaje.

Alojamiento

Luego de regresar del viaje me enteré de la existencia de Hotels Combined, un sitio web que me hubiese ahorrado tanto tiempo en la búsqueda de alojamiento, como lo hizo Kayak con los pasajes aéreos. Para el momento en que escribo esto, Hotels Combined busca simultáneamente en más de 30 sitios de reservaciones de alojamientos de Internet. Y tiene todas las opciones de búsqueda que podríamos esperar: ciudades, fechas, tipos de habitaciones, precios, disponibilidad, fotografías, opiniones de los huéspedes, mapas y direcciones, etc.

A falta de esta web, usé, con muy buenos resultados, el sitio web Hostels. Básicamente tiene las mismas opciones que Hotels Combined, sólo que busca en menos sitios a la vez. De hecho, Hostels.com es uno de los sitios en que busca Hotels Combined.

Y por supuesto, cuando se trata de alojamientos (y de un poco de aventura), siempre está la opción de un sofá amigo.

Qué hacer

Si ya escogimos un destino de viaje, es muy probable que tengamos una idea más o menos clara de lo que queremos ver, visitar o hacer. Pero si no sabemos bien esto, o incluso para averiguar qué otras opciones hay, hay diferentes sitios web con este tipo de información detallada:

  • Wikitravel: este sitio está repleto con tips de todo tipo (sitios, eventos, curiosidades, comidas, bebidas, etc.) sobre casi todos los rincones del planeta. Dado el carácter colaborativo de la web, no todos los consejos son adecuados para todo el mundo. Pero sin duda es una excelente fuente de información antes de viajar.
  • What's on when: aquí podemos escoger una ciudad, indicar el período de tiempo en que estaremos, y nos da una lista de todas las atracciones y eventos disponibles. Podemos seleccionar también una categoría de eventos (arte, música, festivales, deporte, ciencia, etc.). Una de las cosas que más me atrajo fue que tiene información de horarios, precios e indicaciones de cómo llegar a cada sitio o evento.
  • World Events Guide: bastante parecida a la anterior.

Planificación

Todas las opciones anteriores nos generaron una buena cantidad de información, la cual había que organizar e incluso compartir con todos los buenos amigos que tuvimos la oportunidad de visitar. Los dos principales recursos de Internet que utilizamos para eso fueron:

  • Google Calendar: todo el itinerario del viaje estaba disponible en un calendario compartido con los amigos que visitaríamos. De esta manera estaban (casi) todos enterados de las fechas y horas de llegada y salida. De igual manera, todos ellos podían agregar cosas al calendario directamente: sugerencias, eventos, cosas por hacer, etc.
  • Google Notebooks: toda la información de los cosas por hacer (que extrajimos de los sitios nombrados anteriormente) la ibamos colocando en un bloc de notas de Google, que también estaba compartido con todos los involucrados en el viaje, para que pudieran colocar sus sugerencias.

Pero no ibamos a estar pegados a un computador durante el viaje para consultar todo esto (de hecho, uno de los objetivos del viaje era desconectarme por completo del computador y de Internet). Así que unos días antes del viaje, con toda la información ya organizada, exporté el calendario y el bloc de notas a Word, lo imprimí y lo encuaderné por país y/o ciudad: nuestro Lonely Planet personal ;-)

El poco tiempo de planificación antes del viaje, la cantidad de cosas que había que preparar, y, por supuesto, el montón de cosas de trabajo que había que dejar listas antes de tomar unas largas vacaciones, exigía un buen método de planificación de tareas. Y nada como el GTD para eso, y mi programa de GTD favorito, ThinkingRock. Gracias a él, y a la disciplina de llevar el método como se debe, pudimos terminar a tiempo todo lo necesario para el viaje.

¿Alguna otra cosa?

Todo esto, por supuesto, es sólo una ñingagésima parte de la multitud de cosas que se pueden encontrar en Internet para viajes. He nombrado sólo las cosas que, de todas las que investigué (y si que fueron bastantes), nos funcionaron para lograr el mejor viaje que pudimos. Si conocen de algún otro recurso que les haya dado buenos resultados, me encantaría escucharlo en los comentarios. Cualquier consejo es válido, ahora que estamos planificando nuestro siguiente destino :-D

Juan David, Carlos, Liza, Ismerai, Laura, Fabian, Hector: muchas gracias por sus consejos, su paciencia y su hospitalidad. Fue un placer verlos a todos, y espero que tengamos otra oportunidad pronto :-) Y les juro que no pasa de esta década la publicación de las fotos del viaje ;-)

miércoles, 23 de abril de 2008

Otras maneras de ver las carreras de Fórmula 1

Me gusta mucho la transmisión que hace Fox Sports de las carreras de Fórmula 1 (sólo en casos de emergencia recurro a Televen o Meridiano). Pero existen otras maneras de ver las carreras.

Live Timing

La página oficial de la Fórmula 1 provee un servicio de transmisión en vivo de datos de las carreras: Live Timing. El servicio requiere registrarse, pero es gratis. Esto es una maravilla para ver de manera conjunta a la transmisión por TV.

La pantalla del Live Timing tiene tres pestañas:

  • Live Timing: posiciones, tiempos por vuelta y por sector, entradas a pits, abandonos, intervalos de tiempo (al primer lugar y al carro de enfrente) y vueltas rápidas, todos los detalles de lo que ocurre en la pista, para todos los pilotos, en vivo. Además trae una columna de comentarios sobre la carrera. Es como ver la carrera como un operador de Matrix ;-)
  • Clima: temperatura ambiente y de la pista, humedad, velocidad del viento, pronósticos de lluvia, etc.
  • Seguimiento de posiciones: es un gráfico que muestra los cambios de posición de cada piloto, a lo largo de la carrera. Es fantástico para ver en perspectiva cómo se mueven nuestros pilotos favoritos en toda la carrera.

¿Por qué ver el Live Timing? La transmisión de TV sólo nos muestra una fracción de lo que está ocurriendo en la carrera. El Live Timing nos da una visión general. También nos brinda mucha información que sería muy difícil de ver en la pantalla de TV todo el tiempo.

Además, si eres fanático de un piloto que no es una de las estrellas de la temporada, a menos que se dé un tortazo memorable, o esté molestando a alguna de esas estrellas, muy pocas veces lo podrás ver en la temporada. El Live Timing te puede dar la oportunidad de ver siempre cómo se comporta en carrera. Por ejemplo, hasta hace un tiempo, esta era casi la única manera de saber de Kubica en carrera. Y ahora que Kubica empieza a tener espacio en pantalla, podemos seguir a Vetel con detalle también.

El Live Timing funciona también durante las sesiones de prácticas y clasificación, además de las carreras.

Descargar las carreras de internet

Me encanta ver las carreras en vivo. Aun más desde que descubrí el Live Timing. Incluso, Brasil y Canadá normalmente van acompañadas de almuerzo con amigos, y hasta Australia y Japón van de la mano con tragos y fiesta. Pero no siempre es cómodo, o siquiera posible: las sesiones de China o Malasia son toda una prueba de resistencia; los fines de semana de las carreras en Europa hay que limitar las salidas los sábados, para poder estar despierto y lúcido a las 7am del domingo frente al TV; y este fin de semana me encantaría irme a la playa, pero no dejo de pensar en Barcelona. Y todo esto hay que manejarlo públicamente disimulando la obsesión, o aguantándote la caras de la gente (normal) cuando dices algo como "Me encantaría, pero es que la carrera es a las...". (Si, ya estoy buscando ayuda, gracias por mencionarlo ;-)

Pero a finales del año pasado, curioseando en unos buscadores de torrentes, me encontré con la agradable sorpresa de que se pueden descargar las transmisiones de las carreras. Problema solucionado. Lo siento Fox Sports.

(Para los que no conocen mucho sobre los torrentes, les recomiendo dos excelentes tutoriales de Hernán Casciari, publicados en su blog Espoiler: "Paso uno: encienda el ordenador" y "Cómo ver series sin usar el televisor". Ahí podrán aprender qué es eso, cómo se usa y qué necesitan)

Uso varios buscadores de torrentes, pero MotorWorld tiene una sección dedicada exclusivamente a torrentes de deportes de motor. Ahí se puede encontrar de todo, nuevo y viejo. Requiere registro, aunque es también gratuito. Y además tiene un feed con todo lo último disponible en la sección.

He encontrado transmisiones de las carreras en español, del canal Telecinco español, así como las excelentes transmisiones del canal británico ITV (el nivel de acceso a personalidades para entrevistas y la cobertura de la pista y los pits en la antesala de la carrera es impresionante). Por supuesto, también se pueden descargar las clasificaciones.

ITV transmite también las carreras a través de internet en su web, pero sólo hay acceso desde Inglaterra (más detalles al respecto en BlogF1).

ACTUALIZACIÓN (24/04/2008): Miguel Onorato me envió un enlace a una excelente web para "ver" las carreras: VisionF1. En sus propias palabras: "es para los mas fiebruos (como nosotros) que quieran visualizar realmente como fueron las vueltas en la carrera". En la web podemos ver una animación de las carreras, con pequeños círculos que nos indican donde está cada carro. Tiene bastantes opciones interesantes para visualizar la carrera (variar la velocidad de la animación, seleccionar pilotos, diferentes colores para los estados, etc.). Además tiene una sección de análisis de las carreras, con tablas repletas de datos y detalles de la actuación de cada piloto. Es sin duda un recurso excelente para conocer más detalles sobre cada carrera. Me parece también un excelente recurso para acompañarlo con las carreras descargadas de internet, un poco para suplir el Live Timing que no tendríamos disponibles con ellas.

viernes, 18 de abril de 2008

"Cuando sea grande..."

Banda Show (6)

"Cuando yo sea grande, quiero..."

La banda en la plaza (2)

"... ser como ellos"

Concierto de la Banda Simón Bolívar (Zulia)
Plaza Bolívar de Santa Rosa, 17 de Abril del 2008
Primer Seminario Internacional de Bandas Yamaha


ACTUALIZACIÓN (22/04/2008): Otros álbumes del evento:

sábado, 12 de abril de 2008

Clase PCGuard en Ruby

PC Guard es una excelente herramienta para la protección de software y generación de licencias de usuario en Windows. Uno de sus productos es el Activation suite, que permite desarrollar aplicaciones que generen licencias válidas de PC Guard.

La documentación del Activation suite Web sólo proporciona ejemplos de uso en PHP y ASP. La siguiente es una clase hecha en Ruby para manejar la validación y generación de licencias.

require 'win32ole'

class PCGuard
  
  # Propiedades de sólo lectura
  attr_reader :activacion, :remocion, :volumendd, :bios, :cpu, :serialdd, :os, :cd, :red
  # Propiedades de lectura y escritura
  attr_accessor :programid, :sitecode, :mid, :features
  
  # Valores del "ResponseCode" del PCGuard
  STATUS_OK = 0             # Success
  STATUS_BAD_SITE_CODE = 1  # Site code is invalid
  STATUS_BAD_PROGRAM_ID = 3 # ProgramID is invalid
  STATUS_BAD_MID_CODE = 6   # Machine ID is invalid
  STATUS_MID_CODE_ERROR = 7 # Machine ID decryption error
  
  # Excepciones que genera la clase
  class BadSiteCode < StandardError; end  
  class BadProgramID < StandardError; end  
  class BadMID < StandardError; end  
  class MIDCodeError < StandardError; end  
  
  # Valida y genera todos los códigos de la licencia
  def initialize(programid = "", sitecode = "", mid = "", features = 0)
    
    # Inicializar variables con los códigos de PCGuard
    @programid, @sitecode, @mid, @features = programid, sitecode, mid, features
    
    # Inicializar variables de las propiedades
    @activacion, @remocion, @volumendd, @bios, @cpu, @serialdd, @os, @cd, @red = "", "", 0, 0, 0, 0, 0, 0, 0
    
    # Generar códigos, si se han pasado todos los campos necesarios al inicializar el objeto
    self.generar unless @programid.empty? || @sitecode.empty? || @mid.empty?
    
  end
  
  # Genera todos los códigos
  def generar
    
    # Generar un error si no se han cargado todos los códigos de PCGuard necesarios para generar una licencia
    raise ArgumentError if  @programid.empty? || @sitecode.empty? || @mid.empty?
    
    # Crear objeto
    l = WIN32OLE.new("icgweb.icgen")
    
    # Inicializar códigos
    l.ProgramID = @programid

    # Generar códigos de ifentificación de la máquina
    l.SiteCode = @sitecode
    l.MachineID = @mid
    l.V5_CheckMachineID()
    
    # Validar
    if l.ResponseCode != STATUS_OK
      raise BadSiteCode if l.ResponseCode == STATUS_BAD_SITE_CODE
      raise BadMID if l.ResponseCode == STATUS_BAD_MID_CODE
      raise MIDCodeError if l.ResponseCode == STATUS_MID_CODE_ERROR
    end
    
    # Generar código de activación y remosión
    l.SiteCode = @sitecode
    l.MachineID = @mid
    l.Features = @features
    l.V5_CalculateActivationCode()
    
    # Validar
    if l.ResponseCode != STATUS_OK
      raise BadSiteCode if l.ResponseCode == STATUS_BAD_SITE_CODE
      raise BadProgramID if l.ResponseCode == STATUS_BAD_PROGRAM_ID
      raise BadMID if l.ResponseCode == STATUS_BAD_MID_CODE
    end
    
    # Asignar valores a las variables del objeto
    @activacion = l.ActivationCode # Código de activación
    @remocion = l.RemoveCode       # Código de remosión
    @volumendd = l.DriveID.to_i    # Hard drive volume serial ID
    @bios = l.BiosID.to_i          # Motherboard bios ID
    @cpu = l.CPUID.to_i            # CPU ID
    @serialdd = l.HDHWID.to_i      # Hard drive hardware ID
    @os = l.OSID.to_i              # Operating system ID
    @cd = l.CDHWID.to_i            # CD/DVD hardware ID
    @red = l.NETID.to_i            # Network card ID 
    
    # Retornar el código de activación de la licencia
    @activacion
    
  end
  
end

Tiene propiedades de lectura/escritura para los códigos principales de PC Guard: ProgramID (programid), Site Code (sitecode), MID (mid) y Features (features); propiedades de sólo lectura para los resultados de la generación: código de activación (activacion), código de remoción (remocion); propiedades de sólo lectura para los código de identificación del equipo: serial de la partición del disco duro (volumendd), BIOS del equipo (bios), CPU (cpu), serial del disco duro (serialdd), sistema operativo (os), CD/DVD (cd), tarjeta de red (red); y un único método para generar todos los códigos (generar).

Para usarla, puedes hacer algo como:

require 'PCGuard'

licencia = PCGuard.new
licencia.programid = "XXXXXXXXXXXXXXXXXXXXXXXX"
licencia.sitecode = "YYYYYYYY"
licencia.mid = "ZZZZ-ZZZZ-ZZZZ-ZZZZ"
licencia.generar  # => "ABCD1234-ABCD1234-ABCD1234-ABCD1234"

O, de manera más resumida:

licencia = PCGuard.new("XXXXXXXXXXXXXXXXXXXXXXXX", "YYYYYYYY", "ZZZZ-ZZZZ-ZZZZ-ZZZZ")

Por supuesto, proporcionando códigos válidos para ProgramID, Site Code y MID.

También genera las siguientes excepciones:

  • ArgumentError: falta alguno de los códigos necesarios (programid, sitecode o mid)
  • BadProgramID: error en el ProgramID (identificador del proveedor de software)
  • BadSiteCode: error en el Site Code del equipo
  • BadMID: error en el MID del equipo
  • MIDCodeError: error en el Site Code y/o el MID.

miércoles, 9 de abril de 2008

AutoHotKey, usos y ejemplos (3): enviar mensajes de texto (sms) de Movilnet

Esta es la tercera parte de la serie de artículos sobre el AutoHotkey. En la primera parte vimos algunos de los ejemplos más sencillos de sustitución de textos y arranque de aplicaciones. En la segunda parte vimos casos un poco más elaborados de automatización de aplicaciones. Ahora vamos a ver un ejemplo de aplicaciones con el AutoHotkey.

Aplicación para enviar mensajes de texto de Movilnet

Hace algún tiempo estuve jugando un poco con el código del sitio web de Movilnet, buscando una manera de enviar mensajes sin tener que pasar por la web (que me parece un poco sobrecargada y lenta). Luego de hacer algunas cosas con el AutoHotkey supe que este sería la herramienta ideal para hacer una pequeña aplicación, como la que yo quería, para enviar sms. La idea era sencilla: escribir un mensaje (sin importar cuan largo fuera), escoger uno o más destinatarios de una lista, y que la aplicación se encargara de dividir el mensaje en las partes necesarias y enviarlas a cada uno de los destinatarios seleccionados.

Y eso fue exactamente lo que hice. Y mucho más fácilmente de lo que me imaginé que sería, gracias a algunas de las maravillas del AutoHotkey. Cuando vi esta herramienta por primera vez, pensé que tendría un conjunto de comandos reducido, ideales para manejar casos sencillos como los que ya hemos visto (abrir aplicaciones, presionar teclas, etc.). Pero leyendo la documentación me encontré con una lista inmensa de comandos e instrucciones. Es un lenguaje de programación bastante completo, muy bien adaptado a todos los eventos y objetos del sistema operativo (Windows), y con todas las herramientas que se esperarían de un lenguaje de programación (como ciclos, operadores, manejo de archivos, controles para interfaz, etc.).

Pueden descargar el código de la aplicación aquí (Por supuesto, si tienes correcciones o mejoras que hacerle, me gustaría escucharlas). Si no les interesa el código completo, o instalar el AutoHotkey, también pueden descargar el ejecutable de la aplicación. Porque el AutoHotkey también tiene un compilador, y genera unos ejecutables bastante pequeños, considerando que no requiere tener instalado el AutoHotkey para ejecutarlos, o librerías externas de ningún tipo.

Agenda de destinatarios

La aplicación requiere la existencia de un archivo de texto (Agenda.txt) con la lista de los destinatarios (nombres y teléfonos) en un formato como el siguiente:

Jesús Dugarte, 04261111111
Pedro Perez, 04262222222
Juan Gonzalez, 04163333333
Maria Garcia, 04264444444

La ubicación, y nombre, de este archivo de contactos se indica al principio del programa. Los códigos de área (0416, 0426) deben indicarse completos, como aparecen en el ejemplo.

Uso de la aplicación

Yo ejecuto la aplicación con una tecla rápida, como las que vimos en los artículos anteriores:

#X::Run "C:\Movilnet\Movilnet.ahk"

La web de Movilnet usa un código de verificación para los envíos de los mensajes sms. Así que, lamentablemente, hay que ingresar ese código por cada uno de los mensajes que se envían. Al principio no estaba seguro de que la aplicación fuese realmente útil, dada la molestia del código de seguridad. Pero, un poco por curiosidad (y un poco más por necedad) la hice y la he estado usando ya por un par de meses, y no me ha parecido que el código de seguridad sea demasiada molestia, o que sobrepase las ventajas de usar la aplicación.

Diariamente uso ambos, el teléfono y la aplicación, dependiendo de lo que necesite hacer. Si sólo necesito responder un "Ok" a un mensaje que me envíen, por supuesto que es más rápido hacerlo desde el teléfono. Pero si quiero escribir un mensaje más largo, o no sé muy bien que voy a enviar(es más fácil dudar y corregir frente al teclado del computador que en el teclado del teléfono), o quiero enviarlo a varias personas (también es más rápido seleccionar personas de la lista de la aplicación que en el teléfono), prefiero usar la aplicación. También la uso, por supuesto, en situaciones más mundanas como falta de batería o de saldo ;-)

Conclusión

Lo que más me gusta del AutoHotkey es que me ahorra tiempo, y me evita repeticiones innecesarias y errores, en áreas o tareas donde incluso ni me imaginaba que se podía. Luego de intentar diferentes tipos de herramientas de automatización en Windows (lenguajes de secuencias de comandos, herramientas de sustitución de textos, de asignación de teclas rápidas, etc.), encontré en él una de las herramientas de productividad más importantes que he encontrado. Definitivamente requiere al menos una base de conocimiento de programación, pero también es cierto que se pueden encontrar en internet muchas soluciones ya hechas para casos comunes (como algunos de lo que mostré en la primera parte de esta serie) y otros no tan comunes (como el que vimos aquí y en el artículo anterior).

Espero que les sea de utilidad esta información. Y si tienen alguna solución interesante hecha con el AutoHotkey, también me encantaría escucharla.

ACTUALIZACIÓN (04/08/2009): Si habían descargado en las últimas semanas la aplicación para SMS de Movilnet quizás no les haya funcionado: la web de Movilnet cambió la dirección del servicio. Acabo de subir una actualización del código (y el ejecutable) de la aplicación, con la dirección corregida

martes, 1 de abril de 2008

Rails en español

Existen muchas opciones para hacer localización e internacionalización en Ruby on Rails. Entre todas ellas, la que me parece más sencilla es el plugin Localization Simplified. Sin embargo, me interesaban principalmente dos cosas: (1) agregar código sólo para español a mi aplicación, y (2) meterle la mano en los bolsillos a Rails y averiguar bien qué se debía hacer y por qué. En menos palabras: porque soy un maniático y un idiota ;-)

Hay diferentes cosas que hay que ajustar en Rails para que toda la información que colocamos en nuestras aplicaciones salga correctamente en español. Buscando en internet, encontré bastantes sitios donde aparecen consejos sobre cómo hacer muchas de estas cosas. Pero cada consejo, cada nueva solución, generaba un nuevo error, o advertencia, y tenía que seguir buscando. Con un poco de lectura y trabajo, fui uniendo y ajustando las diferentes soluciones que iba encontrando. A continuación les muestro la solución final que logré.

En primer lugar creamos un subdirectorio app\overrides, y allí colocamos los siguientes archivos:

  • errores.rb
module ActiveRecord
  class Errors
    begin
      @@default_error_messages = {
        :inclusion => "no está incluido en la lista",
        :exclusion => "está reservado",
        :invalid => "no es válido",
        :confirmation => "no es una confirmación",
        :accepted  => "debe ser aceptado",
        :empty => "no puede estar vacío",
        :blank => "no puede estar en blanco",
        :too_long => "es demasiado largo (máximo %d caracteres)",
        :too_short => "es demasiado corto (mínimo %d caracteres)",
        :wrong_length => "no tiene la longitud correcta (debería tener %d caracteres)",
        :taken => "ya ha sido incluido",
        :not_a_number => "debe ser un número" }
    end
  end
end

module ActionView #nodoc
  module Helpers
    module ActiveRecordHelper
      def error_messages_for(object_name, options = {})
        options = options.symbolize_keys
        object = instance_variable_get("@#{object_name}")
        unless object.errors.empty?
          content_tag("div", content_tag(options[:header_tag] || "h2", "Hay errores que impiden guardar el registro") +
          content_tag("p", "Compruebe los siguientes campos:") +
          content_tag("ul", object.errors.full_messages.collect { |msg| content_tag("li", msg) }), "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation" )
        end
      end
    end
  end
end
  • date.rb
require 'date'

class Date
  remove_const(:MONTHNAMES)
  MONTHNAMES = [nil] + %w(Enero Febrero Marzo Abril Mayo Junio Julio Agosto Septiembre Octubre Noviembre Diciembre)
  remove_const(:ABBR_MONTHNAMES)
  ABBR_MONTHNAMES = [nil] + %w(Ene Feb Mar Abr May Jun Jul Ago Sep Oct Nov Dic)
  remove_const(:DAYNAMES)
  DAYNAMES = %w(Domingo Lunes Martes Miercoles Jueves Viernes Sábado)
  remove_const(:ABBR_DAYNAMES)
  ABBR_DAYNAMES = %w(Dom Lun Mar Mié Jue Vie Sáb)
end

class Time
  alias :strftime_nolocale :strftime

  def strftime(format)
    format = format.dup
    format.gsub!(/%a/, Date::ABBR_DAYNAMES[self.wday])
    format.gsub!(/%A/, Date::DAYNAMES[self.wday])
    format.gsub!(/%b/, Date::ABBR_MONTHNAMES[self.mon])
    format.gsub!(/%B/, Date::MONTHNAMES[self.mon])
    self.strftime_nolocale(format)
  end
end

module ActionView
  module Helpers
    module DateHelper

      def distance_of_time_in_words(from_time, to_time = 0, include_seconds = false)
        from_time = from_time.to_time if from_time.respond_to?(:to_time)
        to_time = to_time.to_time if to_time.respond_to?(:to_time)
        distance_in_minutes = (((to_time - from_time).abs)/60).round
        distance_in_seconds = ((to_time - from_time).abs).round

        case distance_in_minutes
          when 0..1
            return (distance_in_minutes == 0) ? 'menos de un minuto' : '1 minuto' unless include_seconds
            case distance_in_seconds
              when 0..4   then 'menos de 5 segundos'
              when 5..9   then 'menos de 10 segundos'
              when 10..19 then 'menos de 20 segundos'
              when 20..39 then 'medio minuto'
              when 40..59 then 'menos de un minuto'
              else             '1 minuto'
            end

          when 2..44           then "#{distance_in_minutes} minutos"
          when 45..89          then 'aprox. 1 hora'
          when 90..1439        then "aprox. #{(distance_in_minutes.to_f / 60.0).round} horas"
          when 1440..2879      then '1 día'
          when 2880..43199     then "#{(distance_in_minutes / 1440).round} días"
          when 43200..86399    then 'aprox. 1 mes'
          when 86400..525599   then "#{(distance_in_minutes / 43200).round} months"
          when 525600..1051199 then 'aprox. 1 año'
          else                      "over #{(distance_in_minutes / 525600).round} years"
        end
      end
      
    end
  end
end
  • all.rb
Dir[File.dirname(__FILE__) + "/**/*.rb"].each { |file| require(file) }

Luego colocamos, al final del archivo config\environment.rb:

require "#{RAILS_ROOT}/app/overrides/all"

Por último, en el archivo config\initializers\inflections.rb:

Inflector.inflections do |inflect|
  inflect.plural /([aeiou])([A-Z]|_|$)/, '\1s\2'
  inflect.plural /([rlnd])([A-Z]|_|$)/, '\1es\2'
  inflect.singular /([aeiou])s([A-Z]|_|$)/, '\1\2'
  inflect.singular /([rlnd])es([A-Z]|_|$)/, '\1\2'
  inflect.irregular 'user', 'users'
  inflect.irregular 'account', 'accounts'
  inflect.irregular 'password', 'passwords'
  inflect.irregular 'session', 'sessions'
end

Noten que el final del código de pluralizaciones agrego cuatro líneas para user, account, password y session. Esto se debe a que quiero que todas las pluralizaciones que haga Rails en mi aplicación, las haga con las reglas del español, así que tengo que agregar excepciones para los modelos que están en inglés (en este caso, los modelos para el manejo de usuarios, que vienen del plugin Restful Authentication). Si tienen algún modelo en inglés, pueden agregar la regla para pluralizarlo de la misma manera allí.

Todo esto se debe encargar de colocar en español los mensajes de error, las fechas (meses, días), y las pluralizaciones de Rails.

ACTUALIZACIÓN (12/04/2008): Agregué la traducción de la función distance_of_time_in_words al archivo app\overrides\date.rb. También es recomendable traducir las plantillas del generador scaffold que se encuentran en {RUBY}\lib\ruby\gems\{VERSION DE RUBY}\gems\rails-{VERSION DE RAILS}\lib\rails_generator\generators\components\scaffold\templates

Fuentes del código: