Hlavní navigace

Resource soubory a i18n ve wxPythonu

Pavel Šibal

V dnešní části našeho seriálu o programování ve wxPythonu rozvedeme předchozí díl o vytvoření a použití resource souboru a lokalizaci programu s využitím GNU prográmků. Podíváme se především na vkládání ikon a obrázků a lokalizace našich programů.

Vkládání ikon a obrázků

Začneme s trochou praxe – občas při programování GUI vyvstane problém s načítáním různých ikon a obrázků obsažených ve vašem programu. Pokud toto budete řešit otevřením přímo z určeného adresáře, vyvstane problém s cestami. Dejme tomu, že máte ikony uloženy v podadresáři „icons/“. Pokud budete program někam distribuovat, museli byste zkopírovat i všechny obrázky a zajistit, aby byly v adresářové struktuře programu. To by se dalo vyřešit např. pomocí:

import os
icoPath = os.path.join( os.getcwd(), 'icons', '' )
... 

A později přidávat k údajům o jménu souboru i proměnnou icoPath. Výše uvedené řešení sice funguje, ale není moc elegantní. Lepším řešením je vytvořit „resource“ soubor, který přímo obsahuje dané obrázky a ikony. Ve wxPythonu existuje modul wx.tools.img2py, který provádí konverzi obrázků ve formátu PNG do textového souboru, který je pak nahrán do programu místo jednotlivých obrázků pomocí příkazu „import …“.

Nyní si to vyzkoušíme prakticky. Např. pomocí Gimpu vytvořte nějakou ikonu (o velikosti 24×24) a uložíme ji pod názvem „ico01.png“ do adresáře „HelloWorld/i­cons/“. Rovněž ji uložíme jako „ico01.ico“ (použijeme ji později v překladu do binárky pro MS Windows). V adresáři „HelloWorld/ vytvoříme soubor s názvem "code-img.py“ s následujícím obsahem:

#!/usr/bin/env python
import sys, os, glob
from wxPython.tools import img2py

output = 'ui/myImgRes.py'
files = glob.glob('icons/*.png')
dst=open(output, 'w')
dst.write('#Boa:PyImgResource:\n\n#')
for file in files:
    name = os.path.splitext(os.path.basename(file))[0]
    if file == files[0]:
        cmd = "-u -i -n %s %s %s" % (name, file, output)
    else:
        cmd = "-a -u -i -n %s %s %s" % (name, file, output)
    img2py.main(cmd.split()) 

Tento prográmek je mírně poupravenou verzí (pro použití s Boa Constructorem), která byla publikována na stránkách www.koders.com. Pokud se vám nebude chtít jej opisovat, můžete si jej stáhnout (bude se Vám hodit i pro pozdější využití). Po jeho spuštění se vám vytvoří v adresáři „HelloWorld/ui/“ soubor s názvem „myImgRes.py“, který obsahuje jak obrázky z podadresáře „icons/“, tak i funkce potřebné pro jejich načtení ve formátu, který je podporován / vyžadován „Boa Constructorem“ a je kompatibilní s wxPythonem.

Spusťte „Boa Constructor“ a otevřete si příklad z předchozího dílu. V Editoru se přepněte se na záložku „App1“. V podzáložce Application stiskněte klávesu „Insert“ a vyberte soubor „HelloWorld/u­i/myImgRes.py“, čímž soubor s obrázky přidáme k našemu projektu. Nezapomeňte uložit (starší verze Boa Constructoru v linuxu byla poměrně nestabilní;-).

Otevřeme „frmHelloWorld“ a pomocí tlačítka icon spustíme „Designer panel“. V Inspectoru (pravé okno) v záložce „Props“ v položce „Icon“ vybereme náš soubor „myImgRes.py“. Otevře se nám okno „Select resource“ a v něm si vybereme naši ikonu „ico01“.

Boa 2 - 02

a ukončíme pomocí tlačítka icon „Designer panel“. Opět nezapomeňte uložit.

Lokalizace programu

Python vnitřně využívá pro zpracování znaků národních abeced „unicode“. Na jednu stranu je to výhoda, ale museli byste všechny zdrojové kódy ukládat rovněž v unicode. A i když neplánujete psát vícejazyčnou verzi programu, je dle mého názoru a zkušeností vhodné napsat program v angličtině a teprve posléze jej lokalizovat. Pro lokalizaci programu, který využívá knihovny wxPython, lze s uspěchem využít standardní GNU prográmky:

  • xgettext – v zadaných souborech vyhledá všechny řetězce určené k přeložení. Vytváří katalog zpráv („.po“)
  • msgfmt – zkompiluje katalog zpráv („.po“) do jeho binární podoby (*.mo")
  • poEdit – slouží ke komfortní úpravě katalogu zpráv.

Všechny tyto prográmky se dají sehnat jak pro Linux (jsou součástí většiny standardních distribucí), tak i pro MS Windows.

A nyní k samotné lokalizaci. Zobrazíme v „Editoru“ „frmHelloWorld“ a v podzáložce „Source“ vložíme za „import wx“ (zhruba 3. řádek shora) následující kód:

from wx import GetTranslation as _ 

Pokud chceme nejaký řetězec lokalizovat, stačí nyní použít _(‚nějaký text k lokalizaci‘). Takto zapsaný řetězec je pak akceptován jak programem „xgettext“, tak i samotnou wx knihovnou. Jako první ve formuláři upravíme nadpis „title=u'Hello World !‚“ na „title=_(‘Hello World !')“

...
        wx.Frame.__init__(self, id=wxID_FRMHELLOWORLD, name=u'frmHelloWorld',
              parent=prnt, pos=wx.Point(359, 140), size=wx.Size(164, 102),
              style=wx.DEFAULT_FRAME_STYLE, title=_('Hello World !'))
... 

rovněž i v tlačítku „btClose“ upravíme nápis a Tool Tip – „label=u'&Close'“ na „label=_(‚&Close‘)“ a „self.btClose­.SetToolTipStrin­g(u'Close me')“ na „self.btClose­.SetToolTipStrin­g(_(‚Close me‘))“.

...
        self.btClose = wx.Button(id=wxID_FRMHELLOWORLDBTCLOSE, label=_('&Close'),
              name=u'btClose', parent=self, pos=wx.Point(40, 49),
              size=wx.Size(75, 23), style=0)
        self.btClose.SetToolTipString(_('Close me'))
... 

Jako poslední upravíme v „stHello“ položku „label=u'Hello world !‚“ na "label=_(‘Hello world !')

...
        self.stHello = wx.StaticText(id=wxID_FRMHELLOWORLDSTHELLO,
              label=_('Hello World !'), name=u'stHello', parent=self,
              pos=wx.Point(0, 18), size=wx.Size(156, 28),
              style=wx.ALIGN_CENTRE)
... 

Aby nám překlady (binární podoba katalogu zpráv – „*.mo“) začaly fungovat, musíme mu nejprve ukázat, co se má vlastně načíst a posléze jej inicializovat. V praxi to znamená, že upravíme v „Editoru“ soubor „App1.py“ zhruba následovně:

...

import wx 
import os, gettext 
...

class BoaApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers()
        path = os.getcwd()
        localedir = os.path.join( path, "i18n" )
        langid = wx.LANGUAGE_DEFAULT
        domain = "helloworld"
        self.mylocale = wx.Locale(langid)
        self.mylocale.AddCatalogLookupPathPrefix(localedir)
        self.mylocale.AddCatalog(domain)
        self.mytranslation = gettext.translation(domain, localedir,
[self.mylocale.GetCanonicalName()], fallback = True)
        self.mytranslation.install()
        self.main = ui.frmHelloWorld.create(None)

        ... 

Samotný katalog zpráv („i18n/hello.po“) vytvoříme pomocí příkazu (předpokládám, že jste v adresáři „HelloWorld/“):

xgettext -d helloworld -s --no-location -o i18n/cs_CZ/helloworld.po
ui/frmHelloWorld.py 

Tento soubor otevřeme např. pomocí programu poEdit a lokalizujeme jej. Obsluha tohoto programu je naprosto triviální, pouze nezapomeňte vyplnit údaje z menu „Katalog ->Nastavení“ – předejdete následným chybám.

Boa 2 - 03

Nyní nastal čas na přeložení souboru „i18n/hello.po“ na „i18n/cz_CZ/h­ello.mo“. K tomu slouží prográmekmsgfmt. Překlad provedeme pomocí:

msgfmt -v -o ./i18n/cs_CZ/helloworld.mo ./i18n/cs_CZ/helloworld.po 

Pro dnešek snad stačí. Původně jsem chtěl ještě probrat vytvoření spustitelných binárek jak pro Linux tak i pro MS Windows, ale nechám to do příštího dílu seriálu. I dneska máte k dispozici zdrojové kódy.

Našli jste v článku chybu?