Translating an external workbench/es

En las siguientes notas, "context" debe ser el nombre de su complemento o entorno de trabajo, por ejemplo, "MySuperAddon" o "DraftPlus", o cualquier otro. Aquí importa el uso de mayúsculas: "Context" no es lo mismo que "context", por ejemplo. El contexto permite que todas las traducciones de su código se agrupen bajo el mismo nombre, para que los traductores puedan identificarlas más fácilmente. Es decir, sabrán exactamente a qué complemento o entorno de trabajo pertenece una cadena de texto en particular.

Nota: Aquí tiene un script todo en uno que automatiza el procedimiento completo mencionado a continuación (aunque se recomienda leer el procedimiento para saber qué debe hacer el script): https://github.com/yorikvanhavre/BIM_Workbench/blob/master/utils/updateTranslations.py

Preparación de las fuentes

General

En cada archivo .py de Python

import FreeCAD
translate = FreeCAD.Qt.translate
print("My text")
se convierte en:
print(translate("context", "My text"))

Tenga en cuenta que translate() no es una función normal: también sirve como "etiqueta" para la utilidad de procesamiento de texto lupdate, por lo que debe llamarse exactamente "translate". El programa lupdate es un procesador de texto simple; no ejecuta su código. Debe pasar cadenas literales directamente a la función translate(): no puede pasar variables, constantes, etc. Por ejemplo:

# 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")

Esto se puede usar en cualquier lugar: en print(), en FreeCAD.Console.PrintMessage(), en diálogos de Qt, etc. Las funciones FreeCAD.Console no agregan automáticamente el carácter de nueva línea (\n), por lo que, si se desea, se debe agregar al final. Este carácter tampoco necesita traducción, por lo que puede estar fuera de la función de traducción:

FreeCAD.Console.PrintMessage(translate("context", "My text") + "\n")
obj.addProperty("App::PropertyBool", "MyProperty", "PropertyGroup", QT_TRANSLATE_NOOP("App::Property", "This is what My Property does"))
No use su propio "context" en este caso específico. Mantenga "App::Property".

En InitGui.py

from PySide.QtCore import QT_TRANSLATE_NOOP

La función QT_TRANSLATE_NOOP no hace nada, pero marca los textos que la utilidad lupdate procesará posteriormente. Solo la utilizamos en casos especiales donde FreeCAD se encarga de todo.

self.appendMenu(QT_TRANSLATE_NOOP("Workbench", "My menu"), [list of commands, ...])
self.appendToolbar(QT_TRANSLATE_NOOP("Workbench", "My toolbar"), [list of commands, ...])
FreeCADGui.addLanguagePath("/path/to/translations")
FreeCADGui.updateLocale()

El archivo InitGui.py no tiene el atributo 'file, por lo que no es fácil encontrar la ubicación relativa de la carpeta de traducciones. Una forma sencilla de solucionar esto es hacer que importe otro archivo de la misma carpeta y, en ese archivo, hacer lo siguiente:

FreeCADGui.addLanguagePath(os.path.join(os.path.dirname(__file__), "translations"))
FreeCADGui.updateLocale()

Dentro de cada clase de comando de FreeCAD

def QT_TRANSLATE_NOOP(context, text):
    return text
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"
    }
donde "CommandName" es el nombre del comando, definido por:
FreeCADGui.addCommand('CommandName', My_Command_Class())

Reúna todas las cadenas de su módulo

lupdate *.ui -ts translations/uifiles.ts
Esto es recursivo y encontrará archivos .ui dentro de toda su estructura de directorios.
pylupdate *.py -ts translations/pyfiles.ts
lconvert -i translations/uifiles.ts translations/pyfiles.ts -o translations/MyModule.ts
#!/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

Enviar el archivo .ts a una plataforma de traducción

Es momento de traducir su archivo .ts. Puede crear una cuenta en una plataforma de traducción pública como Crowdin o Transifex, o puede aprovechar nuestra cuenta existente FreeCAD-addons en Crowdin, que ya cuenta con muchos usuarios, lo que aumenta las posibilidades de que su archivo sea traducido rápidamente por personas que conocen FreeCAD.

Si desea alojar su archivo en la cuenta FreeCAD Crowdin, póngase en contacto con Yorik en el FreeCAD forum.

Nota: Algunas plataformas como Crowdin pueden integrarse con GitHub y realizar automáticamente todo el proceso de los puntos 2, 3 y 4. Para que esto sea posible, no podrá usar la cuenta de FreeCAD Crowdin; tendrá que crear su propia cuenta.

Combinar las traducciones

Una vez que su archivo .ts haya sido traducido, aunque sea parcialmente, puede descargar las traducciones desde el sitio:

Compilar las traducciones

Ahora ejecute el programa lrelease en cada archivo que tenga:

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

Puede automatizar el proceso:

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

Debería encontrar un archivo .qm por cada archivo .ts traducido. Los archivos .qm son los que usarán Qt y FreeCAD durante la ejecución.

Eso es todo lo que necesita. Tenga en cuenta que algunas partes de su entorno de trabajo no se pueden traducir automáticamente si cambia de idioma. En ese caso, tendrá que reiniciar FreeCAD para que el nuevo idioma surta efecto.

Probando traducciones

  1. Cambie FreeCAD a un idioma que haya traducido (por ejemplo, alemán)
  2. Cargue la traducción en FreeCAD, por ejemplo: FreeCADGui.addTranslationPath("/ruta/a/la/carpeta/que/contiene/el/archivo/qm")
  3. Pruebe algo, por ejemplo: FreeCAD.Qt.translate("tu contexto","alguna cadena")

Resultado: Esto debería proporcionarle la traducción al alemán. Si funciona, la configuración básica es correcta. Entonces podemos analizar otros aspectos. Por ejemplo, los nombres de los comandos siempre deben usar un contexto especial, que es el nombre del comando tal como está registrado en FreeCAD.

Notas importantes

Script de conveniencia

Yorik mantiene un script práctico para el entorno de trabajo BIM que permite recopilar, cargar y descargar archivos .ts.

Simplemente copie y adapte ese script para su entorno de trabajo:

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

Detalles técnicos y uso avanzado

En los ejemplos anteriores se utilizan dos funciones distintas: translate() y QT_TRANSLATE_NOOP. También es posible encontrar tr() y QT_TR_NOOP, que proporcionan automáticamente el argumento "context" según su ubicación de llamada. Estos dos pares de funciones son fundamentalmente diferentes.

Las funciones translate() y tr() realizan dos tareas distintas: en tiempo de ejecución, llevan a cabo la traducción real de la cadena que se les pasa a la cadena traducida final. Esto se cumple tanto si se les proporciona una cadena literal, una variable o una constante: la búsqueda es dinámica y en tiempo real durante la ejecución del código. Sin embargo, proporcionan una función adicional fuera del tiempo de ejecución: son reconocidas por la utilidad pylupdate. Si (y solo si) contienen una cadena literal, esta se extrae mediante la utilidad. SOLO las cadenas literales son extraídas por pylupdate; si se pasa una variable, esta se ignora. Qt intentará proporcionar una traducción en tiempo de ejecución, pero esto solo funcionará si otra parte del código llama a una de las funciones de traducción con la cadena literal que necesita ser traducida, de modo que pylupdate pueda extraerla. Tenga en cuenta que el código con la cadena literal no necesita ejecutarse nunca, simplemente debe existir como una línea de código en algún archivo: pylupdate no realiza ningún análisis ni ejecución de código, simplemente realiza una búsqueda y extracción de cadena.

En cambio, QT_TRANSLATE_NOOP y QT_TR_NOOP no hacen absolutamente nada en tiempo de ejecución: son literalmente "no-ops" y el código en ejecución las ignora por completo. Su único uso es marcar una cadena literal para su extracción por pylupdate: nunca tiene sentido colocar una variable dentro de una llamada a una de estas funciones, ya que no tendrá ningún efecto. Se utilizan en circunstancias en las que se llamará a translate() o tr() con una variable que contiene el texto a traducir. Por ejemplo, cualquier código que se utilice para crear un Comando o una Propiedad utilizará una función de tipo NOOP alrededor del texto del menú del comando o la información sobre herramientas, o la cadena de documentación de la propiedad: en tiempo de ejecución, cuando FreeCAD muestra estos elementos al usuario, llama a translate(): las cadenas literales deben haber sido extraídas por pylupdate en el punto de creación, por ejemplo:

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"
    }

En este uso, en tiempo de ejecución el diccionario devuelto por esta función es literalmente:

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

No hay ninguna referencia a ningún tipo de información de traducción. Cuando FreeCAD muestra esta información al usuario, el pseudocódigo es:

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

En este caso, lupdate no puede extraer ninguna cadena de la llamada a translate() porque hace referencia a una variable. Por lo tanto, lupdate ignora esa llamada, pero en tiempo de ejecución Qt busca la cadena que se le pasa. Siempre que en algún lugar del código haya una llamada a una de las funciones de traducción con una cadena literal coincidente (en este caso, en la función GetResources()), esta llamada de traducción se realizará correctamente.

Para verificar que se están extrayendo las cadenas esperadas, puede ejecutar manualmente el comando pylupdate:

pylupdate myfile.py -ts outfile.ts

El archivo outfile.ts contendrá el conjunto de cadenas que se cargan en CrowdIn para su traducción.

Referencias importantes

Páginas relacionadas