Quem sou eu

Minha foto

Formado em Computação, desenvolvedor web, interessado em tecnologia, metaleiro e um gamer inveterado.

Pesquisar

quinta-feira, 15 de janeiro de 2015

Tradução de maneira descomplicada com o Model Translation


Todo mundo já deve ter passado por um projeto multi-idioma. Se ainda não, recomendo mesmo assim a leitura deste post. Por participar de algo assim, pude aprender mais algumas coisas interessantes.

Aqui seguem alguns passos que podem auxiliar e muito a confecção de um projeto multi-idioma

1. Primeiro de tudo, defina quais idiomas o projeto terá. 

Isso se faz com algumas configurações no settings.py:

LANGUAGE_CODE = 'pt-br'
TIME_ZONE = 'America/Sao_Paulo'
USE_I18N = True
USE_L10N = True
ugettext = lambda s: s
LANGUAGES = (
    ('pt-BR', ugettext(u'Português')),
    ('en-US', ugettext(u'Inglês')),
    ('es-ES', ugettext(u'Espanhol')),
)
USE_TZ = False
LOCALE_PATHS = (
   os.path.join( PROJECT_PATH, '../locale' ),
)
  • LANGUAGE_CODE: Aqui é definido a linguagem inicial do projeto. Valor padrão: 'en-us'. Veja a lista de outras línguas aqui: http://www.i18nguy.com/unicode/language-identifiers.html
  • TIME_ZONE: Define o fuso horário do projeto. Valor padrão: 'America/Chicago' 
  • USE_I18N: Flag que determina se o sistema de tradução do Django deve ser habilitado ou não. Deve ser True para multi-idiomas e False, por questões de otimização, quando tiver apenas um idioma. Valor padrão: False 
  • USE_L10N: Um booleano que especifica se a formatação localizada de dados será ativado por padrão ou não. Se esta é definida como True , por exemplo Django irá exibir números e datas usando o formato da localidade atual. Valor padrão: True 
  • LANGUAGES: Tupla com as linguagens que serão utilizadas no site. 
  • USE_TZ: Determina se o django usará o datetime com base no fuso ou não.Valor padrão: False 
  • LOCALE_PATH: Tupla com os diretórios onde serão gerados os arquivos para tradução.

2. Instale o django-modeltranslation

$ pip install django-modeltranslation

No settings, certifique-se que o modeltranslation está acima do admin do Django, pra não ter problemas, coloque ele como a primeira linha do INSTALLED_APPS:
INSTALLED_APPS = (
    # TRANSLATION
    'modeltranslation',
    ...
)

Cerfitique-se que o Locale Middleware está instalado:
MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

E inclua a url de tradução no urls.py:
...
(r'^i18n/', include('django.conf.urls.i18n')),
...

Na aplicação que terá conteúdos dinâmicos para cada idioma deixe os arquivos como abaixo:

models.py
# coding: utf-8
from django.db import models

# Create your models here.

class Conteudo(models.Model):
	"""(Conteudo description)"""
	titulo = models.CharField(u'Título', max_length=255)
	texto = models.TextField()
	slug = models.SlugField(verbose_name=u'Slug / URL')

	class Meta:
		verbose_name, verbose_name_plural = u"Conteúdo" , u"Conteúdos"
		ordering = ('titulo',)

	def __unicode__(self):
		return u"%s" % self.titulo

admin.py
# Register your models here.

from django.contrib import admin
from .models import *
from modeltranslation.admin import TranslationAdmin

class ConteudoAdmin(TranslationAdmin):
	search_fields = ('titulo', 'texto',)
	list_display = ('titulo', 'texto')
	prepopulated_fields = {"slug": ("titulo",)}
	save_on_top = True

admin.site.register(Conteudo, ConteudoAdmin)

translation.py
# translation.py

from modeltranslation.translator import translator, TranslationOptions
from .models import *

class ConteudoOptions(TranslationOptions):
    fields = ('titulo', 'texto',)
translator.register(Conteudo, ConteudoOptions)


Quando usar a migração (South para Django<1.7, ou nativo para Django>=1.7), serão gerados no banco os campos definidos no translation.py para cada idioma, isto é, o resultado será uma tabela com:
  • titulo_pt_br
  • texto_pt_br
  • titulo_en_us
  • texto_en_us
  • titulo_es_es
  • texto_es_es
  • slug

E o admin já trará todos eles com uma marcação de idioma através de [<idioma>] nas labels de cada campo.


Observação Importante: 

Caso não haja necessidade de traduzir a url que ficará no navegador, não inclua o slug no translation.py (recomendo que não inclua! Insista, convença seu chefe!). Isso facilita e muito quando o usuario troca de idioma para redirecioná-lo para a mesma página ao invés de mandá-lo de volta pra home do site e/ou fazer qualquer gambiarra para redirecioná-lo corretamente.

3. Nos templates, fica muito simples:

{{ obj.titulo }}

Aqui o próprio Model Translation irá verificar qual o é o idioma atual e exibir o valor correto. Sem IFs e sem duplicação de templates.

4. Para conteúdos estáticos, o processo continua o mesmo com a geração dos .po

Carrege o módulo i18n nos templates que for traduzir:
{% load i18n %}

Marque nos templates estáticos onde sofrerá tradução com as tags trans e blocktrans
{% trans "Exemplo de texto a ser traduzido nos seus htmls" %}

Execute o comando makemessages para gerar as mensagens:
$ python manage.py makemessages --locale=en --ignore=templates/admin --ignore=project/settings.py

Serão gerados arquivos .po para tradução no LOCALE_PATH definido nas settings com a seguinte estrutura:
  • locale
    • en
      • LC_MESSAGES
        • django.po
    • es
      • LC_MESSAGES
        • django.po


Nestes arquivos, serão armazenados os termos a serem traduzidos para envio para a pessoa responsável para tradução, e eles se parecem com isso:
#: templates/atendimento/atendimento.html:21
#: templates/atendimento/sucesso.html:21 templates/curriculos/sucesso.html:21
#: templates/curriculos/trabalhe-conosco.html:25
msgid "Dados enviados com sucesso"
msgstr ""

No exemplo acima, as linhas iniciadas com # indicam o caminho dos arquivos em tem o termo contido no msgid em comum, e no msgstr é onde deve ser preenchido com a tradução para o idioma correspondente.

Caso a pessoa responsável pela tradução não conseguir/quiser editar direto os .po, existem alguns apps que podem ser utilizados para facilitar esse processo, como o Rosetta (mais informações em: https://github.com/mbi/django-rosetta) por exemplo. Este cria uma interface com base no bom e velho admin provido pelo Django.

Depois de tudo preenchido, basta compilar as mensagens com o comando compilemessages:
$ python manage.py compilemessages --locale=en
$ python manage.py compilemessages --locale=es


5. Para trocar de idioma no site, basta um form:


{% get_available_languages as LANGUAGES %}
{% get_current_language as LANGUAGE_CODE %}

<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language">
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
    {{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>


Em {{ redirect_to }}, se o slug não tiver sido traduzido e cada conteúdo tiver uma única url, aqui vc pode por a url atual, {{ request.META.PATH_INFO }},  e quando o usuário trocar de idioma, já vai ser redirecionado para a mesma página que estava visualizando.



Referências:


hasta!