Přejít k navigační liště

Zdroják » Různé » Django: Internacionalizace

Django: Internacionalizace

Články Různé

Pokud webový projekt chcete zpřístupnit co nejširšímu publiku, musíte ho lokalizovat do dalších jazyků, nebo alespoň umožnit, aby byl v případě potřeby lokalizován. Django na tyto účely využívá externí nástroj gettext.

Opět si na začátku představíme trochu terminologie: lokalizace znamená přizpůsobení aplikace určitému národnostnímu prostředí. To kromě překladu zahrnuje i kupříkladu správné formátování čísel a časových údajů. Oproti tomu internacionalizace znamená zmezinárodnění, tedy úprava našeho jednojazyčného produktu, abychom mohli přidávat další jazyky. Tyto termíny se v anglickém IT žargonu často zkracují na výrazy l10n a i18n — čísla zde znázorňují počet vynechaných znaků v původních slovech.

Nastavení projektu

Abychom umožnili lokalizaci, musíme mít v konfiguračním souboru settings.py povoleno několik nastavení. První je konstanta LANGUAGE_CODE, jež znázorňuje výchozí jazyk projektu. Podle této konstanty se mimo jiné nastaví jazyk administračního rozhraní. Jazykový kód pro češtinu je 'cs', pro slovenštinu 'sk', kódy dalších jazyků naleznete v seznamu identifikátorů. Další důležitou konstantou je LANGUAGES. Ta pomocí n-tic zapisuje použité jazyky v projektu a jejich názvy. A konečně, pomocí konstanty USE_I18N máme možnost úplně vypnout internacionalizaci, v případě, že se bez ní obejdeme.

Jestliže bychom chtěli náš projekt přeložit do angličtiny, nastavení by vypadalo takto:

LANGUAGE_CODE = 'cs'

LANGUAGES = (
    ('cs', u'Čeština'),
    ('en', u'English'),
)

USE_I18N = True

Dalším krokem je vytvoření adresáře, do kterého se budou ukládat překlady do jednotlivých jazyků. Konvence nám stanovuje ho vytvořit přímo v adresáři projektu a pojmenovat ho locale. Jakmile ho vytvoříte, můžeme se vrhnout na zadávání lokalizačních řetězců. Pomocí nich určíme, které kusy kódu mají být přeloženy.

Vyznačení textu k překladu

Před započetím práce na každém novém projektu bychom se měli vždy nejprve rozmyslet, jestli daný projekt bude potřeba někdy přeložit do dalšího jazyka. Ne, že by nebylo možné projekt internacionalizovat později. Je jenom mnohem otravnější procházet již hotovou aplikaci a vyznačovat lokalizační řetězce, než to dělat průběžně. Také je vhodné určit, zda je lepší psát texty v mateřském jazyce nebo v angličtině. Pokud na projektu pracují (nebo budou výhledově pracovat) vývojáři různých národností, angličtina by měla být samozřejmostí.

Lokalizačních řetězce se mohou vyskytnout na dvou různých místech — v šablonách a v aplikačním kódu (tedy např. v modelech nebo v pohledech).

Lokalizace šablon

Na začátku každé šablony obsahující lokalizační řetězce musí být uveden kód pro načtení internacionalizačního modulu {% load i18n %}. Poté jenom stačí řetězce označovat pomocí značky {% trans "řetězec k překladu" %}. Pro delší texty lze použít párovou značku {% blocktrans %}řetězec k překladu{% endblocktrans %}.

Lokalizace pythonového kódu

V modulu django.utils.translation máme k dispozici několik lokalizačních funkcí, nás budou zajímat pouze tyto: ugettext, ugettext_lazy a string_concat. První dvě mají stejnou funkci, vyznačí daný text k překladu, liší se jenom v době překladu řetězce. Funkce ugettext přeloží řetězec do daného jazyka řetězec ihned, kdežto funkce ugettext_lazy až když je to potřeba. Proto je úspornější používat funkci ugettext_lazy. Obě funkce jsou často používané, takže bývá zvykem je při importování zkracovat na pouhou pomlčku:

from django.utils.translation import ugettext as _

Parametrem těchto dvou funkcí je unikódový řetězec:

translated = _(u'řetězec k překladu')

Další zajímavou funkcí je string_concat, jež slouží ke spojování překladových řetězců. Protože funkce ugettext_lazy vrací objekt, který se přeloží na řetězec, až bude třeba, běžné spojování řetězců pomocí operátoru plus nefunguje. Proto musíme požadované řetězce vložit do seznamu a ten předat jako parametr funkci string_concat. V tomto seznamu můžeme libovolně míchat obyčejné řetězce s překladovými:

concated = string_concat([_(u'řetězec'), ' k ', _(u'překladu')])

Když už teď víme, jak v projektu vyznačit lokalizační řetězce, ukážeme si, jak z nich vytvořit překladové soubory.

Překladové soubory

Unixový nástroj gettext, který je v Djangu využíván pro překlad, pracuje se dvěma druhy souborů: jedny jsou textové a mají příponu .po a ty druhé, s příponou .mo, jsou binární. V textovém souboru budeme udržovat překlad, který je potřeba při každé změně převést do binárního souboru.

Vytváření a aktualizace se dělá pomocí příkazu django-admin.py makemessages. Je potřeba ho napsat do příkazové řádky v adresáři projektu a připojit k němu parametr -l se specifikací jazyka. Tedy například řetězce pro angličtinu vygenerujeme takto:

$ django-admin.py makemessages -l en
processing language en

Abyste nemuseli při aktualizaci mnoha jazyků psát tento příkaz vícekrát, můžete použít parametr -a, ten aktualizuje řetězce pro všechny jazyky. Každopádně, po provedení příkazu se nám vytvořil nový soubor locale/en/LC_MESSAGES/django.po, který má zhruba takovýto obsah:

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSIONn"
"Report-Msgid-Bugs-To: n"
"POT-Creation-Date: 2009-11-04 20:01+0100n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONEn"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>n"
"Language-Team: LANGUAGE <LL@li.org>n"
"MIME-Version: 1.0n"
"Content-Type: text/plain; charset=UTF-8n"
"Content-Transfer-Encoding: 8bitn"

#: templates/base.html:20
msgid "Titulní strana"
msgstr ""

Prvních sedmnáct řádků souboru jsou metainformace o souboru, např. údaje o autorovi a překladateli. Je vhodné přepsat předvyplněné údaje svými, zvláště když pracujete na větším projektu. Lokalizační řetězce uvozuje klíčové slovo msgid (dvacátý řádek) a překlad je potřeba napsat do uvozovek za klíčové slovo msgstr (dvacátý první řádek). V případě, že se jedná o delší překlad, můžeme nechat uvozovky za klíčovým slovem prázdné a text rozepsat do uvozovek na další řádky. Django mimochodem automaticky do komentáře vypisuje umístění řetězce, což považuji za užitečné. Za povšimnutí také stojí, že poznámka začínající čárkou a slovem fuzzy (šestý řádek) značí, že následující překlad bude ignorován.

Když doplníme překlady do příslušných polí, je potřeba soubory převést do binární podoby. Toho docílíme napsáním příkazu django-admin.py compilemessages:

$ django-admin.py compilemessages
processing file django.po in /home/dqd/hrajeme_si/locale/en/LC_MESSAGES

Tím se nám vytvoří soubory s příponou .mo, jež se používají při generování stránek.

Přepínání jazyků

Jakmile máme všechno přeloženo, potřebujeme dát návštěvníkovi možnost zvolit si jazykovou verzi webu. Tuto funkci zajišťuje kontextový procesor django.core.context_processors.i18n. Je potřeba ho tedy mít zařazený v konfigurační konstantě TEMPLATE_CONTEXT_PROCESSORS. (O kontextových procesorech jsme se zmiňovali v minulém dílu.) Kromě toho musíme v souboru settings.py do konstanty MIDDLEWARE_CLASSES přidat položku 'django.middleware.locale.LocaleMiddleware':

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

Pomocí tohoto nastavení se uživateli do prohlížeče ukládá cookie s aktuálně zvoleným jazykem. Kontextový procesor nám poskytuje několik proměnných pro výběr jazyka. Přidáme si proto do hlavní šablony templates/base.html tento kód:

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

<form action="/i18n/setlang/" method="POST" id="lang">
<select name="language" onchange="this.form.submit();">
{% for lang in LANGUAGES %}
<option value="{{ lang.0 }}"{% ifequal lang.0 LANGUAGE_CODE %} selected{% endifequal %}>{{ lang.1 }}</option>
{% endfor %}
</select>
<noscript><input type="submit"></noscript>
</form>

Na prvních dvou řádcích načteme aktuálně vybraný jazyk do proměnné LANGUAGE_CODE a seznam všech dostupných jazyků do proměnné LANGUAGES. Poté zobrazíme formulář pro změnu jazyka se všemi možnostmi. Uživatel je po výběru jazyka pomocí JavaScriptu přesměrován na stránku, která mu nastaví správný jazyk. Tu jsme si zatím nedefinovali, proto otevřeme soubor urls.py a na jeho konec připíšeme následující kód:

urlpatterns += patterns('',
    # ...
    (r'^i18n/', include('django.conf.urls.i18n')),
)

A takto vypadá výsledek:

Django 13 - internationalization

Související odkazy

V následujícím dílu si konečně ukážeme přemístění projektu na ostrý server.

Komentáře

Subscribe
Upozornit na
guest
17 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Mintaka

Tip pro zhýčkané uživatele GUI. Editory překladových souborů: http://gorm.po.dk/ a živejší projekt http://www.gted.org/.

Jakub Vrána

Zásadní chyba tohoto řešení je v tom, že identifikátor jazyka se nepřenáší v URL. Jedním z důsledků je, že do indexu vyhledávačů se dostane jen jedna jazyková verze. Další problém tkví v tom, že stránky nejdou kešovat v HTTP.

Funkce string_concat je ukázaná na zcela nevhodném příkladě.

Proč v příkladu pro stažení není soubor settings.py? Je to jeden z nejdůležitějších souborů a rekonstruovat ho ručně dá dost práce.

Jakub Vrána

Lepší příklad by byl třeba string_concat([_(u’Sta­v‘), ‚: ‚, _(u‘nový‘)]. Příklad z článku rozděluje řetězec, který by měl být přeložen vcelku a ještě navíc z něj kus nepřeloží. Z dobrého příkladu by měla být vidět nejen syntaxe, ale i smysluplné použití.

Při chybějícím settings.py tedy nechápu, proč se v článku projekt vůbec nabízí ke stažení. Stejný argument by šel totiž použít i na jeho ostatní části. Verze pro stažení by měla sloužit k tomu, aby si čtenář ověřil, jestli má všechno správně nebo aby se podíval, jestli to vůbec správně funguje. Když tam chybí nejdůležitější soubor, tak to oba účely plní špatně.

os.path

ad 3)settings.py je závislý na adresářové struktuře, protože s ním tak nakládáte vy, stačilo by v něm použít os.path a na adresářové struktuře by již závislý nebyl, tím že v tomto seriálu tyto cesty píšete „natvrdo“ dáváte dle mého názoru úplným začátečníkům špatné návyky.

calyx
calyx

To fakt netusim, mimo wsgi som django app nikdy nenasadzoval.

PMD

Zdravím, zdá se mi, že žádoucí chování by bylo: pokud není v url specifikován jazyk a není nastaveno cookie, zjisti jazyk z hlavičky requestu a teprve pokud ten není mezi podporovanými jazyky, použij nastavení settings.py. Podle výsledku nastav cookie a přesměruj nás na správně „lokalizované“ url.
Vámi odkazovaná aplikace je sice užitečná pro vyhledávače, ale uživatelům na drzovku nastaví implicitní jazyk podle settings.py a proto nejde použít zároveň s LocaleMiddleware, které si čte ACCEPT_LANGUAGE a stará se o ty cookies. Tlučou se spolu kdo má pravdu.
Docela by mě potěšilo, kdyby existovalo _univerzální_ řešení a nemusel bych ho psát sám. Znáte nějaké?

.

Co ti brani napsat si vlastni middleware, kterej bude v URL resit identifikator jazyka?

Vrat se k PHP a Django nech na pokoji.

kiot

Dobry den,
chtel bych mit web pripraven k multijazycnosti s EN identifikatory, ale zatim mit vse pouze v CZ jazyce.

Identifikatory {% trans „i want this in EN“ %}.

Problem je v tom, ze pokud prijdu na stranky s jazykem pro ktery neni preklad (EN, PT, …) , tak potrebuju nastavit, aby se automaticky nastavila CZ verze.

Muzete me poradit, jak se toho da dosahnout?

Dekuji,
Tom

kiot

Zajimave je, ze pokud si vlozim do projektu (‚cs‘, u’Čeština‘), tak se mi objevi error serveru. nevite cim to muze byt?

Muj kus kodu ze settings.py

LANGUAGE_CODE = ‚cs‘
LANGUAGES = (
(‚cs‘, u’Čeština‘)
)
USE_I18N = True

MIDDLEWARE_CLASSES = (
‚django.middle­ware.common.Com­monMiddleware‘,
‚django.contrib­.sessions.mid­dleware.Sessi­onMiddleware‘,
‚django.contrib­.auth.middlewa­re.Authentica­tionMiddleware‘,
‚django.middle­ware.locale.Lo­caleMiddleware‘,
)

TEMPLATE_CONTEX­T_PROCESSORS = (
„django.core.con­text_processor­s.auth“,
„django.core.con­text_processor­s.debug“,
„django.core.con­text_processor­s.i18n“,
„django.core.con­text_processor­s.media“,
 )

kiot

Mam tam znacku:
# coding=UTF-8

Pri pouziti
# coding: utf-8 me to napise unsupported encoding

Mintaka

Používám na začátku souboru
# –– coding: utf-8 –

( ty -*- jsou tam pro parádu ale leckde se používají)

Kromě téhle informace, která se hledá (tuším) na prvních dvou řádcích souboru je také dobré si zkontrolovat, zda editor ukládá daný soubor opravdu ve formátu utf-8

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.