Chapitre 18: Internationalisation
Django a été développé à l’origine au beau milieu des États-Unis (litéralement; Lawrence, Kansas, est à moins de 40 miles (ndt: environ 65 km) du centre géographique des États-Unis continental). Comme beaucoup de projets oepn source, la communauté Django s’est aggrandie pour y inclure les gens répartis un peu partout dans le monde. Alors que la communauté Django devenait incroyablement diverse, l’internationalisation et la localisation pris une importance croissante. Puisque beaucoup de développeurs ont au mieu une compréhension floue de ces termes, nous allons les définir brièvement.
L’internationalisation fait référence à l’architecture des programmes afin qu’ils puissent potentiellement utilisés n’importe quelle paramètre régional. Ceci inclut le marquage du texte (comme les élémentes d’interface utilisateur et les messages d’erreur) en prévision de futures traductions, en faisant abstraction de l’affichage des dates et du temps afin que les différents paramètres régionaux standards puissent être respectées, fournissant ainsi le support des diverses zones horaires, et généralement en assurant que le code ne contienne pas d’à priori sur la localisation de ses utilisateurs. Vous verrez souvent l’«internationalisation» abrégée en I18N (le nombre de 18 se réfère au nombre de lettres omises entre l’ «I» initial et le «N» final).
La localization fait référence au fait de traduire un programme internationalisé afin de l’utiliser avec des paramètres régionaux particulièrs. Vous verrez parfois «localisation» abrégée en L10N.
Django lui même est totalement internationalisé; toutes les chaînes sont marquées en prévision d’une traduction, et les paramètres contrôlent l’affichage des valeurs dépendantes de la localité tels que les dates et les heures. Django est aussi livré avec près de 40 fichiers de localisation différents. Si vous n’êtes pas nativement Anglophone, il y a de grandes chances pour que Django soit déjà traduit dans votre langue maternelle.
Le même framework d’internationalisation utilisé pour ces localisations est disponible pour que vous puissiez l’utiliser dans votre propre code et vos propres gabarits.
En condensé, vous devrez ajouter un nombre minimal d’accroches dans votre code Python et dans vos gabarits. Ces points d’entrée sont appelées chaîne de traduction. Elles indiquent à Django que «ce texte doit être traduit dans la langue de l’utilisateur final, si une traduction pour ce texte est disponible pour cette langue».
Django prends soin d’utiliser ces accroches pour traduire les applications web, à la volée, selon les préférences de langue de l’utilisateur.
Django fait essentiellement deux choses:
- il laisse les développeurs et les auteurs de gabarits préciser quelles sont les parties de leurs applications qui doivent être traduites.
- il utilise cette information pour traduire et personaliser les applications web selon les préférences de langue des utilisateurs.
Note
La mécanique de traduction sous Django utilise GNU gettext (http://www.gnu.org/software/gettext/) via le module standard gettext qui est livré avec Python.
Si vous n’avez pas besoin d’internationalisation:
Les points d’entrée pour l’internationalisation de DJango sont activés par défaut, ce qui génère une légère surcharge. Si vous n’utilisez pas l’internationalisation, vous devriez paramètrer USE_I18N = False dans votre fichier des paramètres. If USE_I18N est placé à False, alors DJango fera quelques optimisations de façon à ne pas charger la machinerie nécessaire à l’internationalisation.
Vous voudrez probablement aussi supprimer 'django.core.context_processors.i18n' dans votre paramètre TEMPLATE_CONTEXT_PROCESSORS.
Préciser les chaînes de traduction dans du code Python
Les chaînes de traduction précisent que «ces chaînes de caractère doivent être traduites». Ces chaînes peuvent apparaîtres dans votre code Python ou dans vos gabarits. Le marquage des chaînes traduisibles reste à votre charge; le système ne peut traduire que les chaînes dont il à connaissance.
Fonctions standards de traduction
Précisez une chaîne à traduire en utilisant la fonction _(). (Oui, le nom de la fonction est le caractère de soulignement). Cette fonction est disponible globalement (c’est à dire, en tant que primitive du langages); vous n’avez pas à l’importer.
Dans cet exemple, le texte "Welcome to my site." est marqué comme étant une chaîne à traduire:
def my_view(request):
output = _("Welcome to my site.")
return HttpResponse(output)
La fonction django.utils.translation.gettext() est identique à _(). Cet exemple revient au même que le précédent:
from django.utils.translation import gettext
def my_view(request):
output = gettext("Welcome to my site.")
return HttpResponse(output)
La plupart des développeurs préfèrent utiliser _(), car c’est plus court.
La traduction fonctionne aussi sur les valeurs calculées. Cet exemple est lui aussi identique au précédent:
def my_view(request):
words = ['Welcome', 'to', 'my', 'site.']
output = _(' '.join(words))
return HttpResponse(output)
La traduction fonctionne aussi pour les varialbes. Encore une fois, voici un exemple identique:
def my_view(request):
sentence = 'Welcome to my site.'
output = _(sentence)
return HttpResponse(output)
(Le soucis avec l’usage des variables ou des valeurs calculées, comme dans les deux exemples précédents, est que l’utilitaire de détection des chaînes à traduire, make-messages.py, ne sera pas capable de trouver ces chaînes. Vous trouverez plus de détail sur make-messages un peu plus loin).
Les chaînes que vous passez à _() ou à gettext() peuvent utiliser la substitution, en utilisant la syntaxe d’interpolation des chaînes nommées standard en Python, comme par exemple:
def my_view(request, n):
output = _('%(name)s is my name.') % {'name': n}
return HttpResponse(output)
Cette technique permet aux traductions spécifiques à la langue de réordonner le texte à substitué. Par exemple, une traduction Anglaise pourrait être "Adrian is my name.", alors qu’une traduction Espagnole serait "Me llamo Adrian.", avec la substitution (le prénom) placée après le texte traduit au lieu de se trouver avant.
Pour cette raison, vous devez utiliser l’interpolation des chaînes nommées (par exemple, %(name)s) au lieu de l’interpolation positionnelle (par exemple, %s ou %d). Si vous utilisez l’interpolation positionelle, les traductions ne seront pas capables de réordonner le texte substitué.
Marquer les chaînes en tant que No-op
Utilisez la fonction django.utils.translation.gettext_noop() pour marquer une chaîne en tant que chaîne à traduire sans pour autant la traduire sur l’instant. Les chaînes ainsi marquées ne sont traduite que le plus tard possible.
Utilisez cette approche si vous avez des chaînes constantes qui doivent être stockées dans la langue d’origine - comme les chaînes dans une base de données - et qui doivent être traduites le plus tardivement 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 paresseusement les chaînes - lorsque la valeur est accédée plutôt que lorsque la fonction gettext_lazy() est appellée.
Par exemple, pour marquer l’attribut des champs help_text comme étant traduisible, faite la chose suivante:
from django.utils.translation import gettext_lazy
class MyThing(models.Model):
name = models.CharField(help_text=gettext_lazy('This is the
help text'))
Dans cet exemple, gettext_lazy() stocke une référence paresseuse vers la chaîne - pas la traduction actuelle. La traduction elle-même sera effectuée lorsque la chaîne sera utilisée dans un contexte de chaîne, tel que le rendu d’un gabarit sur le site d’admin de Django.
Si vous n’aimez pas la forme verbeuse du nom gettext_lazy, vous pouvez simplement en faire un raccourcis sous la forme d’un _ (soulignement), comme ceci:
from django.utils.translation import gettext_lazy as _
class MyThing(models.Model):
name = models.CharField(help_text=_('This is the help text'))
Utilisez toujours des traductions paresseuses dans les modèles Django (autrement il ne seront pas traduits correctement en fonction de l’utilisateur). C’est une bonne idée d’ajouter les traductions pour les noms de champ et les noms de tables aussi. Cela signifie qu’il faut écrire explicitement les options verbose_name et verbose_name_plural de 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')
Pluralisation
Utilisez la fonction django.utils.translation.ngettext() pour préciser les messages qui ont des formes singulières et plurielles différentes, comme par 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 prends trois arguments: la chaîne de traduction au singulier, la chaîne de traduction au pluriel, et le nombre d’objets (qui est transmis aux langues traduites sous forme de variable count).
Préciser les chaînes de traduction dans le code du gabarit
L’utilisation des traductions dans les gabarits Django repose sur deux balises de gabarits et une légère différence de syntaxe par rapport au code Python. Pour donner à votre gabarit l’accès à ces balises, placez {% load i18n %} en haut de votre gabarit.
La balise de gabarit {% trans %} marque une chaîne à traduire:
<title>{% trans "This is the title." %}</title>
Si vous voulez seulement marquer une valeur à traduire, mais faire la traduction plus tard, utlisez l’option noop:
<title>{% trans "value" noop %}</title>
Il n’est pas possible d’utiliser les variables de gabarit au sein de {% trans %} - seules les chaînes constantes, entre simple ou double parenthèses, sont permises. Si votre traduction nécessite des variables (substitutions), utilisez {% blocktrans %}, par exemple:
{% blocktrans %}This will have {{ value }} inside.{% endblocktrans %}
Pour traduire une expression de gabarit - disons, utiliser les filtres de gabarit - vous devez lier l’expression à une variable locale à utiliser dans le bloc de traduction:
{% blocktrans with value|filter as myvar %}
This will have {{ myvar }} inside.
{% endblocktrans %}
Si vous devez lier plus d’une expression à l’intérieur d’une balise blocktrans, séparez les parties à l’aide de and:
{% blocktrans with book|title as book_t and author|title as author_t %}
This is {{ book_t }} by {{ author_t }}
{% endblocktrans %}
Pour pluraliser, précisez à la fois les formes singulière et plurielle avec la balise {% plural%}, qui apparait entre {% blocktrans %} et {% endblocktrans %}, par exemple:
{% blocktrans count list|length as counter %}
There is only one {{ name }} object.
{% plural %}
There are {{ counter }} {{ name }} objects.
{% endblocktrans %}
En interne, tous les blocs et les traductions en ligne utilisent l’appel gettext/ngettext approprié.
Lorsque vous utilisez RequestContext (lisez le Chapitre 10), vos gabarits ont accès à trois variables spécifique à la traduction:
- {{ LANGUAGES }} est une liste de tuples dans laquelle le premier élément est le code de langue et le second est le nom de la langue (dans cette langue).
- {{ LANGUAGE_CODE }} est la langue courante préférée de l’utilisateur, sous forme de chaîne (par exemple, en-us). (Lisez «Comment Django trouve la préférence linguistique» pour plus d’information).
- {{ LANGUAGE_BIDI }} est la langue courante du système d’écriture. Si elle est à True, il sagit d’une langue de-droite-à-gauche (par exemple, l’Arabe, l’Hébreu). Si elle est à False, il s’agit d’une langue de gauche-à-droite (par exemple, l’Anglais, le Français, l’Allemand).
Vous pouvez aussi charger ces valeurs en utilisant les balises de gabarits:
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_current_language_bidi as LANGUAGE_BIDI %}
Les points d’entrée de traduction sont aussi disponibles dans tous les blocs de gabarit qui acceptent des chaînes constantes. Dans ces cas, utilisez la syntaxe _() pour préciser une chaîne de traduction, par exemple:
{% some_special_tag _("Page not found") value|yesno:_("yes,no") %}
Dans ce cas, la balise et le filtre verront la chaîne déjà traduite (c’est à dire aue la chaîne est traduite avant d’être transmise au fonctions gestionnaires de balise), aussi n’ont-elles pas besoin d’être au courant des traducitons.
Créer des fichiers de langue
Une fois que vous avez balisé vos chaînes pour une traduction ultérieure, vous devez écrire (ou obtenir) les langues de traduction elles-mêmes. Dans cette section nous expliquons comment cela fonctionne.
Créer des fichiers de message
La première étape consiste à créer un fichier message pour une nouvelle langue. Un fichier message est une fichier texte représentant une unique langue contenant toutes les chaînes de traduction disponibles et comment elles doivent être représentées dans la langue donnée. Les fichiers message ont une extension de fichier .po.
Django est fourni avec un outil, bin/make-messages.py, qui automatise la créatio et la maintenance de ces fichiers.
Pour créer ou mettre à jour un fichier message, lancez cette commande:
bin/make-messages.py -l de
Où de est le code de langue pour le fichier message que vous voulez créer. Le code de langue, dans ce cas, est au format local. Par exemple, il s’agit de pt_BR pour le Portuguais Brésilien et de de_AT pour l’Allemand Autrichien. Jetez un oeil aux codes de langues dans le répertoire ``django/conf/locale/``pour voir quelles sont les langues actuellement supportées.
Le script doit être lancé depuis l’un de ces trois endroits:
- Le répertoire racine django (pas un checkout Subversion, mais celui qui lui est lié via $PYTHONPATH ou qui se trouve ailleurs sur ce chemin)
- le répertoire racine de votre projet Django
- le répertoire racine de votre application Django.
Le script parcours entièrement l’arborescence sur laquelle il est lancé et récupère toutes les chaînes marquées pour traduction. Il créer (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.
S’il est lancé depuis l’arborescence des sources de votre projet ou depuis celle de votre application, il fera la même chose, mais l’emplacement du répertoire des paramètres régionaux sera locale/LANG/LC_MESSAGES (notez l’absence du préfix conf). La première fois que vous le lancez sur votre arborescence vous devrez créer le répertoire locale.
Pas de gettext ?
Si vous n’avez pas les utilitaires gettext installés, make-messages.py créera les fichiers vides. Si c’est le cas, installez les utilitaires gettext ou copiez simplement le fichier message Anglais (conf/locale/en/LC_MESSAGES/django.po) et utilisez le comme point de départ; c’est juste un fichier de traduction vierge.
Le format des fichiers .po est simple. Chaque fichier .po contient quelques métadonnées, comme par exemple des information pour contacter le mainteneur de la traduction, mais le corps du fichier est une liste de messages - une simple correspondance entre les chaînes de traduction et le texte actuel traduit pour la langue particulière.
Par exemple, si votre application Django contient une chaîne de traduction pour le texte "Welcome to my site.", comme ceci:
_("Welcome to my site.")
alors make-messages.py va créer un fichier .po contenant l’extrait suivant - un message:
#: path/to/python/module.py:23 msgid "Welcome to my site." msgstr ""
Une rapide explication est nécessaire:
- msgid est la chaîne de traduction, qui apparait dans la source. Ne le modifier pas.
- msgstr est l’endroit où vous placez la traduction spécifique à la langue. Il est vide au départ, il est donc de votre ressort de le modifier. Assurez-vous de conserver les guillemets autour de votre traduction.
- par commodité, chaque message inclu le nom de fichier et le numéro de ligne d’où la chaîne de traduction à été tirée.
Les messages longs sont des cas spéciaux. La première chaîne directement après msgstr (ou msgid) est une chaîne vide. Ensuite le contenu lui-même sera écrit sur les quelques lignes qui suivent sous forme d’une chaîne par ligne. Ces chaînes sont directement concaténées. N’oubliez pas l’espace final entre les chaînes; autrement, elles seront assemblées sans espace !
Par exemple , voici une traduction multilignes (exraite de la localisation Espagnol qui est fournie avec Django):
msgid "" "There's been an error. It's been reported to the site administrators via e-" "mail and should be fixed shortly. Thanks for your patience." msgstr "" "Ha ocurrido un error. Se ha informado a los administradores del sitio " "mediante correo electr?nico y deber?a arreglarse en breve. Gracias por su " "paciencia."
Notez les espaces finaux.
Mind Your Charset
Lorsque vous créez un fichier .po avec votre éditeur de texte favoris, commencer par éditer la ligne concernant le jeu de caractères, (cherchez "CHARSET") et fixez le avec le jeu de caractères que vous utiliserez pour éditer le contenu. Généralement, UTF-8 doit fonctionner pour laplupart des langages, mais gettext doit gérer n’importe quel jeu que vous lui indiquerez.
Pour réexaminer tout le code source et tous les gabarits pour de nouvelles chaînes de traduction et mettre à jour tous les fichiers messages pour toutes les langues, lancez la commande:
make-messages.py -a
Compiler les fichiers messages
Après avoir crée votre fichier message, à chaque fois que vous y apporterez des modifications, vous devrez le comiler dans une forme plus efficiente, pour pouvoir être utilisé par gettext. Faîtes ceci avec l’utilitaire bin/compile-messages.py.
Cet outil parcours tous les fichiers .po disponibles et créer des fichiers .mo, qui sont des fichiers binaires optimisés pour utilisation par gettext. Dans le même répertoire que celui où vous avez lancé make-messages.py, lancez compile- messages.py comme ceci:
bin/compile-messages.py
C’est tout. Vos traductions sont prêtes à l’emploi.
Comment Django trouve la préférence linguistique
Lorsque vous avez préparé vos traductions - ou, si vous voulez seulement utiliser les traductions qui sont incluses dans Django - vous devrez activer la traduction pour votre application.
En coulisses, Django possède un modèle très flexible pour décider quel est la langue à utiliser - pour toute l’installation, pour un utilisateur particulier, ou les deux.
Pour paramétrer une préférence de langue sur l’ensemble du site, configurez LANGUAGE_CODE dans votre fichier de paramètres. Django utilise cette langue comme celle étant la traduction par défaut - c’est à dire en dernier recours si aucun traducteur ne trouve de traduction.
Si vous voulez simplement lancer Django avec votre langue native, et qu’un fichier de langue est disponible pour celle-ci, il suffit de configurer LANGUAGE_CODE.
Si vous voulez laisser chaque utilisateur individuel préciser la langue qu’il ou elle préfère, utilisez LocaleMiddleware. LocaleMiddleware active la selection des langues sur la base des données issues de la requête. Il personnalise le contenu pour chaque utilisateur.
Pour utiliser LocaleMiddleware, ajoutez 'django.middleware.locale.LocaleMiddleware' à votre paramètre MIDDLEWARE_CLASSES. Puisque l’ordre des middlewares importe, vous devez suivre ces consignes:
- Assurez vous qu’il est parmi les premières classes de middleware installées.
- il doit être placé après SessionMiddleware, parce que LocaleMiddleware utilise les données de session.
- Si vous utilisez CacheMiddleware, placez LocaleMiddleware après lui (autrement les utilisateurs peuvent obtenir du contenu en cache depuis la mauvaise localisation).
Par exemple, votre MIDDLEWARE_CLASSES doit ressembler à ceci:
MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware' )
LocaleMiddleware essaie de déterminer la préférence de langue de l’utilisateur en suivant cet algorithme:
- premièrement, il cherche une clef django_language dans la session courante de l’utilisateur.
- si cela échoue, il cherche un cookie appelé django_language.
- si cela échoue, il cherche l’en-tête HTTP Accept-Language. Cet en-tête est envoyé par votre navigateur et indique au serveur quelle(s) langue(s) vous préféré, selon l’odre des priorité. Django essaie chaque langue de l’en-tête jusqu’a ce qu’il en trouve un ayant des traductions disponibles.
- si cela échoue, il utilise le paramètre global LANGUAGE_CODE.
Dans chaquun de ces endroits, la préférence de langue est censée être au format de langue standard, sous forme de chaîne. Par exemple, le Portuguais Brésilien est pt-br. Si une langue de base est disponible mais que le sous-langage précisé ne l’est pas, Django utilise la langue de base. Par exemple, si un utilisateur précise de-at (Allemand Autrichien) mais que Django ne possède que de de disponible, Django utilise de.
Seules les langues listées dans le paramètre LANGUAGES peuvent être choisies. Si vous voulez restreindre la selection des langues à une poignée parmi les langues disponibles, (parce que votre application ne fourni pas toutes ces langues), fixez votre paramètre LANGUAGES sous forme de liste de langues, par exemple:
LANGUAGES = (
('de', _('German')),
('en', _('English')),
)
Cet exemple restreint les langues disponibles pour une selection automatique à l’Allemand et à l’Anglais (et tout les dérivés, tels que de-ch ou en-us).
Si vous définissez des LANGUAGES personalisés, il est possible de marquer ces langues comme étant des chaînes de traduction - il faut alors utiliser la fonction factice gettext() et non celle présente dans django.utils.translation. Vous ne devez jamais importer django.utils.translation depuis votre fichier de paramètres, parce que ce module dépend lui-même des paramètres, ceci pourrait créer un import circulaire.
La solution est d’utiliser la fonction factice gettext(). Voici un fichier de paramètre pour l’exemple:
_ = lambda s: s
LANGUAGES = (
('de', _('German')),
('en', _('English')),
)
Avec cet arrangement, make-messages.py continuera à trouver et à marquer ces chaînes pour traduction, mais la traduction n’arrivera pas lors de l’exécution, vous devrez donc vous souvenir d’emballer les langues dans la fonction gettext() réelle au sein de n’importe quel code qui utilise LANGUAGES lors de l’exécution.
LocaleMiddleware peut seulement sélectioner les langues pour lesquelles il existe une base de traduction fournie par Django. Si vous voulez fournir des traductions pour votre application qui ne sont pas encore dans le jeu de traduction de l’arborescence de Django, vous devrez fournir au moins une traduction basique pour cette langue. Par exemple, Django utilise les IDs des messages techniques pour traduire les formats de date et d’heure - vous aurez donc au moins besoin de ces traduction pour que le système fonctionne coorectement.
Un bon point de départ consiste à copier le fichier Anglais .po et de traduire au moins les messages techniques, et peut être aussi les messages de validation.
Les IDs de message technique sont facilement reconnaissables; ils sont tous en capitales. Vous n’avez pas traduire le message ID comme comme pour les autres messages; au lieu de cela, vous fournissez la variante locale correcte pour la valeur Anglaise prévue. Par exemple, avec DATETIME_FORMAT (ou DATE_FORMAT ou TIME_FORMAT), ceci pourrait être le format de la chaîne que vous voulez utiliser dans votre langue. Le format est identique au format des chaînes utilisées par la balise de gabarit now.
Une fois que le LocaleMiddleware determine la préférence de l’utilisateur, il met à disposition cette varaibel sous la forme de request.LANGUAGE_CODE pour chaque objet requête. N’hésitez pas à lire cette valeur dans le code de votre vue. Voici un simple exemple:
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.")
Notez qu’avecla traduction statique (c’est à dire sans middleware), la langue se trouve dans settings.LANGUAGE_CODE, alors qu’avec une traduction dynamique (midleware), elle se trouve dans request.LANGUAGE_CODE.
La vue de redirection set_language
Par commodité, Django propose une vue, django.views.i18n.set_language, qui fixe la préférence de langue d’un utilisateur puis redirige sur la page précédente.
Acitvez cette vue en ajoutant la ligne suivante à votre URLconf:
(r'^i18n/', include('django.conf.urls.i18n')),
(Notez que cet exemple rends la vue disponible à l’adresse /i18n/setlang/.)
Cette vue s’attend à être appelée via la méthode GET, avec un paramètre language fixé dans la chaîne de requête. Si le support de session est activé, la vue conserve le choix de la langue dans la session de l’utilisateur. Autrement, elle conserve le choix de la langue dans une cookie django_language.
Après avoir déterminer le choix de la langue, Django redirige l’utilisateurn en suivant cet algorithme:
- Django recherche un paramètre next dans la chaîne de requête.
- S’il n’existe pas ou s’il est vide, Django essaie l’URL du Referer de l’en-tête.
- Si cela est vide - admettons que le navigateur d’un utilisateur supprime cet en-tête - alors l’utilisateur sera redirigé vers / (la racine du site) en ultime recours.
Voici un exemple de code HTML pour un gabarit:
<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>
Utiliser les chaînes de traduction dans vos propres projets
Django recherche les traductions ensuivant cet algorithme:
- Tout d’abord, il cherche un répertoire de locale dans le dossier de l’application correspondant à la vue qui est appelée. S’il trouve une traduciton pour la langue sélectionnée, la traduction sera installée.
- Ensuite, il recherche un répertoire locale dans le dossier du projet. S’il trouve une traduction, celle-ci sera installée.
- Enfin, il regarde vers la traduction de base dans django/conf/locale.
De cette façon, vous pouvez écrire des applications qui embarquent leurs propres traductions, et vous pouvez outrepasser les traductions de base dans le chemin de votre projet. Vous pouvez aussi simplement construire un gros projet à partir de plusieurs applications et placer toutes les traductions dans un seul gros fichier message de ce projet. C’est vous qui décidez.
Note
Si vous utilisez des paramètres configurés manuellement, le répertoire locale dans votre dossier de projet ne sera pas examiné, puisque Django perd alors la capacité d’explorer l’emplacement de votre répertoire de projet. (Django utilise normalement l’emplacement du fichier de paramètres pour déterminer cela, or le fichier de paramètres n’existe pas si vous avez configurer manuellement vos paramètres).
Tous les dépôts de fichier message sont structurés de la même façon:
- $APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
- $PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
- tous les chemins listés dans le LOCALE_PATHS de votre fichier de paramètres sont recherchés dans cet ordre <language>/LC_MESSAGES/django.(po|mo)
- $PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)
Pour créer des fichiers message, utilisez le même outil make-messages.py tout comme pour les fichiers message. Vous aurez seulement besoin d’être à la bonne place - dans le répertoire où se trouve soit conf/locale (dans le cas de l’arborescence source), soit dans le répertoire ou se trouve locale/ (dans le cas des messages de l’application ou des messages du projet). Vous utiliserez de même compile-messages.py pour produire les fichiers binaires django.mo qui sont utilisés par gettext.
Les fichiers message des applications sont un peu plus compliqués à trouver - ils nécessitent LocaleMiddleware. Si vous n’utilisez pas le middleware, seul les fichiers message de Django et les fichiers message de projet seront traités.
Finallement, vous devrez penser à la structure de vos fichiers de traduction. Si vos applications doivent être livrées à d’autres utilisateur pour être utilisées dans d’autres projets, vous pourriez vouloir utiliser des traductions spécifique à l’application. Utiliser des traductions spécifiques à l’application et des traductions de projet peut générer des problèmes étranges avec make-messages. make-messages parcourera tous les répertoires appartenant au chemin courant et peut donc placer des IDs de message dans le fichier de message du projet qui sont déjà dans les fichiers message de l’application.
La manière la plus simple de s’en sortir consiste à stocker les applications qui ne font pas partie du projet (et qui embarquent leurs propres traductions) à l’exterieur de l’arborescence du projet. De cette façon, make-messages au niveau du projet traduira uniquement les chaînes qui sont connectées à votre projet, sans les chaînes qui sont distribuées indépendament.
Traductions et Javascript
Ajouter des traductions au Javascript pose quelques problèmes:
- le code JavaScript n’a pas accès à une implémentation de gettext.
- le code JavaScript n’a pas accès aux fichiers .po ou .mo; ils doivent être fournis par le serveur.
- les catalogues de traductions pour Javascript doivent être gardés aussi petits que possible.
Django fourni une solution intégrée pour ces problèmes: elle transmet les traductions au Javascript, ainsi pouvez-vous appeler gettext et consort depuis Javascript.
La vue javascript_catalog
La principale solution à ces problèmes est la vue javascript_catalog, qui génère une bibliothèque de Javascript avec des fonctions qui imitent l’interface gettext, plus un tableau de chaînes de traduction. Ces chaînes de traduction sont extraites de l’application, du projet, ou du coeur de Django, selon ce que vous avez spécifié soit dans info_dict ou dans l’URL.
Vous l’utilisez comme ceci:
js_info_dict = {
'packages': ('your.app.package',),
}
urlpatterns = patterns('',
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog',
js_info_dict),
)
Chaque chaîne présentes dans les packages doit répondre à la syntaxe pointée de Python (le même format que les chaînes dans INSTALLED_APPS) et doit se référer à un paquet qui contient un répertoire locale. Si vous précisez de multiples paquets, tous ces catalogues sont fusionnés en un seul catalogue. C’est pratique si vous dépendez d’un Javascript qui utilise les chaînes de diverses applications.
Vous pouvez rendre la vue dynamique en placant les paquets dans le patron d’URL:
urlpatterns = patterns('',
(r'^jsi18n/(?P<packages>\S+?)/$,
'django.views.i18n.javascript_catalog'),
)
Avec ceci, vous précisez les paquets sous forme de liste de noms de paquets délimités par des signes plus (+) au sein de l’URL. C’est particulièrement pratique si votre page utilise du code provenant d’applications différentes, que celles-ci changent souvent et que vous ne voulez pas tous placer dans un seul gros fichier catalogue. Par mesure de sécurité , ces valeurs peuvent être présentes uniquement dans django.conf ou dans tout paquet présent dans le paramètre INSTALLED_APPS.
Utiliser le catalogue de traduction Javascript
Pour utiliser le catalogue, ajoutez simplement le script dynamiquement généré comme ceci:
<script type="text/javascript" src="/path/to/jsi18n/"></script>
Voici comment le site d’administration récupère le catalogue de traduction depuis le serveur. Lorsque le catalogue est chargé, votre code Javascript peut utiliser l’interface standard gettext pour y accéder:
document.write(gettext('this is to be translated'));
Il y à même une interface ngettext et une fonction d’interpolation de chaîne:
d = {
count: 10
};
s = interpolate(ngettext('this is %(count)s object', 'this are
%(count)s objects', d.count), d);
La fonction interpolate supporte à la fois l’interpolation postionelle et l’interpolation nommée. Ainsi le code précédent pourrait avoir été écrit comme suit:
s = interpolate(ngettext('this is %s object', 'this are %s objects', 11),[11]);
Cette syntaxe d’interpolation est tirée de Python. Vous ne devriez pas aller plus haut avec la chaîne d’interpolation, cependant - cela reste du Javascript, aussi le code aura à faire des substitutions d’expressions rationelles de façon répétitive. Ce n’est pas aussi rapide que l’interpolation de chaîne sous Python, aussi conservez ces cas pour les fois ou vous en aureez vraiment besoin (par exemple, en conjonction avec ngettext pour produire une pluralisation propre).
Créer des catalogues de traduction Javascript
Vois créez et mettez à jour les catalogues de traduciton de la même façon que pour les autres catalogues de traduction de Django: avec l’outil `make-messages.py`. La seule différence est que vous devez fournir un paramètre -d djangojs, comme ceci:
make-messages.py -d djangojs -l de
Ceci crée ou met à jour le catalogue de traduction Javascript pour l’Allemand. Après avoir mis à jour le catalogue de traduction, lancez simplement compile-messages.py de la même façon que vous le feriez avec les catalogues de traduction Django normaux.
Notes pour les utilisateurs familier de gettext
Si vous connaissez gettext, vous pouvez notez la façon particulière dont Django effectue les traductions:
- le domaine de chaîne est django ou djangojs. Le domaine de chaîne est utilisé pour différencier des programmes qui stockent leurs données dans une bibliothèque standard de fichier message (habituellement /usr/share/locale/). Le domaine django est utilisé pour Python et pour les chaînes de traduction de gabarit, et est chargé globalement dans les catalogues de traduction. Le domaine djangojs est seulement utilisé pour les catalogues de traduction Javascript afin de s’assurer que ceux-ci sont aussi petits que possible.
- Django utilise uniquement gettext et gettext_noop. C’est parce que Django utilise toujours les chaînes DEFAULT_CHARSET en interne. Il n’y a pas beaucoup de bénéfice à utliser ugettext, puisque vous aurez toujours besoin de produire de l’UTF-8 quoi qu’il en soit.
- Django n’utilise pas xgettext seul. Il utilise un emballage Python autour de xgettext et de msgfmt. C’est principalement par commodité.
Et ensuite ?
Ce chapitre assure la couverture des fonctionnalités de Django. Vous devez en savoir assez pour commencer à produire vos propres sites Django.
Cependant, écrire le code est seulement la première étape dans le déploiement réussi d’un site web. Les deux prochains chapitres couvrent les choses dont vous devrez connaître si vous voulez que votre site survive au monde réel. Le chapitre 19 aborde la façon dont vous pouvez sécuriser vos sites et vos utilisateurs des attaques malicieuses, et le chapitre 20 détaille la façon de déployer une application Django sur un ou plusieurs serveurs.
Dernière modification: 2008-08-05 15:22:44.320418