Interfaz de usuario multilingüe: un ejecutable, N idiomas (segunda parte)
En la anterior entrega, estudiamos un método para separar el código de los recursos a traducir utilizando archivos de recursos. Ahora veremos como es posible separar estos recursos del código no sólo en nuestras fuentes, sino también en los binarios que se distribuyen.
Normalmente nuestro código compilado se puede describir por la siguiente imagen:
Donde vemos que tanto el código como los datos usados para desplegar el interfaz de usuario. Utilizando MUI lo que podemos hacer es lo siguiente:
En este caso tenemos un archivo de tipo .exe (o .dll) que contiene el código y un archivo .mui que contiene los recursos a traducir.
Esto ya es muy bueno, pues nos permite sustituir el archivo con los recursos independientemente del código. Pero además el diseño de MUI nos permite instalar múltiples idiomas conforme sean necesarios. Nuestros archivos ahora deben contener lo siguiente:
- Hello01.exe - Código ejecutable válido para todos los idiomas
- Hello01.exe.mui - Recursos traducidos para un idioma (inglés)
Y para que esto funcione correctamente necesitamos instalarlos con la siguiente estructura de directorios:
<appdir>\Hello01.exe
<appdir>\en-us\Hello01.exe.mui
Esto nos permite crear un nuevo archivo .mui para otro idioma y con instalarlo en el directorio correcto tendremos una aplicación que soporta múltiples idiomas.
Volviendo al ejemplo
Regresando a nuestro ejemplo anterior, veamos como compilar nuestro ejecutable en dos archivos, uno conteniendo el código y otro con los recursos a traducir.
Los comandos descritos a continuación se ejecutan en la línea de comandos de VS 2008, y en el directorio donde trabajaremos debemos tener los siguientes archivos:
resource.h
1: #define IDS_TITULO 1001
2: #define IDS_MENSAJE 1002
resource.rc - Nótese que ahora definimos el lenguaje en qué están creados los recursos.
1: #include "winnt.h"
2: #include "resource.h"
3:
4: LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
5:
6: STRINGTABLE
7: BEGIN
8: IDS_TITULO "Hello world!"
9: IDS_MENSAJE "Sample App"
10: END
resource.rcconfig - Este archivo indica qué tipo de recursos son localizables y deben traducirse. Aquí indicamos qué recursos se mantienen en el archivo ejecutable y cuáles van al archivo .mui. Al final de este artículo hay una liga donde se describe la sintaxis de los archivos .rcconfig.
1: <?xml version="1.0" encoding="utf-8"?>
2: <localization>
3: <resources>
4: <win32Resources fileType="Application">
5: <neutralResources>
6: <resourceType
7: typeNameId="#16"
8: />
9: </neutralResources>
10: <localizedResources>
11: <resourceType
12: typeNameId="#2"
13: itemId="5 6 7 8 9 10 11 12"
14: itemName="HTML PRI"
15: />
16: <resourceType
17: typeNameId="#4"
18: />
19: <resourceType
20: typeNameId="#5"
21: />
22: <resourceType
23: typeNameId="#6"
24: />
25: <resourceType
26: typeNameId="#9"
27: />
28: <resourceType
29: typeNameId="#11"
30: />
31: <resourceType
32: typeNameId="#16"
33: />
34: <resourceType
35: typeNameId="HTML"
36: />
37: <resourceType
38: typeNameId="#23"
39: />
40: <resourceType
41: typeNameId="#240"
42: />
43: <resourceType
44: typeNameId="#1024"
45: />
46: <resourceType
47: typeNameId="MY_TYPE"
48: />
49: </localizedResources>
50: </win32Resources>
51: </resources>
52: </localization>
hello01.cpp
1: #include <windows.h>
2: #include "resource.h"
3:
4: #define BUFFER_MAX 100
5:
6: int main(int argc, WCHAR** argv)
7: {
8: WCHAR mensaje[BUFFER_MAX];
9: WCHAR titulo[BUFFER_MAX];
10: ::LoadString(::GetModuleHandle(NULL), IDS_MENSAJE, mensaje, BUFFER_MAX);
11: ::LoadString(::GetModuleHandle(NULL), IDS_TITULO, titulo, BUFFER_MAX);
12: ::MessageBox(NULL, mensaje, titulo, MB_OK);
13: return 0;
14: }
Y deben existir los subdirectorios
- out
- out\en-us
Nota: Todos los comandos para compilar se ejecutan desde el directorio donde tenemos nuestro código. Comenzamos compilando el código fuente:
cl /Fo"out\\" /D "UNICODE" /D "_UNICODE" /c Hello01.cpp
Y a continuación compilamos los recursos:
rc -fo out\resource.res -fm out\resource.loc.res -q resource.rcconfig resource.rc
Finalmente enlazamos los resultados de los pasos anteriores para crear nuestro ejecutable final:
link /out:"out\Hello01.complete.exe" out\Hello01.obj out\resource.res user32.lib
Hasta ahora no hemos hecho nada distinto, excepto por etiquetar los recursos utilizando con el archivo .rcconfig. El siguiente paso es el que utilizará esta información para separar nuestro ejecutable en un archivo que contiene el código y otro con los recursos.
muirct -q resource.rcconfig out\Hello01.complete.exe out\Hello01.exe out\en-us\Hello01.exe.mui
Es muy importante hacer notar que si el ejecutable se encuentra en el directorio x, el archivo .mui debe aparecer en el directorio x\<codigo de lenguaje>. Si no hacemos esto correctamente, el manejador de recursos no podrá encontrarlo. Ejecutando nuestro programa, obtenemos el resultado esperado:
Ahora, sólo para confirmar qué sucede si eliminamos el archivo .mui (o se encuentra en una ubicación incorrecta), esto es lo que ocurre con el programa después de borrar out\en-us\Hello01.exe.mui:
En la tercera parte veremos cómo se pueden generar recursos para otros idiomas y cómo determina el sistema que recursos utilizar.
Referencias:
Comments
Anonymous
October 12, 2009
Hola. Sabes si hay algún modo de traducir un archivo .mui de windows a un idioma todavía no incluído en las lenguas disponibles de Windows. Lo que pretendo hacer es descargar el archivo .mui de español por ejemplo para windows vista y traducir el texto a otro idioma; y así poder disponer de un windows Wista en Gascón, o en berebér... Muchas gracias d antemanoAnonymous
October 13, 2009
losocarrat, Gracias por tu pregunta. En este momento no tengo una respuesta, pero estoy investigando qué opciones tienes y en un par de días pondré un comentario con lo que averigüe.