Inici de sessió d'usuari


Capítol 19: Internacionalització i localització


Django té suport complert per la internacionalització del text en el codi i en les plantilles. Aquí expliquem com funciona.

Introducció

L'objectiu de la internacionalització és permetre a una única aplicació web oferir els seus continguts i funcionalitats en múltiples idiomes.

El desenvolupador Django, pot aconseguir aquest objectiu afegint una mínima quantitat de ganxos en el codi i plantilles Python. Aquests ganxos s'anomenen cadenes de text de traducció. Aquestes li diuen a Django: "Aquest text s'ha de traduir en l'idioma de l'usuari, si existeix una traducció d'aquest text en aquell idioma".

Django s'ocupa d'utilitzar aquests ganxos per traduir les aplicacions web, mentre funciona, d'acord amb les preferències de l'idioma de l'usuari.

Essencialment, Django fa dues coses:

  • Permet als desenvolupadors i autors de plantilles especificar quines parts de les seves aplicacions poden ser traduïbles.
  • Utilitza aquests ganxos per traduir aplicacions web per usuaris particulars d'acord amb les seves preferències d'idioma.

Com internacionalitzar la teva aplicació: en tres passes

  1. Cadenes de text de traducció introduïdes en el teu codi Python i en les plantilles.
  2. Obtenir les traduccions per aquestes cadenes, en qualsevol dels idiomes que vulguis donar suport.
  3. Activar l'intermediari "locale" en la configuració de Django.

Darrera de l'escenari
La maquinaria de traducció de Django utilitza el mòdul estàndard gettext que vé amb Python.

Si no necessites la internacionalització

Els ganxos per la internacionalització a Django hi són per defecte, i això vol dir que hi ha una mica de codi i18n en cert llocs de la framework. Si utilitzes la internacionalització, hauràs de fixar-te dos segons per activar el paràmetre USE_I18N = False del teu fitxer de configuració. Si USE_I18N = False, llavors Django fan alguna optimització al no carregar la maquinària de la internacionalització.

Probablement també podràs eliminar el 'django.core.context_processors.i18n' del paràmetre TEMPLATE_CONTEXT_PROCESSORS.

Com especificar les cadenes de traducció

Les cadenes de traducció especifiquen "Aquest text ha de traduir-se". Aquestes cadenes poden aparèixer en el teu codi Python i en les plantilles. És responsabilitat teva marcar les cadenes traduïbles; el sistema només pot traduir les cadenes que coneix.

En el codi Python

Traducció estàndard

Especifica una cadena de traducció utilitzant la funció _(). (Sí, el nom de la funció és un caràcter de guió baix). Aquesta funció està disponible globalment en qualsevol mòdul Python; no l'has d'importar. És una característica de Python.

En aquest exemple, el text "Welcome to my site." està marcat com una cadena de traducció:

def my_view(request):
    output = _("Welcome to my site.")
    return HttpResponse(output)

La funció django.utils.translation.gettext() és idèntica a _(). Aquest exemple és idèntic a l'anterior:

from django.utils.translation import gettext
def my_view(request):
    output = gettext("Welcome to my site.")
    return HttpResponse(output)

La traducció funciona sobre valors computats. Aquest exemple és idèntic als dos anteriors:

def my_view(request):
    words = ['Welcome', 'to', 'my', 'site.']
    output = _(' '.join(words))
    return HttpResponse(output)

La traducció funciona sobre variables. Així, aquí hi ha un exemple idèntic:

def my_view(request):
    sentence = 'Welcome to my site.'
    output = _(sentence)
    return HttpResponse(output)

(L'advertència d'usar variables o valors calculats, com en els dos exemples previs, és que l'utilitat de detecció de cadenes a traduir, make-messages.py, no pot trobar aquestes cadenes. Després en parlarem més sobre make-messages.

Les cadenes que passes a _() o gettext() pot tenir buits, especificats en la sintaxi de cadenes amb noms de Python. Per exemple:

def my_view(request, n):
    output = _('%(name)s is my name.') % {'name': n}
    return HttpResponse(output)

Aquesta tècnica permet a les traduccions específiques reordenar el lloc on situar el text. Per exemple, una traducció en anglès podria ser "Adrian is my name", mentre que una traducció al Català seria "Em dic Adrian" -- amb el nom situat després del text en comptes del principi.

Per aquesta raó, hauries d'usar la interpolació de cadenes amb noms (p.e. %(name)s) en comptes de la interpolació posicional (p.e. %s o %d). Si utilitzes interpolació posicional, les traduccions no podran canviar l'ordre dels forats del text.

Marcant cadenes com a no-op

Utilitza la funció django.utils.translation.gettext_noop() per marcar una cadena com una traducció sense traduir-la. La cadena es traduirà després des d'una variable.

Utilitza això si tens cadenes constants que poden guardar-se en l'idioma original perquè seran canviats obre sistemes o usuaris -- com cadenes en una base de dades -- però seran traduïdes tant tard com sigui possible, com quan la cadena es presentada a l'usuari.

Traducció mandrosa

Utilitza la funció django.utils.translation.gettext_lazy() per traduir les cadenes de forma mandrosa -- quan s'accedeix a la variable en compte de quan la funció es crida a la funció gettext_lazy().

Per exemple, per traduir un help_text del model, fent el següent:

from django.utils.translation import gettext_lazy

class MyThing(models.Model):
    name = models.CharField(help_text=gettext_lazy('This is the help text'))

En aquest exemple, gettext_lazy() guarda referències a les cades -- no a la traducció actual. La pròpia traducció es farà quan la cadena s'utilitzi en el context, com en la impressió de la plantilla o en el lloc d'administració de Django.

Si no t'agrada utilitzar el nom de gettext_lazy, pots crear-ne una àlies a un guió baix, així:

from django.utils.translation import gettext_lazy as _

class MyThing(models.Model):
    name = models.CharField(help_text=_('This is the help text'))

Sempre que utilitzis traduccions mandroses en els models Django. I és una bona idea afegir traduccions per als noms dels camps i els noms de les taules, també. Això significa que s'escriuran opcions verbose_name i verbose_name_plural de forma explícita en la classe Meta:

from django.utils.translation import gettext_lazy as _

class MyThing(models.Model):
    name = models.CharField(_('name'), help_text=_('This is the help text'))
    class Meta:
        verbose_name = _('my thing')
        verbose_name_plural = _('mythings')

Pluralització

Utilitza la funció django.utils.translation.ngettext() per especificar els missatges plurals. Exemple:

from django.utils.translation import ngettext
def hello_world(request, count):
    page = ngettext('there is %(count)d object', 'there are %(count)d objects', count) % {
        'count': count,
    }
    return HttpResponse(page)

ngettext agafa tres arguments: la cadena a traduir en singular, la cadena a traduir en plural i el número d'objectes (que que serà passada als idiomes a traduir com una variable count).

En el codi de la plantilla

Utilitzar les traduccions en les plantilles Django utilitza duees etiquetes de plantilla i una sintaxi lleugerament diferent que en el codi Python. Per tenir accés a aquestes etiquetes, posa {% load i18n %} a dalt de tot de la teva plantilla.

L'etiqueta de plantilla {% trans %} tradueix una cadena constant o un contingut d'una variable:

<title>{% trans "This is the title." %}</title>

Si només vols marcar un valor per a la traducció, però traduir-la després des d'una variable, utilitza l'opció noop:

<title>{% trans "value" noop %}</title>

No és possible utilitzar variable de plantilla a {% trans %} -- només es permeten cadenes constants, amb cometes simples o dobles. Si les teves traduccions necessiten variables, utilitza l'etiqueta {% blocktrans %}. Per exemple:

{% blocktrans %}This will have {{ value }} inside.{% endblocktrans %}

Per traduir una expressió de plantilla -- diguem, utilitzant filtres de plantilles -- cal que enllacis l'expressió a la variable local per utilitzar-la dins el bloc de la traducció:

{% blocktrans with value|filter as myvar %}
This will have {{ myvar }} inside.
{% endblocktrans %}

Si necessites enllaçar més d'una expressió en una etiqueta blocktrans, separa les peces amb un and:

{% blocktrans with book|title as book_t and author|title as author_t %}
This is {{ book_t }} by {{ author_t }}
{% endblocktrans %}

Per pluralitzar, especifica tant la forma singular com la plural amb l'etiqueta {% plural %}, que apareix entre {% blocktrans %} i {% endblocktrans %}. Exemple:

{% blocktrans count list|count as counter %}
There is only one {{ name }} object.
{% plural %}
There are {{ counter }} {{ name }} objects.
{% endblocktrans %}

Internament, tots els blocs en les traduccions utilitzen les crides apropiades gettext / ngettext.

Cada RequestContext té accés a dos variables específiques de la traducció:

  • LANGUAGE és un llistat de tuples en que el primer element és el codi de l'idioma i el segon és el nom de l'idioma (en aquest idioma).
  • LANGUAGE_CODE és l'actual idioma preferit de l'usuari, com una cadena de text. Per exemple: en-us. (Mira "Com es troba l'idioma preferit", més endavant).
  • LANGUAGE_BIDI és la direcció de l'idioma actual. Si és cert, l'idioma és de dreta a esquerra, p.e.: Hebreu, aràbic. Si és fals, és un idioma d'esquerra a dreta, p.e: Anglès, Català, Alemany.

Si no uses l'extensió RequestContext, pots obtenir aquests valors amb aquestes tres etiquetes:

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

Les etiquetes també necessiten un {% load i18n %}.

Els ganxos de traducció també estan disponibles dins de qualsevol etiqueta de bloc de plantilla que accepta les cadenes constants. En aquells casos, només cal que utilitzis la sintaxi _() per especificar a la cadena de traducció. Per exemple:

{% some_special_tag _("Page not found") value|yesno:_("yes,no") %}

En aquest cas, tant l'etiqueta com el filtre utilitzaran la cadena traduïda, així no cal que et preocupis de les traduccions.

Com crear fitxers d'idiomes

Un cop has etiquetat les teves cadenes per traduir-les, cal escriure (o obtenir) les pròpies traduccions de l'idioma. Aquí s'explica com funciona:

Fitxers de Missatges

El primer pas és crear un fitxer de missatges per a un nou idioma. Un fitxer de missatges és un fitxer de text pla, que representa un únic idioma, que conté totes les cadenes disponibles per traduir-se i com han de representar-se en un idioma en concret. Els fitxers de missatges tenen l'extensió del fitxer .po.

Django duu una eina, bin/make-messages.py, que automàticament crea un manteniment d'aquests fitxers.

Crear i modificar un fitxer de missatges, executa aquesta comanda:

bin/make-messages.py -l de

... on de és el codi de l'idioma per al fitxer de missatges que vols crear. El codi de l'idioma, en aquest cas, està en format "locale". Per exemple, aquest pt_BR és per al braziler i de_AT per a l'alemany austríac.

L'escript hauria d'executar-se des d'un d'aquests tres llocs:

  • El directori arrel de django (no del directori del subversion)
  • El directori arrel del teu projecte Django.
  • El directori arrel de la teva aplicació Django.

L'escript s'executa sobre l'arbre complert de Django i extreu totes les cadenes marcades per a la traducció. Crea (o actualitza) un fitxer de missatges en el directori conf/locale. En l'exemple de de, el fitxer serà conf/locale/de/LC_MESSAGES/django.po.

Si l'executem sobre l'arbre del teu projecte o de la teva aplicació, farà el mateix, però el lloc del directori "locale" serà locale/LANG/LC_MESSAGES (fixa't que es perd el prefix conf).

No gettext?
Si no tens l'util·litat gettext instal·lada, make-messages.py crearà fitxers buits.

El format dels fitxers .po és directe. Cada fitxer .po conté un mica de metadades, com la informació de contacte de qui manté la traducció. Però nucli d'aquest fitxer és el llistat de missatges -- simplement assigna les cadenes de traducció amb els textos traduïts per a aquest idioma en particular.

Per exemple, si la teva aplicació Django conté una cadena de traducció per al text "Welcome to my site", com aquest:

_("Welcome to my site.")

... llavors make-messages.py haurà creat un fitxer .po que contindrà el següent tros -- un missatge:

#: path/to/python/module.py:23
msgid "Welcome to my site."
msgstr ""

Cal una petita explicació:

  • msgid és la cadena a traduir, que apareix en el codi font. No el canviïs.
  • msgstr és on posaràs la teva traducció. Aquesta comença amb una cadena buida, així que és responsabilitat teva canviar-ho. Assegura't de mantenir les comentes en la teva traducció.
  • Com a conveniència, cada missatge inclou el fitxer i el número de línia d'on l'ha extret la cadena de text a traduir.

Els missatges llargs són un cas especial. Aquí, la primera cadena després de msgstr (o msgid) és una cadena buida. Llavors el propi contingut serà escrit sobre les pròximes línies amb una cadena per línia. Aquestes cadenes de text són directament concatenades. No t'oblidis dels espais dins de les cadenes; sinó, seran situades juntes sense espais!

Pensa en el joc de caràcters
Quan creis un fitxer .po amb el teu editor de text preferit, primer modifica la línia del joc de caràcters (busca per "CHARSET") i indica el joc de caràcters que usaràs a l'editar el contingut. Generalment, utf-8 funciona per la majoria dels idiomes, però gettext podrà agafar qualsevol joc de caràcters que li indiquis.

Per re-examinar tot el codi font i les plantilles per a noves cadenes per traduir i modificar totes els fitxers de missatges per a tots els idiomes, executa això:

make-messages.py -a

Compilant fitxers de missatges

Després que creis els teus fitxer de missatges -- i cada cop que en facis canvis -- caldrà que compilis per fer-ho més eficient, a l'usar-lo amb gettext. Fes això amb l'utilitat bin/compile-messages.py.

Aquesta eina s'executa sobre tots els fitxers .po disponibles i crea fitxers .mo, que són fitxers binaris optimitzats per usar amb gettext. En el mateix directori des del que has executat make-messages.py, executa tt>compile-messages.py així:

bin/compile-messages.py

Això és tot. Les teves traduccions ja estan a punt.

Com descobreix Django les preferències d'idioma

Un cop has preparat les teves traduccions -- o, si només vols utilitzar les traduccions que venen amb Django -- només et cat activar la traducció de les teves aplicacions.

Darrera de l'escenari, Django té un model moilt flexible de decisió de quin idioma ha d'usar-se -- per la banda de la instal·lació, per un usuari en particular, o ambdues.

Per activar una preferència d'idioma per a la instal·lació, activa el paràmetre de configuració LANGUAGE_CODE. Django utilitza aquest idioma com la traducció per defecte -- l'últim intent si no es troba cap altre traducció.

Si només vols executar Django amb el teu idioma natura, i el fitxer d'idioma hi és disponible per al teu idioma, tot el que et cal es activar el paràmetre LANGUAGE_CODE.

Si vols permetre que cada usuari especifiqui quin idioma prefereix, utilitza LocaleMiddleware. LocaleMiddleware activa la selecció de l'idioma basat amb les dades de la petició. Aquest contingut personalitzar per a cada usuari.

Per usar LocaleMiddleware, afegeix 'django.middleware.local.LocaleMiddleware' al paràmetre de configuració MIDDLEWARE_CLASSE. Com que l'ordre dels intermediaris és important, hauries de seguir aquestes regles:

  • Assegura't que és un dels primers intermediaris instal·lats.
  • Hauria d'anar després de SessionMiddleware, perquè LocaleMiddleware utilitza les dades de la sessió.
  • Si utilitzes CacheMiddleware, posa'l després d'aquest.

Per exemple, el teu MIDDLEWARE_CLASSES serà quelcom així:

MIDDLEWARE_CLASSES = (
   'django.contrib.sessions.middleware.SessionMiddleware',
   'django.middleware.locale.LocaleMiddleware',
   'django.middleware.common.CommonMiddleware',
)

LocaleMiddleware intenta determinar l'idioma preferit de l'usuari seguint el següent algorisme:

  • Primer, busca la clau django_language en la sessió de l'usuari actual.
  • Si falla això, mirar la galeta anomenada django_language.
  • Si falla d'això, mirar la capçalera Accept-Language. Aquesta capçalera l'envia el teu navegador i indica quines idiomes prefereix, en ordre de prioritat. Django prova cada idioma de la capçalera fins que en troba un en les traduccions disponibles.
  • Si falla això, utilitza el paràmetre de configuració LANGUAGE_CODE.

Notes:

  • En cada un d'aquests punts, les preferències de l'idioma s'esperen en el format de l'idioma estàndard, com una cadena. Per exemple, Brasiler és pt-br.
  • Si un idioma base hi és disponible però el sub-idioma especificat no, Django utilitza l'idioma base. Per exemple, si un usuari especifica de-at (Alemany Austríac) però django només té disponible el de, Django utilitzarà de.
  • Només els idiomes llistats a LANGUAGES poden seleccionar-se. Si vols restringir la selecció d'idiomes a un conjunt de idiomes proporcionats (perquè la teva aplicació no proporciona tots els altres idiomes), activa LANGUAGES a una llista d'idiomes. Per exemple:
    LANGUAGES = (
      ('de', _('German')),
      ('en', _('English')),
    )
    

    Aquest exemple restringeix als idiomes que estan disponibles de la selecció automàtica a Alemany i Anglès (i qualsevol subidioma, com de-ch o en-us).

  • Si defineixes una paràmetre LANGUAGES personalitzat, com s'ha explica en el punt anterior, és correcte marcar els idiomes com cadenes de traducció -- però una funció "tonta" gettext(), no la de django.utils.tranlation. Mai podries importar django.utils.translation des de dins del teu fitxer de configuració, perquè el propi mòdul depèn de la configuració, i això causaria una importació cíclica.

    La solució és usar la funció "tonta" gettext(). Aquí hi ha un exemple de fitxer de configuració:

    gettext = lambda s: s
    
    LANGUAGES = (
        ('de', gettext('German')),
        ('en', gettext('English')),
    )
    

    Amb aquest arranjament, make-messages.py trobarà i marcarà aquestes cadenes per a la traducció, però la traducció no es realitzarà durant l'execució -- així que hauràs de recordar-te d'embolcallar els idiomes amb el gettext() real en qualsevol codi que utilitzi LANGUAGES durant l'execució.

  • El paràmetre LocaleMiddleware només pot seleccionar idiomes per als que hi ha una traducció base de Django. Si vols proporcionar traducció per la teva aplicació que no existeixen en el conjunt de traduccions de Django, voldràs proporcionar-nos les traduccions bàsiques per a aquest idioma. Per exemple, Django utilitzar IDs de missatges tècnics per traduir formats de dades i formats de temps -- així necessitaràs com mínim aquestes traduccions per a que el sistema treballi correctament.

    Un bon punt d'inici és copiar el fitxer .po anglès i traduir com a mínim els missatges tècnics -- potser també els missatges de validació.

    Els IDs dels missatges tècnics són fàcilment identificables; tots estan en majúscules. No tradueixis el missatge ID com a amb altres missatges, proporciona la variant local correcta d'un valor proporcionat en anglès. Per exemple, amb el DATETIME_FORMAT (o DATE_FORMAT o TIME_FORMAT), aquest hauria de ser la cadena de format que vols utilitzar en el teu idioma. El format és idèntic que la cadena de format usada en l'etiqueta now de la plantilla.

Un cop LocaleMiddleware determinar les preferències de l'usuari, aquest fa que aquesta preferència estigui disponible a request.LANGUAGE_CODE per a cada objecte request. Sigues lliure de llegir aquest valor en el teu codi de la vista. Aquí hi ha un exemple simple:

def hello_world(request, count):
    if request.LANGUAGE_CODE == 'de-at':
        return HttpResponse("You prefer to read Austrian German.")
    else:
        return HttpResponse("You prefer to read another language.")

Fixa't que, amb traduccions estàtiques (sense mitjancers), l'idioma és a settings.LANGUAGE_CODE, mentre que en traduccions dinàmiques (amb mitjancers), és a request.LANGUAGE_CODE.

La vista de redirecció set_language

Per una conveniència, Django ve amb una vista, django.views.i18n.set_language, que activar l'idioma preferit de l'usuari i et re-dirigeix a la pàgina anterior.

Activa aquesta vista afegint la següent línia en la teva URLconf:

(r'^i18n/', include('django.conf.urls.i18n')),

(Fixa't que aquest exemple fa que vista estigui disponible a /i18n/setlang/).

Aquesta vista espera que es cridi amb el mètode GET, amb el paràmetre language en una cadena. Si el suport a sessions s'ha activat, la vista guarda d'idioma escollit en la sessió de l'usuari. De totes formes, ho grava a la galeta django_language.

Després d'activar l'opció de l'idioma, Django redirigeix l'usuari, seguint el següent algoritme:

  • Django mira el paràmetre next de la cadena de la consulta.
  • Si no existeix, o és buida, django prova la URL en la capçalera Referer.
  • Si aquesta és buida -- diguem que un usuari ha eliminat aquesta capçalera del navegador -- llavors l'usuari se'l re-dirigirà a / (l'arrel del lloc) com a última opció.

Aquí hi ha un exemple de codi HTML:

<form action="/i18n/setlang/" method="get">
<input name="next" type="hidden" value="/next/page/" />
<select name="language">
{% for lang in LANGUAGES %}
<option value="{{ lang.0 }}">{{ lang.1 }}</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>

Utilitzant traduccions en els teus propis projectes

Django busca les traduccions seguint aquest algorisme:

  • Primer, mira en el directori locale en el directori de l'aplicació de la vista que s'ha cridat. si es troba una traducció per a l'idioma indicat, la traducció es realitzarà.
  • Després, busca en el directori locale en el directori del projecte. Si troba una traducció, s'usarà aquesta.
  • Finalment, comprova la traducció base a django/conf/locale.

D'aquesta forma, pots escriure aplicacions que inclouen les pròpies traduccions, i pots sobre-escriure les traduccions base del teu projecte. O, pots construir un projecte gran per sobre de cada aplicació i posar totes les traducció dins un únic fitxer de missatges del projecte. La decisió és teva.

Nota
Si estàs realitzant manualment la configuració, el directori locale del directori del projecte no s'examinarà, ja que Django perd d'habilitat de treballar fora de la localització del directori del projecte. (Django normalment utilitza la localització del fitxer de configuració per determinar aquesta, i un fitxer de configuració no existeix perquè has realitzat la configuració manualment).

Tots els repositoris dels fitxers de missatges estan estructurats de la mateixa forma. Hi ha:

  • $APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
  • $PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
  • Tots els camins llistats a LOCALE_PATHS del teu fitxer de configuració es busquen en aquest ordre per<language>/LC_MESSAGES/django.(po|mo)
  • $PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)

Per crear fitxers de missatges, utilitza la mateixa eina make-messages.py com amb els fitxers de missatges Django. Només necessiten estar en el lloc correcte -- tant en el directori conf/locale (en cas de l'arbre del codi font) com en el locale/ (en cas dels missatges de les aplicacions o dels projectes). I utilitzaràs el mateix compile-messages.py per produir els fitxers binaris django.mo que s'utilitzen per gettext.

Els fitxers de missatges de l'aplicació són una mica complicats de trobar -- necessiten el paràmetre LocaleMiddleware. Si no utilitzes el mitjancer, només els fitxers de missatges de Django i els fitxers de missatges del projecte es processaran.

Finalment, hauràs de pensar sobre l'estructura dels teus fitxers de traducció. Si les teves aplicacions han de distribuir-se a altres usuaris o han d'usar-se en altres projectes, podries voles usar les traduccions específiques per les aplicacions. Però utilitzant les traduccions específiques per les aplicacions i les traduccions del projecte poden produir problemes amb make-messages: make-messages passa per tots les directoris per sota de path actual i així possat els IDs dels missatges dins del fitxer de missatges del projecte que també contindrà els dels fitxers de missatges de les aplicacions.

La forma més fàcil serà guardar les aplicacions que no formen part del projecte (i així duguin les seves pròpies traduccions) fora de l'arbre del projecte. D'aquesta forma, make-messages a nivell del projecte només traduirà les cadenes que estiguin connectades explícitament en el projecte i no les cadenes que es distribueixen independentment.

Traduccions i JavaScrip

Afegir traduccions a JavaScript implica alguns problemes:

  • El codi JavaScript no té accés a la implementació gettext.
  • El codi JavaScript no té accés als fitxers .po i .mo; cal que les hi doni el servidor.
  • Els catàlegs de traducció per a JavaScript s'han de mantenir el més petits possible.

Django proporciona una solució integrada per aquests problemes: Aquesta és passar les traduccions dins del JavaScript, així pots cridar a gettext, etc, des de dins de JavaScript.

La vista javascript_catalog

La solució principal a aquests problemes és la vista javascript_catalog, que envia una llibreria de codi JavaScript amb funcions que imiten la interfície de gettext, més una matriu de cadenes de traducció. Aquestes cadenes de traducció s'agafen de l'aplicació, el projecte o del cor de Django, d'acord amb el que especifiquis a {{{info_dict}}} o la URL.

Mira com queda:

js_info_dict = {
    'packages': ('your.app.package',),
}

urlpatterns = patterns('',
    (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
)

Cada cadena de packages ha d'estar en una sintaxi de paquet de Python (el mateix format que les cadenes de INSTALLED_APPS) i ha de referir-se a un paquet que conté un directori locale. Si especifiques múltiples paquets, tots aquests catàlegs s'afegiran dins un catàleg. Això és útil si tens JavaScript que utilitza cadenen des de diferents aplicacions.

Pots fer una vista dinàmica per posar els paquets dins un patró URL:

urlpatterns = patterns('',
    (r'^jsi18n/(?P<packages>\S+?)/$, 'django.views.i18n.javascript_catalog'),
)

Amb això, especifica el paquet com una llista de noms de paquets delimitats per el signe '+' en la URL. Això és especialment útil si els teus paquets utilitzen codi des de diferents aplicacions i aquests canvien sovint i no vols posar-los en un únic fitxer de catàleg gran. Com a mesura de seguretat, aquests valors només poden ser o a django.conf o en qualsevol paquet dels indicats en el paràmetre INSTALLED_APPS.

Utilitzant el catàleg de traducció de JavaScript

Usar el catàleg, només posa'ls en l'escript generat dinàmicament així:

<script type="text/javascript" src="/path/to/jsi18n/"></script>

Així és com l'administrador enganxa el catàleg de traducció des del servidor. Quan el catàleg es carrega, el teu codi JavaScript pot usar la interfície gettext estàndard per accedir-hi:

document.write(gettext('this is to be translated'));

Fins i tot hi ha la interfície ngettext i una funció d'interpolació de cadenes:

d = {
    count: 10
};
s = interpolate(ngettext('this is %(count)s object', 'this are %(count)s objects', d.count), d);

La funció interpolate permet la interpolació posicional i la interpolació amb nom. Així el codi anterior podria escriure's així:

s = interpolate(ngettext('this is %s object', 'this are %s objects', 11), [11]);

La sintaxi d'interpolació s'ha manllevat de Python. No has de preocupar-te amb la interpolació de cadenes, pensa però: que això del JavaScript és immòbil, així que el codi haurà de repetir les substitucions cada cop. Això no és tant ràpid com ho fa Python, així que evita aquesta casos on realment els necessitis (per exemple, dins una conjunció amb ngettext per produir pluralitzacions).

Creant catàlegs de traducció per JavaScript

Crear i actualitzar els catàlegs de traducció es fa de la mateixa manera que amb la traducció de catàlegs de traducció de Django -- amb l'eina {{{make-messages.py}}}. L'única diferència és que has d'indicar el paràmetre -d djangojs, així:

make-messages.py -d djangojs -l de

Això et crearà o actualitzarà el catàleg de traduccions per al JavaScript en Alemany. Després d'actualitzar els catàlegs de traduccions, només has d'executar compile-messages.py de la mateixa manera que ho fas amb els catàlegs normals de traducció de Django.

Notes per usuaris familiaritzats amb gettext

Si coneixes gettext, notaràs aquestes especialitzats de com Django fa la traducció:

  • La cadena de domini és django o djangojs. La cadena de domini s'utilitza per diferenciar entre els diferents programes que guarden les seves dades en una llibreria de fitxers de missatges comuna (normalment /usr/share/locale/). El domini django s'utilitza per python, per les cadenes de traducció de plantilles i es carrega dins dels catàlegs de traducció globals. El domini djangojs només s'usa en els catàlegs de traducció JavaScript per assegurar-se que aquestes siguin el més petites possible.
  • Django només utilitza gettext i gettext_noop. Això és així perquè sempre utilitzen el joc de caràcters DEFAULT_CHARSET internament. No fem massa ús de ugettext, perquè sempre necessitaràs proporcionar utf-8.
  • Django no utilitza xgettext enlloc. Aquest utilitza embolcalls de Python. Això és fa per conveniència.