以下是在 Debian 上重新创建一个最小示例的步骤。我不知道这个例子对其他操作系统的可移植性如何,但至少它是一个起点。恕我直言,使用语言环境并不简单。 GtkAda 中的大部分国际化机制都围绕着包gtkada-intl.ads。
-
首先我通过运行启用了感兴趣的语言环境
$ sudo dpkg-reconfigure locales
我想要荷兰语和法语的测试翻译,所以我选择了fr_FR.UTF-8 和nl_NL.UTF-8 以及已经选择的那些(例如,在我的例子中,en_US.UTF-8)。我还保留了en_US.UTF-8 作为默认语言环境。这是我重新配置后的语言环境配置:
$ locale -a
C
C.UTF-8
en_US.utf8
fr_FR.utf8
nl_NL.utf8
POSIX
-
然后,我创建了一个简单的 Glade UI 文件,其中包含一个标签(带有文本 “Hello world!”)的窗口(标题为 "English")。我确保所有文本都被标记为“可翻译”。这是一个可以通过“编辑文本”对话框启用的属性属性。通过单击您输入的文本区域右侧的按钮可以访问此对话框,例如标签文本。
example.glade(特别注意translatable="yes" 属性)
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="Window">
<property name="can_focus">False</property>
<property name="title" translatable="yes">English</property>
<property name="window_position">center</property>
<property name="default_width">300</property>
<property name="default_height">60</property>
<child>
<object class="GtkLabel" id="Label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Hello world!</property>
</object>
</child>
</object>
</interface>
-
我现在创建了两个翻译文件(.po 文件),如下所示:一个用于荷兰语,一个用于法语。注意msgid 是如何匹配窗口标题文本和标签文本的。
translations_nl.po
msgid "English"
msgstr "Nederlands"
msgid "Hello world!"
msgstr "Hallo wereld!"
translations_fr.po
msgid "English"
msgstr "Français"
msgid "Hello world!"
msgstr "Bonjour le monde!"
必须使用 GtkAda 附带的 msgfmt 工具将这些文件转换为机器可读文件(参见 GtkAda 的 bin 目录),即
$ msgfmt translations_nl.po -o messages.mo
-
我终于使用 GNAT Studio CE 2020 创建了一个项目和所需的 Ada 源(源在此答案的末尾)。我确保所有文件的组织如下:
example/
+- example.glade
+- default.gpr
+- obj/
| +- <various build files>
+- src/
| +- main.adb
| +- translation_demo.ads
| +- translation_demo.adb
| +- po/
| +- translations_nl.po
| +- translations_fr.po
+- locales/
+- nl_NL/
| +- LC_MESSAGES/
| +- messages.mo (generated using msgfmt)
+- fr_FR/
+- LC_MESSAGES/
+- messages.mo (generated using msgfmt)
如果一切顺利,那么在构建并运行可执行文件后,根据LANGUAGE environment variable 的设置,正确的翻译将出现在 UI 中。
请注意,在此示例中,我使用Ada.Environment_Variables.Set 过程在程序中设置了LANGUAGE 环境变量(请参阅main.adb)。这只是为了展示如何在应用程序启动时从程序中控制语言(例如,如果您想通过在启动时读取的配置文件来控制语言;在 Linux 以外的操作系统上可能需要这种方法)。在 Debian(以及一般的 Linux)上,LANGUAGE 环境变量通常由操作系统代表用户设置(检查env 命令的输出)。
作为替代方案,您也可以在不设置main.adb 中的环境变量的情况下尝试该示例,并在通过以下方式启动程序时检查结果
LANGUAGE=nl_NL ./obj/main
或
LANGUAGE=fr_FR ./obj/main.adb
总之,请注意,让它工作的过程是一个精确的过程:Debian 必须知道语言环境 nl_NL.UTF-8 和 fr_FR.UTF-8,.mo 文件必须在正确的目录中可用,LANGUAGE必须设置环境变量。此外,由于我在示例代码中使用了相对路径,因此必须从项目根目录启动应用程序,即
$ ./obj/main
如果出现问题,则不会进行翻译,也不会提供错误和/或警告。
main.adb
with Ada.Environment_Variables;
with Translation_Demo;
procedure Main is
NL : constant string := "nl_NL:nl";
FR : constant String := "fr_FR:fr";
begin
-- Set environment varianble.
Ada.Environment_Variables.Set ("LANGUAGE", NL);
Translation_Demo.Run;
end Main;
translation_demo.ads
package Translation_Demo is
procedure Run;
end Translation_Demo;
translation_demo.adb
with Ada.Text_IO;
with Gtk.Main;
with Gtk.Widget;
with Gtk.Builder;
with Gtk.Window;
with Gtk.Button;
with Gtkada.Intl;
with Glib; use Glib;
with Glib.Error; use Glib.Error;
package body Translation_Demo is
-- Name of the .mo file without extention.
Text_Domain : constant String := "messages";
-- (Relative) location of the <lang>/LC_MESSAGES/<domain>.mo files.
Text_Domain_Dir : constant String := "./locale";
-- (Relative) location of the Glade file.
Glade_File : constant String := "./example.glade";
Builder : Gtk.Builder.Gtk_Builder;
Window : Gtk.Window.Gtk_Window;
procedure Destroy_Event_Callback
(Widget : access Gtk.Widget.Gtk_Widget_Record'Class);
---------
-- Run --
---------
procedure Run is
use Gtk.Builder;
use Gtk.Window;
Success : GUint;
Error : aliased GError;
begin
-- Initialize GtkAda.
Gtk.Main.Init;
-- Setup the translation domain and directory where to find the .mo files.
Gtkada.Intl.Setlocale;
Gtkada.Intl.Text_Domain (Text_Domain);
Gtkada.Intl.Bind_Text_Domain (Text_Domain, Text_Domain_Dir);
-- Construct a Gtk_Builder instance and load our UI description.
Gtk_New (Builder);
-- Set the translation domain for the Glade file.
Builder.Set_Translation_Domain (Text_Domain);
-- Read the Glade file.
Success := Builder.Add_From_File (Glade_File, Error'Access);
if Success = 0 then
Ada.Text_IO.Put_Line ("failed to read Glade file");
Error_Free (Error);
Gtk.Main.Main_Quit;
end if;
-- Window
Window := Gtk_Window (Builder.Get_Object ("Window"));
Window.On_Destroy (Destroy_Event_Callback'Access);
Window.Show_All;
-- Start the main event loop
Gtk.Main.Main;
end Run;
----------------------------
-- Destroy_Event_Callback --
----------------------------
procedure Destroy_Event_Callback
(Widget : access Gtk.Widget.Gtk_Widget_Record'Class)
is
begin
Gtk.Main.Main_Quit;
end Destroy_Event_Callback;
end Translation_Demo;
default.gpr
with "gtkada";
project Default is
for Source_Dirs use ("src");
for Object_Dir use "obj";
for Main use ("main.adb");
end Default;