Dnia 2011-06-07, wto o godzinie 15:17 -0700, margie_foster pisze:
> How developers of qml-based apps should be using comments for qsTr() /
> tr().

Hello,

I would like to include some as-of-yet unused i18n features that would
enormously increase the quality (and speed) of our translations. I blame
lack of documentation on the subject for QML. Some of the things covered
I got directly from source code.


Problem
=======
The two most important i18n concepts that are currently unused in all
MeeGo QML code are:

     1. context [1]
     2. plural handling [2]


Ad. 1
=====
Each QML file has a separate context (the file name, without extension)
in terms of translation strings. That's all good in itself, but if there
are identical translatable strings in two different files in a project,
they need to get translated twice. Just as if you've used
disambiguation. As an example, some of the current UX apps one QML file
for portrait and one for landscape orientation or a separate file for
different views. Each of those file have multiple translation strings in
common, yet translators see several identical strings that they need to
translate multiple times.

Solution
========
> qsTranslate("context", "Translatable string")

where "context" is either of:
      * an arbitrary string (e.g. "SomeApp")
      * name of the main file where the strings are originally
        translated (without extension, e.g. "main") - you can then use
        simple qsTr() syntax in the main.qml file

This way, all the common strings will only need to be translated once
and your application's translations will be consistent.

There's also another way, sadly it will be available in Qt 4.8 [3] [4].
The following comment will change the translation context for all
subsequent calls to qsTr(). You could put that at the top of your qml
files and that's all that would be required to unify the translatable
strings.
> // TRANSLATOR MyApp


Ad. 2
=====
English is easy. "One computer", "Two computers". Just slap a "s" onto
the back of a computer and you have two or more. Others have to buy the
second one. In most languages, providing two strings: "One computer", "%
1 computers" is enough, but some have more forms depending on the number
of computers.

Solution
========
> qsTr("%n computer(s)", "disambiguation", n)
> qsTranslate("context", "%n computers(s)", "disambiguation", "CodecForTr", n)

where disambiguation is the optional "comment" Margie wrote about in the
previous e-mail (use empty string if not needed) and n is the count of
apples. "CodecForTr" is the encoding used, see [5].

Translators for English will then provide:
      * "%n computer" or - even better - "one computer" for n == 1,
      * "%n computers" for n >= 1

Translators for Polish will provide:
  * "%n komputer" or "jeden komputer" for n == 1,
  * "%n komputery" for... there's a bunch of cases, see e.g. [6]
  * "%n komputerów" for some other cases
  * "%n komputera" for all the rest

Qt will then take care of the rest. It will display:
      * "one computer" / "jeden komputer"
      * "2 computers" / "2 komputery"
      * "5 computers" / "5 komputerów"
      * "0.5 computers" / "0.5 komputera"
      * etc.

It's a win-win situation - you, as a developer, only need to provide one
translatable string: "%n computer(s)", translators will provide all the
proper forms in their language, and the app will look great in all
languages. The only thing I'm not 100% sure of, is whether Transifex
supports plural forms from TS files. Dimitris? Diego?


NOOPs
=====
There are also two NOOP "macros":
> QT_TR_NOOP()
> QT_TRANSLATE_NOOP()
which have roughly the same meaning that qsTr() and qsTranslate() have,
respectively, except that they return the original, untranslated string
and don't handle plurals. Their purpose is to mark for translation
strings that are supposed to be translated dynamically. [7] [8]


Testing
=======
I'm attaching three QML files with which you can see all that I've
described above. Disambiguation and translator comments are tested, too.


Summary
=======
I recommend [9] as a reading exercise for everyone. Even though it talks
mostly Qt, not QML, the concepts are the same. It would be best if
someone converts this post into a proper wiki page. [10]

The complete argument list for the functions are:

> qsTr(string, disambiguation="", count=-1)
> QT_TR_NOOP(string, disambiguation="")
> qsTranslate(context, string, disambiguation="", encoding="CodecForTr", 
> count=-1)
> QT_TRANSLATE_NOOP(context, string, disambiguation="")


Apologies
=========
Please forgive me this lengthy post, but the topics covered are dear to
me. You know, as the one that needs to buy his second computer. ;>


[1]
http://doc.qt.nokia.com/latest/i18n-source-translation.html#defining-a-translation-context
[2]
http://doc.qt.nokia.com/latest/i18n-source-translation.html#handling-plurals
[3] http://bugreports.qt.nokia.com/browse/QTBUG-15502
[4]
http://qt.gitorious.org/qt/qt/commit/9e06896a9a49685dc97eb2aafdf55eef33a75507
[5] http://doc.qt.nokia.com/latest/qcoreapplication.html#Encoding-enum
[6] http://www.gnu.org/s/hello/manual/gettext/Plural-forms.html
[7] http://doc.qt.nokia.com/4.7-snapshot/qtglobal.html#QT_TR_NOOP
[8] http://doc.qt.nokia.com/4.7-snapshot/qtglobal.html#QT_TRANSLATE_NOOP
[9] http://doc.qt.nokia.com/latest/i18n-source-translation.html
[10] http://wiki.meego.com/QML/Internationalisation

-- 
Michał (Saviq) Sawicz <[email protected]>
import QtQuick 1.0

Rectangle {
    width: 360
    height: 360
    Text {
        id: first
        anchors.top: parent.top
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: "Hello World"
    }
    Text {
        id: second
        anchors.top: first.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: standard translatable
        text: qsTr("First translatable string")
    }
    Text {
        id: third
        anchors.top: second.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: translatable with disambiguation
        text: qsTr("Second translatable string", "first")
    }
    Text {
        id: fourth
        anchors.top: third.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: second translatable with disambiguation
        text: qsTr("Second translatable string", "second")
    }
    Text {
        id: fifth
        anchors.top: fourth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: translatable with plural forms
        text: qsTr("%n plural(s)", "", 1)
    }
    Text {
        id: sixth
        anchors.top: fifth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: second comment here, unnecessary
        text: qsTr("%n plural(s)", "", 2)
    }
    Text {
        id: seventh
        anchors.top: sixth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: qsTr("%n plural(s)", "", 5)
    }
    Text {
        id: eighth
        anchors.top: seventh.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: QT_TR_NOOP("First translatable string")
    }
    Text {
        id: nineth
        anchors.top: eighth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: QT_TR_NOOP("Second translatable string", "second")
    }
}
import QtQuick 1.0

Rectangle {
    width: 360
    height: 360
    Text {
        id: first
        anchors.top: parent.top
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: "Hello World"
    }
    Text {
        id: second
        anchors.top: first.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: standard translatable
        text: qsTranslate("i18n-test", "First translatable string")
    }
    Text {
        id: third
        anchors.top: second.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: translatable with disambiguation
        text: qsTranslate("i18n-test", "Second translatable string", "first")
    }
    Text {
        id: fourth
        anchors.top: third.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: second translatable with disambiguation
        text: qsTranslate("i18n-test", "Second translatable string", "second")
    }
    Text {
        id: fifth
        anchors.top: fourth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: translatable with plural forms
        text: qsTranslate("i18n-test", "%n plural(s)", "", "CodecForTr", 1)
    }
    Text {
        id: sixth
        anchors.top: fifth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: second comment here, unnecessary
        text: qsTranslate("i18n-test", "%n plural(s)", "", "CodecForTr", 2)
    }
    Text {
        id: seventh
        anchors.top: sixth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: qsTranslate("i18n-test", "%n plural(s)", "", "CodecForTr", 5)
    }
    Text {
        id: eighth
        anchors.top: seventh.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: qsTr("A single new string in i18n-test2")
    }
    Text {
        id: nineth
        anchors.top: eighth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: QT_TRANSLATE_NOOP("i18n-test", "First translatable string")
    }
    Text {
        id: tenth
        anchors.top: nineth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: QT_TRANSLATE_NOOP("i18n-test", "Second translatable string", 
"second")
    }
}
// TRANSLATOR i18n-test

import QtQuick 1.0

Rectangle {
    width: 360
    height: 360
    Text {
        id: first
        anchors.top: parent.top
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: "Hello World"
    }
    Text {
        id: second
        anchors.top: first.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: standard translatable
        text: qsTr("First translatable string")
    }
    Text {
        id: third
        anchors.top: second.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: translatable with disambiguation
        text: qsTr("Second translatable string", "first")
    }
    Text {
        id: fourth
        anchors.top: third.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: second translatable with disambiguation
        text: qsTr("Second translatable string", "second")
    }
    Text {
        id: fifth
        anchors.top: fourth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: translatable with plural forms
        text: qsTr("%n plural(s)", "", 1)
    }
    Text {
        id: sixth
        anchors.top: fifth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        //: second comment here, unnecessary
        text: qsTr("%n plural(s)", "", 2)
    }
    Text {
        id: seventh
        anchors.top: sixth.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: qsTr("%n plural(s)", "", 5)
    }
    // TRANSLATOR i18n-test3
    Text {
        id: eight
        anchors.top: seventh.bottom
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.margins: 5
        text: qsTr("A single new string in i18n-test3", "", 5)
    }
}

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
MeeGo-dev mailing list
[email protected]
http://lists.meego.com/listinfo/meego-dev
http://wiki.meego.com/Mailing_list_guidelines

Reply via email to