Using modern gettext

gettext has seen quite some enhancements in recent years, after Daiki Ueno started maintaining it. It can now extract (and merge back) strings from diverse file formats, including many of the formats that are important for desktop applications. With gettext 0.19.8, there is really no need  anymore to use intltool or GLib’s dated gettext glue (AM_GLIB_GNU_GETTEXT and glib-gettextize).

Since intltool still sticks around in quite a few projects, I thought that I should perhaps explain some of the dos and don’ts for how to get by with plain gettext. Javier Jardon has been tirelessly fighting a battle for using upstream gettext, maybe this will help him reaching the finish line with that project.

Extracting strings

xgettext is the tool used to extract strings from sources into .pot files.

In addition to programming languages such as C, C++, Java, Scheme, etc, it recognizes the following files by their typical file extensions (and it is smart enough to disregard a .in extension):

    • Desktop files: .desktop
    • GSettings schemas: .gschema.xml
    • GtkBuilder ui files: .ui
    • Appdata files: .appdata.xml and .metainfo.xml

You can just add these files to POTFILES.in, without the extra type hints that intltool requires.

One important advantage of xgettext’s xml support, compared to intltool, is that you can install .in files that are valid; no more tag mutilation like <_description> required.

Merging translations

The trickier part is merging translations back into the various file formats. Sometimes that is not necessary, since the file has a reference to the gettext domain, and consumers know to use gettext at runtime: that is the case for GSettings schemas and GtkBuilder ui files, for example.

But in other cases, the translations need to be merged back into  the original file before installing it. In these cases, the original file from which the strings are extracted often has an extra .in extension. The tool that is doing this task is msgfmt.

Intltool installs autotools glue which can define make rules for many of these cases, such as @INTLTOOL_DESKTOP_RULE@. Gettext does not provide this kind of glue, but the msgfmt tool is versatile enough that you can write your own rules fairly easily, for example:

%.desktop: %.desktop.in
        msgfmt --desktop -d $(top_srcdir)/po \
               --template $< -o $@

Extending gettext

Gettext can be extended to understand new xml formats. To do so, you install .its and .loc files. The syntax for these files is explained in detail in the gettext docs. Libraries are expected to install these files for ‘their’ formats (GLib and GTK+ already do, and  PolicyKit will do the same soon.

If you don’t want to wait for your favorite format to come with built-in its support, you can also include its files with your application; gettext will look for such files in $XDG_DATA_DIRS/gettext/its/.

 

Portals: Using GTK+ in a Flatpak

The time is ripe for new ways to distribute and deploy desktop applications: between snappy, Flatpak, AppImage and others there are quite a few projects in this area.

Sandboxing

Most of these projects involve some notion of sandboxing: isolating the application from the rest of the system.

Snappy does this by setting environment variables like XDG_DATA_DIRS, PATH, etc,  to tell apps where to find their ‘stuff’ and using app-armor to not let them access things they shouldn’t.

Flatpak takes a somewhat different approach: it uses bind mounts and namespaces to construct a separate view of the world for the app in which it can only see what it is supposed to access.

Regardless which approach you take to sandboxing, desktop applications are not very useful without access to the rest of the system.  So, clearly, we need to poke some holes in the walls of the sandbox, since we want apps to interact with the rest of the system.

The important thing to keep in mind is that we always want to give the user control over these interactions and in particular, control over the data that goes in and out of the sandbox.

Portals

The flatpak story for this has been portals. To quickly summarize: Portals are high-level (in the sense that they talk about concepts that are relevant to users) APIs that let sandboxed applications request access to resources outside. Portal calls will (almost) always involve user interaction (basically, a dialog).

We have talked about portals for quite a while, see for example this post by Allan from two years ago. Therefore,  I am very happy to announce that we now have first release of the portal infrastructure :

Note that the portal APIs themselves are desktop-neutral, and we have separated the implementation using GTK+ dialogs into their own module. We are also working on a qt/KDE  implementation.

The  APIs included in these releases cover a lot of basic things:

  • opening files
  • opening uris
  • printing
  • taking screenshots
  • notifications
  • inhibiting screen lock
  • network status
  • proxy information

Using portals in apps

The good news is that most of these will just work transparently in GTK+ applications, since GTK+ and GLib have suitable APIs that can be made to use the portals without any changes required from the sandboxed application. This support is already in place in the master branches; and will be in the 3.22 releases. We are working on a similar level of support for qt/KDE.

In detail, for opening files, you can use GtkFileChooserNative (a file chooser implementation that will also use a native Windows filechooser if you are on that platform). GtkFileChooserButton will do this for you, unless you manually set its dialog to something else. Certain things will not work with the portal, such as previews, or adding extra custom widgets.

For printing, use GtkPrintOperation (again a long-standing GTK+ api that will use a native Windows print dialog if you are on that platform).

For opening uris, use gtk_show_uri or g_app_info_launch_default_for_uri. We also added a new function that works slightly better in this context, gtk_show_uri_on_window().

Testing

As I said, most of the portals will just be transparently used by sandboxed GTK+ applications (provided they use GTK+ from git), but I’ve also written a portal-test application to try all the available portals.

portal-test

All of the tests use the regular GTK+ APIs, with the exception of the Screenshot button. Since we don’t have a screenshooting API in GTK+, that button makes a direct D-Bus call to the portal. Here is how it looks in action:

portal-test2

Whats next ?

For the first release, we’ve focused on portals for toolkit-level functionality. There is obvously a long list of other system integration points that will need to be covered. High up on our list for the near future are access to devices like webcams and microphones, and pulseaudio. If you are interested, the list of issues has some more information.

Update: I’ve been asked: Why do I need a portal, the file chooser in the libreoffice flatpak seems to work just fine ?! Most of the current flatpaks are shipping with a relatively open sandbox configuration that allows the application full access to the host filesystem, or at least to your entire home directory. Portals enable applications to  function in a constrained sandbox that does not have this.