Pregunta

Digamos que tengo el siguiente modelo de Django:

class StandardLabel(models.Model):
    id = models.AutoField(primary_key=True)
    label = models.CharField(max_length=255)
    abbreviation = models.CharField(max_length=255)

Cada etiqueta tiene un número de ID, el texto de la etiqueta y una abreviatura. Ahora, quiero que estas etiquetas sean traducibles a otros idiomas. ¿Cuál es la mejor manera de hacer esto?

Como lo veo, tengo algunas opciones:

1: agregue las traducciones como campos en el modelo:

class StandardLabel(models.Model):
    id = models.AutoField(primary_key=True)
    label_english = models.CharField(max_length=255)
    abbreviation_english = models.CharField(max_length=255)
    label_spanish = models.CharField(max_length=255)
    abbreviation_spanish = models.CharField(max_length=255)

Obviamente, esto no es lo ideal: agregar idiomas requiere editar el modelo, el nombre de campo correcto depende del idioma.

2: agregue el idioma como clave externa:

class StandardLabel(models.Model):
    id = models.AutoField(primary_key=True)
    label = models.CharField(max_length=255)
    abbreviation = models.CharField(max_length=255)
    language = models.ForeignKey('languages.Language')

Esto es mucho mejor, ahora puedo pedir todas las etiquetas con un determinado idioma y lanzarlas a un dictado:

labels = StandardLabel.objects.filter(language=1)
labels = dict((x.pk, x) for x in labels)

Pero el problema aquí es que las etiquetas dict están destinadas a ser una tabla de búsqueda, como la siguiente:

x = OtherObjectWithAReferenceToTheseLabels.object.get(pk=3)
thelabel = labels[x.labelIdNumber].label

Lo que no funciona si hay una fila por etiqueta, posiblemente con varios idiomas para una sola etiqueta. Para resolver eso, necesito otro campo:

class StandardLabel(models.Model):
    id = models.AutoField(primary_key=True)
    group_id = models.IntegerField(db_index=True)
    label = models.CharField(max_length=255)
    abbreviation = models.CharField(max_length=255)
    language = models.ForeignKey('languages.Language')
    class Meta:
        unique_together=(("group_id", "language"),)
#and I need to group them differently:
labels = StandardLabel.objects.filter(language=1)
labels = dict((x.group_id, x) for x in labels)

3: tira el texto de la etiqueta en un nuevo modelo:

class StandardLabel(models.Model):
    id = models.AutoField(primary_key=True)
    text = models.ManyToManyField('LabelText')

class LabelText(models.Model):
    id = models.AutoField(primary_key=True)
    label = models.CharField(max_length=255)
    abbreviation = models.CharField(max_length=255)
    language = models.ForeignKey('languages.Language')

labels = StandardLabel.objects.filter(text__language=1)
labels = dict((x.pk, x) for x in labels)

Pero esto no funciona y causa un impacto en la base de datos cada vez que hago referencia al texto de la etiqueta:

x = OtherObjectWithAReferenceToTheseLabels.object.get(pk=3)
thelabel = labels[x.labelIdNumber].text.get(language=1)

He implementado la opción 2, pero me parece muy desagradable; no me gusta el campo group_id, y no puedo pensar en nada mejor para nombrarlo. Además, StandardLabel como lo estoy usando es un modelo abstracto, que yo subclaro para obtener diferentes conjuntos de etiquetas para diferentes campos.

Supongo que si la opción 3 / no / golpeara la base de datos, es lo que elegiría. Creo que el problema real es que el filtro text__language = 1 no almacena en caché las instancias de LabelText , por lo que se golpea el DB cuando text.get (idioma = 1)

¿Qué piensas de esto? ¿Alguien puede recomendar una solución más limpia?

Editar : solo para dejarlo claro, no son etiquetas de formularios, por lo que el sistema de internacionalización de Django no ayuda.

¿Fue útil?

Solución

Prefiero agregar un campo por idioma que una nueva instancia de modelo por idioma. Requiere una modificación de esquema cuando agrega un nuevo idioma, pero eso no es difícil, y ¿con qué frecuencia espera agregar idiomas? Mientras tanto, le proporcionará un mejor rendimiento de la base de datos (sin uniones o índices agregados) y no tendrá que arruinar su lógica de consulta con cosas de traducción; guárdelo todo en las plantillas a las que pertenece.

Aún mejor, use una aplicación reutilizable como django-transmeta o django-modeltranslation que hace que este estúpido sea simple y casi completamente transparente.

Otros consejos

Otra opción que podría considerar, dependiendo del diseño de su aplicación, por supuesto, es hacer uso de las características de internacionalización de Django. El enfoque que utilizan es bastante común al enfoque que se encuentra en el software de escritorio.

Veo que la pregunta se editó para agregar una referencia a la internacionalización de Django, por lo que sí lo sabe, pero las características de intl en Django se aplican a mucho más que solo Formularios; toca bastante y solo necesita algunos ajustes para el diseño de la aplicación.

Sus documentos están aquí: http: //docs.djangoproject .com / en / dev / topics / i18n / # topics-i18n

La idea es que usted defina su modelo como si solo hubiera un idioma. En otras palabras, no haga referencia alguna al idioma, y ??solo incluya, digamos, el inglés en el modelo.

Entonces:

class StandardLabel(models.Model):
    abbreviation = models.CharField(max_length=255)
    label = models.CharField(max_length=255)

Sé que parece que has eliminado totalmente el problema del idioma, pero en realidad lo acabas de reubicar. En lugar de que el idioma esté en su modelo de datos, lo ha insertado en la vista.

Las funciones de internacionalización de django le permiten generar archivos de traducción de texto y proporciona una serie de funciones para extraer texto del sistema y convertirlo en archivos. En realidad, esto es bastante útil porque le permite enviar archivos simples a su traductor, lo que facilita su trabajo. Agregar un nuevo idioma es tan fácil como traducir el archivo a un nuevo idioma.

Los archivos de traducción definen la etiqueta de la base de datos y una traducción para ese idioma. Hay funciones para manejar la traducción de idiomas dinámicamente en tiempo de ejecución para modelos, vistas de administrador, javascript y plantillas.

Por ejemplo, en una plantilla, puedes hacer algo como:

<b>Hello {% trans "Here's the string in english" %}</b>

O en el código de vista, puedes hacer:

# See docs on setting language, or getting Django to auto-set language
s = StandardLabel.objects.get(id=1)
lang_specific_label = ugettext(s.label)

Por supuesto, si su aplicación se trata de ingresar nuevos idiomas sobre la marcha , es posible que este enfoque no funcione para usted. De todos modos, eche un vistazo al proyecto de internacionalización, ya que puede usarlo " tal como está " ;, o inspirarse en una solución apropiada para django que funcione para su dominio.

Mantendría las cosas lo más simples posible. La búsqueda será más rápida y el código más limpio con algo como esto:

class StandardLabel(models.Model):
    abbreviation = models.CharField(max_length=255)
    label = models.CharField(max_length=255)
    language = models.CharField(max_length=2)
    # or, alternately, specify language as a foreign key:
    #language = models.ForeignKey(Language)

    class Meta:
        unique_together = ('language', 'abbreviation')

Luego la consulta se basa en la abreviatura y el idioma:

l = StandardLabel.objects.get(language='en', abbreviation='suite')

Aunque iría con la solución de Daniel , aquí es una alternativa a lo que he entendido de sus comentarios:

Puede usar un XMLField o JSONField para almacena tu idioma / pares de traducción. Esto permitiría que sus objetos que hacen referencia a sus etiquetas utilicen un único id para todas las traducciones. Y luego puede tener un método de administrador personalizado para llamar a una traducción específica:

Label.objects.get_by_language('ru', **kwargs)

O una solución un poco más limpia y un poco más complicada que funcione bien con admin sería desnormalizar XMLField a otro modelo con una relación de varios a uno con la etiqueta modelo. La misma API, pero en lugar de analizar XML podría consultar modelos relacionados.

Para ambas sugerencias, hay un único objeto al que apuntarán los usuarios de una etiqueta.

No me preocuparía demasiado por las consultas, Django almacena consultas en caché y es probable que su DBMS también tenga un almacenamiento en caché superior allí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top