Internacionalizar un proyecto django. Cómo implanté boolino en UK y otros países

En este post hablaré de cómo he logrado que una web de ámbito español se pueda replicar en otros páises con dominio y base de datos propios, intentando minimizar los cambios en el código y explotar la filosofía DRY (don’t repeat yourself)

Especificación:

  • Todas las funcionalidades, modelos, vistas… son las mismas. Pero eso quiere decir que si hay una funcionalidad vinculada a un idioma o país (por ejemplo, búsqueda en lenguaje natural) se debe replicar al nuevo idioma.
  • Cada país tendrá su propia bdd
  • Cada lenguaje tendrá sus urls, para SEO
  • Los templates serán comunes para todos, pero como ya he dicho, deberán contemplar algún cambio puntual para algún país.
  • Cada país tendrá su propio analytics, y otros ids de 3rd party apps.
  • Boolino españa es multiidioma (español, catalán e inglés). Los nuevos países solo contemplan un idioma.
  • Boolini España debe moverse a .es (era .com) y en boolino.com irá el sitio para los USA

boolino.com (.es)

boolino España tiene una complejidad adicional, ya que tratamos la web como multidioma, el usuario puede elegir el idioma de sus menús y otros textos estáticos. Todo esto django lo resuelve magnificamente con sus herramientas de i18n, pero nosotros tenemos un handicap más. Nuestras urls llevan el nombre del idioma explícito: Por ejemplo http://www.boolino.es/ca/blogboolino/categoria/joc-i-lectura/ y http://www.boolino.es/es/blogboolino/categoria/juego-y-lectura/

Con todo este backgroung veamos ahora los pasos más interesantes del proceso de i18n

1. Settings, deploy y ejecución de la web

Este paso es sencillo y es de manual de buenas prácticas. Los settings específicos de cada país van en ficheros separados y a la hora de ejecutar la web solamente hay que especificar el fichero indicado mediante el parámente –settings

El proceso de deploy lo ejecuto con fabric. Cada país corre con su usuario de sistema operativo y así es sencillo mantener las mismas rutas para los archivos. En el fabfile solo hay que indicar nombre de usuario y host y el proceso es el mismo para todos.

2.- URLs

El tema de las urls es uno de los más complejos. En el mismo fichero hay que contemplar que la url pueda ser multidioma o no, y además que la url debe estar traducida para cada idioma.

Para el primer problema, el mismo urls.py debe soportar estas urls:

http://www.boolino.es/es/libros-cuentos/un-dia-conmigo/

http://www.boolino.co.uk/kids-childrens-books/asterix-and-the-class-act/

Es decir, con el prefijo de idioma y sin él. Para resolverlo he utilizado la librería django-solid-i18n-urls y cambiando la configuración en función del país. De esta forma, en uk no es necesario el prefijo, mientras que en España sí lo es.

Por otro lado está la traducción de la url. Django también facilita mucho esto permitiendo introducir ugettext en la mima url por lo que tengo urls del tipo

url(_(r'^libros-cuentos/'), include('boolino.urls')),

Y automáticamente (mediante .po files) se traducen a su idioma.

3.- Estructura de templates

Hemos dicho que los templates serán los mismos en cada web, sin embargo existirán pequeñas diferencias en cada una. ¿Cómo hacer que se pueda heredar un template sin tener que cambiar su nombre en la vista? En 2 sencillos pasos

Declarar los templates en el settings:

TEMPLATE_DIRS = (
    os.path.join(PROJECT_HOME, 'templates/uk'),
    os.path.join(PROJECT_HOME, 'templates/es'),
    os.path.join(PROJECT_HOME, 'templates'),
)

Realmente solo tengo 2 directorios de templates. En templates/es están todos los templates completos, y en templates/uk están los pocos con modificaciones. Y el templates/ realmente no tiene nada (es el directorio padre)

Cuando quiero sobreescribir un template en UK  simplemente lo llamo igual que el español (por ejemplo templates/uk/libros/show.html) y su primera línea dice:

{% extends "es/libros/show.html" %}

De esta forma busca entre todo los templates declarados y lo encontrará en la tercera línea del TEMPLATE_DIRS. Es la única forma de poder heredar un template de /es sin tener que reescribirlo completamente.

4.- ETL

El proceso de carga de ficheros los he creado siguiendo una lógica de ETL (extract, transform y load). En cada país tendré una fuente de datos diferente por lo que la parte Extract será nueva en cada caso. La parte transform es la que normaliza los datos, y finalmente el load es común para todo el proyecto, ya que con los datos normalizados la carga es igual.

5.- Traducir todos los textos

Boolino ya es un proyecto bastante grande en templates y código. Para identificar todos los literales que no estaban traducidos he utilizado django-lint, y ha funcionado muy bien.

Por otro lado, hay algún texto en javascript que también ha de ser traducido. Existen varias formas de hacerlo, yo me he inclinado a hacer una vista django que renderiza un template que en realidad son variables .js.

{% load i18n %}
var ver_todos = "{% trans 'Ver todos' %}";
var ver_todas = "{% trans 'Ver todas' %}";
var ocultar = "{% trans 'Ocultar' %}";
var publicidad = "{% trans 'Publicidad' %}";

Y en el html simplemente llamo a la vista como si fuera un js más:

<script src="{% url 'i18n.js' %}" type="text/javascript"></script>

6.- Migración del .com al .es

Hasta hace nada boolino España era .com, Debido al caracter internacional del proyecto ahora Boolino España está en .es y el .com lo reservaremos para los USA. El cambio en este caso es trivial, 2 líneas en el nginx para forzar un 301 a todo el tráfico .com, sin embargo es un momento crítico para no perder todo el SEO conseguido, incoming links y el PageRank del antiguo .com. Lo recomendado es informar a google del cambio de domio a través del web master tools. Esperemos que funcione…

7. Relanzamiento del .com (USA) y conservación de los antiguos incoming links

Próximamente lanzaremos la web en los USA, el momento más delicado para el SEO de .es. Hasta ese momento google simplemente verá un 301 en todos nuestros antiguos incoming links y (en teoría) no afectará al SEO. Sin embargo con el nuevo .com he de quitar esta regla del nginx y google se podría hacer un lío patatero, ya que todas las urls del .com serán diferentes al .es

Para intentar solucionarlo he creado un middleware para reconocer las urls españolas y redirigir el tráfico al .es si se da el caso. De esta forma si al .com llega una petición con una url en formato española, el .com no resolvería el pattern matching y en vez de lanzar el 404 lanzaría un 301 hacia el dominio .es conservando todo el path. En teoría eso funcionará, veremos si a google le gusta. Os dejo el código del middleware

class OldDotComRedirectMiddleware(object):

    def process_response(self, request, response):
        if response.status_code != 404:
            return response # No need to check for a redirect for non-404 responses.

        try:
            current_url = request.resolver_match.url_name
        except Exception, ex:
            return http.HttpResponsePermanentRedirect('%s%s' % (settings.BOOLINO_URL_ES, request.get_full_path()))

        return response

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *