=== Recipes about Internationalization === This section of the [[wxPython Cookbook]] contains recipes about Internationalization and Localization of wxPython apps. If you can't find what you're looking for then please consider figuring it out and then writing a recipe for the Cookbook so others won't have to go through the same pain you did. === Overview of Internationalization === See the overview of source code internationalization (inside [[Internationalization]]) using the gettext system supported by Python and wxPython. You can use the mki18n.py script (attached to the [[Internationalization]] page) to create the Portable Object (.po) and Machine Object (.mo) files easily for all Python source code (or C, C++,....) files inside a directory. The mki18n Python script uses the GNU gettext tools. === Recipes === * [[Internationalization]] Overview === A Simple walk-through === Once I read the [[Internationalization]] overview and got everything installed as instructed, I felt the need to play with it. Here's what I did and what I wrote. 1. The first thing I did was create a folder called "i18ntest". It seems easiest if the folder name and the project name match. I copied the mki18n.py file into that folder. (Note: I had to edit the file slightly to get it to run, removing a "unixpath" call that didn't work on my machine.) 2. I then wrote the following code, in a file called "i18ntest.py". {{{ #!python # This example is provided with no promises or warranties whatsoever # import wxPython from wxPython import wx # import Python gettext import gettext # Declare Menu Constants MENU_FILE_EXIT = 101 MENU_LANGUAGE_ENGLISH = 201 MENU_LANGUAGE_SPANISH = 202 MENU_LANGUAGE_FRENCH = 203 class I18ntest(wx.wxFrame): """ This class demonstrates Internationalization. """ def __init__(self): """ Create I18ntest form. """ # Install gettext. Once this is done, all strings enclosed in "_()" will automatically be translated. gettext.install('i18ntest', './locale', unicode=False) # Define supported languages self.presLan_en = gettext.translation('i18ntest', './locale', languages=['en']) # English self.presLan_es = gettext.translation('i18ntest', './locale', languages=['es']) # Spanish self.presLan_fr = gettext.translation('i18ntest', './locale', languages=['fr']) # French # Install English as the initial language self.presLan_en.install() # Define the main Frame for the Application. Note that the Application Title in enclosed in _() wx.wxFrame.__init__(self, None, -4, _('MiniApp'), size = (500,250), style=wx.wxDEFAULT_FRAME_STYLE|wx.wxNO_FULL_REPAINT_ON_RESIZE) # Set the background color to White self.SetBackgroundColour(wx.wxWHITE) # Menu Bar # File Menu # Create a MenuBar self.menuBar = wx.wxMenuBar() # Build a Menu Object to go into the Menu Bar self.menu1 = wx.wxMenu() # Define the Exit Menu. Note that the menu text and hint are enclosed in _() self.menu1.Append(MENU_FILE_EXIT, _("E&xit"), _("Quit Application")) #Place the Menu Item in the Menu Bar. Note that the menu text is enclosed in _() self.menuBar.Append(self.menu1, _("&File")) # Language Menu # Build a Menu Object to go into the Menu Bar self.menu2 = wx.wxMenu() # Define the Menu Options. Note that menu names are enclosed in _(). I chose to leave the Help Text untranslated, as I don't want it to change. self.menu2.Append(MENU_LANGUAGE_ENGLISH, _("&English"), "Do You Speak English? (Spoken slowly and loudly)") self.menu2.Append(MENU_LANGUAGE_SPANISH, _("&Spanish"), "Se habla Espanol?") self.menu2.Append(MENU_LANGUAGE_FRENCH, _("&French"), "Parlez vous Francais?") #Place the Menu Item in the Menu Bar. Note the menu text is enclosed in _() self.menuBar.Append(self.menu2, _("&Language")) # Place the Menu on the Application Frame. self.SetMenuBar(self.menuBar) #Define Events for the Menu Items wx.EVT_MENU(self, MENU_FILE_EXIT, self.CloseWindow) wx.EVT_MENU_RANGE(self, MENU_LANGUAGE_ENGLISH, MENU_LANGUAGE_FRENCH, self.Language) # Create two labels on the Frame. (I won't mess with Sizers or Layout Constraint here.) # The first label will display the selected Language. It does NOT need translatable text. self.txt = wx.wxStaticText(self, -1, 'English', pos=(10, 20)) # The second label will contain translatable text, but I don't need to put any text in it yet. self.txt2 = wx.wxStaticText(self, -1, '', pos=(10, 40)) # Create a Status Bar self.CreateStatusBar() # Show the Frame self.Show(True) # Populate all text in the installed language self.UpdateText() # In order to be able to update all of the text on the Application Frame, I have written a method that # updates all of the text. def UpdateText(self): """ Update all Text on the Application Frame. """ # Set the Frame Title self.SetTitle(_('MiniApp')) # Define the String for the second wxStaticText label and the Status Bar str = _("Hello. This is translatable.") # Set the wxStaticText label self.txt2.SetLabel(str) # Update the text for the Main Menubar Items self.menuBar.SetLabelTop(0, _("&File")) self.menuBar.SetLabelTop(1, _("&Language")) # Update the text and Help Strings for the File Menu Items self.menu1.SetLabel(MENU_FILE_EXIT, _('E&xit')) self.menu1.SetHelpString(MENU_FILE_EXIT, _("Quit Application")) # Update the text for the Language Menu Items. (I do not want to update the Help Strings.) self.menu2.SetLabel(MENU_LANGUAGE_ENGLISH, _('&English')) self.menu2.SetLabel(MENU_LANGUAGE_SPANISH, _('&Spanish')) self.menu2.SetLabel(MENU_LANGUAGE_FRENCH, _('&French')) # Update the Status Bar Text self.SetStatusText(str) def CloseWindow(self, event): """ Method that Exits the program. """ self.Close() def Language(self, event): """ Method to change application Language based on a Menu Selection """ if event.GetId() == MENU_LANGUAGE_ENGLISH: # Set Language to English self.presLan_en.install() # Set wxStaticText Label to indicate that English has been selected self.txt.SetLabel("English") elif event.GetId() == MENU_LANGUAGE_SPANISH: # Set Language to Spanish self.presLan_es.install() # Set wxStaticText Label to indicate that Spanish has been selected self.txt.SetLabel("Espanol") elif event.GetId() == MENU_LANGUAGE_FRENCH: # Set Language to French self.presLan_fr.install() # Set wxStaticText Label to indicate that French has been selected self.txt.SetLabel("Francais") # Update all Application text to reflect Language change self.UpdateText() class MyApp(wx.wxApp): """ Define Application """ def OnInit(self): """ Initialize the Application """ # Define the Frame using the I18ntest class frame = I18ntest() # Set the Frame as the Top Window self.SetTopWindow(frame) return True # Define the Application and run it app = MyApp(0) app.MainLoop() }}} 3. Next, I created a file called "app.fil" which contained only one line. {{{ i18ntest.py }}} 4. I then issued the following command at the DOS prompt: {{{ python mki18n.py –-p }}} 5. This created a file called "messages.pot", which is the template for the ".po" (portable object) files used for translation. {{{
#: i18ntest.py:49 i18ntest.py:91 msgid "&English" msgstr "" #: i18ntest.py:43 i18ntest.py:85 msgid "&File" msgstr "" #: i18ntest.py:51 i18ntest.py:93 msgid "&French" msgstr "" #: i18ntest.py:53 i18ntest.py:86 msgid "&Language" msgstr "" #: i18ntest.py:50 i18ntest.py:92 msgid "&Spanish" msgstr "" #: i18ntest.py:41 i18ntest.py:88 msgid "E&xit" msgstr "" #: i18ntest.py:81 msgid "Hello. This is translatable." msgstr "" #: i18ntest.py:30 i18ntest.py:79 msgid "MiniApp" msgstr "" #: i18ntest.py:41 i18ntest.py:89 msgid "Quit Application" msgstr "" }}} 6. I copied messages.pot to create files called "i18ntest_en_US.po", "i18ntest_es_ES.po", and "i18ntest_fr_FR.po". I then edited these files as best I could to provide the necessary translations. (I don't know either Spanish or French, so can't vouch for the translations presented here. If something translates to "My hovercraft is filled with eels," don't blame me. If you know Spanish or French, feel free to correct the translations!) (Check this list for ValidI18nCodes.) i18ntest_es_ES.po: {{{
#: i18ntest.py:49 i18ntest.py:91 msgid "&English" msgstr "&Inglés" #: i18ntest.py:43 i18ntest.py:85 msgid "&File" msgstr "&Archivo" #: i18ntest.py:51 i18ntest.py:93 msgid "&French" msgstr "&Francés" #: i18ntest.py:53 i18ntest.py:86 msgid "&Language" msgstr "&Lenguage" #: i18ntest.py:50 i18ntest.py:92 msgid "&Spanish" msgstr "&Español" #: i18ntest.py:41 i18ntest.py:88 msgid "E&xit" msgstr "&Salir" #: i18ntest.py:81 msgid "Hello. This is translatable." msgstr "Hola. Esto es traducible." #: i18ntest.py:30 i18ntest.py:79 msgid "MiniApp" msgstr "Applicación Pequeña" #: i18ntest.py:41 i18ntest.py:89 msgid "Quit Application" msgstr "Salir de la Applicación" }}} i18ntest_fr_FR.po {{{
#: i18ntest.py:49 i18ntest.py:91 msgid "&English" msgstr "&Anglais" #: i18ntest.py:43 i18ntest.py:85 msgid "&File" msgstr "&Fichier" #: i18ntest.py:51 i18ntest.py:93 msgid "&French" msgstr "&Français" #: i18ntest.py:53 i18ntest.py:86 msgid "&Language" msgstr "&Langue" #: i18ntest.py:50 i18ntest.py:92 msgid "&Spanish" msgstr "&Espagnol" #: i18ntest.py:41 i18ntest.py:88 msgid "E&xit" msgstr "&Quitter" #: i18ntest.py:81 msgid "Hello. This is translatable." msgstr "Bonjour. Ceci est traduisible." #: i18ntest.py:30 i18ntest.py:79 msgid "MiniApp" msgstr "Petite application" #: i18ntest.py:41 i18ntest.py:89 msgid "Quit Application" msgstr "Quitter l'application" }}} 7. I then typed the following at the DOS prompt: {{{ python mki18n.py –-m –-e }}} This created a "locale" folder with folders for the English, Spanish, and French translation ".mo" files properly distributed. (The "-e" parameter ensures that an English "translation" is created.) 8. Finally, I typed: {{{ python i18ntest.py }}} to run my sample program. It actually worked! I hope you find this helpful. - David Woods . Wisconsin Center for Education Research, University of Wisconsin, Madison === Comments === Pierre Rouleau, Nov 11,2003: - I updated some of the French text. Really only minor touches to the French text inside the example written by David. Note that French and Spanish and other languages use accentuated letters. Inside real applications, you would place the accentated characters inside the .po files. However, I don't currently know how to put accents inside a wiki text page. If someone knows how to do this, feel free to update the translations. - The mki18n.py file I posted originally was missing the definition of the function unixpath(). . It has been updated. See the [[Internationalization]] page for the attachment. Dave Cridland, 05/03/2004 (That's March. l11n is down the corridor...) - I ran through the Spanish and French to get some translations (which were probably correct anyway), and figure out where the accents go. PPW, 26-Jul-2006: - Apparently the mki18n.py file was updated by E. A. Tacao 2006-04-21 since this tutorial was written: I tried to use the Pierre Rouleau's mki18n.py script at http://wiki.wxpython.org/index.cgi/Internationalization and I ran into a couple of issues: (1) it supports only the two letter ISO language code (for example, "pt"), and not a language code followed by the country code ("pt_BR") and (2) things become weird if the app's directory contains spaces. I fixed both issues here (Python 2.3.5, wxPython 2.6.3.0 ansi, msw XP (pt_BR)), and replaced the 'iso639_languageDict' by some code that finds out what are the currently wx supported canonical forms of current locale names. It seems to be working. http://www.archivesat.com/wxPython/thread596595.htm So I initially got stuck at Step 7., where "mki18n.py -m -e" would not output anything at all. Files called "i18ntest_en.po", "i18ntest_es.po", and "i18ntest_fr.po" will not work any more as country code settings are expected. Use files called "i18ntest_en_US.po", "i18ntest_es_ES.po", and "i18ntest_fr_FR.po" instead. A whole list of current locale settings supported by wxPython 2.6.3-unicode can be found at ValidI18nCodes. (I amended the tutorial in step 6. accordingly.) === Accents in .po === perico, 15-09-06 Let's go to see an example with spanish accents. If you want to write accents in your .po files, you have to do two things: 1.- Spanish codification is ISO-8859-1. So when the .po file is generated, you only have to change one of the lines that are at the begining of the file. Have a look at this line: "Content-Type: text/plain; charset=iso-8859-1\n". 2.- From this moment you can write spanish accents in the file, just as you would do in your favorite text processor, and they will appear after translation. If you are not spanish, let's say you are norwegian, so you have to look for you ISO language. I think it is really easy, the problem has been to find it out. Don't you think? === Accents in .po mk2 === Much better to use Unicode (UTF-8) for all po files. No need to hunt for specific ISO code, ability to mix different codes together at will, better compability. "Content-Type: text/plain; charset=utf-8\n" - ianaré 2007-08-12