Domanda

Diciamo che ho il seguente modello Django:

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

Ogni etichetta ha un numero ID, il testo dell'etichetta e un'abbreviazione. Ora voglio che queste etichette siano traducibili in altre lingue. Qual è il modo migliore per farlo?

A mio avviso, ho alcune opzioni:

1: aggiungi le traduzioni come campi nel modello:

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)

Questo ovviamente non è l'ideale - l'aggiunta di lingue richiede la modifica del modello, il nome del campo corretto dipende dalla lingua.

2: aggiungi la lingua come chiave esterna:

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

Questo è molto meglio, ora posso chiedere tutte le etichette con una certa lingua e gettarle in un dict:

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

Ma il problema qui è che le etichette dict è pensata per essere una tabella di ricerca, in questo modo:

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

Che non funziona se esiste una riga per etichetta, possibilmente con più lingue per una singola etichetta. Per risolverlo, ho bisogno di un altro 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: getta il testo dell'etichetta in un nuovo modello:

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)

Ma allora questo non funziona e provoca un hit del database ogni volta che faccio riferimento al testo dell'etichetta:

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

Ho implementato l'opzione 2, ma la trovo molto brutta - non mi piace il campo group_id e non riesco a pensare a qualcosa di meglio per nominarlo. Inoltre, StandardLabel, come lo sto usando, è un modello astratto, che faccio una sottoclasse per ottenere diversi set di etichette per campi diversi.

Suppongo che se l'opzione 3 / non funzionasse / colpisse il database, è quello che sceglierei. Credo che il vero problema sia che il filtro text__language = 1 non memorizza nella cache le istanze LabelText , quindi il DB viene colpito quando text.get (lingua = 1)

Cosa ne pensi di questo? Qualcuno può raccomandare una soluzione più pulita?

Modifica : solo per chiarire, queste non sono etichette dei moduli, quindi il sistema di internazionalizzazione di Django non aiuta.

È stato utile?

Soluzione

Preferirei di gran lunga aggiungere un campo per lingua rispetto a una nuova istanza del modello per lingua. Richiede una modifica dello schema quando aggiungi una nuova lingua, ma non è difficile e con quale frequenza ti aspetti di aggiungere le lingue? Nel frattempo, ti darà migliori prestazioni del database (senza join o indici aggiunti) e non dovrai confondere la tua logica di query con elementi di traduzione; tienilo tutto nei modelli a cui appartiene.

Ancora meglio, usa un'app riutilizzabile come django-transmeta o django-modeltranslation che rende questo stupido semplice e quasi completamente trasparente.

Altri suggerimenti

Un'altra opzione che potresti prendere in considerazione, ovviamente a seconda del design della tua applicazione, è quella di utilizzare le funzionalità di internazionalizzazione di Django. L'approccio che usano è abbastanza comune all'approccio trovato nel software desktop.

Vedo che la domanda è stata modificata per aggiungere un riferimento all'internazionalizzazione di Django, quindi tu lo sai, ma le funzionalità intl di Django si applicano a molto più che ai semplici Form; tocca parecchio e richiede solo alcune modifiche al design della tua app.

I loro documenti sono qui: http: //docs.djangoproject .com / it / dev / argomenti / i18n / # argomenti-i18n

L'idea è che tu definisca il tuo modello come se ci fosse una sola lingua. In altre parole, non fare alcun riferimento alla lingua e inserire solo, per esempio, inglese nel modello.

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

So che sembra che tu abbia completamente eliminato il problema della lingua, ma in realtà lo hai appena trasferito. Invece che la lingua sia nel tuo modello di dati, l'hai portata alla vista.

Le funzionalità di internazionalizzazione di django consentono di generare file di traduzione di testo e forniscono una serie di funzioni per estrarre il testo dal sistema in file. Questo è in realtà abbastanza utile perché ti consente di inviare file semplici al tuo traduttore, il che semplifica il loro lavoro. Aggiungere una nuova lingua è facile come tradurre il file in una nuova lingua.

I file di traduzione definiscono l'etichetta dal database e una traduzione per quella lingua. Esistono funzioni per gestire dinamicamente la traduzione della lingua in fase di esecuzione per modelli, viste di amministrazione, javascript e modelli.

Ad esempio, in un modello, potresti fare qualcosa del tipo:

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

O nel codice di visualizzazione, puoi fare:

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

Ovviamente, se la tua app riguarda l'inserimento di nuove lingue al volo , questo approccio potrebbe non funzionare per te. Tuttavia, dai un'occhiata al progetto di internazionalizzazione in quanto potresti essere in grado di usarlo "come è" o essere ispirato a una soluzione appropriata per django che funziona per il tuo dominio.

Vorrei mantenere le cose il più semplice possibile. La ricerca sarà più veloce e il codice più pulito con qualcosa del genere:

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

Quindi esegui una query in base all'abbreviazione e alla lingua:

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

Anche se andrei con Soluzione di Daniel , qui è un'alternativa a quanto ho capito dai tuoi commenti:

Puoi utilizzare un XMLField o JSONField per memorizzare le coppie di lingua / traduzione. Ciò consentirebbe ai tuoi oggetti che fanno riferimento alle etichette di utilizzare un singolo id per tutte le traduzioni. E poi puoi avere un metodo manager personalizzato per chiamare una traduzione specifica:

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

O una soluzione leggermente più pulita e leggermente più complicata che funziona bene con admin sarebbe denormalizzare XMLField su un altro modello con una relazione molti-a-uno con Etichetta modello. Stessa API, ma invece di analizzare XML potrebbe interrogare modelli correlati.

Per entrambi i suggerimenti c'è un singolo oggetto a cui gli utenti di un'etichetta indicheranno.

Non mi preoccuperei troppo delle query, Django memorizza nella cache le query e il tuo DBMS probabilmente avrebbe anche una cache superiore anche lì.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top