Using relative coordinates in KiCad to design mechanical aspects of PCB boards

TL;DR: press the space bar to set the origin of the relative coordinate system and then watch the dx,dy cursor coordinates in the status bar as you draw.

See  section 2.6. “Displaying cursor coordinates” of the Eeschema reference manual.

There are two coordinates systems (frames) in KiCad:

  • absolute: origin is in one of the corners of the “paper” sheet, displays as “X…Y…”
  • relative: origin is wherever you set it using the space bar, displays as “dx…dy….”

KiCad continually displays the location of the cursor in the right side of the status bar which appears near the bottom of the application window.  KiCad updates the displayed location even as you use some tool to draw, place, etc.  KiCad displays the location of the cursor in both coordinate systems.

Use the relative coordinate system to layout a board mechanically.  First set the origin, say to the upper left corner of your board:

  • move the cursor to where you want it
  • press the space bar.  Expect the relative coordinates to change to “dx 0.0000 dy 0.0000.”

Then as you draw, you can stop the cursor at some precise dimension.

KiCad does not persist the origin of the relative coordinate system (save it in your project.)  You need to set the origin at the beginning of each design session.

KiCad does not display any particular symbol at the origin of the relative coordinate system.  You can add a fiducial symbol at the origin.

Few people use the absolute coordinate system and many people complain that you can’t set its origin.  But they should just use the relative coordinate system.

From a user-interface viewpoint, maybe KiCad should:

  • place more emphasis on the relative coordinate system (display relative coords left of/preceding the absolute coords)
  • make the origin persist
  • add a pop-up menu item to set the origin (space bar is too obscure)
  • make the displayed nomenclature more consistent (why is it not “dX,dY and dx,dy” or “X,Y and x,y” or “aX, aY and rX, rY” or “abs x,y and rel x, y”)

Counting touches in touchesBegan() and gestures

This discusses a surprise!  something I learned the hard way.

Many touch events may come via touchesBegan() for multi-finger touches .  For example, for a three finger touch, you may get one event having one touch followed a fraction of a second later by another event having two touches, where each touch is for a different finger (having a different location.)

In other words, you can NOT rely on getting one touch event having all the touches.    You shouldn’t check Set<UITouch>.count() to determine the number of fingers the user is using.

That is the job of a gesture recognizer.  A gesture recognizer typically establishes a short window in time, and gathers all the distinctly located touches begun in that window, to determine whether the count of touches meets the requirements of the gesture.  (I presume a gesture recognizer also filters out touches that later drop out of the gesture.)

Every gesture (the superclass  UIGestureRecognizer) has the method numberOfTouches().

Many gestures can be configured with a minimum count of touches.  This is only a minimum.  A user can use more fingers and the gesture still be recognized.

  • Pan: minimumNumberOfTouches()
  • LongPress, Tap: numberOfTouchesRequired()
  • etc.

Some of the gestures also allow a maximum to be defined.

In summary: if your app supports only one finger, you might be able to use touchesBegan() and touchesEnded() to crudely determine what the user is doing.  Otherwise, you should rely on gesture recognizers to count the number of touches.

Note that certain combinations of gestures (e.g. Tap and double Tap, with a dependency defined between them) might incur a lag for gesture recognition.   In other words, using touchesBegan, you can soon determine whether a user is acting, but using gestures you might later determine a user is acting.  It can get complicated.  For example, is the  lag between start of the real gesture and when a recognizer is in the Begin state or is the lag until the the single tap recognizer is in the Finished state (which comes no sooner than the double Tap recognizer being in the Canceled state) ?

Scalable user interfaces: phone, pad, and desktop

This is a brief note, at a high level about designing the GUI of an application for portability across platforms (of different screen sizes and pointer devices.)  Bottom line: use context menus.

This is mostly about small, focused, document centered apps, not large, complex, bloated apps.

Skins

Skins are look and feels, or views of your app (but more than just decorations.)  Use the MVC paradigm to separate the model from the view so that you can reskin your app.

Even if you don’t offer the user a choice of skin, you probably will reskin your app during its lifetime.

Skins can vary by platform.  Here I mostly discuss trying to design one skin that is cross-platform.

Actions are central to reskinning.  Actions are fundamental things the user can do.  They are in the view, but they are linked to a method in the model.  Actions in the view can be shared (without change) across many skins.  For example, an action can be associated with a toolbar icon, a context menu item text, or button in a dialog.

Context menu GUI’s are cross-platform

A context menu driven app is mostly cross-platform.

A context menu is also known as a pop-up, or action sheet.

A context menu actually varies across platforms:

  • phone: slides up (drawers) from the bottom (iOS), NOT at the pointer (touch)
  • pad and desktop: appears at the pointer, or with a keyboard key (Win) at the selection

The notion of context is tied to the notion of selection.  The context is of the object that the user designated but the object need not become a long-term selection.

An alternative to a context menu is a toolbar (toolbars are context sensitive, their contents change according to the user’s designated place in a hierarchy or place in the app.)  The UI problem with toolbars is that they are away from the focus, unlike context menus.  On a phone, context menus are also ‘away’ from the focus (not at the pointer), but since the screen is small, they are not far away.

Document centered apps are NOT cross platform

Many apps on desktops are document centered.  Conversely, few apps on mobile platforms are document centered.  This is mostly because mobile devices are used for communicating and browsing, and are hindered  by sandboxing between apps.

An exception is photos as documents: most mobile devices are also cameras.  Many mobile devices are photo centered: the OS supports save, open, and edit photos.

This is changing: iOS8 is beginning to support document centered with the notion of document providers.

Document centered and navigation

Mobile platforms support navigation using navigation bars (when an app has hierarchical data or nature, e.g. a music library.)

A file system having documents is also hierarchical and amenable to a navigation based UI.  The problem is that on mobile platforms, the file system is not usually navigable (there is no native file browser or Finder and app files are sandboxed i.e. segregated.)

A cross-platform document centered GUI

On mobile platforms, for  document centered apps, one possible navigation-based  GUI comprises three paged views, where the navigation bars for the views are :

  •                 Docs          Edit>
  • <Docs     document   Meta>     where ‘document’ is the title of the current document
  • <document   Meta

The first view lets the user browse the app’s private store of documents (or in upcoming iOS8 apps, the private data stores of all apps that provide the mimetype which the current app understands and consumes.)

The second view lets the user edit a document, in WYSIWYG (the user sees the document.)

The third view lets the user change meta data of the document (e.g. the style or non-visible attributes.)

So, to make a cross-platform, document centered app,  you use different skins:

  • mobile: a skin such as the above
  • on the desktop, a traditional skin having a menubar with a File menu and File Chooser dialog (instead of the first view above) and with a File>Properties or other menu item for the third view above.

Share: the OS as a clearing-house, broker for documents and apps that understand them

An OS understands what apps can publish and subscribe to document types (mimetypes.)

This is done at installation time, via resources in the app’s package:

  • iOS and OSX: document icons in the bundle
  • Android: ??? in the manifest
  • Linux: desktop ??? in the .deb package

Mobile platform OS’s also support the notion of ‘share’, with a native dialog that shows the user which apps can understand your mimetypes.  The desktops (and frameworks on top of them) don’t provide that dialog.

Sharing is broad, meaning either:

  • open with another application, right now (print, or view in another application)
  • send a copy to another place (a website, the cloud, or a file system)

You can see that in the iOS share dialog, separated top and bottom.  Loosely, the top is ‘send to another place’, the bottom is ‘open with another application’.

Sharing is similar to drag and drop, except it crosses devices and has different syntax (order of steps):  with drag and drop, both applications must be open or have an icon on the screen.  So you must decide what the target is, open the applications, then sharedrag.  With share, you don’t decide first; you might decide the target after you start the sharedrag.  The target application need not be ‘open’ (displaying, because the mobile platforms have only one active window.)

I suspect that the notion of share will be soon supported by desktops (OS or frameworks), precisely because it would simplify the development of cross-platform apps.

Embellishing a skin with menubar on the desktop

A menubar is absent from most mobile platforms.  But, an apps skin on the desktop might in addition have a menubar.

A menubar is a necessary wart on desktops: when you have many windows, the menubar tells you which window is active.

A menubar also helps a user because it might be redundant: it might include all the same actions that the context menu system does, but all in one place.  A user can navigate in the menu system without navigating in the other app views.

A menubar also has global actions such as undo and redo.  A notable wart of iOS is that there is an action for undo (shake) but no global action for redo (AFAIK that requires using the virtual keyboard.)  Android also lacks undo/redo.

 

Switching to QML from QWidget using Qt and PyQt

This is high-level, loose assemblage of discussion and links.

Context: you have a cross-platform app written using Qt and PyQt.  It is written using QWidgets.  You want to switch from QWidgets to QML.

The discussion is not exclusive to PyQt.  Much of the discussion also applies to apps writtent in C++, but mentions PyQt also.

This might also have some relevance for apps written purely in QML/Qt Quick.

Why switch to QML from QWidget?

These are possible reasons:

  • QML uses native platform style whereas QWidget fails to have native look and feel on some platforms (iOS)
  • QML more strongly follows the ModelViewController paradigm
  • QML is declarative (more compact and dense)
  • a QML GUI is easier to change (to provide multiple or improved GUI’s for the same business model)

To me, the first reason is the most compelling.  The last reason is least compelling: you probably won’t be changing the GUI often (but then here we are talking about changing at least the implementation of a GUI.)

(Qt apps are excluded from the Windows Store because Qt did not support Windows8/WinRt but Qt5.4 and QML may remedy that?)

Model View Controller paradigm

Qt documentation: Model – View Options in Qt

Wiki: Model–view–controller

It is quite likely that your existing QWidget apps does not strictly adhere to the MVC paradigm.  Thus you will be probably need to refactor your code: separate model code from view code.

A strategy for  developing (code changes) to switch to QML from QWidget

Assuming your app using QWidgets already runs and has tests, a good strategy is to keep the QWidget implementation of the View working, while you develop the QML implementation of the View.   In other words, use test driven development: make small changes, then test the QWidget implementation AND the QML implementation.  The QWidget implementation should always remain fully functional after each change.  The QML implementation will also always work, but in a stubbed-out, minimal fashion.

Changing the existing QWidget app will largely entail:

  • splitting classes along model/view lines
  • converting procedure calls to signals, connections, and properties

Swapping in the QML implementation of the view will be just a small change in the startup code: creating QML instead of QWidgets.  (Its a little more complicated than that, you might be making connections in the QML instead of in the main app.)

Embedding QML in a QWidget app

You can implement the main app window (and all other GUI) in QML.  But you can also embed QML GUI inside a QWidget app.

Briefly, it entails using QQuickView.  But a QQuickView not is-a QWidget.  But you can wrap a QQuickView in a QWidget:  Qt documentation: Introducing QWidget::createWindowContainer() discusses how to wrap a QQuickView in a QWidget.

Why retain a QWidget shell embedding QML?  I suspect there are few reasons to do so.  One reason might be just the strategy discussed above; get your feet wet by embedding QML and make the last step converting the main window from QWidget to QML.

My reason was different: my app uses elaborate UI  picking of objects from a QGraphicsScene.  The QML scene graph doesn’t expose the same API for picking that the QGraphicsScene does.

More on the interface between model and view using QML

Qt documentation:

Where ‘from C++’  more generally means ‘from model objects’ .  And the discussion applies to model objects written in PyQt.

The interaction is two-way, bidirectional:

  •  Control (in MVC) is from the view to the model
  • View is from the model to the view

Your interaction may be one direction or both:

  • a weather app is just a viewer of the weather
  • a styling app is just a controller of a document

Much of the logic in the QML is not business logic, just GUI logic.  For example, a button may switch pages and have no effect on the business model.  The button ‘controls’ the view, but not the business model.

Not all the interaction need be between the model and the view.  For example, if you are embedding QML in a QWidget app, the QWidget app may need to simply activate (show, make visible) a QML view component.  In other words, the interactions may be between the part of the view implemented in QWidgets and the part of the view implemented in QML.

PyQt and QML

PyQt fully supports QML.  You can use Python and PyQt for your model.

PyQt documentation:  Integrating Python and QML

I have shared a hacky Github project where I learn and test PyQt and QML.

For the same reason you use QML for the view, you should consider Python for the model (more expressive in fewer lines of code.)

The QML tradeoff: more portable but less native?

Typically, a cross-platform solution makes certain compromises.  Sometimes its discussed using terms such as “least common denominator” or “adaption.”

I can’t fully discuss this here.  (And probably the set of compromises that have been made are not fully documented in one place.)  But you should consider whether you will be able to live with any such compromises.

For example, I found that a QML Dialog on a desktop (Linux, I haven’t tested OSX) opens in a separate window, not on top of (transient to) the main window.  That probably doesn’t meet the HIG’s for desktops.  Possibly there is a solution that I haven’t yet found.  Or possibly I should look at that as a feature to embrace: I should make my dialogs non-modal and treat them as tear-offs that should not obscure the main window anyway.  But its an example of the compromises you might need to make.

There is much more to discuss here.  Briefly, Qt Quick Controls does use native widgets where possible, then falls back to QWidget implementations if possible, and then to a pure-QML implementation.

But again, its hard to know in advance without trying it.

Structuring your QML source code

In many examples, you see long QML files.  I  think that is an artifact of being an example: put everything in one file for ease of reading.  You can structure you QML source files into smaller files in more directories, using imports.

Qt documentation: Import Statements | QtQml 5.3

Packaging your app

I don’t foresee any show stoppers here.  Just more to learn.  If you are already packaging a PyQt app, you probably are already packaging resources using pyrcc.  The QML is just another resource to package.

But, I’m not sure how third-party QML plugins get packaged?

A strange architecture: PyQt and QML uses two interpreters

A PyQt app using QML uses two interpreters: the Python interpreter and QML’s Javascript interpreter.  (And on Android, there is a third Java interpreter.)  There is much discussion about the safety of, and constraints applied by app stores, re interpreters.   But this is just a curiousity, there are already shipping apps, using interpreters, in the stores .

A template for QML using models

Qt’s example Weather App is a starting place for reading code: Cross-Platform Applications in iOS and Android Stores with Qt

(I hope to reduce it to a simple template.)

Desktop to Mobile GUI difference: sharing

The main problem that I have found is that for certain apps (document editing or creation apps as opposed to reading or browings apps) the desktop:

  • exposes the file system to the user (in the File menu)
  • uses drag and drop

whereas mobile platforms use the notion of ‘sharing’ to the file system and other apps

Notably lacking in Qt Quick Control is a ‘share sheet’.  A github project QtSharingKit seeks to remedy that, with a QML plugin.

Pragmatically, that means more work for you:

More links about QML, Qt Quick, and Quick Controls.

You use these technology pieces:

  • QML a language.
  • Qt Quick: the standard library of types and functionality for QML
  • Qt Quick Controls: canned (pre-built) QUI controls built using QML
  • QML Applications

Porting Qt apps from desktop to mobile: look and feel: developer responsibilities

Porting a cross-platform app from desktop to mobile is non-trivial!  Especially porting cross mobile platforms (Android and iOS.)

About

A brief overview of look and feel differences when porting a Qt app from desktops to mobile platforms. Emphasizing the divide of responsibilities between developer and Qt .  In other words, a to-do list for app developers, with some how-to for Qt.

For each topic:

  • nature of the problem
  • what Qt solves
  • what a developer must solve
  • references to relevant Qt documentation

This is:

  • time sensitive: Qt and others may solve some problems.
  • preliminary draft: not definitive, as I am just starting to explore this topic

Topics /Contents

A different word/widget for everything

Mobile platform islanding

Small screen

Gestures and touch

Look (platform style)

Single window

Dynamic orientation

Quitless

File system / document-centered

Printing

Screen resolution

Virtual keyboards

Version lag

Sensor gestures and undo

Share / Drag and drop

Settings

Examples and references

An example app from Qt that crosses desktop and mobile: QuickForecast including source weather-app

A similar post about native look-and-feel with Qt.

A different word/widget for everything

Mobile platforms use different widgets (feel?) For example iOS uses ActionSheets (now deprecated in iOS8 in favor of AlertControllers.) Some of these widgets may have no corresponding widget in Qt.  (Although an iOS ActionSheet is just a pop-up QMenu?)

Qt Widgets doesn’t seem to have specialized their widget behaviour for mobile platforms. Qt QML seems to be more targeted for mobile platforms, including the widget classes that only the mobile platforms have, and using native widgets so that their style (look) is correct for the platform.

Developer might need to implement widgets unique to each platform (to achieve native feel.)  For example, here is a QtWidgets implementation of a mobile widget (Toolbar or ActionBar) that largely achieves the Android platform’s look and feel.  (I’m not sure it achieves iOS look and feel.)

Mobile platform islanding

The mobile platforms attempt to differentiate themselves.  Usually they claim user interface reasons (this is the best way to do UI) but possibly just for business marketing reasons.  See Pure Android. (Whenever you see the word ‘pure’ you know that marketing and politics are involved.  99.99% pure. )  For example, toolbars are on the bottom in iOS, and at the top in Android.

Qt solved some of this on the desktop, for example, adapting differences in the menubar among desktop platforms.  Has Qt solved if for mobile platforms?

This is related to gestures, there is not a universal set across mobile platforms.

Small screen

This is the major hurdle.  Unless your app was designed from the start for mobile platforms.  Related to feel.

Smart phones have less GUI real estate.

Qt doesn’t fully solve this? Some widgets may automagically adjust to a smaller size, for example by scrolling?

A developer may need to:

  • redesign many dialogs, menus, and toolbars to take less space.
  • use different interaction techniques and widgets

Gestures and touch

Mobile platforms use multi-touch instead of pointers (mice, etc.)

Qt supports gestures and touch.

Developer:

  • learn and implement gestures/touch.  There is a significant learning curve, since it involves elements of multi-processing/concurrent programming: gestures may happen concurrently and be canceled.
  • may need to implement gesture recognizers for gestures not built into Qt (e.g. TapTapSlide on WinRT)
  • may need platform specific code to adapt the semantics of gestures where the semantics are not the same across platform (for example, TapAndHold is similar to RMB on desktops, but WinRT says it ‘shows option’ while iOS seems to limit it to text items?)

Look (platform style)

Mobile platforms have their own style.

Qt provides stylesheets/themes for the platforms.

!!! Except not for QtWidgets on iOS !!! (Just using QML.  Since iOS does not expose enough to Qt.  See this long discussion on the Qt dev mailing list. )

Developer may need to use QML, or avoid iOS, or implement and style their own widgets.

Single window

Mobile platforms do not have a window manager.  Each of an app’s top-level windows (called a view on mobile platforms?)

Qt:  ???? I don’t know whether for example QToolBar is specialized for mobile platforms.

Developer: add a navigation toolbar so user can navigate between screens (‘navigate an information hierarchy or manage screen content’ .)  Called a ‘Navigation Bar’ on iOS

Dynamic orientation

A user expects to be able to rotate a mobile device from landscape to portrait orientation, and for the app to adjust in real time.  On a desktop, a user can rotate their screens, but they must restart the OS and apps.

Qt provides needed signals and methods.

Developer:

  • react to orientation changes, especially if an orientation change requires a change to the app’s feel (widgets).
  • mobile platforms support restriction of an app to certain orientations (say to landscape) but an app may still need to recognize physical ‘command’ button on right or left.

Quitless

On mobile platforms, a user hardly ever quits an app, instead just putting it in the background.  There is usually no File>Quit and no Close icon in a window title bar.  However, this is not unlike Sleep on desktops, which requires apps to be able to resume where they left off.

Qt supports state changes for applications.

Developer may need to save more context in settings?

File system / document-centered

Mobile platforms do not emphasize files and filesystems, or provide file browsers.  Mobile platforms sandbox (limit access) to the filesystem.  New is iOS8 is a feature called ‘Document Provider’, which seems to treat each application as a repository of document types (MimeTypes.)

QtWidgets QFileDialog seems to work on mobile platforms, but it is inappropriate for most users.  QML FileChooser???

Developer must provide their own dialogs for managing saved content.

Printing

Users don’t often print from mobile devices.  Note that simplified print support is new to iOS8.  Android?

Qt currently does not support the printing architectures of mobile platforms (the module QtPrintSupport is not compiled.)

A developer should wait for Qt to adapt QtPrintSupport to the mobile platforms?

Screen resolution

Mobile platforms often have higher resolution (pixels per inch) since a user holds the device closer.  (However, desktops are also trending to higher resolution just because it looks better.)  But I think this is orthogonal to screen size.  A mobile device may have a high resolution yet still have a small screen in terms of Point (Device Independent Pixels.)  Qt supporting high resolution does not magically solve the problem of a small screen.

Qt provides support for higher resolution using the concept of Device Independent Pixel (or Point.)

Developer may still have work to do?  See Qt’s Weather App, where the use a ratio?

See Retina Support in Qt

Virtual keyboards

A user on mobile platforms may not have a physical keyboard, but a virtual keyboard.  Also known as Software Input Panel or SIP (in Qt.)

Qt supports virtual keyboards transparently for TextEdit widgets.  However, they don’t expose the underlying classes, so it might be difficult to use if your app doesn’t use stock TextEdit widgets?

A developer must learn how to control a virtual keyboard via Qt’s methods on TextEdit.

QApplication.autoSipEnabled

WA_InputMethodEnabled

Version lag

The platforms roll out new versions more often than on the desktop.  Qt lags behind.  For example, iOS8 is out but Qt will not have bug free support until Qt 5.4?

Qt is committed to supporting new versions (and hopefully they will reduce the lag.)

Developer: suffer the delay, or contribute to Qt.

Sensor gestures and undo

Users on mobile platforms use sensors as input methods.  Desktops don’t (a desktop computer doesn’t move, i.e. change location.)  But mobile users expect to request undo using a shake.  Undo is common to both desktops and mobile.

Qt provides a plugin for gestures from sensor.  Qt does not seem to automatically convert a shake gesture to an undo event.

Developer must implement avail sensor gestures and call app undostack methods.  In other words, add mobile specific code to subscribe to sensor gestures, and connect the shake gesture to undo.

Share / Drag and drop

Since mobile platforms are single window, a user can’t drag and drop between windows.  Sending data between apps (typically social websites, but also including copy to clipboard, and printing) is known as ‘sharing.’  On mobile platforms, a user presses a ‘Share’ button and expects a view of targets that accept the current content.

Qt doesn’t yet seem to support this notion (UIActivityViewController on iOS, Intent.createChooser() on Android.)

Developer:

  • disable drag and drop.
  • implement this themselves, or contribute a solution to Qt?

Settings

On a desktop, an app usually provides a dialog for settings.  On a mobile platform, a user accesses the settiings for an app by choosing the system settings button, then finding your app in a list.

Qt doesn’t make this change automagically?

Developer: ??

Adventures in translating an app to Chinese

This is a how-to.  A log of steps to take.  I am not an expert.  This is rudimentary, but better than nothing.  The results of this amateur translation might not be the best.   But the results are probably no worse then translations coming in the other direction.

Preparing your development computer

Your development computer must be capable of displaying the glyphs of the language into which you will be translating.  You usually must install more packages.

For Ubuntu, see Pinyin Joe.  Pinyin is a standard way of writing Chinese, across many dialects of Chinese.

If you don’t have the necessary software, the symptom is that when you paste Chinese characters onto your computer, they appear as boxes.

For translation, you don’t need ‘input methods.’  You will only be copy and pasting Chinese characters, not inputting them.  You don’t need a special keyboard.

General comments about the ease of translating apps

For an app, much that needs translation are simple words or phrases, and  have special computer meanings.  Such special computer meanings often appear as separate definitions at translating web sites.

Alternatively, you can find another app that is translated, and copy the translations from it.

Error messages, which are often complete sentences and questions, are more difficult to translate well.

Translating simple words and phrases

The best web site for translating is wordreference.com

The steps are:

  • enter an English word or phrase and choose the ‘Search’ button.  You will see a list of translations.
  • pick a translation with the appropriate meaning and part of speech
  • click on the translated string to see a list of reverse translations to English.  That helps you know whether the forward translation is correct, or gives you ideas for a better forward translation
  • copy and paste the translation (Chinese characters) into your translating program (such as Qt Linguist.)

Translating sentences

To translate sentences, you need at least a rudimentary knowledge of the grammar.   See Wiki.

The steps are:

  • translate words and put them in what you think is an appropriate order
  • copy the translated sentence into Google translate and translate it.  Check that the English meaning is not too strange.

The difference between a word translator and Google translate

I think that a site such as wordreference starts with translated words  (it also may have translations for idiomatic phrases.)  It is your responsibility to understand grammar and parts of speech.  The data there is much about parts of speech, tense, gender and so forth.  In other words, the data there is provided by humans, asserting attributes of words (but usually just words, not always phrases or sentences).

Whereas Google simply has a codex of translated text.  It finds the best match for your source text in that codex.  It has little understanding of grammar, parts of speech, etc.  It’s success depends on whether it has indexed documents in the ‘computer application’ arena.  For example, if it has indexed the user’s manuals for many applications, it might find a good translation for phrases in your app.

 

Internationalizing Python PyQt Apps

About this post

This post is a brief summary of the translating subtask of the internationalizing task of software development.  The larger internationalization task is discussed in Qt documentation.  The subtask of translating string literals is also discussed in Mark Summerfield’s book, page 512 (although the word “internationalize” is not in the book’s index!)

This post is relevant for different situations:

  • c++ versus python versus other languages
  • language used to write literals in the software
  • declarative GUI versus procedural definition of GUI (declarative: using uic or QML)

But the examples assume:

  • you are writing an app in Python using PyQt and Qt
  • you are an English speaker and coded your string literals in English (ASCII characters.)
  • you are procedurally defining your GUI (not declarative)

What is i18n?

i18n stands for “internationalization”, also called “localization”.  It is a set of business procedures, programming tools, operating system support, etc. to: make a software application display a different language than used for string literals in the source code.

The gist of i18n translations

You write your program using a few idioms and a little boilerplate in app startup code.  Use the checklist below to be sure you coded everywhere for i18n.

You modify your build process with a few extra steps.

Data flow

This is the dataflow using Qt and its tools:

From your Python source (with i18n idioms and boilerplate) and a .pro file, the program pylupdate4 produces (or updates an existing) a .ts (translations file.)

The program Qt Linguist edits the .ts file in place (like a database.)  A person in the translator role uses the program Qt Linguist.

From a .ts file the program lrelease creates .qm files.

From .qm files (in your apps resource directory, i.e. in your apps package somewhere) AND from system environment variables, your app reads and displays translated strings appropriate to your locale (as your app starts up.)

Creating a .pro file

The .pro file specifies:

  • which of your source files contain translatable string literals
  • which languages you want to translate into

Example:

SOURCES += appName.py
TRANSLATIONS += appName_es.ts

Running pylupdate5

>pylupdate5 appName.pro

This assumes:

  • the current directory is the project directory.
  • you are using Qt 5
  • the .pro file is in the current directory

It creates many .ts files in the current directory (one for each language specified in the .pro file.)

Installing the tools

Some of the tools come with Qt SDK ( Qt Creator) and some come with PyQt.  In particular, pylupdate5 from PyQt is a specialized version of lupdate5 from Qt SDK (for c++.)

Note that there is now ‘qtchooser’.  Often a command you might run e.g. ‘lrelease’ invokes (through a link in /usr/bin/lrelease) the qtchooser command, which determines which version of the tool ( loosely referred to as lrelease) to invoke.  Some of the commands from Qt 4 and Qt 5 are different commands?

Installing Qt Linguist for Qt5 on Linux

sudo apt-get install qttools5-dev-tool

Note that Qt Linguist is not specialized for Python code (the same whether the app is written in C++ or Python.)

Using Qt Linguist

Qt Linguist steps you (a person in the translator role) through phrases needing translation.  It doesn’t actually translate.

To start it, on a command line:

>linguist

A GUI app starts.  It is a document oriented app.  The document is a .ts file.  You Open the file, edit it, and Save it.  Your edits are: creating a translated string from an English language string (from the Python source, which is always in English, or ASCII anyway?)

Using Qt Linguist is iterative in this sense: in a session you iterate through the strings that have not been translated yet.

Using Qt Linguist is also iterative in this sense: when you change the GUI of your app (when you add a displayable string), you (or your person in the translator role) repeat (again) use Qt Linguist on the same .ts file as before (again, its a database.)

Do it yourself translating phrases for software apps

Even if you don’t know many foreign languages, you translate reasonably by yourself, without enlisting a specialized translator person.

There is a website Ostext.org offering access to a database of phrases used in other software and already translated.

I suppose the internal query is something like “select appName, outPhrase from translations where inPhrase contains ‘foo’ and outLanguage = ‘bar’.  In other words, it returns a set of translations of an English phrase found inside translated phrases from many apps.

There is also Google translation.

It might be easy to do a reasonable translation of the important phrases of an app because such phrases are of the grammatical form “imperative-verb noun”, that is, not grammatically correct sentences.  Then again, most users might be able to understand those phrases in English, just because of their context in menus, dialogs, etc.

Testing an internationalization

You don’t need to package your app.  Just cd to your project directory (where the .pro, .ts, .qm, and .py files are.)  Then set your locale and start your app:

>export LANGUAGE=es_es
>./my_app.py

Note this will mess the locale of any programs you start from the same terminal (shell having the same environment.)

Here es_es means: the Spanish language, in the Spain region (Castillian dialect of Spanish?)

Organizing the files in directories

Some developers seem to put all their .ts and .qm files in a subdirectory ‘i18n’ of their project directory.

When packaged, only the .qm files are needed, again usually in a subdirectory, but now a subdirectory of the resource directory.

The idioms for i18n

Wherever you first define a string literal that will be visible to a user, bracket the string literal in a call to self.tr():

self.tr("foo")

Caution: you can’t bracket a variable (a reference), only a string literal.  This won’t work (pylupdate will fail to parse it into the .ts file):

bar = "foo"
self.tr(bar)

In other words, the tool pylupdate5 parses your code (looking for string literals that need translating), but is limited in its understanding of which references have type ‘string’.

Caution: the method tr() is defined in class QObject (the root class of most Qt classes.)  You can’t use self.tr() in an object that is not derived from QObject.  In that case, you can delegate to another object that is derived from QObject (one that you defined, or a QApplication instance.)

Gotchas: complexities

Install translator early

You must install a QTranslator instance into the app before procedurally creating the GUI (otherwise you create the GUI with untranslated strings.)

One flavor: don’t create singleton instances ( that include to-be-translated strings) at the top level of imported modules (outside of a class), if you import the modules before installing a translator (otherwise, the singleton instance is untranslated.)  In other words, don’t invoke tr() at import time (statements at the top level of modules get executed at import time.)   This mistake is very easy to do if your app is at all complex i.e. having many modules.

Keep a reference to translator instances

Using PyQt, when you create a QTranslator instance and call app.installTranslator(instance), you should keep a reference to the instance.  Otherwise the instance may go out of scope and the instance get garbage collected.  That is, when you install into the app, apparently Qt only keeps a reference, and not a copy.  (??? Is this still correct.???)

Don’t call tr() in mixin classes

At ‘required translation extraction time’ (when you call pylupdate5) it establishes the context key from the class name containing a call to  tr(), that is, statically or lexically.  At runtime, a call to tr() establishes the context from the class name of the object (dynamically).  If you use mixin classes, these two context keys don’t match.

Understanding translation context

Summerfield say context ‘… is only important to translators.’  That is wrong.  The context is used as a key (in various ways and times) including by the Qt translation system at app execution time.

Installing many translators

You install many (a sequence of) translators.  When your app calls for a  translation, the Qt machinery searches the sequence of translators in the order installed.

Generally speaking, the many translators include:

  • your app e.g. myApp_es.qm
  • external (installed separately) Python modules that your app imports e.g.  myPySubmodule_es.qm
  • Qt e.g. qt_es.qm

You include the Qt translations so that the dialogs, etc. built into Qt library are translated. Similarly for external modules that you import.

Note that the order above may be significant, since Qt may translate the same phrases that your app includes.  The above order gives precedence to your app’s translations.

It seems like most people just copy the .qm files to an app’s resource file.  Alternatively, on certain platforms, at translator install time you might search the system for the .qm files in standard places.  For example, on Linux, your app might use the installed Qt library and install translators that load from the installed Qt translations (wherever that is?)

Boilerplate example

TODO

String literals that you don’t need to translate

Some strings are universal across languages and regions, and should not be translated:

  • app names: this is more or less a brand name, or iconic name?
  • file suffixes: these are international standards (mimetypes)
  • strings built into Qt that Qt translates, e.g. “OK” for a standard button (but maybe “Apply” would be a better example, since isn’t ‘OK’ universal?)
  • strings used as keys in the settings database (the user should never see these.)

Special characters in translated strings

Certain strings in Qt use special characters, such as ‘&’ in menu item texts, to mark the character which should be underlined so that when the menu is open, a user can select that menu item using the keyboard.  Note that this usage is only on the Win platform, and is deprecated on other platforms?  I don’t know whether the translator must retain that special character in the translated phrase.  Since translation may involve changing characters, and since the set of underlined characters in a menu should be a proper set (no duplicates), it is probably something the translator needs to do, but doesn’t have enough information to do properly?

Packaging your translations

When you package your app, the .qm files should be in the resources part of the package.

The boilerplate code should access the resource part of the package for the .qm files.  In Qt, the path prefix “:/” refers to the resources part of the app’s installation (installed from the resource part of the package.)

I think different platforms might not actually install all the translations from the resource part of the package to the standard installation places on the install target computer?

Checklist for internationalizing an app

This is a checklist for complete internationalization of your code.  Check these things:

  • the boilerplate is in your app startup code
  • every string literal that you define in your app code that the user may see is idiomized for translation (grep for “[A-Z]+.*” or a better regex for string literals ?)
  • every file that includes an idiomized string is listed as a SOURCE in the .pro file (grep for “.tr(” )

Strings user may see:

  • strings in the GUI
  • constant strings (not entered by the user) that your app writes into document files
  • error messages (resulting from user errors; you might omit critical exceptions from system or app coding errors.)
  • license and copyright notices?

Representations of custom key sequences such as “Ctl-Z” ?  I don’t know whether these need translation.

Prioritizing language for internationalization

You have limited resources.  You can only translate for the most popular languages.

The most popular spoken languages are Mandarin, Spanish, English, Hindi, Arabic, Portuguese, …

Unfortunately, that is not weighted by the count of speakers who use computers.  The most popular languages for Internet users are English, Mandarin, Spanish, Japanese.  (Internet usage is a good proxy for users who have computing devices, even just mobile phones?)

Unfortunately, that is not weighted by the count of computer users who might pay for your app.  Some countries have lax intellectual property standards, and in some countries many people can’t afford to pay for apps.  So I might guess that the priority is: English, Spanish, Japanese, …

Also, consider that some language pairs are more close than others: people who speak Portuguese may prefer a Spanish translation over no translation (that is, a default English translation.)

My guess is that Spanish is the most important (and easiest from English) language to translate to.

Translating to Chinese Using Qt Linguist

When I tried to cut and paste from Google Translate into Qt Linguist operating on a Spanish translation, it showed square box characters!  To see the proper characters, open Linguist on a foo_cn.ts file.  When Linguist starts, there is a dialog: choose the target language to be a Chinese.

Links

An old discussion about alternative idioms, and other alternatives

A discussion about common mistakes in using tr(), and how to test using MockSwedish

PyQt’s documentation about translation, including a discussion of c++ and python differences.