Pergunta

Vamos dizer que eu tenho o seguinte 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 possui um número de identificação, o texto da etiqueta, e uma abreviatura. Agora, eu quero ter esses rótulos traduzíveis para outras línguas. Qual é a melhor maneira de fazer isso?

A meu ver, tenho algumas opções:

1: Adicione as traduções como campos no 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)

Isso obviamente não é ideal -. Adicionando idiomas requer a edição do modelo, o nome do campo correto depende do idioma

2: Adicionar a língua como uma chave estrangeira:

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')

Este é muito melhor, agora eu posso pedir para todas as etiquetas com uma certa linguagem, e jogá-los em um dicionário:

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

Mas o problema aqui é que os rótulos dict se destina a ser uma tabela de pesquisa, assim:

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

que não funciona se houver uma linha por etiqueta, possivelmente com vários idiomas para um único rótulo. Para solucionar esse, eu preciso de outro 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: texto do rótulo jogar fora em um novo 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)

Mas então isso não funcionar, e faz com que um banco de dados atingido cada vez que faz referência o texto do rótulo:

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

Eu tenho implementado a opção 2, mas acho que é muito feio - Eu não gosto do campo group_id, e eu não consigo pensar em melhor coisa para nomeá-lo. Além disso, StandardLabel como eu estou usando é um modelo abstrato, que eu subclasse para obter diferentes conjuntos de etiquetas para diferentes campos.

Suponho que, se a opção 3 / fez não / bater o banco de dados, é o que eu escolheria. Eu acredito que o problema real é que o text__language=1 filtro não armazena em cache as instâncias LabelText, e assim o DB é hit quando eu text.get(language=1)

Quais são seus pensamentos sobre isso? Alguém pode recomendar uma solução mais limpa?

Editar :. Só para deixar claro, estes não são formar rótulos, de modo que o sistema de Django Internacionalização não ajuda

Foi útil?

Solução

Eu prefiro muito mais para adicionar um campo para cada língua do que uma nova instância do modelo por língua. Ele requer alteração de esquema quando você adicionar um novo idioma, mas isso não é difícil, e quantas vezes você espera para adicionar idiomas? Nesse meio tempo, ele vai dar-lhe um melhor desempenho do banco de dados (sem adição de junta ou índices) e você não tem que estragar a sua lógica de consulta com o material de tradução; manter tudo nos modelos onde pertence.

Mesmo melhor, usar um aplicativo reutilizável como django-transmeta ou django-modeltranslation que torna este simples estúpido e quase completamente transparente.

Outras dicas

Outra opção que você pode considerar, dependendo do seu design do aplicativo é claro, é fazer uso de recursos de internacionalização do Django. A abordagem que eles usam é bastante comum a abordagem encontrada no software desktop.

Eu vejo a questão foi editada para adicionar uma referência para Django internacionalização, assim que você sabe sobre ele, mas o aeroporto internacional apresenta em Django se aplicam a muito mais do que apenas as Formas; ele touchs bastante, e precisa apenas de alguns ajustes para seu projeto aplicativo.

Os docs aqui: http: //docs.djangoproject .com / en / dev / temas / i18n / # temas-i18n

A idéia é que você define o seu modelo como se houvesse apenas um idioma. Em outras palavras, não fazem referência à linguagem em tudo, e colocar apenas, digamos, Inglês no modelo.

Assim:

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

Eu sei que isso parece que você totalmente jogado para fora da questão da língua, mas você realmente apenas mudou-lo. Em vez da língua estar em seu modelo de dados, você empurrou-o para a vista.

As características django internacionalização permitem a geração de arquivos de tradução de texto, e fornece uma série de recursos para puxar texto fora do sistema em arquivos. Isso é realmente muito útil porque permite que você envie arquivos simples para o seu tradutor, o que torna seu trabalho mais fácil. Adicionando uma nova língua é tão fácil como obter o arquivo traduzido em um novo idioma.

Os arquivos de tradução definir o rótulo do banco de dados, e uma tradução para esse idioma. Há funções para a manipulação da tradução dinamicamente em tempo de execução para os modelos, visualizações admin, javascript, e modelos.

Por exemplo, em um modelo, você pode fazer algo como:

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

Ou no código vista, você poderia fazer:

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

É claro que, se o seu aplicativo é tudo sobre como inserir novas linguagens on the fly, então esta abordagem não pode trabalhar para você. Ainda assim, ter um olhar para o projeto de internacionalização como você pode tanto ser capaz de usá-lo "como está", ou seja inspirado a uma solução django-apropriado que funciona para o seu domínio.

Gostaria de manter as coisas o mais simples possível. A pesquisa será mais rápido e o código mais limpo com algo parecido com isto:

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')

Em seguida, consulta com base na abreviação e idioma:

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

Embora eu iria com solução de Daniel , aqui é uma alternativa a partir do que eu entendi de seus comentários:

Você pode usar um XMLField ou JSONField para armazenar seus pares idioma / tradução. Isso permitiria que seus objetos referenciar a sua rótulos para usar um único id para todas as traduções. E então você pode ter um método gerente de costume para chamar uma tradução específica:

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

Ou uma solução ligeiramente mais limpo e um pouco mais complicado que joga bem com admin seria desnormalizar o XMLField para outro modelo com muitos-para-um relacionamento com o modelo Label. Mesma API, mas em vez de analisar XML poderia consultar os modelos relacionados.

Para ambas as sugestões não há um único objeto onde os usuários de uma etiqueta irá apontar para.

Eu não se preocupar com as consultas demais, Django armazena em cache consultas e seu DBMS provavelmente teria caching superiores lá também.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top