2011-06-23 40 views
8

Me ha dado la (bastante desalentadora) tarea de presentar i18n en una aplicación web J2EE utilizando la especificación 2.3 servlet. La aplicación es muy grande y ha estado en desarrollo activo durante más de 8 años.Aplicación web Java i18n

Como tal, quiero hacer las cosas bien la primera vez para poder limitar la cantidad de tiempo que necesito garabatear a través de JSP, JavaScript, servlets y cualquier otro lugar, reemplazando cadenas codificadas con valores de paquetes de mensajes.

No se utiliza ningún marco aquí. ¿Cómo puedo abordar el apoyo a i18n? Tenga en cuenta que quiero tener un único JSP por vista que cargue texto de (a) archivo (s) de propiedades y no un JSP diferente para cada configuración regional admitida.

Supongo que mi pregunta principal es si puedo configurar la ubicación en algún lugar del backend (es decir, leer la configuración regional del perfil de usuario al iniciar sesión y almacenar el valor en la sesión) y luego esperar que las páginas JSP puedan cargar correctamente la cadena especificada del archivo de propiedades correcto (es decir, de messages_fr.properties cuando la configuración regional es en francés) en lugar de agregar lógica para encontrar la configuración regional correcta en cada JSP.

¿Alguna idea de cómo puedo abordar esto?

+0

posible duplicado de [Cómo internacionalizar una aplicación web java.] (Http://stackoverflow.com/questions/4276061/how-to-internationalize-a-java-web-application) – BalusC

Respuesta

18

Hay muchas cosas que necesitan ser atendidos, mientras la internacionalización de aplicación:

detección Locale

La primera cosa que hay que pensar es detectar la configuración regional del usuario final. Dependiendo de lo que quiera apoyar, puede ser fácil o un poco complicado.

  1. Como seguramente sabe, los navegadores web tienden a enviar el idioma preferido del usuario final a través del encabezado HTTP Accept-Language. El acceso a esta información en el servlet puede ser tan simple como llamar al request.getLocale().Si no está planeando admitir ningún elegante Locale Detection workflow, puede seguir este método.
  2. Si tiene perfiles de usuario en su aplicación, es posible que desee agregar el idioma preferido y la configuración regional de formato preferido. En tal caso, deberá cambiar la configuración regional después de que el usuario inicie sesión.
  3. Es posible que desee admitir el cambio de idioma basado en URL (por ejemplo: http://deutsch.example.com/ o http://example.com?lang=de). Debería establecer una configuración regional válida en función de la información de URL, esto podría hacerse de varias maneras (es decir, filtro de URL).
  4. Es posible que desee admitir el cambio de idioma (seleccionándolo del menú desplegable, o algo así), sin embargo, no lo recomendaría (a menos que se combine con el punto 3).

JSTL enfoque podría ser suficiente si lo que desea es apoyar primer método o si usted no está planeando añadir las dependencias adicionales (como Spring Framework).

Mientras estamos en Spring Framework tiene bastantes características agradables que se pueden utilizar tanto para detectar Locale (como CookieLocaleResolver, AcceptHeaderLocaleResolver, SessionLocaleResolver y LocaleChangeInterceptor) y cadenas de externalización y los mensajes de formato (ver spring:message tab).
Spring Framework le permitiría implementar fácilmente todos los escenarios anteriores y es por eso que lo prefiero.

cadena externalización

Esto es algo que debería ser fácil, ¿verdad? Bueno, principalmente lo es, solo usa la etiqueta adecuada. El único problema que puede enfrentar es cuando se trata de externalizar textos del lado del cliente (JavaScript). Hay varios enfoques posibles, pero permítanme mencionar estos dos:

  1. Haga que cada JSP escriba un conjunto de cadenas traducidas (con etiqueta de mensaje) y simplemente acceda a esa matriz en el código del cliente. Este es un enfoque más fácil, pero menos sostenible: sería necesario escribir cadenas válidas a partir de páginas válidas (las que realmente hacen referencia a las secuencias de comandos del lado del cliente). Lo he hecho antes y créeme, esto no es algo que quieras hacer en una aplicación grande (pero probablemente sea la mejor solución para una pequeña).
  2. Otro enfoque puede sonar duro en principio, pero en realidad es mucho más fácil de manejar en el futuro. La idea es centralizar cadenas en el lado del cliente (moverlas a un archivo JavaScript común). Después de eso, necesitarás implementar tu propio Servlet que devolverá este script a petición, los contenidos deben ser traducidos. No podrá usar JSTL aquí, necesitaría obtener cadenas directamente de los paquetes de recursos.
    Es mucho más fácil de mantener, porque tendría un punto central para agregar cadenas traducibles.

Concatenaciones

me gusta decir eso, pero concatenaciones son muy doloroso desde la perspectiva localizabilidad. Son muy comunes y la mayoría de las personas no se dan cuenta.

Entonces, ¿qué es la concatenación?

Por principio, cada oración en inglés debe traducirse al idioma de destino.El problema es que muchas veces el mensaje correctamente traducido utiliza un orden de palabras diferente al de su equivalente en inglés (por lo que la "política de seguridad" en inglés se traduce al polaco "Polityka bezpieczeństwa" - "policy" es "polityka" - el orden es diferente).

Bien, pero ¿cómo se relaciona con el software?

En aplicación web que podría concatenar cadenas como esto:

String securityPolicy = "Security " + "policy"; 

o como esto:

<p><span style="font-weight:bold">Security</span> policy</p> 

Ambos serían problemáticos. En el primer caso necesitaría usar el método MessageFormat.format() y externalizar cadenas como (por ejemplo) "Security {0}" y "policy", en este último se externalizaría el contenido de todo el párrafo (etiqueta p), incluyendo la etiqueta span. Sé que esto es doloroso para los traductores, pero en realidad no hay una mejor manera.
A veces tienes que usar contenido dinámico en tu párrafo: la etiqueta JSTL fmt: format también te ayudará aquí (funciona lima MessageFormat en el lado del backend).

Presentaciones

En aplicación localizada, a menudo sucede que las cadenas traducidas son mucho más largos que los ingleses. El resultado puede parecer muy feo. De alguna manera, necesitarías arreglar estilos. Hay de nuevo dos enfoques:

  1. Corrija los problemas tal como suceden mediante el ajuste de estilos comunes (y ore para que no rompa otros idiomas). Esto es muy doloroso de mantener.
  2. Implementar Mecanismo de localización de CSS. El mecanismo del que estoy hablando debería servir para el archivo CSS predeterminado independiente del idioma y las anulaciones por idioma. La idea es anular el archivo CSS para cada idioma, de modo que pueda ajustar los diseños a pedido (solo para un idioma). Para hacer eso, el archivo CSS predeterminado, así como las páginas JSP no deben contener la palabra clave !important junto a las definiciones de estilo. Si realmente tiene que usarlo, muévalo a en.css basado en el lenguaje; esto permitiría que otros lenguajes los modifiquen.

Cultura temas específicos

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

Fechas y zonas horarias

Manejo de fechas en los tiempos en Java es por decir lo menos no es fácil. Si no va a admitir nada más que el calendario gregoriano, podría apegarse a las clases incorporadas de fecha y calendario. Puede usar JSTL fmt: timeZone, fmt: formatDate y fmt: parseDate para establecer correctamente la zona horaria, formatear y analizar la fecha en JSP.

me sugieren fuertemente utilizar fmt: formatDate así:

<fmt:formatDate value="${someController.somedate}" 
    timeZone="${someController.detectedTimeZone}" 
    dateStyle="default" 
    timeStyle="default" /> 

Es importante fecha y hora encubierta a la zona horaria válida (de usuario final). También es muy importante convertirlo a un formato fácil de entender, es por eso que recomiendo el estilo de formato predeterminado.
BTW. La detección de zona horaria no es algo fácil, ya que los navegadores web no son tan buenos para enviar nada. En su lugar, puede agregar campo de zona horaria de preferencia a las preferencias del usuario (si lo tiene) o conseguir actual desplazamiento de zona horaria desde el navegador web a través de script del lado del cliente (ver Date object's methods)

Los números y las monedas

Números así como las monedas deben convertirse a formato local. Se lleva a cabo de forma similar a formatear fechas (análisis también se realiza de manera similar):

<fmt:formatNumber value="1.21" type="currency"/> 

mensajes compuestos

Ya se les ha advertido que no concatenar cadenas. En cambio, probablemente usaría MessgageFormat. Sin embargo, debo decir que debe minimizar el uso de mensajes compuestos. Esto se debe a que 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 MessageFormat.format()), sino que traducen la oración completa de forma diferente en función de lo que se sustituirá . Te voy a dar 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ę. 

Codificación de caracteres

Si usted está planeando para localizar a los idiomas que no soportan la norma ISO 8859-1 página de códigos, lo que tendría que ser compatible con Unicode - el mejor forma es establecer la codificación de la página a UTF-8. He visto gente que lo hace así:

<%@ page contentType="text/html; charset=UTF-8" %> 

debo advertirle: esto es no lo suficientemente . Que realmente necesita esta declaración:

<%@page pageEncoding="UTF-8" %> 

Además, seguiría siendo necesario para declarar la codificación en el encabezado de la página, sólo para estar en el lado seguro:

<META http-equiv="Content-Type" content="text/html;charset=UTF-8"> 

La lista que te di no es exhaustiva pero este es un buen punto de partida. Buena suerte :)

+0

Gracias por la excelente respuesta. Lamentablemente, la aplicación que estoy usando es mamut (es un proyecto muy antiguo). Spring se introdujo en algún momento del proyecto (que es ~ 10 años iirc) y estoy usando el soporte i18n de Spring en parte de la aplicación haciendo uso de cadenas. Desafortunadamente, no parece que alguien realmente haya pensado en i18n, así que parece que estoy atascado en una tarea bastante larga y tediosa ... – NRaf

1

Puede hacer exactamente esto usando la biblioteca de etiquetas estándar JSTL con la etiqueta. Tome una copia de la especificación JSTL, lea los capítulos i8N, que analizan texto general + fecha, hora y moneda. Muy claramente escrito y le muestra cómo puede hacerlo todo con las etiquetas. También puede configurar cosas como Configuración regional

1

No necesita (y no debe) tener un archivo JSP separado por ubicación. La tarea difícil es descubrir las claves que no son i18n-ed y moverlas a un archivo por configuración regional, por ejemplo, messages_en.properties, messages_fr.properties, etc.

El cálculo de la configuración regional puede realizarse en varios lugares según su lógica. Admitimos entornos locales de usuario almacenados en una base de datos, así como la configuración regional del navegador. Cada solicitud que ingrese a su aplicación tendrá un encabezado "Accept-Language" que indica cuáles son los idiomas con los que se configuró su navegador, con preferencias, es decir, primero japonés y luego inglés. Si ese es el caso, la aplicación debe leer los messages_ja.properties y para las claves que no están en ese archivo, recurrir a messages_en.properties. Lo mismo puede ser cierto para las configuraciones regionales del usuario que están almacenadas dentro de la base de datos. Tenga en cuenta que el estándar es solo cambiar el idioma en el navegador y esperar que el contenido se publique. (Inicialmente comenzamos con el almacenamiento de la configuración regional en la base de datos y luego pasamos a las configuraciones regionales compatibles desde el navegador). También necesitará un valor predeterminado de todos modos ya que los traductores pierden la copia de claves y valores del inglés (archivo de idioma principal) a otros idiomas, por lo que tendrá que usar inglés para valores que no están en otros archivos.

También encontré mygengo muy útil al dar trabajo de traducción a otras personas que conocen un idioma en particular, nos ha ahorrado mucho tiempo.

Cuestiones relacionadas