Сразу оговорюсь, что python и gtk у меня 2й версии.
Неожиданное желание сделать надписи на главной форме разрабатываемой мной программы не только русскими, но и на других языках (а вдруг она нужна будет не только мне), вынудило начать поиск методов реализации. С наскока найти рабочую документацию по локализации glade форм не удалось, потому было решено написать в будущем эту статью, чтобы другим повезло больше.
Чего нет в этой статье:
— как делать перевод формы в процессе работы. Этого я не смог найти, а хотелось бы знать…
— как делать перевод текста в .py коде в процессе работы.
— пива, блэкджека и остального тут тоже конечно нет.
Перевод будет осуществляться с помощью указания локали при старте (или локали по умолчанию).
Первое что понадобится — готовая glade форма. Т.к. я специально делал простенький тест, чтобы разобраться, то и формочка у меня простая, с меткой, кнопкой и чекбоксом.
Также понадобится программа на питоне (раз уж я о нём пишу), которая эту форму показывает:
Заодно она будет выводить строку в консоль, чтобы показать, что и в консоли язык меняется.
Локализовывать можно по разному. Например, самому писать код обработки каждой строки/виджета и обновлять строки в зависимости от какой-то управляющей команды. В этом есть крошечный плюс — все действия можно производить в любой момент работы программы, но остальное — минусы. И выглядеть и работать это будет ужасно.
Сам собой напрашиватся вопрос — как не изобретать велосипед с квадратными колёсами? Оказалось, что всё уже есть, нужно только уметь воспользоваться (как и в большинстве случаев).
Для начала нужно сбросить настройки локалей в дефолтовые для пользователя (обычно определены в переменной окружения LANG). Это поможет избавиться от возможных проблем в многонитевой программе. Для подобного действия понадобится подключить модуль locale.
Далее будем пользоваться возможностями модуля gettext (потому его тоже придётся подключить). Глянув на его документацию, можно заметить, что ему необходимы некие «binary .mo files».
.mo файлы — это файлы со списком всех переводимых строк программы.
Как их получить:
Сначала нужно выдрать все строки из glade формы (надписи на виджетах), но делать это вручную, конечно же, не стоит. Для этого воспользуемся набором команд intltool:
при желании дополнительные параметры можно посмотреть в man`е. Последний входной параметр — файл glade формы, откуда нужно выдирать текст. Эта команда создаст файл localize.glade.h:
где, как видно, перечислены все текстовые строки из виджетов формы.
Вспоминаем, что в питоновском файле тоже есть строка, которую хотелось бы переводить. Выдирать её не нужно, надо просто пометить так, чтобы команды локализации поняли, что её нужно переводить. Поэтому документация предлагает записать строку в виде:
т.е. взять в _()
Как можно увидеть выше, в localize.glade.h строки обёрнуты в N_(). Это также своего рода маркер.
Итак, весь необходимый текст помечен и теперь его надо собрать в одном месте. В этом нам поможет команда:
Опция --keyword показывает программе на какие метки обращать внимание при сборе, потому их тут две "_" и «N_». --output задаёт имя выходного файла, а дальше идёт список всех файлов, где нужно искать метки (можно сделать вывод, что метки могут быть и другими, но я с ними не возился, т.к. это не особо важно).
Это шаблон для всех будущих файлов с переводами. Его редактировать не надо. Теперь настало время определиться с языками. Я использовал английский (en_US), русский (ru) и немецкий (de_DE) (на самом деле из немецкого я знаю только «гитлер капут» и «хандехох» и то не письменно, но до кучи пусть будет). Для каждого из языков нужно из шаблона создать локализованный файл. Это делается командами:
В результате появляется три файла ru.po, de.po и en_US.po. Внутри они почти такие же пустые как и шаблон, но заполнена шапка, правда не совсем теми данными, что мне бы хотелось (возможно чего-то не указал в ключах) и без перевода строк на другие языки (естесственно). Перевод придётся вбивать руками в поля msgstr. Также я поправил charset на utf-8, размер символа на 16 бит и e-mail.
В итоге получилось:
Казалось бы — зачем делать родную версию (у меня по умолчанию стоит en_US). Но ведь у другого человека родной может быть, например, de_DE, а он захочет увидеть перевод на английский. Да и разработчики gettext рекомендуют таки создавать.
Некоторые программисты предлагают пользоваться также командой intltool-merge для внесения изменений обратно в форму, но т.к. у меня при этом создавалась точно такая же форма без всяких изменений, то не вижу в ней необходимости.
Итак, есть всё для создания .mo файлов. Это делается командами:
Опция -o (вполне очевидно) указывает каталог, в котором готовый файл будет лежать, причём стоит заметить, что верхний каталог (тут «locale») должен быть один и тот же для всех файлов .mo, а далее должен идти каталог с именем локали (ru, de, en_US, de_DE, ru_RU — т.к. последние два без диалектов, то программы их сокращают до первых букв, но можно использовать и полные имена). Называться он должен так же как указываемый в питоновской программе домен, только с ".mo". Также LC_MESSAGES является одним из нескольких возможных вариантов имени внутреннего каталога (тоже, думаю, лучше использовать одни и те же имена).
Вот что говорит официальная документация по этому поводу:
В итоге получились файлы с переводами строк, которые уже можно использовать в программe (такие манипуляции производятся не только для python/glade).
Вернёмся к программе на python`е.
Сперва настроим gettext. После сброса настроек локалей нужно подсказать ему где брать файлы переводов и какие именно файлы. Для этого у меня введены две переменные:
То, что APP совпадает с названием программы — это осталось от документации, но, думаю, там может быть любое имя. Хотя если смотреть на .mo файлы с названием программы, к которой они относятся, то гораздо проще понимать что к чему.
APP — это имя .mo файлов, DIR — общий каталог с языками. Объяснение этого факта gettext`у производится строками:
Теперь надо объяснить питону, что делать со строками вида _(). Для этого "_" присваивается функция взятия перевода из указанного файла. Записать это можно двумя путями:
или
что, если глянуть в код модуля, одно и то же. Так что имеет смысл выбрать запись покороче.
Этого достаточно, чтобы текст в .py файлах выводился на нужном языке. А для локализации glade формы требуется объяснить gtk, где брать перевод и какой:
Итоговый код:
Запуск:


А тут честно вылетает ошибка, т.к. немецкая локаль у меня не подключена. Таким образом, для использования локали, её нужно добавить в настройках графической оболочки.
На этом всё.
Upd:
Про Builder. Если форма для libglade уже есть, то можно попытаться либо сконвертировать с помощью libglade-convert (у меня выдало ошибку), либо нарисовать новую для builder.
Код будет выглядеть так:
И, как верно заметил Moonrise, Content-Transfer-Encoding официально рекомендуется устанавливать в 8 бит (т.е. не изменять).
Неожиданное желание сделать надписи на главной форме разрабатываемой мной программы не только русскими, но и на других языках (а вдруг она нужна будет не только мне), вынудило начать поиск методов реализации. С наскока найти рабочую документацию по локализации glade форм не удалось, потому было решено написать в будущем эту статью, чтобы другим повезло больше.
Чего нет в этой статье:
— как делать перевод формы в процессе работы. Этого я не смог найти, а хотелось бы знать…
— как делать перевод текста в .py коде в процессе работы.
— пива, блэкджека и остального тут тоже конечно нет.
Перевод будет осуществляться с помощью указания локали при старте (или локали по умолчанию).
Первое что понадобится — готовая glade форма. Т.к. я специально делал простенький тест, чтобы разобраться, то и формочка у меня простая, с меткой, кнопкой и чекбоксом.
xml код формы
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.5 on Tue Nov 13 12:44:47 2012 -->
<glade-interface>
<widget class="GtkWindow" id="window1">
<child>
<widget class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">label text</property>
</widget>
</child>
<child>
<widget class="GtkButton" id="button1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label" translatable="yes">button text</property>
<property name="response_id">0</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="checkbutton1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">checkbutton text</property>
<property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>
Также понадобится программа на питоне (раз уж я о нём пишу), которая эту форму показывает:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygtk, gtk, gtk.glade
print "hello to me"
wTree = gtk.glade.XML("localize.glade", "window1")
window = wTree.get_widget("window1")
window.connect("delete_event", gtk.main_quit)
window.show_all()
gtk.main()
Заодно она будет выводить строку в консоль, чтобы показать, что и в консоли язык меняется.
Локализовывать можно по разному. Например, самому писать код обработки каждой строки/виджета и обновлять строки в зависимости от какой-то управляющей команды. В этом есть крошечный плюс — все действия можно производить в любой момент работы программы, но остальное — минусы. И выглядеть и работать это будет ужасно.
Сам собой напрашиватся вопрос — как не изобретать велосипед с квадратными колёсами? Оказалось, что всё уже есть, нужно только уметь воспользоваться (как и в большинстве случаев).
Для начала нужно сбросить настройки локалей в дефолтовые для пользователя (обычно определены в переменной окружения LANG). Это поможет избавиться от возможных проблем в многонитевой программе. Для подобного действия понадобится подключить модуль locale.
locale.setlocale(locale.LC_ALL, '')
Далее будем пользоваться возможностями модуля gettext (потому его тоже придётся подключить). Глянув на его документацию, можно заметить, что ему необходимы некие «binary .mo files».
.mo файлы — это файлы со списком всех переводимых строк программы.
Как их получить:
Сначала нужно выдрать все строки из glade формы (надписи на виджетах), но делать это вручную, конечно же, не стоит. Для этого воспользуемся набором команд intltool:
intltool-extract --type=gettext/glade localize.glade
при желании дополнительные параметры можно посмотреть в man`е. Последний входной параметр — файл glade формы, откуда нужно выдирать текст. Эта команда создаст файл localize.glade.h:
char *s = N_("label text");
char *s = N_("button text");
char *s = N_("checkbutton text");
где, как видно, перечислены все текстовые строки из виджетов формы.
Вспоминаем, что в питоновском файле тоже есть строка, которую хотелось бы переводить. Выдирать её не нужно, надо просто пометить так, чтобы команды локализации поняли, что её нужно переводить. Поэтому документация предлагает записать строку в виде:
print _("hello to me")
т.е. взять в _()
Как можно увидеть выше, в localize.glade.h строки обёрнуты в N_(). Это также своего рода маркер.
Итак, весь необходимый текст помечен и теперь его надо собрать в одном месте. В этом нам поможет команда:
xgettext --language=Python --keyword=_ --keyword=N_ --output=show_form.pot show_form.py localize.glade.h
Опция --keyword показывает программе на какие метки обращать внимание при сборе, потому их тут две "_" и «N_». --output задаёт имя выходного файла, а дальше идёт список всех файлов, где нужно искать метки (можно сделать вывод, что метки могут быть и другими, но я с ними не возился, т.к. это не особо важно).
В результате получился файл следующего содержания:
# SOME DESCRIPTIVE TITLE.
# Copyright 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: 2012-11-14 13:54+0300\n»
«PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n»
«Last-Translator: FULL NAME <EMAIL@ADDRESS>\n»
«Language-Team: LANGUAGE <LL@li.org>\n»
«Language: \n»
«MIME-Version: 1.0\n»
«Content-Type: text/plain; charset=CHARSET\n»
«Content-Transfer-Encoding: 8bit\n»
#: show_form.py:14
msgid «hello to me»
msgstr ""
#: localize.glade.h:1
msgid «label text»
msgstr ""
#: localize.glade.h:2
msgid «button text»
msgstr ""
#: localize.glade.h:3
msgid «checkbutton text»
msgstr ""
# Copyright 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: 2012-11-14 13:54+0300\n»
«PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n»
«Last-Translator: FULL NAME <EMAIL@ADDRESS>\n»
«Language-Team: LANGUAGE <LL@li.org>\n»
«Language: \n»
«MIME-Version: 1.0\n»
«Content-Type: text/plain; charset=CHARSET\n»
«Content-Transfer-Encoding: 8bit\n»
#: show_form.py:14
msgid «hello to me»
msgstr ""
#: localize.glade.h:1
msgid «label text»
msgstr ""
#: localize.glade.h:2
msgid «button text»
msgstr ""
#: localize.glade.h:3
msgid «checkbutton text»
msgstr ""
Это шаблон для всех будущих файлов с переводами. Его редактировать не надо. Теперь настало время определиться с языками. Я использовал английский (en_US), русский (ru) и немецкий (de_DE) (на самом деле из немецкого я знаю только «гитлер капут» и «хандехох» и то не письменно, но до кучи пусть будет). Для каждого из языков нужно из шаблона создать локализованный файл. Это делается командами:
msginit --locale=ru --input=show_form.pot
msginit --locale=en_US --input=show_form.pot
msginit --locale=de_DE --input=show_form.pot
В результате появляется три файла ru.po, de.po и en_US.po. Внутри они почти такие же пустые как и шаблон, но заполнена шапка, правда не совсем теми данными, что мне бы хотелось (возможно чего-то не указал в ключах) и без перевода строк на другие языки (естесственно). Перевод придётся вбивать руками в поля msgstr. Также я поправил charset на utf-8, размер символа на 16 бит и e-mail.
В итоге получилось:
ru.po
# Russian translations for PACKAGE package.
# Copyright 2012 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# <aaa@bbb>, 2012.
#
msgid ""
msgstr ""
«Project-Id-Version: PACKAGE VERSION\n»
«Report-Msgid-Bugs-To: \n»
«POT-Creation-Date: 2012-11-14 13:54+0300\n»
«PO-Revision-Date: 2012-11-14 13:58+0300\n»
«Last-Translator: <aaa@bbb>\n»
«Language-Team: Russian\n»
«Language: ru\n»
«MIME-Version: 1.0\n»
«Content-Type: text/plain; charset=utf-8\n»
«Content-Transfer-Encoding: 16bit\n»
«Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11? 0: n%10>=2 && n»
"%10<=4 && (n%100<10 || n%100>=20)? 1: 2);\n"
#: show_form.py:14
msgid «hello to me»
msgstr «привет мне»
#: localize.glade.h:1
msgid «label text»
msgstr «метка»
#: localize.glade.h:2
msgid «button text»
msgstr «кнопка»
#: localize.glade.h:3
msgid «checkbutton text»
msgstr «галочка»
# Copyright 2012 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# <aaa@bbb>, 2012.
#
msgid ""
msgstr ""
«Project-Id-Version: PACKAGE VERSION\n»
«Report-Msgid-Bugs-To: \n»
«POT-Creation-Date: 2012-11-14 13:54+0300\n»
«PO-Revision-Date: 2012-11-14 13:58+0300\n»
«Last-Translator: <aaa@bbb>\n»
«Language-Team: Russian\n»
«Language: ru\n»
«MIME-Version: 1.0\n»
«Content-Type: text/plain; charset=utf-8\n»
«Content-Transfer-Encoding: 16bit\n»
«Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11? 0: n%10>=2 && n»
"%10<=4 && (n%100<10 || n%100>=20)? 1: 2);\n"
#: show_form.py:14
msgid «hello to me»
msgstr «привет мне»
#: localize.glade.h:1
msgid «label text»
msgstr «метка»
#: localize.glade.h:2
msgid «button text»
msgstr «кнопка»
#: localize.glade.h:3
msgid «checkbutton text»
msgstr «галочка»
de.po
(да, там не немецкий язык, но это вобщем-то не важно):
# German translations for PACKAGE package.
# Copyright 2012 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# <aaa@bbb>, 2012.
#
msgid ""
msgstr ""
«Project-Id-Version: PACKAGE VERSION\n»
«Report-Msgid-Bugs-To: \n»
«POT-Creation-Date: 2012-11-14 13:54+0300\n»
«PO-Revision-Date: 2012-11-14 14:14+0300\n»
«Last-Translator: <aaa@bbb>\n»
«Language-Team: German\n»
«Language: de\n»
«MIME-Version: 1.0\n»
«Content-Type: text/plain; charset=utf-8\n»
«Content-Transfer-Encoding: 16bit\n»
«Plural-Forms: nplurals=2; plural=(n != 1);\n»
#: show_form.py:14
msgid «hello to me»
msgstr «f»
#: localize.glade.h:1
msgid «label text»
msgstr «d»
#: localize.glade.h:2
msgid «button text»
msgstr «g»
#: localize.glade.h:3
msgid «checkbutton text»
msgstr «e»
# German translations for PACKAGE package.
# Copyright 2012 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# <aaa@bbb>, 2012.
#
msgid ""
msgstr ""
«Project-Id-Version: PACKAGE VERSION\n»
«Report-Msgid-Bugs-To: \n»
«POT-Creation-Date: 2012-11-14 13:54+0300\n»
«PO-Revision-Date: 2012-11-14 14:14+0300\n»
«Last-Translator: <aaa@bbb>\n»
«Language-Team: German\n»
«Language: de\n»
«MIME-Version: 1.0\n»
«Content-Type: text/plain; charset=utf-8\n»
«Content-Transfer-Encoding: 16bit\n»
«Plural-Forms: nplurals=2; plural=(n != 1);\n»
#: show_form.py:14
msgid «hello to me»
msgstr «f»
#: localize.glade.h:1
msgid «label text»
msgstr «d»
#: localize.glade.h:2
msgid «button text»
msgstr «g»
#: localize.glade.h:3
msgid «checkbutton text»
msgstr «e»
en_US.po
# English translations for PACKAGE package.
# Copyright 2012 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# <aaa@bbb>, 2012.
#
msgid ""
msgstr ""
«Project-Id-Version: PACKAGE VERSION\n»
«Report-Msgid-Bugs-To: \n»
«POT-Creation-Date: 2012-11-14 13:54+0300\n»
«PO-Revision-Date: 2012-11-14 13:58+0300\n»
«Last-Translator: <aaa@bbb>\n»
«Language-Team: English\n»
«Language: en_US\n»
«MIME-Version: 1.0\n»
«Content-Type: text/plain; charset=utf-8\n»
«Content-Transfer-Encoding: 16bit\n»
«Plural-Forms: nplurals=2; plural=(n != 1);\n»
#: show_form.py:14
msgid «hello to me»
msgstr «hello to me»
#: localize.glade.h:1
msgid «label text»
msgstr «label text»
#: localize.glade.h:2
msgid «button text»
msgstr «button text»
#: localize.glade.h:3
msgid «checkbutton text»
msgstr «checkbutton text»
# Copyright 2012 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# <aaa@bbb>, 2012.
#
msgid ""
msgstr ""
«Project-Id-Version: PACKAGE VERSION\n»
«Report-Msgid-Bugs-To: \n»
«POT-Creation-Date: 2012-11-14 13:54+0300\n»
«PO-Revision-Date: 2012-11-14 13:58+0300\n»
«Last-Translator: <aaa@bbb>\n»
«Language-Team: English\n»
«Language: en_US\n»
«MIME-Version: 1.0\n»
«Content-Type: text/plain; charset=utf-8\n»
«Content-Transfer-Encoding: 16bit\n»
«Plural-Forms: nplurals=2; plural=(n != 1);\n»
#: show_form.py:14
msgid «hello to me»
msgstr «hello to me»
#: localize.glade.h:1
msgid «label text»
msgstr «label text»
#: localize.glade.h:2
msgid «button text»
msgstr «button text»
#: localize.glade.h:3
msgid «checkbutton text»
msgstr «checkbutton text»
Казалось бы — зачем делать родную версию (у меня по умолчанию стоит en_US). Но ведь у другого человека родной может быть, например, de_DE, а он захочет увидеть перевод на английский. Да и разработчики gettext рекомендуют таки создавать.
Некоторые программисты предлагают пользоваться также командой intltool-merge для внесения изменений обратно в форму, но т.к. у меня при этом создавалась точно такая же форма без всяких изменений, то не вижу в ней необходимости.
Итак, есть всё для создания .mo файлов. Это делается командами:
msgfmt ru.po -o locale/ru/LC_MESSAGES/show_form.mo
msgfmt en_US.po -o locale/en_US/LC_MESSAGES/show_form.mo
msgfmt de.po -o locale/de/LC_MESSAGES/show_form.mo
Опция -o (вполне очевидно) указывает каталог, в котором готовый файл будет лежать, причём стоит заметить, что верхний каталог (тут «locale») должен быть один и тот же для всех файлов .mo, а далее должен идти каталог с именем локали (ru, de, en_US, de_DE, ru_RU — т.к. последние два без диалектов, то программы их сокращают до первых букв, но можно использовать и полные имена). Называться он должен так же как указываемый в питоновской программе домен, только с ".mo". Также LC_MESSAGES является одним из нескольких возможных вариантов имени внутреннего каталога (тоже, думаю, лучше использовать одни и те же имена).
Вот что говорит официальная документация по этому поводу:
…
localedir/language/LC_MESSAGES/domain.mo, where languages is searched for in the environment variables LANGUAGE, LC_ALL, LC_MESSAGES, and LANG respectively.
В итоге получились файлы с переводами строк, которые уже можно использовать в программe (такие манипуляции производятся не только для python/glade).
Вернёмся к программе на python`е.
Сперва настроим gettext. После сброса настроек локалей нужно подсказать ему где брать файлы переводов и какие именно файлы. Для этого у меня введены две переменные:
APP="show_form"
DIR="locale"
То, что APP совпадает с названием программы — это осталось от документации, но, думаю, там может быть любое имя. Хотя если смотреть на .mo файлы с названием программы, к которой они относятся, то гораздо проще понимать что к чему.
APP — это имя .mo файлов, DIR — общий каталог с языками. Объяснение этого факта gettext`у производится строками:
gettext.bindtextdomain(APP, DIR)
gettext.textdomain(APP)
Теперь надо объяснить питону, что делать со строками вида _(). Для этого "_" присваивается функция взятия перевода из указанного файла. Записать это можно двумя путями:
lang = gettext.translation(APP, DIR)
_ = lang.gettext
или
_ = gettext.gettext
что, если глянуть в код модуля, одно и то же. Так что имеет смысл выбрать запись покороче.
Этого достаточно, чтобы текст в .py файлах выводился на нужном языке. А для локализации glade формы требуется объяснить gtk, где брать перевод и какой:
gtk.glade.bindtextdomain(APP, DIR)
wTree = gtk.glade.XML("localize.glade", "window1", APP)
Итоговый код:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygtk, gtk, gtk.glade
import locale, gettext
APP="show_form"
DIR="locale"
locale.setlocale(locale.LC_ALL, '')
gettext.bindtextdomain(APP, DIR)
gettext.textdomain(APP)
_ = gettext.gettext
print _("hello to me")
gtk.glade.bindtextdomain(APP, DIR)
wTree = gtk.glade.XML("localize.glade", "window1", APP)
window = wTree.get_widget("window1")
window.connect("delete_event", gtk.main_quit)
window.show_all()
gtk.main()
Запуск:
LANG=en_US.utf-8 ./show_form.py

LANG=ru_RU.utf-8 ./show_form.py

LANG=de_DE.utf-8 ./show_form.py
А тут честно вылетает ошибка, т.к. немецкая локаль у меня не подключена. Таким образом, для использования локали, её нужно добавить в настройках графической оболочки.
На этом всё.
Upd:
Про Builder. Если форма для libglade уже есть, то можно попытаться либо сконвертировать с помощью libglade-convert (у меня выдало ошибку), либо нарисовать новую для builder.
Код будет выглядеть так:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import gtk, gtk.glade
import locale, gettext
APP="show_form"
DIR="locale"
locale.setlocale(locale.LC_ALL, '')
gettext.bindtextdomain(APP, DIR)
gettext.textdomain(APP)
_ = gettext.gettext
print _("hello to me")
builder = gtk.Builder()
gtk.glade.bindtextdomain(APP, DIR)
builder.set_translation_domain(APP)
builder.add_from_file("localize.xml")
window = builder.get_object("window1")
window.connect("delete_event", gtk.main_quit)
window.show_all()
gtk.main()
И, как верно заметил Moonrise, Content-Transfer-Encoding официально рекомендуется устанавливать в 8 бит (т.е. не изменять).