GTK3下如何将文本域绑定到本地文件夹以获取文本

Posted

技术标签:

【中文标题】GTK3下如何将文本域绑定到本地文件夹以获取文本【英文标题】:How to bind a text domain to a local folder for gettext under GTK3 【发布时间】:2012-04-23 01:45:16 【问题描述】:

使用gettext,您可以使用默认系统范围的语言环境目录,也可以使用bindtextdomain 自己指定一个。当编译的 .mo 翻译文件在系统默认位置不可用时,这在直接从源代码运行程序时很有用。

在 Python 中你会这样做:

import gettext
from gettext import gettext as _
gettext.bindtextdomain('nautilus-image-manipulator', '/path/to/mo/folder')
gettext.textdomain('nautilus-image-manipulator')

其中/path/to/mo/folder 包含熟悉的fr/LC_MESSAGES/nautilus-image-manipulator.mo 结构。像这样的调用:

print _("Delete this profile")

从本地 .mo 文件中返回正确翻译的字符串,非常感谢。

在 GTK+2/pygtk 中,存在 gtk.glade.bindtextdomain,但我想知道在 GTK+3/PyGObject 中是否有任何等价物。

举个具体的例子,Nautilus Image Manipulator;s UI 是如何从其 Glade 文件中创建的:

from gi.repository import Gtk
builder = Gtk.Builder()
builder.set_translation_domain('nautilus-image-manipulator')
builder.add_from_file(ui_filename)
return builder

不是从 Glade 文件构建(即从代码设置)的部分 UI 显示正确翻译,但 Glade 文件中的字符串仍以英文显示。

在我看来,在调用builder.set_translation_domain 之前,我错过了对某种builder.bind_text_domain('nautilus-image-manipulator', '/path/to/mo/folder') 的调用...知道如何执行此操作吗?

【问题讨论】:

您是否尝试过通常的gettext.bindtextdomain() 【参考方案1】:

在 PyGtk 中你也可以使用 Gtk.Builder。根据 PyGtk Gtk.Builder 文档:

http://developer.gnome.org/pygtk/stable/class-gtkbuilder.html#properties-gtkbuilder

翻译属性值时使用的翻译域 在界面描述中被标记为可翻译。如果 翻译域为None,GtkBuilder使用gettext(),否则 dgettext()。默认值:无

也就是说,Gtk.Builder 使用“C 库”中的 dgettext()。问题是 Python 的 gettext 模块,函数 bindtextdomain(),出于某种我不知道的原因,没有设置“C 库”。选项是使用也公开该接口的 locale 模块。来自 Python 语言环境模块文档:

http://docs.python.org/library/locale#access-to-message-catalogs

语言环境模块在系统上公开 C 库的 gettext 接口 提供这个接口。它由函数 gettext() 组成, dgettext()、dcgettext()、textdomain()、bindtextdomain() 和 绑定文本域代码集()。这些与中的相同功能相似 gettext 模块,但使用 C 库的二进制格式的消息 目录,以及用于定位消息的 C 库的搜索算法 目录。

Python 应用程序通常不需要调用这些 函数,应该使用 gettext 代替。一个已知的例外 规则是与其他 C 库链接的应用程序 内部调用 gettext() 或 dcgettext()。对于这些应用程序,它 可能需要绑定文本域,以便库可以 正确定位他们的消息目录。

这是当前的情况。真是个黑客:S

这样就可以了,文件test.py

from gi.repository import Gtk
from os.path import abspath, dirname, join, realpath
import gettext
import locale

APP = 'myapp'
WHERE_AM_I = abspath(dirname(realpath(__file__)))
LOCALE_DIR = join(WHERE_AM_I, 'mo')

locale.setlocale(locale.LC_ALL, '')
locale.bindtextdomain(APP, LOCALE_DIR)
gettext.bindtextdomain(APP, LOCALE_DIR)
gettext.textdomain(APP)
_ = gettext.gettext

print('Using locale directory: '.format(LOCALE_DIR))

class MyApp(object):

    def __init__(self):
        # Build GUI
        self.builder = Gtk.Builder()
        self.glade_file = join(WHERE_AM_I, 'test.glade')
        self.builder.set_translation_domain(APP)
        self.builder.add_from_file(self.glade_file)

        print(_('File'))
        print(_('Edit'))
        print(_('Find'))
        print(_('View'))
        print(_('Document'))

        # Get objects
        go = self.builder.get_object
        self.window = go('window')

        # Connect signals
        self.builder.connect_signals(self)

        # Everything is ready
        self.window.show()

    def main_quit(self, widget):
        Gtk.main_quit()

if __name__ == '__main__':
    gui = MyApp()
    Gtk.main()

我的 Glade 文件 test.glade

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <!-- interface-requires gtk+ 3.0 -->
  <object class="GtkWindow" id="window">
    <property name="can_focus">False</property>
    <property name="window_position">center-always</property>
    <property name="default_width">400</property>
    <signal name="destroy" handler="main_quit" swapped="no"/>
    <child>
      <object class="GtkBox" id="box1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkLabel" id="label1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">File</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="label2">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">Edit</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="label3">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">Find</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">2</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="label4">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">View</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">3</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="label5">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">Document</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">4</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

记得在 mo/LANG/LC_MESSAGES/myapp.mo 中根据提取的 .po 创建 mo:

xgettext --keyword=translatable --sort-output -o en.po test.glade

它的样子:

亲切的问候

【讨论】:

谢谢,这很好用。但我想知道“locale.setlocale(locale.LC_ALL, '')” 行实际上是做什么的 - 我的应用程序即使在我删除它时也会被翻译......这个调用真的有必要吗? 我按照这里的建议添加了它:docs.python.org/2/library/locale.html#locale.setlocale“这会将所有类别的区域设置为用户的默认设置(通常在 LANG 环境变量中指定)。”这可能是在你晚上由于某种原因 LC_* 变量不同于我想的 LC_ALL 的情况下,或者在没有语言环境变量的情况下,但我不太确定。 我知道它已经过时了,但我现在正在面对它......这种方法似乎只适用于 Linux,因为 Windows 没有带有 gettext 的 C 库 @Zvika 如果我记得你在 Windows 中必须这样:github.com/carlos-jenkins/nested/blob/1.x/nested/… ...也许这可以将环境变量设置为 gettext 工作:github.com/carlos-jenkins/nested/blob/1.x/nested/… 它是否适用于 OS X?上次我检查时,locale.bindtextdomain 在这个平台上不存在...(见github.com/multani/sonata/issues/67)【参考方案2】:

Windows下在Gtk/python中激活gettext翻译的解决方案是elib_intl.py 用谷歌很容易找到文件。 这允许翻译代码中的文本和 glade UI 中的文本。

这是用于以下环境的代码:

Windows 7 蟒蛇 2.7 Gtk 3+ 由 pygi-aio-3.10.2-win32_rev18-setup.exe 加载

它应该适用于任何窗口,也适用于 Python 3。 elib_intl.py 可以与 pyGtk (Gtk 2) 一起使用。

from gi.repository import Gtk, Gdk
import cairo

import locale       #for multilanguage support
import gettext
import elib_intl
elib_intl.install("pdfbooklet", "share/locale")

如果你使用 Gtk 3,你可能会收到一个错误:对于第 447 行:

libintl = cdll.intl

此错误表示:未找到模块。 原因是在 Gtk3 中,dll 的名称已更改。它不再是 intl.dll。在所描述的 Pygi 安装中,名称是:libintl-8。您必须将引发错误的行替换为:

libintl = cdll.LoadLibrary("libintl-8.dll")

您可以在此处找到完整的工作示例:pdfBooklet 2.4.0 (警告:我写的时候还没排队)

感谢编写 elib_intl 的节食者 Verfaillie

【讨论】:

【参考方案3】:

在赏金如此悲惨地未能吸引 mac os x 答案之后,我不得不自己进行研究。这是我使用的 sn-p:

import locale, ctypes, sys, os
import gettext

# setup textdomain and install _() for strings from python
gettext.install('domain', '/path/to/locale/dir')

try:
    if hasattr(locale, 'bindtextdomain'):
        libintl = locale
    elif os.name == 'nt':
        libintl = ctypes.cdll.LoadLibrary('libintl-8.dll')
    elif sys.platform == 'darwin':
        libintl = ctypes.cdll.LoadLibrary('libintl.dylib')

    # setup the textdomain in gettext so Gtk3 can find it
    libintl.bindtextdomain('domain', '/path/to/locale/dir')

except (OSError, AttributeError):
    # disable translations altogether for consistency
    gettext.install('')

稍后,当您拥有 Gtk.Builder 后,设置域:

builder.set_translation_domain('domain')

这只有在 gettext 的库 libintl 位于库路径中时才有效,否则会正常失败。为了使翻译工作,您需要安装 gettext 作为依赖项。

【讨论】:

以上是关于GTK3下如何将文本域绑定到本地文件夹以获取文本的主要内容,如果未能解决你的问题,请参考以下文章

如何将文本区域内容保存在本地存储中

将文本区域保存到本地服务器上的 HTML 文件

如何在 Poedit 中设置 gettext 文本域?

Javascript将文本区域保存为UTF-8文件

php 文本域

lable标签(理解)/文本域标签