Django-fr | Documentation | Internationalisation

Django-fr

Documentation Django

Internationalisation

Django supporte pleinement l'internationalisation des textes aussi bien dans le code que dans les templates. Voici comment cela fonctionne :

Aperçu

Le but de l'internationalisation d'une application est de permettre à une application web de proposer son contenu et ses fonctionnalités dans de multiples langages.

En tant que développeur Django vous pouvez atteindre ce but en ajoutant quelques appels de fonctions à votre code Python et à vos templates. Ces appels de fonctions sont appelés "texte à traduire" (translation strings). Elles indiquent à Django : "Ce texte devrait être traduit dans la langue de l'utilisateur, si une traduction pour ce texte est disponible dans cette langue".

Django se charge d'utiliser ces appels pour traduire à la volée les applications selon les préférences de l'utilisateur.

Essentiellement Django fait 2 choses :

  • Il laisse aux développeurs et aux auteurs de templates le soin d'indiquer quelles parties de leurs applications devraient être traduites.
  • Il utilise les appels "texte à traduire" pour traduire les applications web pour les utilisateurs selon leurs préférences de langue.

Comment internationaliser votre application en 3 étapes :

  1. Inclure des appels "texte à traduire" dans votre code Python et vos templates.
  2. Obtenir les traductions pour ces textes, dans toutes les langues que vous souhaitez supporter.
  3. Activer le middleware locale dans votre fichier paramètre Django.

Derrière les fourneaux

La machinerie Django de traduction utilise le module standard gettext qui est livré avec Python.

Si vous n'avez pas besoin de l'internationalisation

Les fonctions d'internationalisation de Django sont activées par défaut, cela signifie une surcharge dans certaines parties du framework. Si vous n'utilisez pas l'internationalisation, vous devriez prendre 2 secondes pour mettre USE_I18N = False dans votre fichier paramètre. Si USE_I18N est positionné à False, Django peut alors procéder à quelques optimisations telles que ne pas charger la machinerie relative à l'internationalisation.

Voir la documentation pour USE_I18N.

Comment spécifier les appels "texte à traduire"

Les appels "texte à traduire" signifient "Ce texte devrait être traduit". Ces appels peuvent apparaître dans votre code Python et vos templates. Il est de votre responsabilité de marquer les textes à traduire; le système ne peut traduire que les textes dont il a connaissance.

Dans le code Python

Traduction standard

Indiquez un texte à traduire en utilisant la fonction _(). (Oui, le nom de la fonction est bien le caractère "souligné".) Cette fonction est disponible globalement dans n'importe quel module Python; vous n'avez pas besoin de l'importer.

Dans cet exemple, le texte "Bienvenue sur mon site." est marqué comme un texte à traduire:

def my_view(request):
    output = _("Bienvenue sur mon site.")
    return HttpResponse(output)

La fonction django.utils.translation.gettext() est identique à _(). Cet exemple est identique au précédent:

from django.utils.translation import gettext
def my_view(request):
    output = gettext("Bienvenue sur mon site.")
    return HttpResponse(output)

La traduction fonctionne avec des valeurs calculées. Cet exemple est identique aux 2 précédents:

def my_view(request):
    words = ['Bienvenue', 'sur', 'mon', 'site.']
    output = _(' '.join(words))
    return HttpResponse(output)

La traduction fonctionne avec des variables. À nouveau voilà un exemple identique:

def my_view(request):
    sentence = 'Bienvenue sur mon site.'
    output = _(sentence)
    return HttpResponse(output)

(Le problème d'utiliser des variables ou des valeurs calculées, comme dans les 2 précédents exemples, est que l'utilitaire Django de détection des textes à traduire, make-messages.py, ne sera pas capable de trouver ces textes. Plus sur make-messages plus tard.)

Les textes que vous passez à _() ou à gettext() peuvent contenir des marqueurs de formatage indiqués avec la même syntaxe standard que celle qu'utilise Python pour les marqueurs nommés.

Exemple:

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

Cette technique permet le réordonnancement des marqueurs de formatage dans les traductions. Par exemple, une traduction anglaise pourrait être "Adrian is my name."; tandis qu'une traduction espagnole pourrait être "Me llamo Adrian." -- avec le marqueur de formatage (le nom) placé après le texte traduit au lieu d'avant.

Pour cette raison, vous devriez utiliser de préférence l'interpolation par les noms (e.g., %(name)s) plutôt que l'interpolation par position (e.g., %s ou %d). Si vous utilisez l'interpolation par position, la traduction sera incapable de réordonnancer les marqueurs de formatage.

Marquage de textes sans traduction

Utilisez la fonction django.utils.translation.gettext_noop() pour marquer un texte comme un texte à traduire mais sans le traduire. Le texte est traduit plus tard à partir d'une variable.

Utilisez cette fonctionnalité si vous avez des chaînes constantes qui doivent être stockées dans le langage d'origine car elles sont échangées entre différents systèmes ou utilisateurs -- telles que les chaînes dans une base de données -- mais qui doivent être traduites le plus tard possible, par exemple lorsque la chaîne est présentée à l'utilisateur.

Traduction "paresseuse"

Utilisez la fonction django.utils.translation.gettext_lazy() pour traduire des textes de manière "paresseuse" -- lorsque la valeur est accédée plutôt que lorsque la fonction gettext_lazy() est appelée.

Par exemple, pour traduire le paramètre help_text d'un modèle, faites ceci:

from django.utils.translation import gettext_lazy

class MyThing(models.Model):
   name = models.CharField(help_text=gettext_lazy("Ceci est le texte d'aide"))

Dans cet exemple, gettext_lazy() stocke une référence "paresseuse" -- pas la traduction actuelle. La traduction proprement dite sera effectuée lorsque le texte sera utilisé dans un contexte chaîne de caractères, comme par exemple dans le rendu d'un template de la partie administration de Django.

Si vous n'aimez pas le nom verbeux gettext_lazy, vous pouvez tout simplement créer un alias de nom _, comme ceci:

from django.utils.translation import gettext_lazy as _

class MyThing(models.Model):
    name = models.CharField(help_text=_("Ceci est le texte d'aide"))

Utilisez toujours la traduction "paresseuse" dans les modèles Django. Et c'est une bonne idée d'ajouter la traduction pour les noms de champs et de tables aussi. Ceci signifie de positionner explicitement les options verbose_name et verbose_name_plural dans la classe Meta, comme:

from django.utils.translation import gettext_lazy as _

class MyThing(models.Model):
    name = models.CharField(_('name'), help_text=_("Ceci est le texte d'aide"))
    class Meta:
        verbose_name = _('my thing')
        verbose_name_plural = _('mythings')

Pluriel

Utilisez la fonction django.utils.translation.ngettext() pour indiquer le pluriel des textes. Exemple:

from django.utils.translation import ngettext
def hello_world(request, count):
    page = ngettext("Il y'a %(count)d objet", "Il y'a %(count)d objets", count) % {
        'count': count,
    }
    return HttpResponse(page)

ngettext prend 3 arguments: le texte à traduire au singulier, le texte à traduire au pluriel et le nombre d'objets (lequel est passé aux traductions comme la variable count).

Dans les templates

La traduction dans les templates Django utilise 2 tags avec une syntaxe légèrement différente que celle utilisée dans le code Python. Pour donner à votre template accès à ces tags, indiquez {% load i18n %} vers le début de votre template.

Le tag {% trans %} traduit une chaîne constante ou le contenu d'une variable:

<title>{% trans "Ceci est un titre" %}</title>

Si vous voulez uniquement marquer une valeur à traduire, mais la traduire plus tard à partir d'une variable, utilisez l'option noop:

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

Il n'est pas possible d'utiliser des variables de template dans le tag {% trans %} -- seules les chaînes constantes, entre apostrophes ou guillemets, sont autorisées. Si votre traduction requiert des variables, utilisez le tag {% blocktrans %}. Exemple:

{% blocktrans %}Ceci aura une {{ valeur }} à l'intérieur.{% endblocktrans %}

Pour traduire une expression template -- par exemple qui utilise un filtre de template -- vous devez mettre en correspondance l'expression avec une variable locale pour pouvoir l'utiliser dans le bloc de traduction:

{% blocktrans with value|filter as myvar %}
Ceci aura {{ myvar }} à l'intérieur.
{% endblocktrans %}

Si vous avez besoin de mettre en correspondance plus d'une expression à l'intérieur d'un tag blocktrans, séparez les avec and:

{% blocktrans with book|title as book_t and author|title as author_t %}
Le livre {{ book_t }} de l'auteur {{ author_t }}
{% endblocktrans %}

Pour mettre au pluriel, indiquez le singulier et le pluriel avec le tag {% plural %}, qui apparaît entre {% blocktrans %} et {% endblocktrans %}. Exemple:

{% blocktrans count list|count as counter %}
Il y'a seulement un objet {{ name }}
{% plural %}
Il y'a {{ counter }} objets {{ name }}.
{% endblocktrans %}

Derrière le rideau, toutes les traductions en ligne ou de bloc utilisent le bon appel gettext / ngettext.

Chaque RequestContext a accès à 3 variables spécifiques au mécanisme de traduction:

  • LANGUAGES est une liste de tuples dans lesquels le premier élément est le code du langage et le second le nom du langage (dans cette langue).
  • LANGUAGE_CODE est une chaîne représentant le langage préféré de l'utilisateur courant. Exemple: en-us. (cf "Comment les préférences de langue sont détectées", ci-dessous)
  • LANGUAGE_BIDI est la direction du langage courant. Si True, il s'agit d'un langage qui se lit de droite à gauche, e.g: Hébreu, Arabe. Si False c'est un langage qui se lit de gauche à droite, e.g: Anglais, Français, Allemand etc.

Si vous n'utilisez pas l'extension RequestContext, vous pouvez obtenir ces valeurs avec ces 3 tags:

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

Ces tags ne sont disponibles qu'après avoir appelé {% load i18n %}.

Les appels texte à traduire sont également disponibles à l'intérieur de tous les tags qui acceptent des chaînes constantes. Dans ces cas, utilisez la syntaxe _() pour indiquer un texte à traduire. Exemple:

{% some_special_tag _("Page non trouvée") value|yesno:_("oui,non") %}

Dans cette hypothèse, aussi bien le tag que le filtre recevrons la chaîne après traduction, ils n'auront alors pas à s'en préoccuper.

Comment créer des fichiers de langues

Une fois que vous avez marqué vos textes pour une future traduction, vous devez écrire (ou obtenir) les traductions proprement dites. Voici comment cela fonctionne :

Fichiers messages

La première opération est de créer un fichier message pour un nouveau langage. Un fichier message est un fichier texte, représentant une langue, qui contient toutes les chaînes de traduction disponibles et leur traduction dans cette langue. Les fichiers messages ont une extension en .po.

Django est fourni avec un utilitaire, bin/make-messages.py, qui automatise la création et la mise à jour de ces fichiers.

Pour créer ou mettre à jour un fichier message, lancer cette commande:

bin/make-messages.py -l de

...où de est le code du langage pour le fichier message que vous voulez créer. Le code du langage, dans ce cas, est dans le format locale. Par exemple, il s'agit de pt_BR pour le brésilien et de_AT pour l'allemand autrichien.

La commande devrait être lancée à partir d'un de ces 3 endroits:

  • Le répertoire racine django (pas un répertoire d'extraction Subversion, mais celui qui est indiqué dans la variable d'environnement $PYTHONPATH ou est situé quelque part dans ce chemin.
  • Le répertoire racine de votre projet Django.
  • Le répertoire racine de votre application Django.

Le script parcourt l'ensemble de l'arborescence Django et extrait toutes les chaînes marquées comme à traduire. Il créé (ou met à jour) un fichier message dans le répertoire conf/locale. Dans l'exemple de, le fichier sera conf/locale/de/LC_MESSAGES/django.po.

Si lancée à partir de la racine de votre projet ou application Django , il fera la même chose, mais la localisation du répertoire de traduction sera dans ce cas locale/LANG/LC_MESSAGES (notez l'absence du préfixe conf).

gettext non disponible ?

Si vous n'avez pas l'utilitaire gettext installé, make-messages.py créera des fichiers vides. Si c'est le cas, soit vous installez l'utilitaire gettext soit vous copiez le fichier message anglais (conf/locale/en/LC_MESSAGES/django.po) et vous l'utilisez comme point de départ; il s'agit uniquement d'un fichier de traduction vide.

Le format des fichiers .po est simple. Chaque fichier .po contient quelques meta-données, telles que l'information de contact du traducteur, mais l'essentiel du fichier est une liste de messages -- simple mise en correspondance entre les chaînes à traduire et la traduction pour le langage donné.

Par exemple, si votre application Django contient une chaîne à traduire pour le texte "Bienvenue sur mon site.", comme ceci:

_("Bienvenue sur mon site.")

... make-messages.py aura alors créé un fichier .po contenant l'extrait suivant -- un message:

#: chemin/vers/python/module.py:23
msgid "Bienvenue sur mon site."
msgstr ""

Une petite explication:

  • msgid est la chaîne à traduire, qui apparaît dans le source. Ne la modifiez pas.
  • msgstr est la partie où vous indiquez la traduction. Elle est initialement vide, il est de votre ressort de la modifiez. Soyez sûr de bien conserver les guillemets autour de votre traduction.
  • À titre de facilité, chaque message comporte le nom du fichier et le numéro de ligne à partir duquel la chaîne à traduire a été récupérée.

Les longs messages sont un cas particulier. D'abord, la 1ère chaîne qui suit msgstr (ou msgid) est une chaîne vide. Puis le contenu lui même sera écrit sur les lignes suivantes une chaîne par ligne. Ces chaînes sont directement concaténées. N'oubliez pas de mettre des espaces en fin de ligne dans ces chaînes; sinon elles seront assemblées ensemble sans espace !

Occupez vous de l'encodage de vos caractères

Quand vous créez un fichier .po avec votre éditeur de textes favori modifiez avant toute chose la ligne d'encodage des caractères (cherchez le mot "CHARSET") et modifiez le pour qu'il corresponde au jeu de caractères que vous utilisez pour éditer le contenu du fichier. Généralement, utf-8 devrait fonctionner pour la plupart des langages, mais gettext devrait accepter n'importe quel jeu que vous lui indiquez.

Pour analyser à nouveau l'ensemble des codes source et templates pour de nouvelles chaînes à traduire et mettre à jour l'ensemble des fichiers message pour l'ensemble des langues, lancez cette commande:

make-messages.py -a

Compilation des fichiers messages

Après avoir créé votre fichier message -- et à chaque fois que vous le modifiez -- vous devez le recompiler dans une forme plus efficace pour gettext. Utilisez pour ce faire l'utilitaire bin/compile-messages.py.

Cette commande parcourt tous les fichiers .po et créée des fichiers .mo, qui sont des fichiers binaires optimisés pour gettext. À partir du même répertoire que celui utilisé pour lancer make-messages.py, lancez compile-messages.py comme ceci:

bin/compile-messages.py

C'est tout. Vos traductions sont prêtes à être utilisées.

Note pour les traducteurs

Si vous avez créé une traduction dans une langue que Django ne supporte pas encore, merci de nous le faire savoir ! Voir Soumettre et maintenir une traduction pour la démarche à suivre.

Comment Django identifie les préférences de langue

Une fois que vos traductions sont prêtes -- ou, si vous désirez utiliser uniquement les traductions livrées avec Django -- vous devez activer la traduction pour votre application.

Derrière les rideaux, Django a un mécanisme très souple pour décider quelle langue devrait être utilisée -- propre à l'installation, pour un utilisateur en particulier, ou pour les 2.

Pour indiquer des préférences de langue propres à une installation de Django, positionnez LANGUAGE_CODE dans votre fichier de paramètres Django. Django utilise cette langue comme la langue par défaut -- si aucune autre n'est trouvée.

Si tout ce que vous voulez est de lancer Django sous votre langue natale, et un fichier de langue est disponible pour celle-ci, tout ce que vous avez à faire est de positionner LANGUAGE_CODE.

Si vous voulez que chaque utilisateur puisse indiquer quelle langue il ou elle préfère, utilisez LocaleMiddleware. LocaleMiddleware active la sélection de langue en fonction de données fournies dans la requête. Il adapte le contenu pour chaque utilisateur.

Pour utiliser LocaleMiddleware, ajoutez 'django.middleware.locale.LocaleMiddleware' à votre paramètre MIDDLEWARE_CLASSES. Parce que l'ordre des middleware compte, vous devriez suivre ces conseils:

  • Soyez sûr que c'est un des premiers middlewares installé.
  • Il devrait suivre SessionMiddleware, parce que LocaleMiddleware utilise les données de session.
  • Si vous utilisez CacheMiddleware, mettez LocaleMiddleware après lui.

Par exemple, votre MIDDLEWARE_CLASSES pourrait ressembler à ceci:

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

(Pour plus d'informations sur les middleware, voir la documentation sur les middleware.)

LocaleMiddleware tente de déterminer les préférences de langue de l'utilisateur en suivant cet algorithme:

  • Premièrement, il recherche une clé django_language dans la session courante de l'utilisateur.
  • Si cela échoue, il recherche un cookie de nom django_language.
  • Si cela échoue, il recherche un en-tête HTTP Accept-Language. Cet en-tête est envoyé par votre navigateur et indique au serveur quel(s) langue(s) vous préférez, par ordre de priorité décroissante. Django essai chaque langue dans cet en-tête jusqu'à ce qu'il trouve une traduction existante.
  • Si tout cela échoue, il utilise la préférence globale LANGUAGE_CODE.

Notes:

  • À chacun de ces endroits, la préférence de langue est attendue dans le format standard, comme une chaîne de caractères. Par exemple, le brésilien est indiqué comme pt-br.

  • Si une langue de base est disponible mais le dialecte spécifié ne l'est pas, Django utilise la langue de base. Par exemple, si un utilisateur indique de-at (allemand autrichien) mais Django ne dispose que de de, Django utilisera de.

  • Seules les langues listées dans le paramètre LANGUAGES peuvent être sélectionnées. Si vous voulez restreindre la sélection de langue à un sous-ensemble des langues fournies (parce que par exemple votre application ne fournie pas toutes ces langues); positionnez LANGUAGES à une liste appropriées. Par exemple:

    LANGUAGES = (
            ('de', _('German')),
            ('en', _('English')),
    )
    
    Cet exemple limite les langues disponibles pour une

    sélection automatique à l'allemand et l'anglais (et tous les dialectes correspondants, comme de-ch ou en-us).

  • Si vous définissez le paramètre LANGUAGES, comme

    expliqué dans le point ci-dessus, il est possible d'indiquer les langues comme des chaînes à traduire -- mais utilisez une fonction gettext() "vide", pas celle dans le module django.utils.translation. Vous ne devriez jamais importer django.utils.translation à partir de votre fichier paramètres, parce que ce module dépend lui même des paramètres, ce qui créerait un import circulaire.

    La solution est d'utiliser une fonction gettext vide. Ci-dessous un exemple de fichier paramètre:

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

    Avec ce code, make-messages.py trouvera et marquera toujours ces chaînes comme à traduire, mais la traduction ne se fera pas lors de l'exécution du code -- aussi vous devrez vous rappeler d'englober les chaînes à traduire avec la véritable fonction gettext() dans tout code qui utilise LANGUAGES lors de l'exécution du code.

  • Le LocaleMiddleware peut sélectionner uniquement les langues pour lesquelles Django fournit une traduction de base. Si vous désirez fournir une traduction pour votre application qui n'est pas déjà dans l'ensemble des traductions incluses dans les sources Django, vous devrez au moins fournir une traduction de base pour cette langue. Par exemple, Django utilise des messages ID technique pour traduire les formats de date et de temps -- aussi vous aurez au minimum besoin d'avoir ces traductions pour que le système fonctionne correctement.

    Un bon point de départ est de copier le fichier .po anglais et de traduire au minimum les messages techniques -- peut être également les messages de validation.

    Les messages ID techniques sont facilement reconnaissables; ils sont tous en majuscules. Vous ne traduisez pas les messages ID comme les autres messages, vous fournissez la variante locale correcte correspondante à la valeur anglaise. Par exemple, avec DATETIME_FORMAT (ou DATE_FORMAT ou TIME_FORMAT), cela serait la chaîne de format que vous voulez utiliser pour cette langue. Le format est identique aux chaînes de format utilisées avec le tag de template now.

Une fois que LocaleMiddleware a déterminé la préférence de l'utilisateur, il rend cette préférence disponible dans request.LANGUAGE_CODE pour chaque objet requête. Vous êtes libre d'utiliser cette valeur dans votre code. Voici un simple exemple:

def hello_world(request, count):
    if request.LANGUAGE_CODE == 'de-at':
        return HttpResponse("Vous préférez lire l'allemand autrichien")
    else:
        return HttpResponse("Vous préférez lire une autre langue")

Notez qu'avec une traduction statique (sans middleware), la langue est dans settings.LANGUAGE_CODE, tandis qu'avec une traduction dynamique (middleware) elle est dans request.LANGUAGE_CODE.

La vue de redirection set_language

À titre de facilité, Django est fournie avec une vue, django.views.i18n.set_language, qui positionne les préférences de langue de l'utilisateur puis redirige vers la page précédente.

Activez cette vue en ajoutant la ligne suivante dans votre URLconf:

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

(Notez que cet exemple rend la vue disponible à l'url /i18n/setlang/.)

La vue attend a être appelée via la méthode GET, avec un paramètre language positionné dans la chaîne de requête. Si le support des sessions est activé, la vue sauvegarde le choix de la langue dans la session de l'utilisateur. Autrement, elle sauvegarde le choix de la langue dans un cookie django_language.

Après avoir positionné le langage choisi, Django redirige l'utilisateur, selon l'algorithme suivant:

  • Django recherche un paramètre de nom next dans la chaîne de requête.
  • Si celui-ci n'existe pas, ou est vide, Django essai l'URL de l'en-tête Referer.
  • Si celui-ci est vide -- disons, si le navigateur de l'utilisateur supprime cet en-tête -- alors l'utilisateur sera redirigé vers / (la racine du site) à défaut.

Ci-dessous un exemple HTML dans un template:

<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>

Utilisation des traductions dans vos propres projets

Django recherche des traductions en suivant cet algorithme:

  • Premièrement, il recherche un répertoire locale dans le répertoire de l'application de la vue qui est appelée. Si il trouve une traduction pour la langue sélectionnée, elle sera installée.
  • Ensuite, il recherche un répertoire locale dans le répertoire du projet Django. Si il trouve une traduction, elle sera installée.
  • Finalement, il vérifie les traductions de base dans django/conf/locale.

De cette manière vous pouvez écrire des applications qui inclut leur propre traductions, et vous pouvez redéfinir les traductions de base dans votre répertoire projet Django. Ou, vous pouvez élaborer un grand projet à partir de plusieurs applications et mettre l'ensemble des traductions dans un grand et unique fichier messages du projet. Le choix vous appartient.

Note

Si vous utilisez la configuration manuelle de votre fichier paramètres, tel que définit dans la documentation sur le fichier paramètres, le répertoire locale de votre répertoire projet ne sera pas examiné, puisque Django perd la possibilité de travailler à partir de l'emplacement de votre projet. (Django normalement utilise l'emplacement du fichier paramètres pour déterminer ceci, et un fichier paramètres n'existe pas si vous configurez manuellement vos paramètres).

L'ensemble des répertoires de fichiers messages ont une structure identique :

  • $APPPATH/locale/<langue>/LC_MESSAGES/django.(po|mo)
  • $PROJECTPATH/locale/<langue>/LC_MESSAGES/django.(po|mo)
  • Tous les chemins indiqués dans la variable LOCALE_PATHS de votre fichier paramètres sont parcourus dans cet ordre à la recherche de fichiers <langue>/LC_MESSAGES/django.(po|mo)
  • $PYTHONPATH/django/conf/locale/<langue>/LC_MESSAGES/django.(po|mo)

Pour créer des fichiers de traduction, vous utilisez le même utilitaire que pour la traduction des fichiers de traduction Django, à savoir make-messages.py. Vous devez seulement vous assurer que vous êtes au bon endroit -- soit dans le répertoire parent de conf/locale (si dans la hiérarchie source Django) soit dans le répertoire parent de locale/``(si il s'agit de traductions de projets ou d'applications). Et vous utilisez le même utilitaire ``compile-messages.py pour générer les fichiers binaires django.mo utilisés par gettext.

Les fichiers de traduction des applications sont plus difficiles à détecter -- ils ont besoin de LocaleMiddleware. Si vous n'utilisez pas le middleware, seuls les fichiers de traduction de Django et des projets seront traités.

Pour finir, vous devriez réfléchir à la structure de vos fichiers de traduction. Si vos applications doivent être distribuées à d'autres utilisateurs pour être utilisées dans d'autres projets, vous pourriez vouloir faire des traductions spécifiques à vos applications. Mais faire des traductions spécifiques à des applications ou à des projets pourrait générer des problèmes avec make-messages: make-messages parcourt l'ensemble des répertoires situés sous le chemin courant et en conséquence pourrait mettre des messages ID dans le fichier de traduction du projet qui sont déjà dans les fichiers de traduction des applications.

Le meilleur moyen de s'en sortir est de mettre les applications qui ne font pas partie du projet (et donc qui comportent leur propre traductions) en dehors de la hiérarchie du projet. De cette manière, make-messages lancé à partir du répertoire du projet ne traduira que les chaînes qui sont spécifiques à votre projet et non les chaînes distribuées indépendamment.

Traductions et Javascript

Ajouter des traductions à Javascript pose certains problèmes :

  • Le code Javascript n'a pas accès à la librairie gettext.
  • Le code Javascript n'a pas accès aux fichiers .po ou .mo; ils doivent être envoyés par le serveur.
  • Le catalogue des chaînes traduites pour Javascript devrait être aussi léger que possible.

Django fournit une solution intégrée pour ces problèmes : il transmet les traductions à Javascript de telle manière que vous puissiez appeler gettext, etc... à partir de votre code Javascript.

La vue javascript_catalog

La solution principale à ces problèmes est la vue javascript_catalog qui renvoie une librairie en Javascript qui reproduit l'interface gettext accompagnée d'un tableau des chaînes traduites. Ces chaînes sont extraites de l'application, du projet ou de Django selon ce que vous indiquez dans soit le dictionnaire {{{info_dict}}} ou l'URL.

Vous assemblez les choses comme suit:

js_info_dict = {
    'packages': ('votre.application.package'),
}

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

Chaque chaîne dans packages devrait être exprimée dans la même syntaxe que Python utilise pour les packages (même format que les chaînes utilisées dans la variable INSTALLED-APPS) et devrait faire référence à un package qui contient un répertoire locale. Si vous indiquez plusieurs packages, tous les catalogues qu'ils contiennent sont fusionnés en un seul catalogue. Ceci peut être utile si votre code Javascript utilise des chaînes de plusieurs applications.

Vous pouvez rendre la vue dynamique en mettant les packages dans les modèles d'URL (URL pattern):

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

Comme ceci vous indiquez les packages comme une liste de noms de packages délimités par le signe '+' dans l'URL. Cela peut être particulièrement utile si vos pages utilisent du code de différentes applications, que cela change souvent et que vous ne voulez pas rassembler le tout dans un unique catalogue. À titre de mesure de sécurité, ces valeurs ne peuvent qu'être soit django.conf, soit n'importe quel package apparaissant dans la variable INSTALLED_APPS.

Utilisation du catalogue de traductions avec Javascript

Pour utiliser le catalogue, appelez le code Javascript généré dynamiquement comme suit:

<script type="text/javascript" src="/chemin/vers/jsi18n/"></script>

C'est comme cela que l'interface d'administration de Django récupère le catalogue de traductions à partir du serveur. Lorsque le catalogue est chargé, votre code Javascript peut utiliser l'interface standard gettext pour y accéder:

document.write(gettext('ceci est à traduire'));

ngettext et la fonction d'interpolation des chaînes sont même disponibles:

d = {
    count: 10
};
s = interpolate(ngettext("il y'a %(count)s objet", "il y'a ù%count)s objets", d.count), d);

La fonction interpolate supporte aussi bien l'interpolation par position que l'interpolation nommée. Le code dessus aurait pu être écrit comme suit:

s = interpolate(ngettext("il y'a %s objet", "il y a %s objets", 11), [11]);

La syntaxe pour l'interpolation est empruntée de Python. Vous ne devriez pas trop en demander cependant avec l'interpolation de chaînes: cela reste du Javascript aussi le code devra faire des substitutions répétées avec des expressions régulières. Ce n'est pas aussi rapide que l'interpolation de chaînes avec Python aussi réservez les aux cas où vous en avez vraiment besoin (par exemple en conjonction avec ngettext pour générer des mises au pluriel correctes)

Création des catalogues de traductions pour Javascript

Vous créez et mettez à jour les catalogues de traductions de la même manière que ceux de Django -- avec l'utilitaire {{{make-messages.py}}}. La seule différence est que vous devez fournir le paramètre -d djangojs, comme ceci:

make-messages.py -d djangojs -l de

Ceci créera ou mettra à jour le catalogue des traductions allemandes pour Javascript. Après mise à jour des catalogues de traductions, lancer compile-messages.py de la même manière que vous le faites pour les catalogues de traductions Django.

Particularités de la traduction Django

Si vous connaissez gettext vous pourriez remarquer ces particularités dans la manière dont Django effectue les traductions:

  • La chaîne de domaine est django ou djangojs. La chaîne de domaine est utilisée pour différencier entre différents programmes qui stockent leurs données dans un fichier des messages commun (généralement /usr/share/locale). Le domaine django est utilisé par Python et les chaînes de traduction des templates et est chargé dans les catalogues de traductions globaux. Le domaine djangojs est uniquement utilisé pour les catalogues de traductions Javascript pour être sûr qu'ils sont le plus lèger possible.
  • Django utilise uniquement gettext et gettext_noop. Parce que Django utilise toujours les chaînes DEFAULT_CHARSET de manière interne. Il n'y a pas beaucoup matière à utiliser ugettext car vous devrez toujours fournir utf-8 dans tous les cas.
  • Django n'utilise pas xgettext seul. Il utilise des enveloppes Python autour de xgettext et msgfmt. Principalement pour convenance.