diff options
Diffstat (limited to 'sources/pyside6/doc/tutorials/basictutorial/translations.rst')
-rw-r--r-- | sources/pyside6/doc/tutorials/basictutorial/translations.rst | 168 |
1 files changed, 93 insertions, 75 deletions
diff --git a/sources/pyside6/doc/tutorials/basictutorial/translations.rst b/sources/pyside6/doc/tutorials/basictutorial/translations.rst index 31cd004a3..21c16cdcd 100644 --- a/sources/pyside6/doc/tutorials/basictutorial/translations.rst +++ b/sources/pyside6/doc/tutorials/basictutorial/translations.rst @@ -9,10 +9,10 @@ Translating Applications Qt Linguist ----------- -`Qt Linguist <https://doc.qt.io/qt-6/qtlinguist-index.html>`_ and +`Qt Linguist`_ and its related tools can be used to provide translations for applications. -The ``examples/widgets/linguist`` example illustrates this. The example is +The :ref:`qt-linguist-example` example illustrates this. The example is very simple, it has a menu and shows a list of programming languages with multiselection. @@ -28,18 +28,18 @@ The linguist example has a number of messages enclosed in ``self.tr()``. The status bar message shown in response to a selection change uses a plural form depending on a count: - .. code-block:: python +.. code-block:: python - count = len(self._list_widget.selectionModel().selectedRows()) - message = self.tr("%n language(s) selected", "", count) + count = len(self._list_widget.selectionModel().selectedRows()) + message = self.tr("%n language(s) selected", "", count) The translation workflow for the example is as follows: The translated messages are extracted using the ``lupdate`` tool, producing XML-based ``.ts`` files: - .. code-block:: bash +.. code-block:: bash - pyside6-lupdate main.py -ts example_de.ts + pyside6-lupdate main.py -ts example_de.ts If ``example_de.ts`` already exists, it will be updated with the new messages added to the code in-between. @@ -52,15 +52,29 @@ they should be passed to the ``pyside6-lupdate`` tool as well: pyside6-lupdate main.py main.qml form.ui -ts example_de.ts The source files generated by ``pyside6-uic`` from the form files -should `not` be passed. +should **not** be passed. + +The ``lupdate`` mode of ``pyside6-project`` can also be used for this. It +collects all source files and runs ``pyside6-lupdate`` when ``.ts`` file(s) +are given in the ``.pyproject`` file: + +.. code-block:: bash + + pyside6-project lupdate . ``.ts`` files are translated using *Qt Linguist*. Once this is complete, the files are converted to a binary form (``.qm`` files): - .. code-block:: bash +.. code-block:: bash + + pyside6-lrelease example_de.ts -qm example_de.qm + +``pyside6-project`` will build the ``.qm`` file automatically when +``.ts`` file(s) are given in the ``.pyproject`` file: - mkdir translations - pyside6-lrelease example_de.ts -qm translations/example_de.qm +.. code-block:: bash + + pyside6-project build . To avoid having to ship the ``.qm`` files, it is recommend to put them into a Qt resource file along with icons and other @@ -68,43 +82,45 @@ applications resources (see :ref:`using_qrc_files`). The resource file ``linguist.qrc`` provides the ``example_de.qm`` under ``:/translations``: - .. code-block:: xml +.. code-block:: xml - <!DOCTYPE RCC><RCC version="1.0"> - <qresource> - <file>translations/example_de.qm</file> - </qresource> - </RCC> + <!DOCTYPE RCC><RCC version="1.0"> + <qresource prefix="translations"> + <file>example_de.qm</file> + </qresource> + </RCC> At runtime, the translations need to be loaded using the ``QTranslator`` class: - .. code-block:: python +.. code-block:: python - path = QLibraryInfo.location(QLibraryInfo.TranslationsPath) - translator = QTranslator(app) - if translator.load(QLocale.system(), 'qtbase', '_', path): - app.installTranslator(translator) - translator = QTranslator(app) - path = ':/translations' - if translator.load(QLocale.system(), 'example', '_', path): - app.installTranslator(translator) + path = QLibraryInfo.location(QLibraryInfo.TranslationsPath) + translator = QTranslator(app) + if translator.load(QLocale.system(), 'qtbase', '_', path): + app.installTranslator(translator) + translator = QTranslator(app) + path = ':/translations' + if translator.load(QLocale.system(), 'example', '_', path): + app.installTranslator(translator) The code first loads the translations shipped for Qt and then the translations of the applications loaded from resources. The example can then be run in German: - .. code-block:: bash +.. code-block:: bash + + LANG=de python main.py - LANG=de python main.py +.. _Qt Linguist: https://doc.qt.io/qt-6/qtlinguist-index.html GNU gettext ----------- -The `GNU gettext <https://docs.python.org/3/library/gettext.html>`_ module +The `GNU gettext`_ module can be used to provide translations for applications. -The ``examples/widgets/gettext`` example illustrates this. The example is +The :ref:`gettext-example` example illustrates this. The example is very simple, it has a menu and shows a list of programming languages with multiselection. @@ -116,29 +132,29 @@ aliased to ``ngettext``. Those functions are defined at the top: - .. code-block:: python +.. code-block:: python - import gettext - ... - _ = None - ngettext = None + import gettext + # ... + _ = None + ngettext = None and later assigned as follows: - .. code-block:: python - - src_dir = Path(__file__).resolve().parent - try: - translation = gettext.translation('example', localedir=src_dir / 'locales') - if translation: - translation.install() - _ = translation.gettext - ngettext = translation.ngettext - except FileNotFoundError: - pass - if not _: - _ = gettext.gettext - ngettext = gettext.ngettext +.. code-block:: python + + src_dir = Path(__file__).resolve().parent + try: + translation = gettext.translation('example', localedir=src_dir / 'locales') + if translation: + translation.install() + _ = translation.gettext + ngettext = translation.ngettext + except FileNotFoundError: + pass + if not _: + _ = gettext.gettext + ngettext = gettext.ngettext This specifies that our translation file has the base name ``example`` and will be found in the source tree under ``locales``. The code will try @@ -146,18 +162,18 @@ to load a translation matching the current language. Messages to be translated look like: - .. code-block:: python +.. code-block:: python - file_menu = self.menuBar().addMenu(_("&File")) + file_menu = self.menuBar().addMenu(_("&File")) The status bar message shown in response to a selection change uses a plural form depending on a count: - .. code-block:: python +.. code-block:: python - count = len(self._list_widget.selectionModel().selectedRows()) - message = ngettext("{0} language selected", - "{0} languages selected", count).format(count) + count = len(self._list_widget.selectionModel().selectedRows()) + message = ngettext("{0} language selected", + "{0} languages selected", count).format(count) The ``ngettext()`` function takes the singular form, plural form and the count. The returned string still contains the formatting placeholder, so it needs @@ -172,43 +188,45 @@ is first created: xgettext -L Python -o locales/example.pot main.py This file has a few generic placeholders which can be replaced by the -appropriate values. It is then copied to the ``de_DE/LC_MESSAGES`` directory. +appropriate values. It is then copied to the ``de_DE/LC_MESSAGES`` directory. - .. code-block:: bash +.. code-block:: bash - cd locales/de_DE/LC_MESSAGES/ - cp ../../example.pot . + cd locales/de_DE/LC_MESSAGES/ + cp ../../example.pot . Further adaptions need to be made to account for the German plural form and encoding: - .. code-block:: +.. code-block:: - "Project-Id-Version: PySide6 gettext example\n" - "POT-Creation-Date: 2021-07-05 14:16+0200\n" - "Language: de_DE\n" - "MIME-Version: 1.0\n" - "Content-Type: text/plain; charset=UTF-8\n" - "Content-Transfer-Encoding: 8bit\n" - "Plural-Forms: nplurals=2; plural=n != 1;\n" + "Project-Id-Version: PySide6 gettext example\n" + "POT-Creation-Date: 2021-07-05 14:16+0200\n" + "Language: de_DE\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + "Plural-Forms: nplurals=2; plural=n != 1;\n" Below, the translated messages can be given: - .. code-block:: +.. code-block:: - #: main.py:57 - msgid "&File" - msgstr "&Datei" + #: main.py:57 + msgid "&File" + msgstr "&Datei" Finally, the ``.pot`` is converted to its binary form (machine object file, ``.mo``), which needs to be deployed: - .. code-block:: bash +.. code-block:: bash - msgfmt -o example.mo example.pot + msgfmt -o example.mo example.pot The example can then be run in German: - .. code-block:: bash +.. code-block:: bash + + LANG=de python main.py - LANG=de python main.py +.. _GNU gettext: https://docs.python.org/3/library/gettext.html |