Django
Umiędzynarodowienie
Szukaj…
Składnia
- gettext (wiadomość)
- ngettext (liczba pojedyncza, liczba mnoga, liczba)
- ugettext (wiadomość)
- tekst nieokreślony (liczba pojedyncza, mnoga, liczba)
- pgettext (kontekst, wiadomość)
- npgettext (kontekst, liczba pojedyncza, liczba mnoga, liczba)
- gettext_lazy (wiadomość)
- ngettext_lazy (liczba pojedyncza, mnoga, liczba = Brak)
- ugettext_lazy (wiadomość)
- ungettext_lazy (liczba pojedyncza, liczba mnoga, liczba = brak)
- pgettext_lazy (kontekst, wiadomość)
- npgettext_lazy (kontekst, liczba pojedyncza, liczba mnoga, liczba = Brak)
- gettext_noop (wiadomość)
- ugettext_noop (wiadomość)
Wprowadzenie do internacjonalizacji
Konfiguracja
settings.py
from django.utils.translation import ugettext_lazy as _
USE_I18N = True # Enable Internationalization
LANGUAGE_CODE = 'en' # Language in which original texts are written
LANGUAGES = [ # Available languages
('en', _("English")),
('de', _("German")),
('fr', _("French")),
]
# Make sure the LocaleMiddleware is included, AFTER SessionMiddleware
# and BEFORE middlewares using internationalization (such as CommonMiddleware)
MIDDLEWARE_CLASSES = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
]
Oznaczanie ciągów znaków jako możliwych do przetłumaczenia
Pierwszym krokiem w tłumaczeniu jest oznaczenie ciągów jako możliwych do przetłumaczenia . Przekazuje je przez jedną z funkcji gettext
(patrz sekcja Składnia ). Na przykład, oto przykładowa definicja modelu:
from django.utils.translation import ugettext_lazy as _
# It is common to import gettext as the shortcut `_` as it is often used
# several times in the same file.
class Child(models.Model):
class Meta:
verbose_name = _("child")
verbose_name_plural = _("children")
first_name = models.CharField(max_length=30, verbose_name=_("first name"))
last_name = models.CharField(max_length=30, verbose_name=_("last name"))
age = models.PositiveSmallIntegerField(verbose_name=_("age"))
Wszystkie ciągi enkapsulowane w _()
są teraz oznaczone jako możliwe do przetłumaczenia. Po wydrukowaniu będą one zawsze wyświetlane jako enkapsulowany ciąg znaków, niezależnie od wybranego języka (ponieważ tłumaczenie nie jest jeszcze dostępne).
Tłumaczenie ciągów znaków
Ten przykład jest wystarczający, aby rozpocząć tłumaczenie. Przez większość czasu będziesz chciał oznaczyć ciągi jako przetłumaczalne, aby przewidzieć potencjalną internacjonalizację swojego projektu. Zatem jest to omówione w innym przykładzie .
Tłumaczenie Lazy kontra Non-Lazy
Podczas korzystania z tłumaczenia nieliniowego ciągi są tłumaczone natychmiast.
>>> from django.utils.translation import activate, ugettext as _
>>> month = _("June")
>>> month
'June'
>>> activate('fr')
>>> _("June")
'juin'
>>> activate('de')
>>> _("June")
'Juni'
>>> month
'June'
Podczas korzystania z lenistwa tłumaczenie występuje tylko wtedy, gdy jest rzeczywiście używane.
>>> from django.utils.translation import activate, ugettext_lazy as _
>>> month = _("June")
>>> month
<django.utils.functional.lazy.<locals>.__proxy__ object at 0x7f61cb805780>
>>> str(month)
'June'
>>> activate('fr')
>>> month
<django.utils.functional.lazy.<locals>.__proxy__ object at 0x7f61cb805780>
>>> "month: {}".format(month)
'month: juin'
>>> "month: %s" % month
'month: Juni'
Musisz używać leniwego tłumaczenia, gdy:
- Tłumaczenie może nie zostać aktywowane (język nie wybrany), gdy
_("some string")
jest obliczany - Niektóre ciągi mogą być oceniane tylko podczas uruchamiania (np. W atrybutach klas, takich jak definicje modeli i pól formularza)
Tłumaczenie w szablonach
Aby włączyć tłumaczenie w szablonach, musisz załadować bibliotekę i18n
.
{% load i18n %}
Podstawowe tłumaczenie odbywa się za pomocą znacznika szablonu trans
.
{% trans "Some translatable text" %}
{# equivalent to python `ugettext("Some translatable text")` #}
Tag szablonu trans
obsługuje kontekst:
{% trans "May" context "month" %}
{# equivalent to python `pgettext("May", "month")` #}
Aby dołączyć symbole zastępcze do ciągu tłumaczenia, jak w:
_("My name is {first_name} {last_name}").format(first_name="John", last_name="Doe")
Będziesz musiał użyć tagu szablonu blocktrans
:
{% blocktrans with first_name="John" last_name="Doe" %}
My name is {{ first_name }} {{ last_name }}
{% endblocktrans %}
Oczywiście zamiast "John"
i "Doe"
możesz mieć zmienne i filtry:
{% blocktrans with first_name=user.first_name last_name=user.last_name|title %}
My name is {{ first_name }} {{ last_name }}
{% endblocktrans %}
Jeśli first_name
i last_name
są już w twoim kontekście, możesz nawet pominąć klauzulę with
:
{% blocktrans %}My name is {{ first_name }} {{ last_name }}{% endblocktrans %}
Można jednak używać tylko zmiennych kontekstowych „najwyższego poziomu”. To NIE zadziała:
{% blocktrans %}
My name is {{ user.first_name }} {{ user.last_name }}
{% endblocktrans %}
Wynika to głównie z tego, że nazwa zmiennej jest używana jako symbol zastępczy w plikach tłumaczeń.
blocktrans
szablonu blocktrans
akceptuje również pluralizację.
{% blocktrans count nb=users|length }}
There is {{ nb }} user.
{% plural %}
There are {{ nb }} users.
{% endblocktrans %}
Wreszcie, niezależnie od biblioteki i18n
, możesz przekazywać ciągi tekstowe do znaczników szablonów, używając składni _("")
.
{{ site_name|default:_("It works!") }}
{% firstof var1 var2 _("translatable fallback") %}
To jest magiczny wbudowany system szablonów django, który naśladuje składnię wywołań funkcji, ale to nie jest wywołanie funkcji. _("It works!")
Przekazany do default
znacznika szablonu jako ciąg '_("It works!")'
Który jest następnie analizowany jako ciąg do przetłumaczenia, tak jak name
byłaby analizowana jako zmienna, a "name"
byłaby parsowane jako ciąg.
Tłumaczenie ciągów znaków
Aby przetłumaczyć ciągi, będziesz musiał utworzyć pliki tłumaczenia. Aby to zrobić, django jest dostarczane z makemessages
polecenia zarządzania.
$ django-admin makemessages -l fr
processing locale fr
Powyższe polecenie odkryje wszystkie ciągi oznaczone jako możliwe do przetłumaczenia w zainstalowanych aplikacjach i utworzy jeden plik językowy dla każdej aplikacji do tłumaczenia na francuski. Na przykład, jeśli masz tylko jedną aplikację myapp
zawierającą przetłumaczalne ciągi, utworzy to plik myapp/locale/fr/LC_MESSAGES/django.po
. Ten plik może wyglądać następująco:
# 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 VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-07-24 14:01+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: myapp/models.py:22
msgid "user"
msgstr ""
#: myapp/models.py:39
msgid "A user already exists with this email address."
msgstr ""
#: myapp/templates/myapp/register.html:155
#, python-format
msgid ""
"By signing up, you accept our <a href=\"%(terms_url)s\" "
"target=_blank>Terms of services</a>."
msgstr ""
Najpierw musisz wypełnić symbole zastępcze (podkreślone dużymi literami). Następnie przetłumacz ciągi znaków. msgid
to ciąg znaków oznaczony jako możliwy do przetłumaczenia w kodzie. msgstr
to miejsce, w którym musisz napisać tłumaczenie ciągu powyżej.
Jeśli ciąg znaków zawiera symbole zastępcze, musisz je również uwzględnić w tłumaczeniu. Na przykład przetłumaczysz najnowszą wiadomość w następujący sposób:
#: myapp/templates/myapp/register.html:155
#, python-format
msgid ""
"By signing up, you accept our <a href=\"%(terms_url)s\" "
"target=_blank>Terms of services</a>."
msgstr ""
"En vous inscrivant, vous acceptez nos <a href=\"%(terms_url)s\" "
"target=_blank>Conditions d'utilisation</a>"
Po ukończeniu pliku tłumaczenia będziesz musiał skompilować pliki .po
do plików .mo
. Odbywa się to przez wywołanie polecenia zarządzania compilemessages
:
$ django-admin compilemessages
To wszystko, teraz dostępne są tłumaczenia.
Aby zaktualizować pliki tłumaczeń podczas wprowadzania zmian w kodzie, możesz ponownie uruchomić django-admin makemessages -l fr
. Spowoduje to zaktualizowanie plików .po
, zachowując istniejące tłumaczenia i dodając nowe. Usunięte ciągi będą nadal dostępne w komentarzach. Aby zaktualizować pliki .po
dla wszystkich języków, uruchom django-admin makemessages -a
. Po zaktualizowaniu plików .po
nie zapomnij ponownie uruchomić django-admin compilemessages
aby wygenerować pliki .mo
.
Przypadek użycia Noop
(u)gettext_noop
pozwala oznaczyć ciąg jako (u)gettext_noop
do przetłumaczenia bez faktycznego tłumaczenia.
Typowy przypadek użycia ma miejsce, gdy chcesz zalogować wiadomość dla programistów (w języku angielskim), ale chcesz także wyświetlić ją klientowi (w żądanym języku). Możesz przekazać zmienną do gettext
, ale jej zawartość nie zostanie odkryta jako ciąg do przetłumaczenia, ponieważ jest ona, z definicji, zmienną. .
# THIS WILL NOT WORK AS EXPECTED
import logging
from django.contrib import messages
logger = logging.getLogger(__name__)
error_message = "Oops, something went wrong!"
logger.error(error_message)
messages.error(request, _(error_message))
Komunikat o błędzie nie pojawi się w pliku .po
i musisz pamiętać, że istnieje, aby dodać go ręcznie. Aby to naprawić, możesz użyć gettext_noop
.
error_message = ugettext_noop("Oops, something went wrong!")
logger.error(error_message)
messages.error(request, _(error_message))
Teraz ciąg "Oops, something went wrong!"
zostaną odkryte i będą dostępne w pliku .po
po wygenerowaniu. Błąd będzie nadal rejestrowany w języku angielskim dla programistów.
Częste pułapki
niewyraźne tłumaczenia
Czasami makemessages
może myśleć, że ciąg znaleziony do tłumaczenia jest nieco podobny do już istniejącego tłumaczenia. .po
to w pliku .po
specjalnym fuzzy
komentarzem, takim jak ten:
#: templates/randa/map.html:91
#, fuzzy
msgid "Country"
msgstr "Länderinfo"
Nawet jeśli tłumaczenie jest poprawne lub zaktualizowałeś je, aby je poprawić, nie będzie ono użyte do przetłumaczenia twojego projektu, chyba że usuniesz fuzzy
linię komentarza.
Ciągi wielowierszowe
makemessages
analizuje pliki w różnych formatach, od zwykłego tekstu po kod Pythona, i nie jest przeznaczony do przestrzegania wszystkich możliwych reguł dotyczących ciągów wieloliniowych w tych formatach. Przez większość czasu będzie działać dobrze z łańcuchami pojedynczej linii, ale jeśli masz taką konstrukcję:
translation = _("firstline"
"secondline"
"thirdline")
firstline
tylko firstline
do tłumaczenia. Rozwiązaniem tego jest unikanie używania ciągów wielowierszowych, gdy jest to możliwe.