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!

terça-feira, 16 de dezembro de 2014

Erros para instalar dependências do virtualenv no Mac OSX Lion

Tentando instalar as dependências do ambiente virutal para trabalhar com Django no OSX Lion me deparei com os seguinte erros:

error command 'llvm-gcc-4.2' failed with exit status 1
mysql_config not found

Além do claro, clássico trabalho para instalar a PIL com suporte a JPEG.

Resolvi as coisas com o a mesma solução: BREW (http://brew.sh/)

Depois de instalar o brew, desinstale PIL e Pillow, caso estejam instaladas  execute os comandos:

brew install libjpeg
brew install mysql
pip install PIL
pip install Pillow


hasta!

segunda-feira, 15 de dezembro de 2014

Apps não aparecem no administrativo mesmo como superuser autenticado

Criou os apps e tem certeza que as classes no admin.py estão corretas?

Caso tenha, e/ou esteja fazendo um downgrade do django 1.7 pro 1.6, e estava funcionando antes, certifique-se que colocou a linha abaixo no urls.py antes do urlpatterns:


...
admin.autodiscover()
...


hasta!