¿Mejores prácticas para textos localizados en aplicaciones multiplataforma C++?

StackOverflow https://stackoverflow.com/questions/403747

  •  03-07-2019
  •  | 
  •  

Pregunta

En el estándar C++ actual (C++03), hay muy pocas especificaciones sobre la localización de texto y eso hace que la vida del desarrollador de C++ sea más difícil de lo habitual cuando trabaja con textos localizados (ciertamente el estándar C++0x ayudará aquí más adelante).

Suponiendo el siguiente escenario (que proviene de casos reales de desarrollo de juegos para PC-Mac):

  1. aplicación responsiva (en tiempo real):la aplicación debe minimizar los tiempos de falta de respuesta a "no perceptibles", por lo que la velocidad de ejecución es importante.
  2. textos localizados:Los textos mostrados están localizados en más de dos idiomas, potencialmente en más; no espere una cantidad fija de idiomas, deberían ser fácilmente extensibles.
  3. lenguaje definido en tiempo de ejecución:los textos no deben compilarse en la aplicación (ni tener una aplicación por idioma), la información del idioma elegido se obtiene al iniciar la aplicación, lo que implica algún tipo de carga de texto.
  4. multiplataforma:La aplicación se codificará teniendo en cuenta la multiplataforma (Windows - Linux/Ubuntu - Mac/OSX), por lo que el sistema de texto localizado también debe ser multiplataforma.
  5. aplicación independiente:la aplicación proporciona todo lo necesario para ejecutarla;No utilizará ninguna biblioteca de entorno ni requerirá que el usuario instale nada más que el sistema operativo (como la mayoría de los juegos, por ejemplo).

¿Cuáles son las mejores prácticas para gestionar textos localizados en C++ en este tipo de aplicaciones?

Investigué esto el año pasado y lo único de lo que estoy seguro es que deberías usar std::wstring o std::basic_string<ABigEnoughType> para manipular los textos en la aplicación.Detuve mi investigación porque estaba trabajando más en el problema de la "visualización de texto" (en el caso de 3D en tiempo real), pero supongo que existen algunas mejores prácticas para administrar textos localizados en C++ sin formato más allá de eso y "usar Unicode". .

Por lo tanto, todas las mejores prácticas, sugerencias e información (creo que la multiplataforma lo dificulta) son bienvenidas.

¿Fue útil?

Solución

En una pequeña empresa de videojuegos, Black Lantern Studios, fui el desarrollador principal de un juego llamado Lionel Trains DS.Localizamos al inglés, español, francés y alemán.Conocíamos todos los idiomas desde el principio, por lo que incluirlos en el momento de la compilación era la única opción.(Están grabados en una ROM, ya ves)

Puedo darte información sobre algunas de las cosas que hicimos.Nuestras cadenas se cargaron en una matriz al inicio según la selección de idioma del reproductor.Cada idioma individual entró en un archivo separado con todas las cadenas en el mismo orden.La cadena 1 siempre fue el título del juego, la cadena 2 siempre la primera opción del menú, y así sucesivamente.Claveamos las matrices de un enum, como integer La indexación es muy rápida y, en los juegos, la velocidad lo es todo.(La solución vinculada en una de las otras respuestas usa string búsquedas, que yo tendería a evitar). Al mostrar las cadenas, utilizamos un printf() escriba la función para reemplazar marcadores con valores."El tren 3 sale de la ciudad 1."

Ahora veamos algunos de los peligros.

1) Entre idiomas, el orden de las frases es completamente diferente."El tren 3 sale de la ciudad 1."traducido al alemán y viceversa termina siendo"Desde la ciudad 1 sale el tren 3.".Si estás usando algo como printf() y tu cadena es "El tren %d sale de la ciudad %d."El alemán terminará diciendo"Desde la ciudad 3 sale el tren 1."lo cual es completamente erróneo.Resolvimos esto forzando que la traducción mantuviera el mismo orden de palabras, pero terminamos con un alemán bastante entrecortado.Si tuviera que hacerlo de nuevo, escribiría una función que tomara la cadena y una matriz de valores de base cero para colocarla.Entonces usaría marcadores como %0 y %1, básicamente incrustando el índice de la matriz en la cadena. Actualizar:@Jonathan Leffler señaló que un compatible con POSIX printf() admite el uso %2$s escriba marcadores donde 2$ porción instruye al printf() para llenar ese marcador con el segundo parámetro adicional.Esto sería bastante útil, siempre y cuando sea lo suficientemente rápido.Una solución personalizada aún puede ser más rápida, por lo que querrás asegurarte y probar ambas.

2) Los idiomas varían mucho en extensión.Lo que en inglés eran 30 caracteres, a veces llegaba a 110 caracteres en alemán.Esto significaba que a menudo no encajaba en las pantallas en las que lo estábamos colocando.Probablemente esto sea una preocupación menor para los juegos de PC/Mac, pero si estás realizando algún trabajo en el que el texto debe caber en un cuadro definido, querrás considerarlo.Para resolver este problema, eliminamos tantos adjetivos de nuestro texto como fuera posible para otros idiomas.Esto acortó la frase, pero conservó el significado, aunque perdió un poco el sabor.Más tarde diseñé una aplicación que podríamos usar y que contendría la fuente y el tamaño del cuadro y permitiría a los traductores hacer sus propias modificaciones para que el texto encajara en el cuadro.No estoy seguro si alguna vez lo implementaron.También podrías considerar tener áreas de texto con desplazamiento, si tienes este problema.

3) En lo que respecta a la multiplataforma, escribimos prácticamente C++ puro para nuestro sistema de localización.Escribimos archivos binarios codificados personalizados para cargar y un programa personalizado para convertir de un CSV de texto de idioma a un .h con la enumeración y el archivo al mapa de idioma, y ​​un .lang para cada idioma.Lo más específico de la plataforma que utilizamos fueron las fuentes y el printf() función, pero tendrá algo adecuado para cualquier lugar donde esté desarrollando, o podría escribir el suyo propio si es necesario.

Otros consejos

GNU Gettext lo hace todo.

Estoy totalmente en desacuerdo con la respuesta aceptada. Primero, la parte sobre el uso de búsquedas de matriz estática para acelerar las búsquedas de texto simplemente muestra que la persona que realiza el la optimización es muy inexperta : calcular el diseño de dicho texto y representar dicho texto utiliza de 2 a 4 órdenes de magnitud más tiempo que una búsqueda hash. Si alguien quisiera implementar su propia biblioteca de idiomas, nunca debería basarse en matrices estáticas.

Pero eso no es realmente relevante, porque escribir su propia biblioteca de idiomas para usar en su propio juego es incluso peor que la optimización prematura sin sentido. Hay algunas razones extremadamente buenas para nunca escriba su propia biblioteca de localización :

  1. Planear el tiempo para usar una biblioteca de localización es mucho más fácil que planificar el tiempo para escribir una biblioteca de localización. Existen bibliotecas de localización, funcionan y muchas personas las han usado.

  2. La localización es complicada, por lo que te equivocarás. Cada idioma agrega una nueva peculiaridad, lo que significa que cada vez que agregue un nuevo idioma a su propia biblioteca de localización local, deberá cambiar el código nuevamente para tener en cuenta las peculiaridades. ¿Sabía que algunos idiomas tienen más de 2 formas plurales, dependiendo del número de elementos en cuestión? ¿Más de 2 géneros (más de 10, incluso)? Además, los formatos de número y fecha varían mucho entre diferentes en muchos idiomas.

  3. Cuando su aplicación tenga éxito, querrá agregar soporte para más idiomas. Idiomas que nadie en tu equipo habla con fluidez. Contratar a alguien para que escriba una traducción será considerablemente más barato si ya conoce las herramientas con las que está trabajando.

Una biblioteca de localización muy conocida y completa es GNU Gettext , que utiliza la GPL y, por lo tanto, debe evitarse para trabajos comerciales En su lugar, puede usar la biblioteca de impulso boost.locale que funciona con archivos Gettext, y es libre de usar y modificar para proyectos comerciales y no comerciales de cualquier tipo.

Por lo que puedo decir, no habrá características adicionales en el estándar C ++ 0x. Sospecho que el Comité considera que esto es un asunto de bibliotecas de terceros.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top