Deploying PyQt Python Qt apps cross platform using pyqtdeploy

These are general notes and links for this subject.  In other words, this is a table of contents.  Many links are often specific to a target platform.

Some of the links to my posts are to incomplete drafts.   Also, I edit these blogs periodically, since pyqtdeploy is actively developed and I am learning too.  It is best to consult source documentation.

Cross-platform and Localization/Internationalization/i18n

You want the largest possible audience or market.  You are using Qt because it:

  •   is cross platform.
  •  is cross language: supports localization ( internationalization)

You increase your audience by porting to new platforms AND by localizing to new languages.

Contents

Original (source) documentation

pyqtdeploy v0.6 User Guide

Qt for iOS

Qt for Android

General

Cross platform software development

More notes about pyqtdeploy

Deciding between Xcode and QtCreator for packaging PyQt apps for OSX

Target Linux and MacOS

Using pyqtdeploy

MacOS bundling (packaging) a pyqtdeployed app using Xcode

 Target iOS

iOS part 1 (prepare tools)

iOS part 2 (cross compile static libraries)

iOS part 3 (cross compile app and deploy)

 Target Android

Android cross compiling Qt example C apps

Android part 1 (prepare tools and cross compile static libraries)

Android part 2  (cross compile app)

Android part 3 (deploy and debug) DRAFT

Localization

General notes

Localizing PyQt app for target OSX using Xcode

More localizing PyQt app for target OSX

Using Qt Linguist phrasebooks

Adventures in translating an app to Chinese

Universal user interface

Commands that support gestures

Localizing (i18n) a PyQt App on OSX using Xcode

INCOMPLETE DRAFT.  I’ve done this process, just haven’t written it up yet.

How to tell Xcode to localize strings in native dialogs of a Qt app.

This is also discussed in many posts on Stack Overflow and in the Qt documentation.

This is about using the Xcode GUI.  If you are using the command line to invoke Xcode tools, or using Qt Creator to bundle your Mac app, the details may not apply.

Checklist of product components to localize

  1. user-facing strings in your Qt code (in the GUI of your app that you wrote.)
  2. user-facing strings in the Qt library (in GUI that the Qt library implements)
  3. strings in platform native dialogs (in the GUI of your app that the platform provides.)
  4. your help files (typically html)
  5. your marketing materials (uploaded to stores)

This blog is most specific about 3.

PyQt and Qt’s user facing strings

The user-facing strings 1 and 2 are embedded resources of your app.  While you could package them as Mac resources, it is more general to package them as Qt and PyQt  resources.  This doesn’t discuss how to do that, except:

  • you use the tools pylupdate, Qt Linguist, lrelease, pyrcc
  • the translation resources end up as a foo_rc.py file in your project
  • PyQt provides the mechanism for finding those resources as needed

The difference between native dialog strings and strings in your Qt code

Qt provides mechanisms to localize strings in the code that it knows about.  But your app, via Qt, can invoke native dialogs, such as the Print dialog.  Qt doesn’t know about the strings in that dialog.

(Qt does know about conventions for naming standard buttons and menu items on certain platforms.   These are in the MAC_APP??? context in Qt .ts files, etc.)

How to tell Xcode to localize native dialogs

  1. Add a localizable string to your project
  2. Add a language to your project
  3. Arrange that .lproj files are in your project and bundled
Add a localizable string

In the Navigator pane, click on the + icon at the lower right (or press RMB on your project and choose “Add New

TO DO

 

Notes on i18n localization of Qt5 using PyQt

These are brief notes about localization of PyQt (or C++) programs using Qt5.  Use with caution, I’m learning too, and this could be wrong.

Localization is also known as:

  • i18n
  • internationalization
  • l10n (common on Qt sites)

The state of Qt translations

Briefly, they are haphazard.  Because of the transition from Qt4 to Qt5, many translations files are waiting to be ‘blessed’ by a third party translator.  You might need to use a mix of files from Qt4 and Qt5.

This page discusses how to contribute translations to Qt.  If you go there, this link takes you to the current translation files and shows you their percentage completion (whether they have been blessed by a person who knows the native language.)  That link also lets you download the current (or future) translation files.

Note that the ‘future’ translation files  (for Qt 5.4 as of the time of this writing) are full of translations, but all are marked ‘unfinished’  (until someone blesses them, sometime during the release of Qt5.4?)

Differences between Qt4 and Qt5 translation files

In Qt4, all translations were in one monolithic file but in Qt5 they are split up into a file per Qt module.  For example, in Qt4 translations were all in qt_xx.ts but in Qt5 translations for QtCore and QtGui are now in qtbase_xx.ts.  This applies both to the templates (.ts) and compiled translations (.qm).

In Qt5, there still exists a translation file having the same name as the Qt4 monolithic file (qt_xx.ts or qt_xx.qm) but it ‘includes’ (in other words references) the split files (e.g. qtbase_xx.ts and qtdeclarative_xx.ts).  In Qt5, that file is called a ‘meta catalog file.’  (Such a .ts file will not open in Linguist; Linguist says it is empty.)

So in your app code, you can still load a translator for the one name.  As discussed here, for C++ it recommends to concatenate .qm files into one file having that same name.

However, for a PyQt app that only uses one module, it might make sense to load a translator with only one file, e.g. qtbase_xx.ts.  But because of the transition from Qt4 to Qt5, a ‘blessed’ qtbase_xx.ts file may not exist.  You might just rename the Qt4 monolithic file qt_xx.ts to qtbase_xx.ts.

It is part of your build process to compile the template files (.ts => .qm) and to concatenate them into one file (or not.)  Your buld process may include a step of downloading the template files (.ts) for Qt library.

In the files at that link for Qt5.3, there are some files such as qt_pt.ts that are the ‘meta catalog file’ but the included split files are not present!  So you must be careful where you get your files: sometimes qt_xx.ts is a Qt4 file of translations, and sometimes it is a Qt5 ‘meta catlog’ that Linguist says is empty.

Understanding the gitorious Qt website

Warning: I don’t really understand it yet.  If you open the qt/qt5 repository, it doesn’t have much in it.  If you read the Qt Wiki about building Qt5 from source, it says you first clone that repository, and then run a script that clones other repositories.  That’s probably the best way to get Qt5 source. (But for example, the web site says the repository will have all branches, but I found that it only has the 5.3 branch (the stable branch), and is missing the ‘dev’ branch described by the Qt Wiki about Qt’s branching model ?)

At the gitorious qt website, if you open the qt/qtranslations repository, it appears to contain Qt4 translations files.  I could be wrong.  As evidence, the files there seem to be missing the ‘QPlatformTheme’ context, which is a Qt5 innovation.

Reiterating, you must be careful where you get your translations files (.ts).

What worked for me

I downloaded qtbase_xx.ts files from this link (an ftp site) under the ‘5.4’ section (which are ‘future’.)  The files seems to be complete in that they have all the user-facing texts from the Qt5 source code.  However, they are all (?) marked unfinished.  As mentioned earlier, they are awaiting the 5.4 release and ‘blessing.’

But I ran an awk script to mark “finished” all translations that have non-empty translated text.  Its not politically correct, since no human has reviewed the status of the translations.  Some of the translated texts may themselves have been generated by a program (by the conversion from Qt4 to Qt5) and might not be correct.  But I found that at least for my app, which uses a minimal but critical subset of the strings, it is better than the alternatives.  The critical set that I need are the strings in the context ‘QPlatformTheme’, which makes standard buttons in dialogs use the platform’s theme.  (This also very much depends on what language you choose, for example German may already be blessed and complete, but Portuguese not.)

The awk script:

# gawk script to mark translations finished in a .ts file

# Usage: gawk -f finish.nawk foo.ts > tmp.ts

# unfinished translations with non-empty text become finished
# Note .+ matches at least one character
/"unfinished">.+<\/translation/ { 
    sub("unfin", "fin")
    }

# print every line (some modified by earlier pattern)
{ print }

 

Cut and paste can garble a template file!

I found the hard way that you must be careful: you can’t browse to a ‘raw blob’ template file at the gitorious qt website and cut and paste it to your computer.  Somehow it garbles the Unicode encoding.  You are better off downloading the files (say using the link above.)

The relationship between KDE and Qt

KDE (an alternative desktop to Gnome) is alive and well in Europe.  It uses Qt instead of GTK as its windowing framework.

Unfortunately, KDE does their own translations of Qt user-facing strings.  They use their own i18n system, including another format (.po) file.   I don’t think they base their translations on Qt translations, and have little interest in updating the Qt translations.  There doesn’t appear to be much flow of translations from KDE back into Qt.  (Its another case of duplication of effort, and difficulty of coordination?)

Japanese still is not well supported on Ubuntu

I especially had trouble with Japanese language on Ubuntu. For example, in Linguist, many characters in translated texts don’t display properly.  I think it is mostly to do with fonts.  It might depend on many factors, such as whether you have exported LANGUAGE=ja in your shell environment, whether you have used System Settings>Language to set the language, whether you have rebooted, and what fonts you have installed.  I struggled to find a combination that was stable.

Bottom line: use something other than Linux/Ubuntu (a Mac?) to use Linguist to translate Japanese (until the mess is straightened out.)

Localizing a PyQt app on MacOS OSX

Brief notes, possibly wrong, from my experience:

Your app must negotiate with OSX using QLocale.uiLanguages, to decide what translators to install.  You have translated your app’s localizable strings to a set of languages (using Qt tools for i18n.)  OSX has a prioritized list of the languages the user prefers (from System Preferences>Languages.)  Your app must find the best fit.  Your app using translators for the language given by QLocale.system().name() is not usually the right thing to do.

In Info.plist, the key CFBundleLocalizations, which appears as key “Localizations” in the Xcode GUI.  I don’t think this has any effect on how OSX treats your app.  I think it is just used in marketing, that is the stores use this to decide whether your app should be in a store in a certain country.

In OSX, a terminal always shows environment variable LANG equal to ‘en’ or similar, that is, English.  Unless you change your environment variables, or the settings of the terminal.  That is, this is not affected by the user reprioritizing languages using System Preferences>Languages.

The file locversion.plist does not seem to be necessary anymore (on OSX 10.9 and Qt5) to get a Qt app to be localized (despite what certain Qt documentation says.)

OSX knows what translations your Qt app supports only by the set of xx.lproj folders in the Resources folder of your app bundle.  For a Qt app, these xx.lproj folders will contain little if anything, just a placeholder, say a single Localizable.string, which really is not used by your app.  By “OSX knows” I mean: OSX translates native dialog strings according to.  Much of your GUI is from Qt, and is translated by Qt, but Qt displays some native dialogs (provided by OSX) and these are localized by OSX according to the presence of the xx.lproj files.

A localization has these components:

  • native dialogs (localized by platform, but depends on your bundling/packaging) e.g. “Save File” dialog
  • Qt dialogs (localized by Qt project, e.g. qt_xx.qm) e.g. standard button “Cancel”
  • your GUI face (localized by your projects .ts files)

In a PyQt projects, localizable resources will be in a myApp_rc.py file.  Your app won’t contain any localizable resources that OSX understands or needs, i.e. in myApp.app/Contents/Resources.

To test, use System Preferences>Languages.  Move a language to the top of the list and close the dialog.  Don’t restart your computer (that just means that Finder, and other apps already running, may not use the chosen language until you do restart, or unless the apps are designed to change language dynamically.)  Start your app.  All the components listed above should appear in the chosen language.

 

 

Using Qt Linguist Phrasebooks

Phrasebooks in Linguist offer suggestions, and makes your job of translating much easier.

About Linguist phrasebooks

Your app will use many phrases that others in the Qt community have already translated.  But your app uses the phrases in a different context than the phrases were originally translated.  This usually is irrelevant, and your session with Linguist then becomes mostly verifying that the existing translation is appropriate for your context.  In other words, Linguist suggests a translation (from a phrasebook) to you for your context, and you OK it for use in your context.  You just click on the suggestion.  You might not need to think much about the meaning of the translation, or its grammar.

A Linguist translation file comprises translations in context.  A Linguist phrasebook comprises translations without context.

Obtaining phrasebooks

Phrasebooks are files with the .qph suffix.

You can often find them at /usr/share/qt5/phrasebooks.   (I suppose installing Qt installs them.)

You can also use other translation files  as a phrasebook, after converting them.

Converting a .ts to a phrasebook

You can convert a translations files ( a .ts file) to a phrasebook.

You need the lconvert tool distributed with Qt.

lconvert -of qph -i  <foo_xx>.ts -o <foo_xx>.qph

This says:

  • -i:  convert the named input file
  • -o: to the named output file
  • -of: outputting the format qph.

Where you substitute the name of an app for foo, and the name of a language for xx, before submitting the command.  For example ‘qt_ja.ts’ for the Qt app (library), and the Japanese language.

Qt .ts files are a very good to convert to phrasebooks.  The Qt library uses many phrases that your app also probably uses, although in a different context.

All the files are XML files.  In a translations files, the translations are nested in contexts.  The conversion just removes the nesting within contexts.  Leaving just a sequence of translations.

Opening multiple phrasebooks

You can open many phrasebooks at the same time.  For example, you can open both:

  • /usr/share/qt5/japanese.qph
  • qt_ja.qph (that you converted from qt_ja.ts)

Opening multiple translations files

Other translation files (not phrasebooks) are NOT a source of suggestions for translations (only translations in other languages that you might understand better).

You can open many translation files simultaneously in Linguist.  But they must all be for the same app.  For example:

  • qt_ja.ts
  • qt_kr.ts

You can’t for example concurrently open:

  • myApp_ja.ts
  • qt_ja.ts

because qt and myApp are different applications.

When you open many translation files, the result is that you see together (in the Linguist GUI) two foreign phrases for a single (context/sourcephrase.)  In other words, the view is of the two translation files merged, sorted first by context, then by source phrase.

Nested translation files

When converting community translation files, you might find some that are nested.  In other words, one just includes others.   For example qt_de.ts includes several other files, such as qtbase_de.ts.

You might only need to convert qtbase_de.ts or other included files.  (I didn’t try to convert the top level file.)

Creating personal phrasebooks

You might want to do that if you translate many related apps using a common set of specialized phrases.  But community phrasebooks, full of common computer terms, will probably be more useful.

Contributing translations back to the community

I don’t know how you would contribute your translations back to the community.  I don’t know who maintains /usr/share/qt5/phrasebooks nor why it doesn’t already include translations from qt_xx.ts.

Other sources of phrasebooks

Several large users of Qt:

  • KDE
  •  Ubuntu

I don’t know whether they have their own translations and phrasebooks.

Licensing

I suppose that if you can find a copy of a phrasebook, you can use it without worrying about licensing?  Although you are copying a translation, you are copying just a few words at a time and putting them in another context, creating a new work.