Incluir ficheros DFM condicionalmente

En los últimos meses he participado en la traducción de un programa hecho con Delphi. Conté por aquí los problemas del Translation Manager incluido con Delphi hasta el punto de recomendar que no se use.

En esa última historia contaba cómo terminé por crear una herramienta propia que usa el parser de DFM de la VCL para filtrar los ficheros DFM y sustituir las cadenas de acuerdo a un diccionario. El resultado final es un juego de ficheros DFM en catalán e inglés.

La primera idea fue hacer un script que copiase los fuentes del proyecto a otro directorio, machacase sus DFM con los traducidos y compilase la versión en catalán o inglés. Pero finalmente se me ocurrió la manera de ponerlo todo junto y controlar el idioma con un fichero incluido y $define.

En principio parece fácil. Todas las units que tienen un DFM asociado llevan la siguiente línea, generada automáticamente por el IDE:

{$R *.dfm}

La directriz del compilador R se usa para incluir ficheros de recursos. Los DFM originales eran siempre ficheros de recursos (los que suelen tener la extensión *.RES) con la definición del formulario metida en un bloque binario del tipo RC_DATA. A partir de Delphi 5 (creo) existe la posibilidad de guardar los DFM en disco en formato texto, aunque antes también era posible acceder a ese texto con Alt-F12 o a través del portapapeles. Sea como sea, $R sigue sirviendo para incluir el DFM, aunque sea en formato texto. El asterisco representa el nombre del fichero actual, así que *.dfm en unit1.pas se referiría a unit1.dfm.

Primer intento

Lo más sencillo parece hacer un simple condicional. Por una parte tendríamos la enumeración de idiomas:

{$DEFINE CASTELLANO}
{ DEFINE CATALAN}
{ DEFINE INGLES}

Al faltar el signo del dólar, sólo la primera línea es válida. Pero es fácil cambiar el signo de sitio.

Después podemos usar un condicional. Parece lógico usar lo siguiente:

{$IFDEF CASTELLANO}{$R *.dfm}{$ENDIF}
{$IFDEF CATALAN}{$R *.cat}{$ENDIF}
{$IFDEF INGLES}{$R *.eng}{$ENDIF}

Pero no funciona. Al menos Delphi 6 no se traga como DFM un fichero que tenga extensión .CAT. Creo que el error era algo sobre el formato. En cualquier caso se puede arreglar así:

{$IFDEF CASTELLANO}{$R *.dfm}{$ENDIF}
{$IFDEF CATALAN}{$R *.cat.dfm}{$ENDIF}
{$IFDEF INGLES}{$R *.eng.dfm}{$ENDIF}

Bien, esto funciona. Pero es muy poco práctico tener el define de idioma en cada uno de las units con DFM asociado. Nueva idea: poner todo en un fichero incluido y dejar sólo la directiva de inclusión:

{$I IDIOMA.INC}

Donde lógicamente habríamos puesto lo siguiente:

{$DEFINE CASTELLANO}
{ DEFINE CATALAN}
{ DEFINE INGLES}
 
{$IFDEF CASTELLANO}{$R *.dfm}{$ENDIF}
{$IFDEF CATALAN}{$R *.cat.dfm}{$ENDIF}
{$IFDEF INGLES}{$R *.eng.dfm}{$ENDIF}

La peculiaridad

Esa simple línea no funciona. La peculiaridad de los DFM es que el entorno va a su bola buscando la directriz {$R *.dfm} para saber si tiene que asociar el DFM. El entorno no entra en los ficheros incluidos, así que nos quedaríamos sin poder usar el diseñador de formularios.

Nuevo intento. Pongo no uno, sino dos ficheros incluidos así:

{$DEFINE CASTELLANO}
{ DEFINE CATALAN}
{ DEFINE INGLES}

{$IFDEF CASTELLANO}

Aquí en medio queda el {$R *.dfm}

{$ENDIF}
{$IFDEF CATALAN}{$R *.cat}{$ENDIF}
{$IFDEF INGLES}{$R *.eng}{$ENDIF}

En el principal tendríamos algo así:

{$I IDIOMA.INC}{$R *.dfm}{$I IDIOMAFIN.INC}

Por desgracia a Delphi tampoco le sienta bien que se deje un bloque de compilación condicional abierto entre ficheros.

Lo que sí funciona

Supongo que se puede resolver de varias formas. Lo que he puesto es una línea ligeramente más larga que la anterior.

{$I IDIOMA.INC}{$IFDEF CASTELLANO}{$R *.dfm}{$ELSE}{$IDIOMAFIN.INC}{$ENDIF}

El fichero IDIOMA.INC contiene sólo los defines de idiomas:

{$DEFINE CASTELLANO}
{ DEFINE CATALAN}
{ DEFINE INGLES}

Mientras que el segundo incluido lleva esto:

{$IFDEF CATALAN}{$R *.cat}{$ENDIF}
{$IFDEF INGLES}{$R *.eng}{$ENDIF}

A pesar el condicional el IDE siempre va a pillar el fichero *.dfm, que es lo que veremos siempre en tiempo de diseño, mientras que el compilador escogerá el que se decida en idioma.inc.

Finalmente podemos meter todos los DFM de todos los idiomas en el mismo directorio y controlar el idioma de compilación modificando un solo fichero.

Responder

El contenido de este campo se mantiene como privado y no se muestra públicamente.
  • Las direcciones de las páginas web y las de correo se convierten en enlaces automáticamente.
  • Etiquetas HTML permitidas: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Saltos automáticos de líneas y de párrafos.

Más información sobre opciones de formato