Estrategias efectivas para la localización en .NET [cerrado]

121

Estoy desarrollando la interfaz de usuario para una aplicación .NET MVC que requerirá la localización internacional de todo el contenido en un futuro próximo. Estoy muy familiarizado con .NET en general, pero nunca he tenido un proyecto que requiera un enfoque tan significativo en la accesibilidad internacional.

El proyecto se está haciendo inicialmente en inglés. ¿Qué medidas debo tomar en este momento para facilitar la implementación de la localización en el futuro?

Smartcaveman
fuente
2
Gran pregunta! Me enfrento a una situación similar y me encantaría ver a los expertos evaluar esto.
¿Alguien tiene algún buen estándar para la gestión de recursos? El valor localizado también puede incluir imágenes, y no solo cadenas.
1
¿Es esta una interfaz de usuario WPF / silverlight o Winforms? Según mi experiencia (limitada), la experiencia de WinForms para la localización es mucho más simple que WPF / Silverlight.
Pete Stensønes
1
Si termina almacenando sus cadenas localizadas en la base de datos, en lugar de archivos de recursos, puede echar un vistazo a esta discusión: stackoverflow.com/questions/2458615/…
1
@Pete, @smartcaveman dijo que está "desarrollando la IU para una aplicación .NET MVC", así que ...
BrunoSalvino

Respuestas:

74

Estás desarrollando la aplicación ASP.Net MVC, ¿verdad? Otras respuestas parecen ser específicas para aplicaciones de escritorio. Déjame capturar cosas comunes:

Detección local

Es bastante importante que su aplicación detecte la configuración regional del usuario correctamente. En la aplicación de escritorio, CultureInfo.CurrentCulture tiene la configuración regional de formato preferida (la que se debe usar para formatear números, fechas, monedas, etc.) mientras que CultureInfo.CurrentUICulture tiene la configuración regional de interfaz de usuario preferida (la que se debe usar para mostrar mensajes localizados) . Para las aplicaciones web, debe configurar ambas culturas en automático (para detectar automáticamente la configuración regional desde el encabezado AcceptLanguage) a menos que desee implementar un flujo de trabajo de detección de configuración regional sofisticado (es decir, que desee admitir cambios de idioma a pedido).

Externalizar cadenas

Todas las cadenas deben provenir de recursos, es decir, archivos Resx. En la aplicación Winforms, se puede lograr fácilmente configurando la propiedad Localizable del formulario en true. También necesitaría externalizar manualmente (desafortunadamente) las cadenas que provienen de sus modelos. También es relativamente simple. En Asp.Net necesitaría externalizar todo manualmente ...

Diseños

Definitivamente debe permitir la expansión de la cadena. En el mundo de Winforms, se puede lograr a través de TableLayoutPanel, que debe usarse para asegurarse de que el diseño se ajuste automáticamente para acomodar texto más largo. En el mundo web, no tienes suerte. Es posible que deba implementar el mecanismo de localización CSS, una forma de modificar (anular) las definiciones CSS. Esto permitiría a las personas de localización modificar los problemas de estilo a pedido. Asegúrese de que cada elemento HTML en la página representada tenga una identificación única, ya que le permitirá apuntar con precisión.

Problemas culturales específicos

Evite usar gráficos, colores y sonidos que puedan ser específicos para la cultura occidental. Si realmente lo necesita, proporcione los medios de localización. Evite los gráficos sensibles a la dirección (ya que esto sería un problema cuando intenta localizar para decir árabe o hebreo). Además, no asuma que todo el mundo está usando los mismos números (es decir, no es cierto para el árabe).

ToString () y Parse ()

Asegúrese de pasar siempre CultureInfo cuando llame a ToString () a menos que no sea compatible. De esa manera estás comentando tus intenciones. Por ejemplo: si está usando algún número internamente y por alguna razón necesita convertirlo a cadena, use:

int i = 42;
var s = i.ToString(CultureInfo.InvariantCulture);

Para los números que se mostrarán al usuario, use:

var s = i.ToString(CultureInfo.CurrentCulture); // formatting culture used

Lo mismo se aplica a Parse (), TryParse () e incluso ParseExact (): se podrían introducir algunos errores desagradables sin el uso adecuado de CultureInfo. Esto se debe a que una pobre alma en Microsoft, llena de buenas intenciones, decidió que es una buena idea tratar CultureInfo.CurrentCulture como la predeterminada (se usaría si no pasa nada), después de todo cuando alguien está usando ToString ( ) él / ella quiere mostrarlo al usuario, ¿verdad? Resulta que no siempre es el caso; por ejemplo, intente almacenar el número de versión de su aplicación en la base de datos y luego convertirlo a la instancia de la clase Versión. Buena suerte.

Fechas y zonas horarias

Asegúrese de siempre almacenar e instanciar DateTime en UTC (use DateTime.UtcNow en lugar de DateTime.Now). Conviértalo a la hora local en formato local al mostrar:

DateTime now = DateTime.UtcNow;
var s = now.ToLocalTime().ToString(CultureInfo.CurrentCulture);

Si necesita enviar correos electrónicos con referencia de tiempo en el cuerpo, asegúrese de incluir información de zona horaria; incluya el desplazamiento UTC y la lista de ciudades:

DateTime someDate; // i.e. from database
var formattedDate = String.Format("{0} {1}", 
             someDate.ToLocaleTime().ToString(CultureInfo.CurrentCulture),
             TimeZoneInfo.Local.DisplayName);

Mensajes compuestos

Ya se le advirtió que no concatene cadenas. En su lugar, probablemente usaría String.Format () como se muestra arriba. Sin embargo, debo decir que debe minimizar el uso de mensajes compuestos. Eso es solo porque las reglas de gramática objetivo son bastante diferentes, por lo que los traductores pueden necesitar no solo reordenar la oración (esto se resolvería usando marcadores de posición y String.Format ()), sino que traduciría la oración completa de manera diferente en función de lo que será sustituido Deja que te dé algunos ejemplos:

// Multiple plural forms
English: 4 viruses found.
Polish: Znaleziono 4 wirusy. **OR** Znaleziono 5 wirusów.

// Conjugation
English: Program encountered incorrect character | Application encountered incorrect character.
Polish: Program napotkał nieznaną literę | Aplikacja napotkała nieznaną literę.

Otros problemas de concatenación

La concatenación no está restringida a cadenas. Evite establecer controles juntos, diga:

Recuérdame nuevamente en [cuadro de texto con número] días.

Esto debería rediseñarse para algo como: Recordarme nuevamente en este número de días: [cuadro de texto].

Codificación de caracteres y fuentes

Siempre guarde, transfiera, cualquier texto en Unicode (es decir, en UTF-8). No codifique las fuentes: es posible que la localización necesite modificarlas y desactivará el mecanismo de reserva de fuentes predeterminado (en el caso de Winforms). Recuerde permitir caracteres "extraños" en la mayoría de los campos (es decir, nombre de usuario).

Prueba

Probablemente necesitará implementar la llamada pseudo traducción, es decir, crear recursos para, por ejemplo, la cultura alemana y copiar sus cadenas en inglés agregando prefijos y sufijos. También puede ajustar marcadores de posición para detectar fácilmente cadenas compuestas. El propósito de la pseudo traducción es detectar problemas de localización como cadenas codificadas, problemas de diseño y uso excesivo de mensajes compuestos.

Paweł Dyda
fuente
55
Con respecto a los mensajes compuestos : tuve que hacer varias formas en plural una vez. Lo extendí String.Formatpara que pueda soportar esta sintaxis genial: "There {0:was|were} {0} {0:virus|viruses} found."cada idioma puede cargar sus propias reglas, por lo que podría hacerlo "Znaleziono {0} {0:wirusy|wirusów}." La fuente está en GitHub: github.com/scottrippey/SmartFormat/wiki
Scott Rippey
2
@Scott Rippey ¿Has notado que el ejemplo polaco dice "Znaleziono 4 wirusy. O Znaleziono 5 wirusów". <- El polaco, como muchos otros idiomas, tiene más de dos formas plurales y las reglas para distinguir entre ellas también pueden ser complejas. Aquí debo dejar el polaco ya que no lo hablo, pero en mi idioma, la forma plural para 101 cosas es la misma que para 1 cosa. Puede echar un vistazo a cómo GNU gettext aborda este problema: gnu.org/s/hello/manual/gettext/Plural-forms.html
gregopet
2
@gregopet Mi ejemplo en polaco fue inventado, porque no lo hablo, pero eso es exactamente lo que hace el proyecto SmartFormat. Aquí hay un ejemplo mejor: "{0} {0:plik|pliki|plików}". El formateador tiene una regla polaca que determina cuál de las 3 formas usar, y determina correctamente los casos especiales. Actualmente estoy trabajando para agregar más reglas, por lo que el gettextartículo será muy útil, gracias.
Scott Rippey
Para la pseudo-localización, construí una herramienta gratuita de pseudolocalización en línea en pseudolocalize.com
JerSchneid
74

Algunas cosas básicas que debes tener en cuenta:

Externalizar todos los recursos de cadena

Todos sus recursos deben estar contenidos en archivos externos que se pueden entregar para su localización. No se olvide de los mensajes de error, si también los quiere localizados.

Deje suficiente espacio para la expansión de la cuerda.

Las cadenas en algunos idiomas tienden a ser hasta un 30% más largas (como el griego), por ejemplo, así que asegúrese de diseñar su interfaz de usuario de tal manera que las cadenas se puedan expandir si es necesario. Aquí hay un ejemplo bastante extremo para el francés:

Ok -> Aceptador (francés - 400% de expansión)

Recomiendo hacer algún tipo de pseudo traducción como punto de partida ( http://en.wikipedia.org/wiki/Pseudolocalization ). O puede traducir sus recursos a través de Google Translate o Bing. Esto le dará una buena indicación de cómo serán las traducciones reales.

Cuidado con el texto en imágenes

Si usa alguna imagen en su aplicación, asegúrese de que no contenga ningún texto, esto obviamente no se puede traducir.

Nunca codifique ninguna ruta a las carpetas de Windows

Obvio, pero lo he visto en el pasado. Por ejemplo, C:\Program Filesse traduce en algunas versiones internacionales de Windows, por ejemplo, C:\Programmeen un sistema operativo alemán.

Evite usar términos específicos de la localidad

Por ejemplo, si le preguntas a alguien por su 'High School' en un formulario, esto tiene poco significado en Europa occidental.

Evite crear cadenas a través de la concatenación de cadenas

Por ejemplo, esto parece inofensivo:

strWelcome = ReadExternalString("Welcome"); 
strMessage = strWelcome + ", " + UserName;

Pero, el orden de las palabras en japonés, por ejemplo, sería diferente, por lo que esto podría no tener ningún sentido.

Configuraciones de hora / fecha

Asegúrese siempre de obtener el formato de hora / fecha del sistema operativo.

Jimmy Collins
fuente
@Jimmy C, ¿cómo haces para construir cadenas para una consistencia lógica independiente del lenguaje?
smartcaveman
14
@Smart hace algo en su recurso como "{0}, {1}" y luego, cuando lo localice, use string.format y pase el saludo y el nombre de usuario. Además, esto le brinda el beneficio de tener "La velocidad actual {0} es {1} {2}" y puede pasar "Motor", "50" y "MPH", y cuando traduce su oración, puede mover { 0} etc a donde tienen sentido en ese idioma
taylonr
44
Buena lista JimmyC. "Nunca codifique ninguna ruta a las carpetas de Windows" me recordó a "Usar siempre Path.Combine" en lugar de la concatenación de cadenas para las rutas de Windows.
@ Jimmy-C Gran respuesta!
1
Environment.GetFolderPath se puede usar para obtener rutas válidas a rutas comunes como Mis documentos sin depender del nombre en inglés de esas carpetas.
Crippledsmurf
24

Consideraciones especiales para lenguas asiáticas

Además de todas las excelentes respuestas que ya se encuentran aquí, algunos de los que están atentos a los idiomas asiáticos:

Cuidado con las diferentes longitudes de texto

El texto en chino y coreano tiende a ser mucho más corto que el texto equivalente en inglés (ya que generalmente necesita menos caracteres en bloque para escribir lo mismo), por lo que una página puede parecer vacía en chino pero atascada en alemán ... Debe hacerlo algunos tamaños dinámicos aquí para verse bien.

Sin embargo, el texto japonés suele ser mucho más largo, incluso más largo que el texto equivalente en inglés en términos de recuento de caracteres.

Tenga cuidado con el diseño de línea de base y el aspecto "deslizado hacia arriba"

Los caracteres asiáticos generalmente se presentan en la línea de base , que no incluyen descendientes (es decir, la parte inferior de y, g, q, j, etc.) cuando formatea un elemento de la pantalla, generalmente botones, con texto dentro, y si eso el texto es solo de idiomas asiáticos (es decir, no tiene alfabetos occidentales), entonces el texto se verá desplazado hacia arriba.

Formateo de números y unidades numéricas localizadas

Manejar el formato de número de manera diferente. Diferentes países asiáticos tienen diferentes formas de formatear números. Lo mismo con las monedas. Por ejemplo, en Asia Oriental, 10,000 (wan) es una unidad común. En India, 100,000 (lakhs) son comunes.

Monedas locales

Las monedas de algunos países tienen muchos ceros y ningún punto decimal (por ejemplo, Japón, Indonesia, Italia), mientras que otros tienen hasta dos dígitos después del punto decimal.

Cuidado con diferentes órdenes de palabras

El orden de las palabras puede no ser siempre el mismo. Lo mejor es utilizar {0}, {1} etc. en el formato de cadena en lugar de codificar el orden de las palabras si su cadena proviene de una combinación de diferentes datos.

Usar ordenación específica de la localidad

La clasificación es diferente según el idioma y la configuración regional: siempre debe confiar en la clasificación específica de la configuración regional de O / S.

Sea muy cauteloso con los caracteres de ancho completo / medio ancho

Tenga cuidado con las diferencias entre los caracteres de "ancho completo" y de "ancho medio". Los corchetes, los signos de puntuación, etc. pueden tener versiones de "ancho completo" que son diferentes de ASCII estándar. Si busca o divide cadenas en función de estas letras, primero deberá convertir todos los símbolos de ancho completo a equivalentes de medio ancho.

Un punto no es un punto ... una coma no es una coma ...

Tenga cuidado con la entrada de datos gotcha's - por ejemplo, en chino, un punto no es un punto ".". Una coma es de ancho completo, no ",". No intente buscar la puntuación occidental si el usuario que realiza la entrada de datos puede activar accidentalmente el IME en idioma asiático.

Números de teléfono

No asumas nada en el formato del número de teléfono. No siempre hay un código de área, etc., y se puede formatear de manera diferente. Por lo general, tiene una cadena de formato por país.

No asuma que las personas solo tendrán un número de teléfono móvil o un número de fax, etc. No es así en Asia.

Direcciones: más densas de lo que piensas

Para las direcciones, no asumas nada . Puede que no siempre haya un código postal. Los códigos postales pueden no ser siempre números. Un país puede no tener provincias / estados. Un país puede ser solo una gran ciudad (por ejemplo, Singapur). Para ciertos países asiáticos, la unidad más pequeña de una casa puede ser "Habitación X, Unidad Y, Sección Z, Piso A, Bloque B, Grupo C, Propiedad D". En general, sea muy liberal en la cantidad de campos y la cantidad de caracteres permitidos en las direcciones.

Saludos

Saludos no sólo se limitan a Sr., Sra etc. Aunque es probable que estés seguro en el uso de "M" y "F" para el sexo - no somos que todavía extraño ...


fuente
1
El último párrafo me hizo sonreír.
BoltClock
Oh, nosotros (chicos de i18n) ni siquiera comenzamos ... Solo pudimos arañar la superficie :) Si tuviéramos que hablar de problemas específicos como el soporte GB18030, nuestra publicación sería demasiado larga para que SO la maneje :) Gracias para su nota de todos modos, me perdí algunos artículos.
Paweł Dyda
Sobre el último, creo que el Reino Unido ahora acepta oficialmente "Otro" como sexo. Piensa en transgénero.
Bart Friederichs
11

Algunos pasos básicos son asegurarse de que cualquier cadena que se muestre en la pantalla no sea literal en su código. Si está haciendo Winforms, cada formulario tendrá un recurso de interfaz de usuario. Para cuadros de diálogo, informes, etc., asegúrese de utilizar los archivos de recursos del proyecto.

Entonces, en lugar de "Error de carga" en su código, es posible que tenga algo como Recursos.UploadFailed

De esta manera, puede crear un nuevo archivo de recursos para cada idioma que use (y .Net lo ayudará). Y tendrá la cadena localizada en cada archivo.

EDITAR Olvidé mencionar cuando estás haciendo tu interfaz de usuario, asegúrate de no solo meter cosas allí. Dependiendo de los idiomas a los que se esté localizando, los bienes raíces podrían ser un problema. Trabajé en un proyecto que tenía a los alemanes y portugueses como los 2 mayores delincuentes por el crecimiento de las cuerdas. Si no fuéramos cuidadosos, las cadenas que estaban bien en inglés, francés e italiano explotarían en alemán.

taylonr
fuente
1
Desde mi experiencia con L10n, el ruso es el peor de los casos. Sin embargo, en Winforms con el usuario adecuado de TableLayoutPanels, uno puede manejar el crecimiento de cadenas con gracia.
Paweł Dyda
Sí, mi experiencia se limitó a 7 idiomas: inglés, alemán, portugués, italiano, francés, español y japonés. Pero puedo ver que los rusos son malos, ya que tienden a tener muchos sufijos y prefijos
taylonr
9

Le sugiero que ejecute FXCop o Visual Studio Code Analysis (son bastante iguales) en sus ensamblajes.

Son buenos para detectar el código .NET que no utiliza las sobrecargas orientadas al cultivo adecuadas, como esta: CA1305: especifique IFormatProvider .

Debo agregar que estas herramientas también son frustrantes porque generalmente detectan millones de problemas en su código, pero aún así, incluso si no sigue cada regla, debe aprender mucho.

Simon Mourier
fuente
¿Es este el valor predeterminado o necesito especificar alguna configuración para buscar reglas específicas de globalización?
smartcaveman
@smartcaveman: es el valor predeterminado (hmm ... en realidad, algunas personas piensan que hay muchas reglas predeterminadas en estas herramientas :-)
Simon Mourier
7

Además de la forma específica de cargar recursos, me aseguraría de que pruebes con una versión pseudolocalizada para empezar. De lo contrario, no es probable que note los lugares donde se omitieron las consideraciones de internacionalización hasta el final.

Jeremy
fuente
Para una forma rápida y fácil de pseudolocalizar, construí una herramienta en línea gratuita en pseudolocalize.com
JerSchneid
6

Además de todos los otros consejos útiles, aquí hay algunos que faltan:

Tenga en cuenta que algunos países usan más de un idioma. Por ejemplo, en Canadá, un usuario esperaría poder cambiar fácilmente entre inglés y francés.

Si le hace una pregunta al usuario que espera una respuesta de una sola letra, no espere que el usuario presione la tecla 'Y' para decir Sí.

Tenga en cuenta en los procesos almacenados que las fechas en la base de datos SQL están en formato de EE. UU.

Colocar cadenas de texto en la base de datos le permite luego agregar idiomas adicionales sin tener que volver a implementarlos.

Cuando envíe archivos de texto escritos para traducción, siempre incluya una descripción del contexto para asegurarse de que el traductor seleccione la palabra correcta. Por ejemplo, sin contexto, podrías traducir "pitch:" en algo relacionado con el sonido o en un lugar en el que juegues fútbol

Las etiquetas de dirección siempre necesitan conversión. Provincia en Canadá, Estado en América, Condado en el Reino Unido

Brian Leeming
fuente
5

Necesitas considerar:

  1. Enrutamiento para multilenguaje

  2. Mover todas las cadenas de código duro al archivo de recursos

Un ejemplo para una propiedad:

Modelo:

[Display(Name = <Resource for display name>.<field for this property>)]
[Required(ErrorMessage = <Resource for error message>.<field for this validate message>)]
public string TestProperty { get; set; }

Ver:

@Html.LabelFor(m=>m.TestProperty)
@Html.EditorFor(m => m.TestProperty)
@Html.ValidationMessageFor(m => m.TestProperty)

fuente
5

Aquí hay algo que no se menciona en el resto de las respuestas.

Dependiendo de la complejidad de su aplicación y su localización, recomendaría implementar un proveedor de recursos alternativo y mantener los recursos localizados en una base de datos. Con el esquema de localización ASP.NET predeterminado, todos los recursos se guardan en archivos RESX, que:

  1. Son una molestia para editar en Visual Studio
  2. Limite la distribución y administración de recursos localizados después de que la aplicación se compila / envía / ejecuta.

Como posible caso de uso, considere proporcionar paquetes de idiomas para su aplicación y la capacidad de importar y exportar idiomas a través de la interfaz de usuario. Los archivos RESX no ayudarían aquí.

En escenarios como este, un proveedor de recursos alternativo es muy útil. Puede encontrar más información sobre cómo implementar uno aquí . Por supuesto, este es un caso raro más comúnmente visto en aplicaciones empresariales, pero aún válido.

Slavo
fuente
1
Gracias por tomarse el tiempo de revisar estas excelentes respuestas y seguir contribuyendo con algo nuevo y útil.
smartcaveman
+1; Creé una extensa aplicación web en Asp.NET y terminamos haciendo traducciones a través de la base de datos. A menudo se agregaban nuevas funciones, pero como nuestros traductores no eran expertos en la terminología particular utilizada, pudimos abordar rápidamente los correos electrónicos de clientes enojados del tipo "¿Por qué estás usando la palabra Y para X, que es simplemente incorrecto?".
gregopet
3

Lo más importante es administrar el contenido en varios idiomas. Yo mismo he desarrollado un par de sitios web y administrar el contenido en varios idiomas es el mayor desafío.

Estoy usando la base de datos para almacenar los recursos / contenido. Me da la flexibilidad de agregar cualquier soporte de idioma que desee. He implementado la lógica de recurrir al idioma inglés si no se encuentra un recurso en un idioma en particular.

Más tarde puede usar un traductor para convertir el valor en inglés a cualquier idioma.


fuente
2

Resumen de cosas a considerar en la internacionalización:

  • Toda la información debe ser internacionalizada. Tenga en cuenta que los gráficos pueden tener información que queremos internacionalizar.

  • El tamaño de los campos o cadenas, dependiendo del idioma porque puede causarnos un problema.

  • El orden de las palabras depende del idioma que seamos, por lo que un orden en un idioma será el mismo en otro.

  • Debemos tener en cuenta que el formato de fecha cambiará de un idioma a otro


fuente
1

Haz la prueba de Turquía :

La internacionalización del software es difícil en las mejores circunstancias , pero siempre me sorprendió la frecuencia con la que un país en particular surgió en discusiones sobre problemas de internacionalización: Turquía ...

Si le importa un poco la localización o la internacionalización, obligue a que su código se ejecute en la ubicación turca tan pronto como sea razonablemente posible . Es un fuerte referente para su código que se ejecuta en la mayoría, pero de ninguna manera en todas, las culturas y los entornos locales ...

Si su sitio / programa funciona bien con un cliente turco, puede estar seguro de que se ejecutará en la mayoría de las otras plataformas.

Carra
fuente