vue react rails i18n localization internationalization

localization - rails - i18n react



¿Cómo internacionalizas el texto en la base de datos? (7)

¿Qué solución alternativa puede evitar que los usuarios reciban texto en un idioma que no entienden?

Eso solo sería un problema para los datos ingresados ​​por el usuario. Por lo tanto, si desea evitar que otros usuarios vean contenido en un idioma que quizás no entiendan, almacene el código de configuración regional junto con el contenido y solo muestre ese contenido a cualquier persona que tenga el mismo idioma elegido por el lugar / usuario.

Por otro lado, los usuarios pueden conocer varios idiomas, por lo que no los restringiría de ver contenido, solo agregaría un aviso como "Este contenido no está disponible en el idioma de su elección, ..." y luego mostrar el contenido en el langauge disponible. De esta forma aumenta la probabilidad de que el usuario obtenga un contenido que pueda entender.

Tener una aplicación totalmente internacionalizada es una necesidad si quieres vender en todo el mundo. En Java, estamos utilizando paquetes de recursos y eso resuelve las cosas para el código de barras de texto estático.

Pero, ¿qué haces con el texto que está almacenado en la base de datos? Comenzando con las definiciones estáticas, los objetos modificables por el usuario y finalizando con los datos ingresados ​​por el usuario.

Suponiendo que tiene una base de datos utilizada por usuarios con configuraciones regionales diferentes, ¿cómo maneja esto? ¿Qué tan lejos se internacionaliza? ¿Dónde se traza la línea? ¿Qué solución alternativa puede evitar que los usuarios reciban texto en un idioma que no entienden?


En primer lugar, sé muy consciente de las limitaciones. Para el contenido creado por el usuario, está buscando traducción comunitaria (errática), traducción automática (no confiable) o pagar traductores humanos (¡caros!) Si desea localizar cosas que los usuarios ingresan en su aplicación. Es posible que desee solicitar a sus usuarios que proporcionen dos versiones, una para su cultura predeterminada (¿inglés?) Y otra para su cultura localizada, para que pueda proporcionar una traducción alternativa para otros usuarios.

En segundo lugar, prepárese para migraciones de bases de datos extremadamente largas ... si tiene cuatro columnas de texto en una hoja de cálculo de Excel, de repente se trata de insertar cada valor en su sistema de traducción, recuperar el ID localizado y luego almacenarlo en la tabla que realmente está importando, y SELECT * solo le dará identificadores de frase, que debe volver a convertir en cadenas localizándolos en sus tablas de traducción.

Dicho eso, puede localizar muchas de las tablas de búsqueda, listas desplegables, etc. que maneja la base de datos en un proyecto típico. Otros comentarios ya han mencionado el almacenamiento de valores de StringId en la base de datos que hacen referencia a archivos de recursos externos u hojas de cálculo, pero si está interesado en mantener TODO su texto localizado en la base de datos junto con los datos, tal vez le resulte útil este enfoque.

Hemos utilizado una tabla llamada Frase, que contiene la ID y el contenido predeterminado (en inglés) para cada fragmento de texto en su aplicación.

Sus otras mesas terminan pareciéndose a esto:

CREATE TABLE ProductType ( Id int primary key, NamePhraseId int, -- link to the Phrase containing the name of this product type. DescriptionPhraseId int )

Crea una segunda tabla Cultura, que contiene las culturas específicas y neutrales que estás apoyando. Para obtener puntos de bonificación, implemente esta tabla como un árbol autorreferencial (cada registro de Cultura contiene una referencia de NullCripCultureCode), de modo que puede retroceder de culturas específicas ("fr-CA" para el francés canadiense) a culturas neutrales ("fr" si no existe una localización regional), a su cultura invariante / predeterminada (normalmente ''en'' porque se habla tan ampliamente)

Sus traducciones reales están en una tabla LocalizedPhrase, que se ve así:

CREATE TABLE LocalizedPhrase ( PhraseId int primary key, CultureCode varchar(8) primary key, Content nvarchar(255) -- the actual localized content )

Puede ampliar este modelo si desea proporcionar localizaciones específicas para hombres y mujeres:

CREATE TABLE GenderedLocalizedPhrase ( PhraseId int primary key, CultureCode varchar(8) primary key, GenderCode char(1) primary key, -- ''m'', ''f'' or ''?'' - links to Gender table Content nvarchar(255) )

Querrá guardar en caché todo el gráfico de la tabla en la memoria y modificar sus estrategias de consulta / unión en consecuencia: almacenar en memoria caché las localizaciones dentro de las clases de Frases y reemplazar el método ToString () en el objeto Frase para inspeccionar la cultura del hilo actual es un enfoque. Si intenta hacer estas cosas dentro de sus consultas, incurrirá en un costo de rendimiento sustancial y cada consulta terminará luciendo así:

-- assume @MyCulture contains the culture code (''ca-FR'') that we are looking for: SELECT Product.Id, Product.Name, COALESCE(ProductStatusLocalizedPhrase.Content, ProductStatusPhrase.Content) as ProductStatus, COALESCE(ProductTypeLocalizedPhrase.Content, ProductTypePhrase.Content) as ProductType, FROM Product INNER JOIN ProductStatus ON Product.StatusId = ProductStatus.Id INNER JOIN Phrase as ProductStatusPhrase ON ProductStatus.NamePhraseId = Phrase.Id LEFT JOIN LocalizedPhrase as ProductStatusLocalizedPhrase ON ProductStatus.NamePhraseId = ProductStatusLocalizedPhrase.Id and CultureCode = @MyCulture INNER JOIN ProductType ON Product.TypeId = ProductType.Id INNER JOIN Phrase as ProductTypePhrase ON ProductType.NamePhraseId = Phrase.Id LEFT JOIN LocalizedPhrase as ProductTypeLocalizedPhrase ON ProductType.NamePhraseId = ProductTypeLocalizedPhrase.Id and CultureCode = @MyCulture


Los datos estáticos son los más sencillos que crearía una tabla de traducción, así que imagine una tabla UserStatus que tenga un StatusId, TranslationToken, luego la TranslationTable tiene un token, un idioma y un texto.

O similar, simplemente podría devolver el token para que la aplicación lo procese utilizando sus archivos de recursos.

En cuanto a los datos de entrada del usuario, esto es mucho más complejo. Debe aceptar caracteres Unicode como mínimo, pero luego la pregunta se convierte en Ordenar y Comparar. La clasificación es la más grande. Mucho de lo que puede hacer depende de su aplicación. Por lo tanto, si su base de datos solo debe admitir un idioma en cualquier momento (imagine si su aplicación se distribuyó a sus clientes), la intercalación es un punto discutible ya que puede configurarlo en el momento de la instalación.

Sin embargo, si tiene que admitir varios idiomas dentro de una única base de datos, deberá manejar la intercalación correctamente. La única forma en que encontramos para cambiar la intercalación sobre la marcha fue establecerla dentro de nuestras consultas, y eso requería que se generase sql dinámico. Este ejemplo sería que está almacenando ruso, inglés y polaco, todo en un solo campo en la misma tabla.

Nunca exploramos nada más allá de las colaciones latinas y cirílicas, pero imagino que los idiomas asiáticos funcionarían de la misma manera.


No almacene texto generado por el sistema en la base de datos. En su lugar, almacene un código (como un número de mensaje) y luego internacionalícelo en el nivel de la GUI. Asegúrese de que el único texto que sale directamente de la base de datos es el texto que el usuario coloca en sí mismo. Asegúrese de que su base de datos esté configurada para aceptar texto unicode.


Usamos archivos XML para nuestro sistema. El archivo contiene asociaciones de teclas con partes específicas de nuestros módulos. De esta forma, podemos hacer XPath rápidamente para recuperar información. Tenemos 1 archivo para cada idioma (admitimos 2 idiomas por el momento, pero agregar un idioma es muy simple, simplemente copie y pegue el archivo). Esta solución no es perfecta, pero tiene algunas ventajas:

  1. No en la base de datos.
  2. Puede ser editado por alguien externo a la programación.
  3. Fácil de implementar en múltiples vistas (tenemos WinForm y WebForm).

Cambiamos gran parte del texto en nuestra base de datos para que sea "clave: texto predeterminado" y luego buscamos la "clave" en nuestros archivos de traducción. Esto cubre todo el texto que el cliente no cambia en la base de datos (por ejemplo, qué llamar una "nota de crédito"). Cuando el cliente cambia el texto, simplemente puede quitar la clave, de modo que siempre obtenga el valor.

Nuestro sistema tiene algunas tablas que contienen datos de configuración que necesitan lo anterior, las tablas que solo contienen texto que los clientes ingresaron no son un problema si cada cliente solo necesita un idioma.


Digamos que tienes una mesa:

create table countries ( country_id int primary key, short_name text not null unique, official_name text not null unique, iso_code char(2) not null unique ); insert into countries values (12, ''Algeria'', ''The People''''s Democratic Republic of Algeria'' ''DZ'');

Luego creas una tabla de traducción:

create table countries_t ( country_id int not null references countries(country_id), short_name text not null, official_name text not null, locale varchar(5) not null, primary key (country_id, locale) ); insert into countries_t values (12, ''Algérie'', ''la République algérienne démocratique et populaire'', ''fr''), (12, ''Algerien'', ''Demokratische Volksrepublik Algerien'', ''de-DE'');

Cree una vista para devolver los datos en función de una variable de sesión definida por el usuario . A continuación es específico de PostgreSQL, pero su base de datos puede admitir variables de sesión personalizadas, de lo contrario, utilice la tabla temporal:

create view countries_i18n as select a.country_id, coalesce(c.short_name, b.short_name, a.short_name) as short_name, --default to countries.name if translation not found coalesce(c.official_name, b.official_name, a.official_name) as official_name countries.iso_code from countries a left join countries_t b on b.id = a.id and b.locale = current_setting(''my_custom_guc.locale'') left join countries_t c on c.id = a.id and c.locale = left(current_setting(''my_custom_guc.locale''), 2); --fall-back to 2-letter locale

Consulta la tabla en alemán como se habla en Alemania:

SET my_custom_guc.language_code = ''de-DE''; select country_id, iso_code, short_name, official_name from countries_i18n; country_id iso_code short_name official_name ----------------------------------------------- 12 DZ Algerien Demokratische ...

Consulta la tabla en francés canadiense (vuelve al francés genérico):

SET my_custom_guc.locale= ''fr-CA''; select country_id, iso_code, short_name, official_name from countries_i18n; country_id iso_code short_name official_name ----------------------------------------------- 12 DZ Algérie la République ...

Consulta la tabla en español (no hay traducción, devuelve inglés):

SET my_custom_guc.language_code = ''es''; select country_id, iso_code, short_name, official_name from countries_i18n; country_id iso_code short_name official_name ----------------------------------------------- 12 DZ Algeria The People''s D ...