ventajas - ¿Mejores prácticas para textos localizados en aplicaciones multiplataforma en C++?
estudiar desarrollo de aplicaciones multiplataforma (4)
No habrá características adicionales en el estándar C ++ 0x, por lo que puedo decir. Sospecho que el Comité considera que esto es asunto de bibliotecas de terceros.
En el estándar actual de C ++ (C ++ 03), hay muy pocas especificaciones sobre localización de texto y eso hace que la vida del desarrollador de C ++ sea más difícil de lo normal cuando se trabaja con textos localizados (sin duda, el estándar C ++ 0x lo ayudará más adelante).
Suponiendo el siguiente escenario (que proviene de casos reales de desarrollo de juegos de PC-Mac):
- aplicación receptiva (en tiempo real) : la aplicación tiene que minimizar los tiempos de inactividad a "no perceptibles", por lo que la velocidad de ejecución es importante.
- textos localizados : los textos mostrados están ubicados en más de dos idiomas, potencialmente más; no espere un número fijo de idiomas, debe ser fácilmente extensible.
- lenguaje definido en tiempo de ejecución : los textos no deben compilarse en la aplicación (ni tener una aplicación por idioma), se obtiene la información del idioma elegido al inicio de la aplicación, lo que implica algún tipo de carga de texto.
- multiplataforma : la aplicación se codifica con multiplataforma en mente (Windows - Linux / Ubuntu - Mac / OSX) por lo que el sistema de texto localizado también debe ser multiplataforma.
- aplicación independiente : la aplicación proporciona todo lo necesario para ejecutarla; no usará 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 administrar textos localizados en C ++ en este tipo de aplicación?
Analicé esto el año pasado y de lo único que estoy seguro es de que debes usar std::wstring
o std::basic_string<ABigEnoughType>
para manipular los textos en la aplicación. Paré mi investigación porque estaba trabajando más en el problema de "visualización de texto" (en el caso del 3D en tiempo real), pero creo que hay algunas mejores prácticas para administrar textos localizados en C ++ sin procesar más allá de eso y "usar Unicode" .
Por lo tanto, todas las mejores prácticas, sugerencias e información (multiplataforma hace que sea difícil, creo) son bienvenidas.
GNU Gettext lo hace todo.
En una pequeña empresa de videojuegos, Black Lantern Studios, yo era el desarrollador principal de un juego llamado Lionel Trains DS. Estamos localizados en inglés, español, francés y alemán. Conocíamos todos los idiomas por adelantado, por lo que incluirlos en el momento de la compilación era la única opción. (Se queman a 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 jugador. Cada idioma individual entró en un archivo separado con todas las cadenas en el mismo orden. String 1 siempre fue el título del juego, string 2 siempre la primera opción de menú, y así sucesivamente. Afincamos las matrices de una enum
, ya que integer
indexación de integer
es muy rápida, y en los juegos, la velocidad lo es todo. (La solución vinculada en una de las otras respuestas utiliza búsquedas de string
, que tendería a evitar). Cuando mostramos las cadenas, usamos una printf()
tipo printf()
para reemplazar los marcadores por valores. "El tren 3 está partiendo de la ciudad 1 ".
Ahora para algunas de las trampas.
1) Entre idiomas, el orden de las frases es completamente diferente. "El tren 3 está partiendo de la ciudad 1. " traducido al alemán y de vuelta termina siendo " Desde la ciudad 1, el tren 3 se va ". Si está utilizando algo como printf()
y su cadena es " Train% d sale de city% d. " El alemán terminará diciendo " From City 3, Train 1 is departure. " Lo cual es completamente incorrecto. Solucionamos esto forzando a la traducción a mantener el mismo orden de palabras, pero terminamos con un alemán bastante roto. Si tuviera que hacerlo de nuevo, escribiría una función que tomara la cadena y una matriz basada en cero de los valores para ponerla. Entonces usaría marcadores como %0
y %1
, básicamente incrustando el índice de matriz en la cadena. Actualización: @Jonathan Leffler señaló que un printf()
compatible con POSIX printf()
admite el uso de marcadores de tipo %2$s
donde la porción 2$
ordena a printf()
que llene ese marcador con el segundo parámetro adicional. Eso sería bastante útil, siempre y cuando sea lo suficientemente rápido. Una solución personalizada puede ser aún más rápida, por lo que querrá asegurarse y probar ambas.
2) Los idiomas varían mucho en longitud. Lo que era 30 caracteres en inglés salió a veces hasta 110 caracteres en alemán. Esto significaba que a menudo no se ajustaría a las pantallas en las que lo estábamos poniendo. Esto probablemente sea una preocupación menor para los juegos de PC / Mac, pero si está haciendo algún trabajo en el que el texto debe caber en una caja definida, querrá considerar esto. Para resolver este problema, eliminamos tantos adjetivos de nuestro texto como sea posible para otros idiomas. Esto acortó la oración, pero conservó el significado, si pierde un poco del sabor. Más tarde diseñé una aplicación que podríamos usar que contendría la fuente y el tamaño de la caja y permitiría a los traductores hacer sus propias modificaciones para que el texto encaje en la caja. No estoy seguro si alguna vez lo implementaron. También podría considerar tener áreas de texto desplazables, si tiene este problema.
3) En lo que respecta a la plataforma cruzada, escribimos 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 un archivo al mapa de idiomas, y un .lang
para cada idioma. Lo más específico de la plataforma que utilizamos fueron las fuentes y la printf()
, pero tendrá algo adecuado para dondequiera que esté desarrollando, o podría escribir el suyo si es necesario.
Estoy totalmente en desacuerdo con la respuesta aceptada. Primero, la parte sobre el uso de búsquedas de arreglos estáticos para acelerar las búsquedas de texto simplemente muestra que la persona que hace la optimización es muy inexperta . Calcular el diseño de dicho texto y renderizar 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 arreglos estáticos.
Pero eso no es realmente relevante, porque escribir tu propia biblioteca de idiomas para usar en tu propio juego es incluso peor que la optimización prematura sin sentido. Hay algunas muy buenas razones para nunca escribir su propia biblioteca de localización :
Planificar 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.
La localización es complicada, por lo que obtendrá las cosas mal. Cada idioma agrega una nueva peculiaridad, lo que significa que cada vez que agregue un nuevo idioma a su propia biblioteca local de localización, tendrá que cambiar el código nuevamente para tener en cuenta las peculiaridades. ¿Sabía que algunos idiomas tienen más de 2 formas de plural, dependiendo de la cantidad 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.
Cuando su aplicación sea exitosa, querrá agregar soporte para más idiomas. Idiomas que nadie en su equipo habla con fluidez. Contratar a alguien para escribir una traducción será considerablemente más barato si ya conocen las herramientas con las que están trabajando.
Una biblioteca de localización muy conocida y completa es GNU Gettext , que utiliza la GPL, y por lo tanto debe evitarse para el trabajo comercial. En su lugar, puede utilizar la biblioteca boost boost.locale que funciona con archivos Gettext, y es de uso y modificación gratuitos para proyectos comerciales y no comerciales de ningún tipo.