Estoy desarrollando un software multilenguaje. En cuanto al código de la aplicación, la localización no es un problema. Podemos usar recursos específicos del idioma y tener todo tipo de herramientas que funcionen bien con ellos.
Pero, ¿cuál es el mejor enfoque para definir un esquema de base de datos multilenguaje? Digamos que tenemos muchas tablas (100 o más), y cada tabla puede tener múltiples columnas que se pueden localizar (la mayoría de las columnas nvarchar deben ser localizables). Por ejemplo, una de las tablas puede contener información del producto:
CREATE TABLE T_PRODUCT (
NAME NVARCHAR(50),
DESCRIPTION NTEXT,
PRICE NUMBER(18, 2)
)
Se me ocurren tres enfoques para admitir texto multilingüe en las columnas NOMBRE y DESCRIPCIÓN:
Columna separada para cada idioma
Cuando agregamos un nuevo idioma al sistema, debemos crear columnas adicionales para almacenar el texto traducido, así:
CREATE TABLE T_PRODUCT ( NAME_EN NVARCHAR(50), NAME_DE NVARCHAR(50), NAME_SP NVARCHAR(50), DESCRIPTION_EN NTEXT, DESCRIPTION_DE NTEXT, DESCRIPTION_SP NTEXT, PRICE NUMBER(18,2) )
Tabla de traducción con columnas para cada idioma.
En lugar de almacenar texto traducido, solo se almacena una clave foránea para la tabla de traducciones. La tabla de traducciones contiene una columna para cada idioma.
CREATE TABLE T_PRODUCT ( NAME_FK int, DESCRIPTION_FK int, PRICE NUMBER(18, 2) ) CREATE TABLE T_TRANSLATION ( TRANSLATION_ID, TEXT_EN NTEXT, TEXT_DE NTEXT, TEXT_SP NTEXT )
Tablas de traducción con filas para cada idioma.
En lugar de almacenar texto traducido, solo se almacena una clave foránea para la tabla de traducciones. La tabla de traducciones contiene solo una clave, y una tabla separada contiene una fila para cada traducción a un idioma.
CREATE TABLE T_PRODUCT ( NAME_FK int, DESCRIPTION_FK int, PRICE NUMBER(18, 2) ) CREATE TABLE T_TRANSLATION ( TRANSLATION_ID ) CREATE TABLE T_TRANSLATION_ENTRY ( TRANSLATION_FK, LANGUAGE_FK, TRANSLATED_TEXT NTEXT ) CREATE TABLE T_TRANSLATION_LANGUAGE ( LANGUAGE_ID, LANGUAGE_CODE CHAR(2) )
Hay ventajas y desventajas de cada solución, y me gustaría saber cuáles son sus experiencias con estos enfoques, qué recomienda y cómo haría para diseñar un esquema de base de datos en varios idiomas.
LANGUAGE_CODE
Son claves naturales, evitarLANGUAGE_ID
.Respuestas:
¿Qué opinas sobre tener una tabla de traducción relacionada para cada tabla traducible?
De esta manera, si tiene varias columnas traducibles, solo necesitaría una sola combinación para obtenerlo, ya que no está generando automáticamente un ID de traducción, puede ser más fácil importar elementos junto con sus traducciones relacionadas.
El lado negativo de esto es que si tiene un mecanismo de recuperación de idioma complejo, es posible que deba implementarlo para cada tabla de traducción, si confía en algún procedimiento almacenado para hacerlo. Si haces eso desde la aplicación, probablemente esto no sea un problema.
Déjame saber lo que piensas: también estoy a punto de tomar una decisión sobre esto para nuestra próxima aplicación. Hasta ahora hemos usado su 3er tipo.
fuente
T_PRODUCT
tiene 1 millón de filas,T_PRODUCT_tr
tendría 2 millones. ¿Reduciría mucho la eficiencia de sql?Este es un tema interesante, así que vamos a la nigromancia.
Comencemos por los problemas del método 1:
Problema: está desnormalizando para ahorrar velocidad.
En SQL (excepto PostGreSQL con hstore), no puede pasar un lenguaje de parámetros y decir:
Entonces tienes que hacer esto:
Lo que significa que debe modificar TODAS sus consultas si agrega un nuevo idioma. Naturalmente, esto lleva a usar "SQL dinámico", por lo que no tiene que alterar todas sus consultas.
Esto generalmente resulta en algo como esto (y no se puede usar en vistas o funciones con valores de tabla por cierto, lo que realmente es un problema si realmente necesita filtrar la fecha del informe)
El problema con esto es
a) El formato de fecha es muy específico del idioma, por lo que tiene un problema allí, si no ingresa en formato ISO (que el programador promedio de variedades de jardín generalmente no hace, y en caso de un informe que el usuario seguramente no hará por usted, incluso si se le indica explícitamente que lo haga).
y
b) lo más importante , se pierde cualquier tipo de comprobación de sintaxis . Si
<insert name of your "favourite" person here>
altera el esquema porque de repente los requisitos para el cambio de alas, y se crea una nueva tabla, la anterior se fue pero se renombró el campo de referencia, no recibe ningún tipo de advertencia. Un informe incluso funciona cuando lo ejecuta sin seleccionar el parámetro de ala (==> guid.empty). Pero de repente, cuando un usuario real realmente selecciona un ala ==>auge . Este método infringe completamente cualquier tipo de prueba.Método 2:
En pocas palabras: "Gran" idea (advertencia - sarcasmo), combinemos las desventajas del método 3 (velocidad lenta cuando hay muchas entradas) con las desventajas bastante horribles del método 1.
La única ventaja de este método es que usted mantiene todas las traducciones en una tabla y, por lo tanto, simplifican el mantenimiento Sin embargo, se puede lograr lo mismo con el método 1 y un procedimiento almacenado dinámico de SQL, y una tabla (posiblemente temporal) que contiene las traducciones, y el nombre de la tabla de destino (y es bastante simple asumiendo que usted nombró todos sus campos de texto) mismo).
Método 3:
una tabla para todas las traducciones: Desventaja: debe almacenar n claves foráneas en la tabla de productos para n campos que desea traducir. Por lo tanto, debe hacer n combinaciones para n campos. Cuando la tabla de traducción es global, tiene muchas entradas y las uniones se vuelven lentas. Además, siempre debe unirse a la tabla T_TRANSLATION n veces para n campos. Esto es un gran gasto. Ahora, ¿qué haces cuando debes acomodar traducciones personalizadas por cliente? Tendrá que agregar otras 2x n combinaciones en una tabla adicional. Si tiene que unirse, digamos 10 tablas, con 2x2xn = 4n combinaciones adicionales, ¡qué desastre! Además, este diseño permite utilizar la misma traducción con 2 tablas. Si cambio el nombre del elemento en una tabla, ¿realmente quiero cambiar también una entrada en otra tabla CADA VEZ?
Además, ya no puede eliminar y volver a insertar la tabla, porque ahora hay claves foráneas EN LA (S) TABLA (S) DEL PRODUCTO ... por supuesto, puede omitir la configuración de los FK y luego
<insert name of your "favourite" person here>
puede eliminar la tabla y volver a insertarla todas las entradas con newid () [o especificando la identificación en la inserción, pero con la inserción de identidad desactivada ], y eso (y conducirá) a basura de datos (y excepciones de referencia nula) muy pronto.Método 4 (no listado): Almacenar todos los idiomas en un campo XML en la base de datos. p.ej
Luego puede obtener el valor mediante XPath-Query en SQL, donde puede colocar la variable de cadena en
Y puede actualizar el valor de esta manera:
Donde puedes reemplazar
/lang/de/...
con'.../' + @in_language + '/...'
Al igual que el hstore de PostGre, excepto que debido a la sobrecarga de analizar XML (en lugar de leer una entrada de una matriz asociativa en PG hstore) se vuelve demasiado lento y la codificación xml hace que sea demasiado doloroso ser útil.
Método 5 (según lo recomendado por SunWuKung, el que debe elegir): una tabla de traducción para cada tabla de "Producto". Eso significa una fila por idioma y varios campos de "texto", por lo que solo se requiere UNA (izquierda) para unirse en N campos. Luego puede agregar fácilmente un campo predeterminado en la tabla "Producto", puede eliminar y volver a insertar fácilmente la tabla de traducción, y puede crear una segunda tabla para traducciones personalizadas (bajo demanda), que también puede eliminar y vuelva a insertar), y todavía tiene todas las claves foráneas.
Hagamos un ejemplo para ver esto FUNCIONA:
Primero, crea las tablas:
Luego complete los datos
Y luego consulta los datos:
Si eres perezoso, entonces también puedes usar el ISO-TwoLetterName ('DE', 'EN', etc.) como clave principal de la tabla de idiomas, entonces no tienes que buscar la identificación del idioma. Pero si lo hace, tal vez desee usar la etiqueta de idioma IETF , lo cual es mejor, porque obtiene de-CH y de-DE, que en realidad no es lo mismo en cuanto a ortografía (doble s en lugar de ß en todas partes) , aunque es el mismo lenguaje base. Es solo un pequeño detalle que puede ser importante para usted, especialmente teniendo en cuenta que en-US y en-GB / en-CA / en-AU o fr-FR / fr-CA tiene problemas similares.
Cita: no lo necesitamos, solo hacemos nuestro software en inglés.
Respuesta: Sí, pero ¿cuál?
De todos modos, si usa una ID de entero, es flexible y puede cambiar su método en cualquier momento posterior.
Y debe usar ese número entero, porque no hay nada más molesto, destructivo y problemático que un diseño Db fallido.
Ver también RFC 5646 , ISO 639-2 ,
Y, si todavía dice "nosotros" solo hacemos nuestra solicitud para "solo una cultura" (como en EE. UU. Por lo general), por lo tanto, no necesito ese número entero adicional, este sería un buen momento y lugar para mencionar el Etiquetas de idioma IANA , ¿no?
Porque van así:
y
(hubo una reforma ortográfica en 1996 ...) Intente encontrar una palabra en un diccionario si está mal escrita; Esto se vuelve muy importante en aplicaciones que tratan con portales legales y de servicio público.
Más importante aún, hay regiones que están cambiando de alfabetos cirílicos a latinos, lo que puede ser más problemático que la molestia superficial de alguna reforma de ortografía oscura, por lo que esto podría ser una consideración importante también, dependiendo del país en el que viva. De una forma u otra, es mejor tener ese número entero allí, por si acaso ...
Editar:
y agregando
ON DELETE CASCADE
despuéssimplemente puede decir:
DELETE FROM T_Products
y no obtener ninguna violación de clave externa.En cuanto a la recopilación, lo haría así:
A) Tenga su propio DAL
B) Guarde el nombre de intercalación deseado en la tabla de idiomas
Es posible que desee colocar las intercalaciones en su propia tabla, por ejemplo:
C) Tenga el nombre de intercalación disponible en su información de idioma de usuario.
D) Escribe tu SQL así:
E) Entonces, puedes hacer esto en tu DAL:
Lo que luego le dará esta consulta SQL perfectamente compuesta
fuente
La tercera opción es la mejor, por algunas razones:
-Adán
fuente
Echa un vistazo a este ejemplo:
Creo que no hay necesidad de explicar, la estructura se describe a sí misma.
fuente
Por lo general, optaría por este enfoque (no sql real), esto corresponde con su última opción.
Porque tener todos los textos traducibles en un solo lugar hace que el mantenimiento sea mucho más fácil. A veces, las traducciones se subcontratan a oficinas de traducción, de esta manera puede enviarles un solo gran archivo de exportación e importarlo de nuevo con la misma facilidad.
fuente
Translation
tabla o laTranslationItem.translationitemid
columna?Antes de ir a detalles técnicos y soluciones, debe detenerse por un minuto y hacer algunas preguntas sobre los requisitos. Las respuestas pueden tener un gran impacto en la solución técnica. Ejemplos de tales preguntas serían:
- ¿Se usarán todos los idiomas todo el tiempo?
- ¿Quién y cuándo llenará las columnas con las diferentes versiones de idioma?
- ¿Qué sucede cuando un usuario necesitará cierto idioma de un texto y no hay ninguno en el sistema?
- Solo se deben localizar los textos o también hay otros elementos (por ejemplo, el PRECIO se puede almacenar en $ y € porque pueden ser diferentes)
fuente
Estaba buscando algunos consejos para la localización y encontré este tema. Me preguntaba por qué se usa esto:
Entonces obtienes algo como user39603 sugiere:
¿No puedes dejar la tabla? Traducción para que obtengas esto:
fuente
ProductItem
mesa algo asíProductTexts
o algo asíProductL10n
. Tiene más sentido.Estoy de acuerdo con randomizer. No veo por qué necesitas una tabla de "traducción".
Creo que esto es suficiente:
fuente
¿Sería viable el siguiente enfoque? Supongamos que tiene tablas en las que se necesita traducir más de 1 columna. Entonces, para el producto, podría tener tanto el nombre del producto como la descripción del producto que necesitan traducción. ¿Podría hacer lo siguiente?
fuente
"Cuál es el mejor" se basa en la situación del proyecto. El primero es fácil de seleccionar y mantener, y también el rendimiento es mejor ya que no es necesario unir las tablas cuando se selecciona la entidad. Si confirmó que su proyecto solo admite 2 o 3 idiomas y no aumentará, puede usarlo.
El segundo es okey pero es difícil de entender y mantener. Y el rendimiento es peor que el primero.
El último es bueno en escalabilidad pero malo en rendimiento. La tabla T_TRANSLATION_ENTRY se volverá más y más grande, es terrible cuando desea recuperar una lista de entidades de algunas tablas.
fuente
Este documento describe las posibles soluciones y las ventajas y desventajas de cada método. Prefiero la "localización de filas" porque no tiene que modificar el esquema de base de datos al agregar un nuevo idioma.
fuente