Translating an external workbench/fr: Difference between revisions

From FreeCAD Documentation
(Created page with ": Cette méthode est récursive et trouvera les fichiers {{incode|.ui}} dans toute la structure de votre répertoire.")
(Created page with "* Si vous avez des fichiers {{incode|.py}}, vous devez aussi exécuter {{incode|pylupdate}} :")
Line 132: Line 132:
: Cette méthode est récursive et trouvera les fichiers {{incode|.ui}} dans toute la structure de votre répertoire.
: Cette méthode est récursive et trouvera les fichiers {{incode|.ui}} dans toute la structure de votre répertoire.


* If you have {{incode|.py}} files, you need to run {{incode|pylupdate}} too:
* Si vous avez des fichiers {{incode|.py}}, vous devez aussi exécuter {{incode|pylupdate}} :


: {{Code|code=
: {{Code|code=

Revision as of 11:02, 28 December 2021

Dans les notes suivantes, "context" doit être le nom de votre addon ou de votre atelier, par exemple, "MySuperAddon" ou "DraftPlus", etc. Ce contexte permet de regrouper toutes les traductions de votre code sous le même nom, afin qu'elles soient plus facilement identifiables par les traducteurs. C'est-à-dire qu'ils sauront exactement à quel addon ou atelier une chaîne particulière appartient.

Remarque : Voici un script tout-en-un qui automatise la procédure complète mentionnée ci-dessous (il est tout de même conseillé de lire la procédure pour savoir ce que le script doit faire) : https://github.com/yorikvanhavre/BIM_Workbench/blob/master/utils/updateTranslations.py.

Préparer les sources

Généralités

  • Ajouter un dossier translations/. Vous pouvez le nommer autrement, mais ce sera plus facile car c'est la même chose dans FreeCAD. Dans ce dossier, vous placerez les fichiers .ts (les fichiers de traduction "source") et les fichiers .qm (fichiers de traduction compilés).
  • Seul le texte affiché pour l'utilisateur dans l'interface de FreeCAD doit être traduit. Le texte affiché uniquement dans la console Python ne doit pas être traduit.
  • Le texte imprimé sur FreeCAD.Console apparaît dans la "Vue Rapport" et doit donc être traduit. La "vue Rapport" est différente depuis la console Python.

Dans chaque fichier Python .py

  • Dans chaque fichier où vous devez traduire du texte, vous devez définir une fonction translate(). Vous pouvez utiliser le nom entièrement qualifié de Qt, mais c'est un peu plus propre d'utiliser :
import FreeCAD
translate = FreeCAD.Qt.translate
  • Tout le texte qui doit être traduit doit être passé par la fonction translate() :
print("My text")
devient :
print(translate("context", "My text"))
Sachez que translate() n'est pas seulement une fonction normale : elle sert également de "balise" (tag) pour l'utilitaire de traitement de texte lupdate, et doit donc être nommée exactement "translate". Le programme lupdate est un simple processeur de texte, il n'exécute pas votre code. Vous devez passer des chaînes de caractères directement à la fonction translate() : vous ne pouvez pas passer de variables, de constantes, etc. Par exemple :
# This works:
FreeCAD.Console.PrintMessage(translate("context", "My text") + "\n")

# This does not, lupdate only sees the word "a_variable", and doesn't know what that is:
a_variable = "My text"
FreeCAD.Console.PrintMessage(translate("context", a_variable ) + "\n")

# But this works -- a_variable will contain the translated string:
a_variable = translate("context", "My text")
FreeCAD.Console.PrintMessage(a_variable  + "\n")
Ceci peut être utilisé partout : dans print(), dans FreeCAD.Console.PrintMessage(), dans les dialogues Qt, etc. Les fonctions FreeCAD.Console n'ajoutent pas automatiquement le caractère de nouvelle ligne (\n), qui doit donc être ajouté à la fin si vous le souhaitez. Ce caractère n'a pas besoin d'être traduit non plus, il peut donc se trouver en dehors de la fonction de traduction :
FreeCAD.Console.PrintMessage(translate("context", "My text") + "\n")
  • Si vous utilisez des fichiers .ui réalisés avec QtDesigner, vous n'avez rien à faire de spécial avec eux.
  • Lorsque vous créez de nouveaux objets, ne traduisez pas le "Name" de l'objet. Traduisez plutôt le "Label" de l'objet. La différence est qu'un "Nom" est unique ; il reste le même pendant toute la durée de vie de l'objet ; en revanche, une "Étiquette" peut être modifiée par l'utilisateur comme il le souhaite.
  • Lorsque vous créez des propriétés pour vos objets, ne traduisez pas le nom de la propriété. Mais placez la description dans QT_TRANSLATE_NOOP :
obj.addProperty("App::PropertyBool", "MyProperty", "PropertyGroup", QT_TRANSLATE_NOOP("App::Property", "This is what My Property does"))
N'utilisez pas votre propre "context" dans ce cas précis. Gardez "App::Property".
  • Ne traduisez pas le texte des opérations sur les documents effectuées à l'aide de la fonction Document.openTransaction().

Dans InitGui.py

  • Ajouter la ligne suivante, près du début du fichier :
def QT_TRANSLATE_NOOP(scope, text):
    return text
  • Pour traduire les noms des menus :
self.appendMenu(QT_TRANSLATE_NOOP("context", "My menu"), [list of commands, ...])
  • La macro QT_TRANSLATE_NOOP ne fait rien, mais elle marque les textes qui seront repris plus tard par l'utilitaire lupdate. Comme elle ne fait rien, nous ne l'utilisons que dans des cas particuliers où FreeCAD s'occupe lui-même de tout.
  • Ajoutez le chemin vers votre dossier translations/ dans la fonction Initialized :
FreeCADGui.addLanguagePath("/path/to/translations")
Le fichier InitGui.py n'a pas d'attribut file, il n'est donc pas facile de trouver l'emplacement relatif du dossier des traductions. Une façon simple de contourner ce problème est de faire en sorte qu'il importe un autre fichier du même dossier, et de faire dans ce fichier :
FreeCADGui.addLanguagePath(os.path.join(os.path.dirname(__file__), "translations"))

À l'intérieur de chaque classe de commande de FreeCAD

  • Ajouter la ligne suivante, près du début du fichier :
def QT_TRANSLATE_NOOP(context, text):
    return text
  • Traduire les 'MenuText' et 'Tooltip' de la commande comme ceci :
def GetResources(self):
    return {'Pixmap'  : "path/to/icon.svg"),
            'MenuText': QT_TRANSLATE_NOOP("CommandName", "My Command"),
            'ToolTip' : QT_TRANSLATE_NOOP("CommandName", "Describes what the command does"),
            'Accel'   : "Shift+A"
    }
"CommandName" est le nom de la commande, défini par :
FreeCADGui.addCommand('CommandName', My_Command_Class())

Rassemblez toutes les chaînes de votre module

  • Vous aurez besoin des outils lupdate, lconvert, lrelease et pylupdate installés sur votre système. Dans les distributions Linux, ils sont généralement fournis dans des paquets nommés pyside-tools ou pyside2-tools. Sur certains systèmes, lupdate est nommé lupdate4 ou lupdate5 ou lupdate-qt4 ou similaire. Idem pour les autres outils. Vous pouvez utiliser la version Qt4 ou Qt5 à votre choix.
  • Si vous avez des fichiers .ui, vous devez d'abord exécuter lupdate :
lupdate *.ui -ts translations/uifiles.ts
Cette méthode est récursive et trouvera les fichiers .ui dans toute la structure de votre répertoire.
  • Si vous avez des fichiers .py, vous devez aussi exécuter pylupdate :
pylupdate *.py -ts translations/pyfiles.ts
  • If you ran both operations, you now need to unify these two files into one:
lconvert -i translations/uifiles.ts translations/pyfiles.ts -o translations/MyModule.ts
  • Check the contents of the three .ts files to make sure that they contain the strings, then you can delete both pyfiles.ts and uifiles.ts.
  • You can do it all in one bash script like this:
#!/bin/sh
lupdate *.ui -ts translations/uifiles.ts
pylupdate *.py -ts translations/pyfiles.ts
lconvert -i translations/uifiles.ts translations/pyfiles.ts -o translations/MyModule.ts
rm translations/pyfiles.ts
rm translations/uifiles.ts

Envoyer le fichier .ts à une plateforme de traduction

Il est temps de faire traduire votre fichier .ts. Vous pouvez choisir de créer un compte sur une plateforme de traduction publique telle que Crowdin ou Transifex, ou vous pouvez bénéficier de notre compte FreeCAD existant sur Crowdin, qui compte déjà de nombreux utilisateurs et qui a donc plus de chance de faire traduire votre fichier rapidement par des personnes connaissant FreeCAD.

Si vous souhaitez héberger votre fichier sur le compte FreeCAD Crowdin, contactez Yorik sur le forum FreeCAD.

Note: certaines plates-formes comme Crowdin peuvent s'intégrer à GitHub et effectuer automatiquement tout le processus à partir des points 2, 3 et 4. Pour cela, vous ne pouvez pas utiliser le compte FreeCAD Crowdin ; vous devrez configurer vôtre propre compte.

Fusionner les traductions

Une fois que votre fichier .ts a été traduit, même partiellement, vous pouvez télécharger les traductions à partir du site :

  • Vous téléchargerez généralement un fichier .zip contenant un .ts par langue
  • Placez tous les fichiers .ts traduits, ainsi que votre fichier .ts de base, dans le dossier translations/

Compiler les traductions

Maintenant, lancez le programme lrelease sur chaque fichier que vous avez.

lrelease "translations/Draft_de.ts"
lrelease "translations/Draft_fr.ts"
lrelease "translations/Draft_pt-BR.ts"

Vous pouvez automatiser le processus

for f in translations/*_*.ts
do
    lrelease "translations/$f"
done

Vous devriez trouver un fichier .qm pour chaque fichier .ts traduit. Les fichiers .qm sont ceux qui seront utilisés par Qt et FreeCAD au moment de l'exécution.

C'est tout ce dont vous avez besoin. Notez que certaines parties de votre atelier ne peuvent pas être traduites à la volée si vous décidez de changer de langue. Si tel est le cas, vous devrez redémarrer FreeCAD pour que la nouvelle langue prenne effet.

Tester les traductions

  1. Basculez FreeCAD dans une langue que vous avez traduite (ex. Allemand)
  2. Chargez la traduction dans FreeCAD, ex. FreeCADGui.addTranslationPath("/path/to/the/folder/containing/qmfile")
  3. Tester quelque chose, ex. FreeCAD.Qt.translate("your context", "some string")

Résultat : Cela devrait vous donner la traduction allemande. Si cela fonctionne bien, alors la configuration de base est correcte. Alors nous pouvons regarder autre chose. Par exemple, les noms des commandes devraient toujours utiliser un contexte spécial qui est le nom de la commande telle qu'elle est enregistrée dans FreeCAD.

Remarques importantes

  • Assurez-vous que vous utilisez un *contexte* et une *chaîne* qui se trouvent réellement dans le fichier ts/qm bien sûr.

Script pratique

Yorik maintient un script pratique pour l'atelier BIM, qui peut rassembler, charger et télécharger des fichiers ts. Vous pouvez simplement copier et adapter ce script à votre atelier :

https://github.com/yorikvanhavre/BIM_Workbench/blob/master/utils/updateTranslations.py

Technical details and advanced usage

In the above examples there are two separate functions being used: translate() and QT_TRANSLATE_NOOP. You may also run across tr() and QT_TR_NOOP, which automatically provide the "context" argument based on their calling location. These two pairs of functions are fundamentally different.

translate() and tr() accomplish two separate tasks: at runtime they perform the actual translation from the string passed into them to the final translated string. This is true whether they are provided a literal string, or a variable, or a constant: the lookup is dynamic and real-time during the run of the code. However, they provide an additional non-runtime function: they are recognized by the pylupdate utility. If (and only if) they contain a string literal, that literal is extracted by the utility. ONLY string literals are extracted by pylupdate -- if a variable is passed it is ignored by the pylupdate utility. Qt will attempt to provide a translation at runtime, but this will only work if some other piece of code called one of the translation functions with the literal string that needs to be translated, so that pylupdate can extract it. Note that the code with the string literal need not actually ever execute, it must simply exist as a line of code in a file somewhere: pylupdate performs no analysis or code execution, it is simply performing a string search and extraction.

In contrast, QT_TRANSLATE_NOOP and QT_TR_NOOP do nothing at all at runtime: they are literal "no-ops", and are completely ignored by running code. Their only use is to mark a literal string for extraction by pylupdate: it never makes sense to place a variable within a call to one of these functions, it will have no effect. They are used in circumstances where translate() or tr() will be called with a variable containing the text to translate. For example, any code that is used to create a Command or a Property will use a NOOP-type function around the command menu text or tooltip, or the property docstring: at runtime when FreeCAD displays these items to the user it calls translate(): the literal strings must have been extracted by pylupdate at the point of creation, for example:

def GetResources(self):
    return {'Pixmap'  : "path/to/icon.svg",
            'MenuText': QT_TRANSLATE_NOOP("CommandName", "My Command"),
            'ToolTip' : QT_TRANSLATE_NOOP("CommandName", "Describes what the command does"),
            'Accel'   : "Shift+A"
    }

In this usage, at runtime the dictionary returned by this function is literally:

{ 
    'Pixmap'  : "path/to/icon.svg",
    'MenuText': "My Command",
    'ToolTip' : "Describes what the command does",
    'Accel'   : "Shift+A"
}

There is no reference to any type of translation information. When FreeCAD actually displays this information to the user, the pseudo-code is:

for command in commands:
    resources = command.GetResources()
    menu_text = translate(resources['MenuText'])

In this case, lupdate cannot extract any string from the call to translate() because it refers to a variable. So lupdate ignores that call, but at runtime Qt searches for the string that's passed to it. As long as someplace in the code there is a call to one of the translation functions with a matching literal string (in this case, in the GetResources() function), this translation call will succeed.

To verify that the expected strings are being extracted, you can manually run the pylupdate command:

pylupdate myfile.py -ts outfile.ts

The file outfile.ts will contain the set of strings that are uploaded to CrowdIn for translation.

Références importantes

Pages en relation