2008-10-08 22 views
20

Esto es un poco una pregunta general, abierta a las opiniones. He estado tratando de encontrar una buena forma de diseñar para la localización de recursos de cadena para una aplicación Windows MFC y utilidades relacionadas. Mi lista es:La mejor manera de diseñar para la localización de cadenas

  • debe preservar los literales de cadena en el código (en oposición a la sustitución con recursos #define macro ID), por lo que los mensajes están todavía en línea legible
  • deben permitir que los recursos cadena localizada (la)
  • no debe imponer restricciones adicionales entorno de ejecución (por ejemplo: la dependencia de .NET, etc.)
  • debería haber intromisión mínima en el código existente (la modificación de menos, mejor)
  • Debe ser depurable
  • debe generar archivos de recursos que son editables por herramientas comunes (es decir: formato común)
  • no deben utilizar bloques de copiar/pegar comentario para preservar las cadenas literales en el código, o cualquier otra cosa que crea el potencial para la desincronización
  • Would sea ​​agradable permitir la comprobación estática (en tiempo de compilación) de que cada cadena "anotada" está en los archivos de recursos
  • Sería bueno permitir la agrupación de cadenas de recursos entre idiomas (para componentes en varios idiomas, p. ej .: C++ nativo) y .NET)

Tengo una manera que cumple con todos mis deseos hasta cierto punto, excepto para la comprobación estática, pero tengo h ad para desarrollar un poco de código personalizado para lograrlo (y tiene limitaciones). Me pregunto si alguien ha resuelto este problema de una manera particularmente buena.

Editar: La solución actualmente tengo es el siguiente:

ShowMessage(RESTRING(_T("Some string"))); 
ShowMessage(RESTRING(_T("Some string with variable %1"), sNonTranslatedStringVariable)); 

entonces tengo una utilidad personalizado para analizar las cadenas de dentro bloquea el 'encordar' y ponerlas en un archivo .resx para localización, y un objeto COM C# separado para cargarlos desde archivos de recursos localizados con repliegue. Si el objeto C# no está disponible (o no se puede cargar), recurro a la cadena en el código. La macro se expande a una clase de plantilla que llama al objeto COM y realiza el formateo, etc.

De todos modos, pensé que sería útil agregar lo que tengo ahora como referencia.

Respuesta

0

En un proyecto que había localizado en más de 10 idiomas, puse todo lo que se iba a localizar en un dll único de recursos. En el momento de la instalación, el usuario seleccionó qué dll se instaló con su aplicación.

Solo tuve que entregar el dll en inglés al equipo de localización. Me devolvieron una dll localizada por cada idioma que incluí en la compilación.

Sé que no es perfecto, pero funcionó.

+0

¿Has descubierto una forma de hacerlo sin reemplazar cadenas en el código con los ID de recursos? Lo que estás describiendo suena como el método coloquial, que ciertamente puede funcionar, pero no es realmente lo que estoy buscando. – Nick

+0

No, no codificamos cadenas en nuestras aplicaciones. Lo que sí vemos es una constante descriptiva que se relaciona con la identificación del recurso. – BoltBait

1

No sé mucho acerca de cómo esto se hace normalmente en Windows, pero la forma en que se manejan las cadenas localizadas en el Cocoa framework de Apple funciona bastante bien. Tienen un archivo de formato de texto muy básico que puede enviar a un traductor y algunas macros de preprocesador para recuperar los valores de los archivos.

En su código, verá las cadenas en su idioma nativo, en lugar de identificadores opacos.

+0

Esto es básicamente lo que estoy buscando, pero en algo que funciona con C++ simple (sin un marco). – Nick

+0

Sí, pensé que podría ser lo que estás buscando. Desafortunadamente, no conozco ninguna versión pura de C++ de tal diseño, pero no me parece (a mí) que sería tan difícil escribir uno. La simplificación de la clave es tener una herramienta "genstrings" para escanear la fuente y crear los archivos. –

3

Utilizamos la cadena en inglés como ID.

Si falla la búsqueda desde el objeto de recurso internacional (cargado desde el dll I18N instalado), de manera predeterminada, tendremos la cadena de ID.

código es el siguiente:

doAction(I18N.get("Press OK to continue")); 

Como parte de los procesos de construcción que tenemos un script en perl que analiza toda fuente de constantes de cadena. Construye un archivo temporal de todas las cadenas en la aplicación y luego las compara con las cadenas de recursos en cada local para ver si existen. Cualquier cadena faltante genera un correo electrónico al equipo de traducción apropiado.

Podemos tener varios dll para cada local. El nombre de la DLL se basa en el RFC 3066
lenguaje [_territorio] [. Conjuntocaract] [@ modificador]

Tratamos y el extracto de la configuración regional de la máquina y ser lo más específico posible cuando se carga la DLL I18N pero repliegue a variaciones locales menos específicas si la versión más específica no está presente.

Ejemplo:

En el Reino Unido: Si el local era en_GB.UTF-8
(utilizo el término DLL libremente no en el sentido ventanas específica).

Primero busque el I18N.en_GB.UTF-8 dll. Si este dll no existe, retroceda a I18N.en_GB. Si no existe este archivo DLL caer de nuevo a I18N.en Si este archivo DLL no existe Beck caída a I18N.default

La única excepción a esta regla es: chino simplificado (zh_CN) donde el repliegue es Inglés de EE. UU. (En_US). Si la máquina no es compatible con chino simplificado, es poco probable que sea compatible con chino completo.

+0

Suena similar a lo que estoy haciendo, pero ¿cómo extraer todas las cadenas para crear las dll de recursos? ¿O se hace a mano? – Nick

+0

Ok, entonces estás haciendo algo muy similar a lo que estoy haciendo (excepto que elegí resx y utilizas bibliotecas de recursos nativos). Buen trato, me hace sentir mucho mejor acerca del enfoque que estoy tomando. Lo dejaré abierto para más comentarios, pero este parece ser un buen enfoque. – Nick

+2

GNU gettext ya está haciendo todo eso, por lo que acaba de reinventar la rueda (versión inferior). –

0

Dado que está abierto a las opiniones, aquí es cómo lo hago.

Mi archivo de texto localizado es un archivo de texto delimitado por tabulaciones simple que se puede cargar en Excel y editar. La primera columna es para la definición y cada columna a la derecha es un lenguaje posterior, por ejemplo:

ID    ENGLISH  FRENCH GERMAN 
STRING_YES  YES   OUI  YA 
STRING_NO  NO   NON  NEIN 

Luego, en mi makefile es un paso cusom compilación que genera un archivo strings.h y una strings.dat . En mi caso, construye una lista de enumeración para los identificadores de cadena y luego un archivo binario con desplazamientos para el texto. Como en mi aplicación el usuario puede cambiar el idioma en cualquier momento, lo tengo todo en la memoria, pero puede hacer que el preprocesador genere un archivo de salida diferente para cada idioma si es necesario.

Lo que me gusta de este diseño es que si faltan algunas cadenas, obtendría un error de compilación, mientras que si se buscaran las cadenas en tiempo de ejecución, es posible que no conozca una cadena faltante en una parte poco utilizada del código hasta más tarde.

0

Desea una utilidad avanzada que siempre quise escribir pero nunca tuve tiempo de hacerlo. Si no encuentra una herramienta de este tipo, puede recurrir a las clases de contenedor CMsg() y CFMsg() que permiten extraer fácilmente cadenas de la tabla de recursos.(CFMsg incluso proporciona una envoltura de un solo lienzo de FormatMessage. Y sí, a falta de esa herramienta que está buscando, mantener una copia de la cadena en el comentario es una buena solución. En cuanto a la desincronización del comentario, recuerde que los literales de cadena se modifica muy raramente.

http://www.codeproject.com/KB/string/stringtable.aspx

por cierto, los programas de Win32 nativas y programas .NET tener una gestión de recursos de almacenamiento totalmente diferente. Vas a tener dificultades para encontrar una solución común para ambos.

1

Su solución es bastante similar a la solución "gettext" de Unix/Linux. De hecho, no necesitaría escribir la rutina de extracción nes.

No estoy seguro de por qué quiere que la macro _RESTRING maneje varios argumentos. Mi código (usando el soporte de wxWidgets para gettext) se ve así: MyString.Format(_("Some string with variable %ls"), _("variable"));. Es decir, String :: Format (...) obtiene dos argumentos traducidos individualmente. En retrospectiva, Boost :: Formato hubiera sido mejor, pero también permitiría boost::format(_("Some string with variable %1")) % _("variable");

(Nosotros usamos la macro _() por razones de brevedad)

+0

Quería que la macro manejara el formato varargs en línea, principalmente por conveniencia. De lo contrario, tendría que poner algo más a su alrededor, posiblemente con otra declaración de variable de cadena, que es un código desperdiciado. – Nick

+0

Utilizamos gettext en proyectos multibyte junto con recursos de varios idiomas. El problema era que no podemos usar la licencia GPL de gettext, tuvimos que escribir la nuestra. Otro problema es la sincronización de cadenas con respecto a los parámetros de formato: printf (_ ("Quiero esto:% .20s y esto:% f% .3s")); La herramienta externa debe hacer la sincronización. – BlackBada

1

La forma más sencilla es sólo ID uso de cadenas en el código - no literal instrumentos de cuerda. A continuación, puede generar versiones diferentes del archivo .rc para cada idioma y crear DLL de solo recursos o simplemente compilaciones de idiomas diferentes.

Hay un par de utilidades de shareware para ayudar a localizar el archivo rc que maneja el cambio de tamaño de elementos de diálogo para idiomas con palabras más largas y warnign sobre traducciones faltantes.

Un problema más complicado es el orden de las palabras, si tiene varios números en un printf que deben estar en un orden diferente para la gramática de otro idioma. Hay algunas clases de printf extendidas en codeproject que le permiten especificar cosas como printf ("palabra% 1s y% 2s", var1, var2) para que pueda cambiar% 1s y% 2s si es necesario.

Cuestiones relacionadas