Skip to content

Overhaul translation deployment - #221

Open
meator wants to merge 5 commits into
linuxdeploy:masterfrom
meator:pr/qt-translations
Open

Overhaul translation deployment#221
meator wants to merge 5 commits into
linuxdeploy:masterfrom
meator:pr/qt-translations

Conversation

@meator

@meator meator commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

As promissed, I fixed linuxdeploy-plugin-qt's translation handling.

I've had to delve into the code a bit deeper to implement these changes. I have some remarks (none of them are particularly important):

  • Taywee/args lacks useful features, especially with the flags I added. I'm missing proper support for --feature/--no-feature flag combos and defaulting to env variables. The competition, like CLI11, offers these basic features.

    If you agree, I can make switching to CLI11 or some other argument parser a part of this PR.

  • Why is deployment.h so chunky? Header files shouldn't contain so much code.

  • The following code:

    if (strStartsWith(fileName.string(), "qt_") && fileName.filename().string().size() >= 5 &&
    fileName.filename().string().size() <= 6)

    does not make sense, a qt_ .qm file has at least 8 characters. I assumed it is broken and removed it in favor of my new qt_*.qm generation.

  • The dependency situation isn't ideal. There's some git submodule vendoring, some old CMake FetchContent fetching straight from git with full history...

    The build system also calls git directly, which is a build system smell. Repos might be built from release archives, but git submodules complicate this task. Well behaved projects either avoid git submodules or provide a separate source release artifact with all submodules and vendored things included.

    I'm a huge advocate for the Meson build system. Its wrap mechanism solves all these issues and more. But if my understanding is correct, one of the aims of linuxdeploy-plugin-qt's build system is compatibility with older distros, which makes the situation more understandable.

    This is not a call for action, I do not expect a fix for this since for example the old distro compatibility can be restrictive.

  • I can contribute a .clang-format file if there's interest.

    Not having to worry about formatting is nice. If there's interest, I'll try to find out which clang format configuration options reflect the current code style best.

    If you agree with this, it would make most sense to add it to other linuxdeploy repos too.

    While we're talking about code formatting, what is this!?

    // tests/test_deploy_qml.cpp
    namespace linuxdeploy {
        namespace plugin {
            namespace qt {
                namespace test {
    // ...

    The fact that all of this can be converted into a single line doesn't help, but I've noticed this pattern in other places too. AppImage devs must have wide monitors.

  • What is this project's stance on exceptions?

    I know this is a controversial topic. I've added a few, but I tried to not get overboard. If you don't like it, I can rework the code to not use exceptions.

Now about the translation deployment:

Since I wrote my comments in #194, I researched this a bit further and have changed my opinion on some of the things. For example, I didn't see a reason for symlinking user translations to usr/translations, but I have since learned that this behavior is reasonable and similar to that of windeployqt and (I think, haven't tested) macdeployqt.

The changes and documentation in this PR should be the autoritative source of how I think these things should work.

I've done most of my testing on Qt6 and some late Qt5. If this code has been written with older Qt in mind (older Qt5, Qt4 or something else), some of my assumptions might not be correct. Perhaps some of linuxdeploy-plugin-qt's stranger choices could be explained by older Qt.

I've written a program to test these changes and to help me during developing: sample_tr_program.gitbundle.gz
(a gziped git bundle)

The program implements several methods of looking up translations. These methods are fully configurable at configure time and can be used to "emulate" the behavior of other programs. For example, if you want sample_tr_program to be a program which installs its translations to <prefix>/usr/share/sample_tr_program/i18n and stubbornly expects to find them in the exact same location where it installed them (this is a naïve behavior of some programs I saw which is incompatible with Windows/Mac/AppImage deployment), one can configure it with

meson setup build --prefix /usr -Dtranslation_dir=usr_share_i18n -Dapp_translation_lookup_dir_1=absolute_hardcoded 

and installed with

meson install -C path/to/build/dir --destdir preferably/absolute/path/to/AppDir

The program can use several app translations loading strategies at once (as I recommend in the developer README documentation I added). They can be controlled with app_translation_lookup_dir_1, app_translation_lookup_dir_2... It is an ordered list, once the translation is found, no further methods are used.

The program provides detailed output on translation loading in stderr logs, with popup windows and with the GUI program itself.

The program pulls in a single translation prefix. This bypasses the lconvert logic I added (there's no need to merge translations when there is only one per language). To add more, dependencies can be artificially injected. For example, the following diff injects QtMultimedia dependency:

diff --git a/main.cpp b/main.cpp
index e363dd4..19649bf 100644
--- a/main.cpp
+++ b/main.cpp
@@ -21,6 +21,7 @@
 #include <QLibraryInfo>
 #include <QLocale>
 #include <QMessageBox>
+#include <QMediaPlayer>
 #include <QTimer>
 #include <QTranslator>
 
@@ -238,6 +239,8 @@ int main(int argc, char * argv[])
 {
 	QApplication app(argc, argv);
 
+	(void)QMediaPlayer();
+
 	Translators translators;
 
 	if (QLocale::system().language() == QLocale::English)
diff --git a/meson.build b/meson.build
index 00f63e3..8ccb803 100644
--- a/meson.build
+++ b/meson.build
@@ -23,7 +23,7 @@ project(
 )
 
 qt6 = import('qt6')
-qt6dep = dependency('qt6', modules : ['Core', 'Widgets'])
+qt6dep = dependency('qt6', modules : ['Core', 'Widgets', 'Multimedia'])
 
 # https://mesonbuild.com/Builtin-options.html#directories
 translation_dirs = {

I've consulted my distro's package repository for reasonable locations of installed .qm application translations and my own best judgement for the methods of looking them up. See the meson_options.txt file (I haven't documented it that thoroughly, it is a test utility).

I've added extensive documentation on translations. It is an user facing documentation though, it doesn't explain linuxdeploy-plugin-qt translation deploying logic.

Also note that the --qt-languages flag I added only affects Qt translations, not user ones. This should be consistent with windeployqt (haven't tested though). This may be counterintuitive, I'm willing to discuss this further.

If you've got better names for the flags and env variables, please share feedback. These are the kinds of things that are hard to change retroactively.

fixes #194

meator added 4 commits August 22, 2026 15:59
Removed old broken qt_*.qm handling, added a smarter new one utilizing
lconvert when needed and made everything configurable.
@meator
meator force-pushed the pr/qt-translations branch 2 times, most recently from fd56852 to db238ae Compare August 23, 2026 19:03
@meator
meator force-pushed the pr/qt-translations branch from db238ae to c824300 Compare August 24, 2026 06:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Please combine all the translations for each locale's modules into a single qt_??.qm file

1 participant