【问题标题】:Glade3 and changing strings within the GUIGlade3 和在 GUI 中更改字符串
【发布时间】:2021-05-07 14:35:07
【问题描述】:

我需要 GUI,其中有许多字符串会定期更改,例如在多语言环境中。那么如何将这些字符串作为变量而不是作为常量输入,并且仍然使用 Gtkbuilder 例程并能够更改字符串运行时。如果这是不可能的,我如何将 .glade 文件翻译成具有相同功能的 ADA 文件。

编辑:我不认为你给我的答案是我的问题的真正答案,因为我希望 GUI 更改语言而不重建程序,即只有一个版本的程序而不是每种语言的版本。第二点是我当时还没有找到,但在其他情况下,我可以在运行程序期间更改变量而不是常量。

【问题讨论】:

    标签: user-interface gtk ada


    【解决方案1】:

    【讨论】:

    【解决方案2】:

    以下是在 Debian 上重新创建一个最小示例的步骤。我不知道这个例子对其他操作系统的可移植性如何,但至少它是一个起点。恕我直言,使用语言环境并不简单。 GtkAda 中的大部分国际化机制都围绕着包gtkada-intl.ads

    • 首先我通过运行启用了感兴趣的语言环境

      $ sudo dpkg-reconfigure locales
      

      我想要荷兰语和法语的测试翻译,所以我选择了fr_FR.UTF-8nl_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-8fr_FR.UTF-8.mo 文件必须在正确的目录中可用,LANGUAGE必须设置环境变量。此外,由于我在示例代码中使用了相对路径,因此必须从项目根目录启动应用程序,即

    $ ./obj/main
    

    如果出现问题,则不会进行翻译,也不会提供错误和/或警告。

    ma​​in.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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多