Inicio > Delphi, Multiidioma > Aplicación multiidioma con GNU Gettext

Aplicación multiidioma con GNU Gettext

Share Button

He probado algunos sistema de traducción para programas Delphi, entre ellos multiidioma2he de destacar los componentes de TsiLang Component Suite , que me parecen muy buenos y completos.

Estos días necesitaba un paquete gratuíto y revisando páginas y foros he llegado a GNU Gettext for Delphi and C++ Builder. Me parece un paquete muy sencillo de utilizar y por lo que he probado hasta ahora, cómodo y eficaz.

En esta entrada voy a explicar desde cero los pasos que he seguido para conseguir una aplicación multiidioma.

PREPARATIVOS

(1) GNU Gettext

Descargar desde la página «GNU Gettext for Delphi and C++ Builder» el programa de instalación. También se puede encontrar la última versión en SourceForge.

Una vez descargado el ficchero e instalado tendremos lo necesario para generar nuestros ficheros de traducción e integrarlos en el programa.

NOTA: Hay una versión especial compatible con Delphi 2009 que podemos descargar desde aquí, si estamos utilizando esta versión de Delphi..

Si se ha instalado correctamente, nos pedirá reiniciar el sistema.
Una vez instalado, si desde el explorador de Windows pulsamos Click derecho con el ratón sobre una carpeta, nos debería aparecer una nueva opción «Extract Translations to Template«.
generar_traducciones

(2) Poedit for Windows

Necesitaremos una herramienta para poder traducir (ya seamos nosotros o una tercera persona) los ficheros de traducción a los diferentes idiomas. Esto está pensado para que esa posible tercera persona (que puede no tener Dephi instalado)  pueda traducir un fichero sólo con esta herramienta (y el fichero .po como veremos después).

Descargamos el programa desde la página (http://www.poedit.net/) y lo nstalaremos.

Una vez realizados estos dos pasos previos, crearemos un pequeño proyecto de ejemplo donde realizar las pruebas.

Para ello, desde Delphi comenzamos una nueva aplicación y en el formulario generaremos algo similar a esto:

TRADUCCIÓN

(a) Preparar el  proyecto.

Una vez tenemos nuestra aplicación funcionando debemos preparnos para comentar lo necesario para traducción.
(1) Lo primero es añadir la unit gnugettext.pas a nuestro proyecto. Las units que usesn traducciones deberán tenerla en el uses.

NOTA: Si habéis realizado la instalación estandard debería estar en:
«c:\Archivos de programa\dxgettext\gnugettext.pas»

(2) Añadir al OnCreate de nuestros formularios el siguiente código:

// Traducir el formulario
TranslateComponent(Self);

(3) Preparar la estructura de directorios para organizar las traducciones. Dentro del directorio de la aplicación crearemos una carpeta llamada locale y dentro de ella un árbol de directorios similar al que se ve en la imagen.

directorios1

En este ejemplos, yo voy a utilizar 4 idiomas (es, en, fr, ca); Contando que el original va a ser el Español(es) debemos crear la estructura para los otros 3 (inglés, francés y catalán). Nos quedará un arbol de directorios como este:

directorios2

(b) Generar fichero de traducciones (.po)

(1) Para generar el fichero de traducciones del proyecto se debe extraer todas las cadena «traducibles» y almacenarlas en un fichero; Para ello basta con que, desde el explorador de Windows, pulsemos Click derecho sobre la carpeta del proyecto y seleccionemos la opción «Extract Translations to template».
Esto generará un fichero default.po en el directorio de la aplicación.

generar_traducciones

(2) Copiaremos este fichero dentro de los directorios LC_MESSAGES; Tantas copias como directorios tengamos. Después de eso tendremos varios ficheros .po; Uno en el directorio de la aplicación y uno dentro de cada carpeta de traducción:

appdir/appTest.exe
appdir/default.po
appdir/locale/en/LC_MESSAGES/default.po (Traducciones al inglés)
appdir/locale/fr/LC_MESSAGES/default.po (Traducciones al francés)
appdir/locale/ca/LC_MESSAGES/default.po (Traducciones al catalán)

(c) Traducir los ficheros.

En este punto ya se pueden abrir cada uno de los ficheros .po y traducirlo utilizando poedit. Una vez abierto el fichero con poedit, veremos una pantalla como esta:


Una vez finalizada la traducción de palabras y cerrado el programa veremos que en cada directorio aparecen 2 ficheros; El  default.po (original) y el de traducción llamado default.mo.
Repetimos esto con todos los ficheros de traducción.

(d) Cómo utilizar las traducciones en nuestro programa

Una vez los ficheros de traducción estén generados, para utilizarlos desde la aplicación añadirenmos el siguiente código a los botones de activación de los idiomas.

botones_idiomas

// para el catalán
UseLanguage('ca');
RetranslateComponent(Self);
 
// para el inglés
UseLanguage('en');
RetranslateComponent(Self);
...

Si ejecutamos la aplicación veremos que al pulsar los botones cambia es aspecto del formulario.

Para finalizar, aun nos queda un detalle, que es, que la cadena que aparece al pulsar el botón «Hola Mundo!»  no aparece traducida.

Para ello utilizaremos la función de traducción  _().
La llamada que actualmente está así:

MessageDlg('Hola', mtInformation, [mbOK], 0);

Pasará a colocarse así:

MessageDlg(_('Hola'), mtInformation, [mbOK], 0);

PASOS FINALES

Con eso nuestro programa debería quedar traducido completamente. Si movemos el EXE y la carpeta locale a cualquier otro sitio veremos que el programa funciona correctamente. Si sólo movemos el EXE, el efecto es que no aparace nada traducido.

Queda un último detalle, que es integrar las traducciones en el EXE, para que todo quede en el ejecutable y no debamos preocuparnos del directorio locale.

integrar_traducciones

Basta con pulsar click derecho sobre el EXE de nuestra aplicación desde el explorador de Windows, Seleccionar la opción «Embeb Translations» y seleccionar los ficheros de traducción que queremos integrar.

integrar_traducciones2

Con esto debería ser todo.

UPDATE: (20/04/2011)

Pues haciendo pruebas he llegado a obtener el mismo proble que comenta Sil en sus comentarios (en mi caso utilizando Delphi XE). Se trata de que al intentar añadir las traducciones al exe se obtiene un error con la referencia: «6637DB2E-62E1-4A60-AC19-C23867046A89».

Revisando por Internet, parece que se solventa sustituyendo unas constantes que hay en gnugettext.pas.

(1) Buscar esta sección en la unit gnugettext.pas:

  // DetectionSignature: used solely to detect gnugettext usage by assemble
  DetectionSignature: array[0..35] of AnsiChar='2E23E563-31FA-4C24-B7B3-90BE720C6B1A';
  // Embedded Header Begin Signature (without dynamic prefix written by assemble)
  BeginHeaderSignature: array[0..35] of AnsiChar='BD7F1BE4-9FCF-4E3A-ABA7-3443D11AB362';
  // Embedded Header End Signature (without dynamic prefix written by assemble)
  EndHeaderSignature: array[0..35] of AnsiChar='1C58841C-D8A0-4457-BF54-D8315D4CF49D';
  // Assemble Prefix (do not put before the Header Signatures!)
  SignaturePrefix: array[0..2] of AnsiChar='DXG'; // written from assemble

(2) Y sustituirlas por estas:

  // DetectionSignature: used solely to detect gnugettext usage by assemble
  DetectionSignature: array[0..35] of AnsiChar='6637DB2E-62E1-4A60-AC19-C23867046A89';
  // Embedded Header Begin Signature (without dynamic prefix written by assemble)
  BeginHeaderSignature: array[0..35] of AnsiChar='';
  // Embedded Header End Signature (without dynamic prefix written by assemble)
  EndHeaderSignature: array[0..35] of AnsiChar='';
  // Assemble Prefix (do not put before the Header Signatures!)
  SignaturePrefix: array[0..16] of AnsiChar='#0#0#0#0#0#0#0#0';//'DXG'; // written from assemble

Con este ambio ha desaparecido el error y se integran perfectamente las traducciones.

Espero que haya sido útil.

Espero comentarios, sugerencias, errores,… y demás.

Vota este post
Subscribe
Notify of
guest

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

28 Comments
Inline Feedbacks
Ver todos los comentarios
David
David
14 years ago

Hola Neftali.

Enhorabuena por tu trabajo sobre Delphi aquí y en otros sitios.

Unas preguntas sobre este sistema:

1. He probado el sistema con una aplicación sencilla y funciona ok. Pero cuando lo pruebo sobre una un poco más grande al generar el mo, me arroja el error msgfmt: found 1 fatal error context separator within string. Parece un error en el formato de alguna cadena pero como puedo saber donde está, teniendo en cuenta que hay «millones» de cadenas para traducir.

2. Por otro lado me surge otra duda. Que ocurre cuando en nuestra aplicación agrgamos un nuevo botón,label… a un form. como podemos añadir ese texto a cada uno de los archivos po. Yo no he visto la forma de eliminar, modificar el texto original dentro de un archivo po con el PoEdit.

Gracias un saludo.

David
David
14 years ago

Gracias lo probaré… aunque también estoy evaluando los TsiLang Component Suite, que tienen muy buena pinta.

david
david
14 years ago

Otra opción de los TSILang es la de Traslate source> CONST declaration que da soporte para los RESOURCESTRING lo cual a mi juicio te ahorra mucho trabajo para traducir y encontrar los mensajes (msgbox, showmessage…),desde luego estos Tsilang parece que valen lo que cuestan y que es la forma mas rapida, completa de implementar un solución multiidioma a las aplicaciones.

hclander
hclander
14 years ago

Hola,
Precisamente estoy con un proyecto bastante grande y estoy buscando una solución para Internacionalizacion…
La verdad es que estoy hecho un lío y no se cual usar. Estoy probando
varias alternativas y me gustaría saber cual me recomendais.
Ya veo que todos valorais bastante bien el TSILang… pero ? alguien ha probado el Paquete opensource Dklang ( http://www.dk-soft.org/products/dklang/ ) o el EMS Advanced Localizer Component Suite ?
¿ Pros ? ¿Contras?
Un saludo.

Terry Yapt
Terry Yapt
14 years ago

Muy bueno Neftalí, me has ahorrado mucho trabajo.

Muchas gracias.

kaki
kaki
14 years ago

Muy bueno este aporte. gracias por el tutorial. solo una pregunta lo he probado con un menu y me traduce los subitems pero el item principal no. por ejemplo item principal Archivo que contiene dos subitems Abrir y Cerrar. cuando traduzco al inglés File – Open – Close. siempre se mantiene Archivo en lugar de cambiar a File

Sil
Sil
14 years ago

Hola, consulta estoy usando esta libreria con el builder 2009. Al momento de hacer «embed translations» me muestra el siguiente error:
Pach code «6637DB2E-62E1-4A60-AC19-C23867046A89» was not found in .exe file. Are you sure the .exe file has been compiled with the correct libraries? ..aceptar.

Cambie el .pas por el compitible con D2009. Y el .exe compila correctamente. Venia usando estas librerias correctamente con builder 6 pero por temas de trabajo con caracteres unicode tuve que mudar todo a builder 2009 y se presento este lema..

Alguien me podra ayudar por favor necesito solucionar esto urgente.
GRACIAS!

Sil
Sil
14 years ago

Hola Neftalí, gracias por tu respuesta! Ahora estoy usando esa funcion gnugettext.pas compatible con delphi 2009 … pero nose a alguien le paso algo similar..
:( Help. Gracias.

Tejadon
13 years ago

Hola:

En principio agradecerte tus aportes Neftali, desde que me inicie en delphi me han ayudado mucho los de la web clubdelphi jeje no se si te sonara un tal maxinitto jeejejejejej… bueno pues eso en uno de los foros de esa web encontre esta pag y con esto de los lenguajes y ami me funciona de lujo, pero cnd cambio las constantes el error desaparece pero luego muevo el .exe a otro lado y no funcionan las traducciones, despues lo vuelvo a mover a la carpeta donde tengo los locale y si me funcionan, mmm ¿alguna sugerencia?. gracias y saludos.

Tejadon
13 years ago

@Germán Estévez pero ese componente no era de pago?

Tejadon
13 years ago

@Germán Estévez Amm otra cosilla que no viene al caso pero bueno, tengo una aplicacion cliente-servidor, y al enviar un texto desde el servidor al cliente me aparece en carateres raros como parecido a simbolos chinos mezclado con numeros sabes a que se debe eso, uso delphi 2009 y uso los socket predeterminados que trae, tambien conozco los indi pero preferi estos, gracias.

Tejadon
13 years ago

@Germán Estévez perdona por tanto mensaje jeje mira aqui te adjunto una foto xk no se si me explique bien http://imageshack.us/photo/my-images/585/errorjc.jpg/

Duilio Juan Isola
Duilio Juan Isola
13 years ago

Hola Neftali. He hecho pruebas y me funciona correctamente hasta que decido quitar un componente (Componente.Free).
Al retraducir la aplicación salta un error que he seguido hasta:

procedure TTP_Retranslator.Execute;

if ppinil then begin
SetWideStrProp(item.obj, ppi, newValue);

Cuando llega aqui TComponent(item.obj).Name=» y la instrucción falla.

He buscado información sobre este fallo y no encuentro absolutamente nada.

Ariel
Ariel
11 years ago

Estoy utilizando este componente en un proyecto Delphi 7, funciona maravillosamente, y ahora mismo estoy migrando este proyecto a Delphi XE pero en cuanto adiciono gnugettext al uses y ejecuto me genera Stack Overflow y no hay manera que funciona.

Alguna idea por favor ?

Blue
Blue
11 years ago

Yo estoy migrando una aplicacion de 2006 a XE4, y me pasa lo mismo.Me falla algunos componentes al traducirlos.Encontre una revision nueva,(220), pero tampoco funciona :(

Mario
Mario
1 month ago

Hola.
Ya han pasado 13 años desde la publicación de este documento cuando yo lo he encontrado cuando buscaba cómo usar gnugettext.

David preguntaba en la primera consulta de este hilo cómo ampliar el fichero .po cuando se modificaba el proyecto Delphi con más cadenas de texto.
En aquel momento le respondiste que se explicaba en la web:
http://dybdahl.dk/dxgettext/docs/beta/online/merging.html
Lamentablemente, esa web ya no está disponible.
¿Sería posible explicar de qué manera se podría hacer, o poner un enlace válido a alguna web donde se explique?

Por cierto, la aplicación Poedit que he instalado recientemente siguiendo el enlace que se indica en el documento, no tiene el mismo aspecto, por lo que supongo que no se trata de la misma versión que se muestra ahí.

Saludos.

28
0
Would love your thoughts, please comment.x
()
x