<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Python GUIs - translations</title><link href="https://www.pythonguis.com/" rel="alternate"/><link href="https://www.pythonguis.com/feeds/translations.tag.atom.xml" rel="self"/><id>https://www.pythonguis.com/</id><updated>2020-06-27T09:00:00+00:00</updated><subtitle>Create GUI applications with Python and Qt</subtitle><entry><title>Impossible Translations — Troubleshooting PyQt6 translation loading issues with QTranslator</title><link href="https://www.pythonguis.com/faq/impossible-translations/" rel="alternate"/><published>2020-06-27T09:00:00+00:00</published><updated>2020-06-27T09:00:00+00:00</updated><author><name>Martin Fitzpatrick</name></author><id>tag:www.pythonguis.com,2020-06-27:/faq/impossible-translations/</id><summary type="html">Getting translations working in a PyQt6 application can be one of the most frustrating experiences in GUI development. The translation system doesn't raise errors when something goes wrong &amp;mdash; it just silently does nothing. Your app loads, your widgets appear, but everything stays in the original language, and you're left wondering what went wrong.</summary><content type="html">
            &lt;p&gt;Getting translations working in a PyQt6 application can be one of the most frustrating experiences in GUI development. The translation system doesn't raise errors when something goes wrong &amp;mdash; it just silently does nothing. Your app loads, your widgets appear, but everything stays in the original language, and you're left wondering what went wrong.&lt;/p&gt;
&lt;p&gt;This tutorial walks through the common problems people run into when setting up translations with &lt;code&gt;QTranslator&lt;/code&gt; in PyQt6, and shows you how to get everything working correctly. We'll cover loading &lt;code&gt;.qm&lt;/code&gt; translation files, getting file paths right, and handling both Qt's built-in translations and your own custom ones.&lt;/p&gt;
&lt;h2 id="how-qt-translations-work"&gt;How Qt translations work&lt;/h2&gt;
&lt;p&gt;Before we get into the problems, a quick refresher on how the translation system fits together.&lt;/p&gt;
&lt;p&gt;Qt uses &lt;code&gt;.qm&lt;/code&gt; files for translations. These are compiled binary files generated from &lt;code&gt;.ts&lt;/code&gt; (translation source) files. The pipeline looks like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You mark strings in your code as translatable using &lt;code&gt;self.tr("Some text")&lt;/code&gt; or &lt;code&gt;QCoreApplication.translate("Context", "Some text")&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You use &lt;code&gt;pylupdate6&lt;/code&gt; (or &lt;code&gt;lupdate&lt;/code&gt; from Qt) to extract those strings into &lt;code&gt;.ts&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;You translate the strings in the &lt;code&gt;.ts&lt;/code&gt; files (using Qt Linguist or a text editor).&lt;/li&gt;
&lt;li&gt;You compile the &lt;code&gt;.ts&lt;/code&gt; files into &lt;code&gt;.qm&lt;/code&gt; files using &lt;code&gt;lrelease&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;At runtime, you load the &lt;code&gt;.qm&lt;/code&gt; files using &lt;code&gt;QTranslator&lt;/code&gt; and install them on your &lt;code&gt;QApplication&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The tricky part is step 5. If anything goes wrong during loading &amp;mdash; wrong path, wrong filename, wrong naming convention &amp;mdash; &lt;code&gt;QTranslator.load()&lt;/code&gt; simply returns &lt;code&gt;False&lt;/code&gt; and your app runs untranslated. No exception, no warning, no log message.&lt;/p&gt;
&lt;h2 id="the-silent-failure-problem"&gt;The silent failure problem&lt;/h2&gt;
&lt;p&gt;Here's a minimal example of loading a translation:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;translator = QTranslator()
translator.load("myapp_fr_FR", "translations")
app.installTranslator(translator)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If the file &lt;code&gt;translations/myapp_fr_FR.qm&lt;/code&gt; doesn't exist, or the path &lt;code&gt;translations&lt;/code&gt; can't be found relative to where the script is running, &lt;code&gt;load()&lt;/code&gt; returns &lt;code&gt;False&lt;/code&gt; and nothing happens. This is the root cause of most translation headaches.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Always check the return value of &lt;code&gt;load()&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;translator = QTranslator()
if translator.load("myapp_fr_FR", "translations"):
    print("Translation loaded successfully!")
    app.installTranslator(translator)
else:
    print("Failed to load translation file.")
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Adding this check is the single most useful thing you can do when debugging translations. It tells you immediately whether the file was found and loaded.&lt;/p&gt;
&lt;h2 id="getting-file-paths-right"&gt;Getting file paths right&lt;/h2&gt;
&lt;p&gt;The most common reason translations fail to load is that the path to the &lt;code&gt;.qm&lt;/code&gt; file is wrong. When you pass a relative path like &lt;code&gt;"translations"&lt;/code&gt; to &lt;code&gt;QTranslator.load()&lt;/code&gt;, it's resolved relative to the &lt;em&gt;current working directory&lt;/em&gt; &amp;mdash; not relative to your Python script.&lt;/p&gt;
&lt;p&gt;If you run your script from a different directory (which happens all the time during development and deployment), the relative path breaks silently.&lt;/p&gt;
&lt;p&gt;The fix is to construct an absolute path based on the location of your script:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import os
from PyQt6.QtCore import QTranslator, QLocale, QLibraryInfo

# Build an absolute path to the translations folder
basedir = os.path.dirname(os.path.abspath(__file__))
translations_path = os.path.join(basedir, "translations")

locale = QLocale.system().name()  # e.g., "fr_FR"

translator = QTranslator()
if translator.load(f"myapp_{locale}", translations_path):
    app.installTranslator(translator)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Using &lt;code&gt;os.path.dirname(os.path.abspath(__file__))&lt;/code&gt; gives you the directory containing the current script, regardless of where the script was launched from.&lt;/p&gt;
&lt;h2 id="file-naming-conventions"&gt;File naming conventions&lt;/h2&gt;
&lt;p&gt;Qt's &lt;code&gt;QTranslator.load()&lt;/code&gt; method has some flexibility in how it searches for files, but it follows specific naming conventions. When you call:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;translator.load("myapp_fr_FR", "/path/to/translations")
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Qt looks for the file &lt;code&gt;/path/to/translations/myapp_fr_FR.qm&lt;/code&gt;. If that's not found, it tries progressively shorter names: &lt;code&gt;myapp_fr.qm&lt;/code&gt;, then &lt;code&gt;myapp.qm&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A common mistake is getting the separator between the base name and locale wrong. In the forum discussion that inspired this article, the solution turned out to be using a &lt;strong&gt;dot&lt;/strong&gt; separator instead of an &lt;strong&gt;underscore&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;# This didn't work:
translator.load("minimal_%s" % locale, "translations")

# This worked:
translator.load("minimal.%s" % locale, "translations")
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The separator you use in &lt;code&gt;load()&lt;/code&gt; must match the actual filename of your &lt;code&gt;.qm&lt;/code&gt; file. If your file is called &lt;code&gt;minimal.fr_FR.qm&lt;/code&gt;, you need &lt;code&gt;"minimal.%s" % locale&lt;/code&gt;. If it's called &lt;code&gt;minimal_fr_FR.qm&lt;/code&gt;, you need &lt;code&gt;"minimal_%s" % locale&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Check your actual filenames carefully. This tiny difference &amp;mdash; a dot vs. an underscore &amp;mdash; can be the entire problem.&lt;/p&gt;
&lt;h2 id="loading-qts-built-in-translations"&gt;Loading Qt's built-in translations&lt;/h2&gt;
&lt;p&gt;Qt itself has translatable strings &amp;mdash; things like "OK", "Cancel", "About Qt", and the text in standard &lt;a href="https://www.pythonguis.com/tutorials/pyqt6-dialogs/"&gt;dialogs&lt;/a&gt;. These translations ship with Qt and are stored in &lt;code&gt;.qm&lt;/code&gt; files at a system-level path.&lt;/p&gt;
&lt;p&gt;To load them, use &lt;code&gt;QLibraryInfo.location(QLibraryInfo.TranslationsPath)&lt;/code&gt; to find where Qt keeps its translation files:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;from PyQt6.QtCore import QTranslator, QLocale, QLibraryInfo

locale = QLocale.system().name()

qt_translator = QTranslator()
if qt_translator.load(f"qt_{locale}",
                       QLibraryInfo.location(QLibraryInfo.TranslationsPath)):
    app.installTranslator(qt_translator)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;On Linux, this typically resolves to something like &lt;code&gt;/usr/share/qt6/translations/&lt;/code&gt;. On other platforms, the path will be different, but &lt;code&gt;QLibraryInfo&lt;/code&gt; handles that for you.&lt;/p&gt;
&lt;p&gt;You should load the Qt base translations &lt;em&gt;in addition to&lt;/em&gt; your own custom translations. They're separate translators installed on the same application:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;locale = QLocale.system().name()

# Load Qt's own translations
qt_translator = QTranslator()
if qt_translator.load(f"qt_{locale}",
                       QLibraryInfo.location(QLibraryInfo.TranslationsPath)):
    app.installTranslator(qt_translator)

# Load your app's translations
app_translator = QTranslator()
if app_translator.load(f"myapp.{locale}", translations_path):
    app.installTranslator(app_translator)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="keeping-translators-alive"&gt;Keeping translators alive&lt;/h2&gt;
&lt;p&gt;There's a subtle gotcha in Python that doesn't exist in C++ Qt code. If you create a &lt;code&gt;QTranslator&lt;/code&gt; as a local variable inside a function and don't keep a reference to it, Python's garbage collector may destroy it. Once the translator object is garbage collected, the translations stop working &amp;mdash; even though you installed it on the application.&lt;/p&gt;
&lt;p&gt;This is a problem:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;def setup_translations(app):
    translator = QTranslator()
    translator.load("myapp_fr_FR", translations_path)
    app.installTranslator(translator)
    # 'translator' goes out of scope and may be garbage collected!
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Instead, keep a reference to the translator object. You can store it as an attribute on the application, or keep it in a list at module level:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;def setup_translations(app):
    translator = QTranslator()
    if translator.load("myapp_fr_FR", translations_path):
        app.installTranslator(translator)
        app._translator = translator  # Keep a reference!
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Or, if you're loading multiple translators:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;translators = []

def setup_translations(app):
    locale = QLocale.system().name()

    qt_translator = QTranslator()
    if qt_translator.load(f"qt_{locale}",
                           QLibraryInfo.location(QLibraryInfo.TranslationsPath)):
        app.installTranslator(qt_translator)
        translators.append(qt_translator)

    app_translator = QTranslator()
    if app_translator.load(f"myapp.{locale}", translations_path):
        app.installTranslator(app_translator)
        translators.append(app_translator)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="translations-must-be-loaded-before-creating-widgets"&gt;Translations must be loaded before creating widgets&lt;/h2&gt;
&lt;p&gt;The order of operations matters. You must load and install your translators &lt;em&gt;before&lt;/em&gt; you create any widgets. When a widget is created, it calls &lt;code&gt;retranslateUi()&lt;/code&gt; (if using &lt;code&gt;.ui&lt;/code&gt; files converted to Python) or reads the &lt;code&gt;self.tr()&lt;/code&gt; strings. If the translator isn't installed yet, those strings come through untranslated.&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;if __name__ == "__main__":
    app = QApplication(sys.argv)

    # Load translations FIRST
    locale = QLocale.system().name()

    qt_translator = QTranslator()
    if qt_translator.load(f"qt_{locale}",
                           QLibraryInfo.location(QLibraryInfo.TranslationsPath)):
        app.installTranslator(qt_translator)

    app_translator = QTranslator()
    if app_translator.load(f"myapp.{locale}", translations_path):
        app.installTranslator(app_translator)

    # THEN create widgets
    window = MainWindow()
    window.show()

    sys.exit(app.exec())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="setting-up-the-pro-file"&gt;Setting up the .pro file&lt;/h2&gt;
&lt;p&gt;To extract translatable strings from your source files, you need a &lt;code&gt;.pro&lt;/code&gt; file that tells &lt;code&gt;pylupdate6&lt;/code&gt; where to look. Here's a clean example:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;SOURCES += windows/minimal.py ui/exempleui.py
TRANSLATIONS += translations/minimal.fr_FR.ts translations/minimal.en_US.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;A few things to watch for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Paths in the &lt;code&gt;.pro&lt;/code&gt; file are relative to where the &lt;code&gt;.pro&lt;/code&gt; file is located.&lt;/strong&gt; If your &lt;code&gt;.pro&lt;/code&gt; file is at the project root, the paths should be relative to the project root.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;List all files that contain translatable strings.&lt;/strong&gt; This includes both your hand-written Python files (with &lt;code&gt;self.tr()&lt;/code&gt; calls) and generated UI files (which use &lt;code&gt;QCoreApplication.translate()&lt;/code&gt;). If you're using Qt Designer to build your interfaces, see our guide on &lt;a href="https://www.pythonguis.com/tutorials/pyqt6-qt-designer-gui-layout/"&gt;using Qt Designer with PyQt6&lt;/a&gt; for more on how &lt;code&gt;.ui&lt;/code&gt; files fit into this workflow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You can list multiple files on one line&lt;/strong&gt; with &lt;code&gt;SOURCES +=&lt;/code&gt; or split them across multiple lines. Both formats work:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-text"&gt;text&lt;/span&gt;
&lt;pre&gt;&lt;code class="text"&gt;# Single line
SOURCES += windows/minimal.py ui/exempleui.py

# Multiple lines (use backslash for continuation)
SOURCES += windows/minimal.py \
           ui/exempleui.py
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;After editing the &lt;code&gt;.pro&lt;/code&gt; file, run:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-sh"&gt;sh&lt;/span&gt;
&lt;pre&gt;&lt;code class="sh"&gt;pylupdate6 myproject.pro
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This generates (or updates) the &lt;code&gt;.ts&lt;/code&gt; files. Translate them with Qt Linguist, then compile to &lt;code&gt;.qm&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-sh"&gt;sh&lt;/span&gt;
&lt;pre&gt;&lt;code class="sh"&gt;lrelease myproject.pro
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="complete-working-example"&gt;Complete working example&lt;/h2&gt;
&lt;p&gt;Here's a full working example that puts everything together. This example has a simple main window with translatable strings and loads translations correctly. If you're new to building PyQt6 applications, you may want to start with &lt;a href="https://www.pythonguis.com/tutorials/pyqt6-creating-your-first-window/"&gt;creating your first window&lt;/a&gt; before tackling translations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Project structure:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-text"&gt;text&lt;/span&gt;
&lt;pre&gt;&lt;code class="text"&gt;myproject/
&amp;boxvr;&amp;boxh;&amp;boxh; main.py
&amp;boxvr;&amp;boxh;&amp;boxh; translations/
&amp;boxv;   &amp;boxur;&amp;boxh;&amp;boxh; myapp.fr_FR.qm    (compiled translation file)
&amp;boxur;&amp;boxh;&amp;boxh; myproject.pro
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;main.py:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;import os
import sys

from PyQt6.QtCore import QLibraryInfo, QLocale, QTranslator
from PyQt6.QtWidgets import (
    QApplication,
    QCheckBox,
    QComboBox,
    QLabel,
    QLineEdit,
    QMainWindow,
    QMessageBox,
    QPushButton,
    QVBoxLayout,
    QWidget,
)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(self.tr("My Application"))

        central = QWidget()
        layout = QVBoxLayout(central)

        self.label = QLabel(self.tr("Film name:"))
        layout.addWidget(self.label)

        self.line_edit = QLineEdit()
        self.line_edit.setPlaceholderText(self.tr("Enter the film name"))
        layout.addWidget(self.line_edit)

        self.button = QPushButton(self.tr("Click me"))
        self.button.setToolTip(self.tr("Press this button to do something"))
        self.button.clicked.connect(self.on_button_clicked)
        layout.addWidget(self.button)

        self.combo = QComboBox()
        self.combo.addItems([
            self.tr("Option A"),
            self.tr("Option B"),
            self.tr("Option C"),
        ])
        layout.addWidget(self.combo)

        self.checkbox = QCheckBox(self.tr("Enable notifications"))
        layout.addWidget(self.checkbox)

        self.setCentralWidget(central)
        self.resize(400, 250)

    def on_button_clicked(self):
        QMessageBox.information(
            self,
            self.tr("Hello"),
            self.tr("You clicked the button!"),
        )


if __name__ == "__main__":
    app = QApplication(sys.argv)

    # Build absolute path to translations folder
    basedir = os.path.dirname(os.path.abspath(__file__))
    translations_path = os.path.join(basedir, "translations")

    # Detect system locale
    locale = QLocale.system().name()
    print(f"System locale: {locale}")

    # Load Qt's built-in translations (for standard dialogs, etc.)
    qt_translator = QTranslator()
    qt_translations_path = QLibraryInfo.location(
        QLibraryInfo.TranslationsPath
    )
    if qt_translator.load(f"qt_{locale}", qt_translations_path):
        app.installTranslator(qt_translator)
        print(f"Loaded Qt translations for {locale}")
    else:
        print(f"No Qt translations found for {locale}")

    # Load this application's custom translations
    app_translator = QTranslator()
    if app_translator.load(f"myapp.{locale}", translations_path):
        app.installTranslator(app_translator)
        print(f"Loaded app translations for {locale}")
    else:
        print(f"No app translations found for {locale}")
        print(f"  Looked in: {translations_path}")

    # Create the window AFTER translations are loaded
    window = MainWindow()
    window.show()

    sys.exit(app.exec())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;myproject.pro:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-python"&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class="python"&gt;SOURCES += main.py
TRANSLATIONS += translations/myapp.fr_FR.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;To generate the translation files and compile them:&lt;/p&gt;
&lt;div class="code-block"&gt;
&lt;span class="code-block-language code-block-sh"&gt;sh&lt;/span&gt;
&lt;pre&gt;&lt;code class="sh"&gt;# Extract translatable strings
pylupdate6 myproject.pro

# Edit translations/myapp.fr_FR.ts with Qt Linguist or a text editor

# Compile to binary .qm format
lrelease myproject.pro
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="debugging-checklist"&gt;Debugging checklist&lt;/h2&gt;
&lt;p&gt;When your translations aren't loading, work through this list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Check the return value of &lt;code&gt;load()&lt;/code&gt;.&lt;/strong&gt; Add a &lt;code&gt;print()&lt;/code&gt; after each &lt;code&gt;load()&lt;/code&gt; call to see if it returns &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check the filename exactly.&lt;/strong&gt; Is it &lt;code&gt;myapp.fr_FR.qm&lt;/code&gt; or &lt;code&gt;myapp_fr_FR.qm&lt;/code&gt;? The separator in your &lt;code&gt;load()&lt;/code&gt; call must match.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check the path.&lt;/strong&gt; Print &lt;code&gt;translations_path&lt;/code&gt; and verify the &lt;code&gt;.qm&lt;/code&gt; file actually exists there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use absolute paths.&lt;/strong&gt; Build them from &lt;code&gt;__file__&lt;/code&gt; to avoid current-working-directory problems.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Load translations before creating widgets.&lt;/strong&gt; If you create a &lt;code&gt;QMainWindow&lt;/code&gt; before installing the translator, its strings won't be translated.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep references to your &lt;code&gt;QTranslator&lt;/code&gt; objects.&lt;/strong&gt; Don't let them get garbage collected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Make sure your &lt;code&gt;.pro&lt;/code&gt; file lists all source files.&lt;/strong&gt; If a file isn't listed, its translatable strings won't appear in the &lt;code&gt;.ts&lt;/code&gt; file, and they won't end up in the &lt;code&gt;.qm&lt;/code&gt; file either.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Translations in PyQt6 can feel like working in the dark, because the system never tells you when something goes wrong. The good news is that once you understand the handful of things that can go wrong &amp;mdash; file paths, naming conventions, load order, and garbage collection &amp;mdash; the system works reliably every time. Once your translations are working, you can move on to &lt;a href="https://www.pythonguis.com/tutorials/packaging-pyqt6-applications-windows-pyinstaller/"&gt;packaging your PyQt6 application&lt;/a&gt; for distribution, making sure your &lt;code&gt;.qm&lt;/code&gt; files are included alongside your code.&lt;/p&gt;
            &lt;p&gt;For an in-depth guide to building Python GUIs with PyQt6 see my book, &lt;a href="https://www.martinfitzpatrick.com/pyqt6-book/"&gt;Create GUI Applications with Python &amp; Qt6.&lt;/a&gt;&lt;/p&gt;
            </content><category term="pyqt6"/><category term="pyqt"/><category term="translations"/><category term="i18n"/><category term="python"/><category term="qt"/><category term="qt6"/></entry></feed>