Dvojitá alchymie VIII - v množném čísle

10. 11. 2013 20:47 Petr Blahoš

Podívejte se na všechny díly seriálu nebo na zdrojáky příkladu.

Všiml jsem si, že jsem si rozepsal díl 5, ale nikdy jsem ho nedopsal ani nepublikoval, takže tam máme díru. Měl být o lokalizaci. Třeba ho někdy napíšu, ale bude o něčem jiném.

Je to taková zajímavá věc. Když máme desktopovou aplikaci, lokalizovanou, tak někdy na začátku se nějak vybere jazyk, zaregistruje se funkce _(…), a je to. Naproti tomu, webová aplikace, která má navíc být vícejazyčná to má složitější. Tam prostě nejde mít globální _(…), protože tam žádné globální nastavení jazyka není – je nanejvýš per-request. To jsem si v Pylons 1 neuvědomoval, protože ty mi na to udělaly threadlocal _(…). To mi zjednodušilo volání _(…), ale skrylo to fakt, že takhle to prostě nefunguje. A jelikož mám rád, když vím, jak věci fungují, tak jsem se toho v Pyramid rád zbavil. Takže beru jako fakt, že ten překlad opravdu můžu udělat jen tam, kde mám request, a když ho nemám, tak mi tam utíká logika. Pokud vidíte v modelu volání _(…), tak kousek výš uvidíte definici

def _(s):
    return s
Tam se nic nepřekládá, ale označí se text, který pak gettext vytáhne do souboru pot. Zároveň mě nečeká žádné překvapení např. v testech. A teď už do práce.

Krok 12

# nezapomeňte git pull
cd step12
python setup.py develop

pserve --reload development.ini

Dnes si tam jenom přidáme podporu pro pluralizaci. Ač jsem dosáhl jistého věku, pluralizaci jsem zatím nikdy nepoužil. Snažil jsem se hledat nějaké konvence, ale na žádnou jsem nenarazil, možná proto, že pluralizace je tak málo častá, že se asi volá přímo funkce ngettext nebo ungettext. Pro ty, kdo neví nic: Např. v angličtině máme 2 formy, jednu pro jednotné číslo, druhou pro množné číslo. V češtině mám 3. Jednu pro 1, druhou pro 2, 3, 4, a třetí pro zbytek. Např.:

  • Jedno rajče
  • 2, 3, 4 rajčata
  • 5, 6, 12, 93 rajčat

No a v kódu se to dělá tak, že napíšete:

  ungettext("One tomato", "%d tomatoes", count)

Následně setup.py extract_messages a setup.py update_catalog vám vygeneruje v po souboru:

msgid "One tomato"
msgid_plural "%d tomatoes"
msgstr[0] "Jedno rajče"
msgstr[1] "%d rajčata"
msgstr[2] "%d rajčat"
Zdalipak víte, proč to takhle nemůže fungovat?

Teď z jiného soudku. Ověříme si, že lokalizace funguje i ve validátorech, které jsme si nadefinovali v našem kódu. Uděláme si jednoduchý validátor, který ověří, že zadané číslo je sudé. V model/tools.py:

def even(value, field=None):
    """
        A validator, successful if the value is even.
    """
    value = integer(value, field)
    if value is None:
        return None
    if value % 2:
        try:
            _ = field.parent.active_request.translate
        except:
            _ = lambda x: x
        raise ValidationError(_('Value is not even'))
    return value

model/fieldsets.py to použijeme:

class Person(FieldSet):
    def __init__(self, model, session=None, data=None, prefix=None,
                 format=u'%(model)s-%(pk)s-%(name)s',
                 request=None):
        super(Person, self).__init__(model, session, data, prefix, format, request)
        self.configure(options=[ self.number.validate(faapp.model.tools.even), ])
Tady si také uvědomte, že není třeba nikde psát, že máme speciální FieldSet pro Person. To nám zařídí ty podpůrné funkce v model/resources.py.

A teď zpět k té pluralizaci. Ten překlad by se použil asi takto:

ungettext("One tomato", "%d tomatoes", count) % count

Z toho nám vypadne pro count=5:

"%d rajčat" % count

jenže pro count=1 dostaneme:

"Jedno rajče" % count

Takže v pluralizovaných textech musíme bezpodmínečně nutně dělat:

  ungettext("One tomato", "%(COUNT)d tomatoes", count)
  ungettext("One tomato", "%(COUNT)d tomatoes", count) % { "COUNT": count }

Sdílet