20

This La domanda StackOverflow mi ha dato spunti di riflessione su cosa sia una buona struttura per i file Rails i18n, quindi ho pensato di condividere un'altra struttura per refactoring i file yml Rails i18n per la vostra considerazione/critica.Refactoring Ruby on Rails file YAML i18n utilizzando i dizionari

Dato che vorrei

  1. mantenere la struttura predefinita applicazione in modo da poter usare stenografia ricerche "pigri" come t('.some_translation') nel mio punto di vista, così come hanno un idea di dove sono utilizzati traduzioni in app,
  2. evitare il più stringa ripetizione come possibile, in particolare con parole che non sono lo stesso, ma anche avere identici contesti/significati,
  3. solo devono cambiare una chiave di volta per averlo riflessa ovunque è referenziata,

per un// file di en.yml locali configurazione che sembra qualcosa di simile:

activerecord: 
    attributes: 
    user: 
     email: Email 
     name: Name 
     password: Password 
     password_confirmation: Confirmation 
    models: 
    user: User 
users: 
    fields: 
    email: Email 
    name: Name 
    password: Password 
    confirmation: Confirmation 
sessions: 
    new: 
    email: Email 
    password: Password 

posso vedere che non v'è la ripetizione significativo, e che il contesto di parole come "Email" e "Password "non sono ambigui e hanno lo stesso significato nelle rispettive opinioni. Sarebbe un po 'fastidioso dover andare e cambiarli tutti se decido di cambiare "Email" in "e-mail", quindi mi piacerebbe rifattorizzare le stringhe per fare riferimento a un dizionario di qualche tipo. Così, come circa l'aggiunta di un hash dizionario per la parte superiore del file con alcuni & ancoraggi come questo:

dictionary: 
    email: &email Email 
    name: &name Name 
    password: &password Password 
    confirmation: &confirmation Confirmation 

activerecord: 
    attributes: 
    user: 
     email: *email 
     name: *name 
     password: *password 
     password_confirmation: *confirmation 
    models: 
    user: User 
users: 
    fields: 
    email: *email 
    name: *name 
    password: *password 
    confirmation: *confirmation 
sessions: 
    new: 
    email: *email 
    password: *password 

si potrebbe ancora continuare a utilizzare stringhe statiche (ad esempio "utente" di cui sopra), ma ogni volta che si ottiene più di un'istanza di esattamente la stessa parola/frase nelle tue visualizzazioni, puoi rifattorizzarla sul dizionario. Se la traduzione del dizionario di una chiave nella lingua di base non ha senso per una lingua di destinazione, basta cambiare il valore di riferimento nella lingua di destinazione in una stringa statica o aggiungerlo come una voce aggiuntiva al dizionario della lingua di destinazione. Sono sicuro che il dizionario di ogni lingua potrebbe essere rielaborato in un altro file se diventa troppo grande e ingombrante (purché venga reimportato nella parte superiore del file di traduzione in modo che i riferimenti funzionino).

Questo modo di strutturare i file i18n yaml sembra funzionare bene con alcune app di test locali che ho provato. Spero che il meraviglioso Localeapp fornirà supporto per questo tipo di ancoraggio/riferimento in futuro. Ma comunque, tutto questo parlare nel dizionario non può essere un'idea originale, quindi ci sono altri problemi con il riferimento all'ancora in YAML, o forse solo con l'intero concetto di "dizionario" in generale? O è solo meglio strappare del tutto il back-end di default e sostituirlo con Redis o qualcosa del genere se hai necessità oltre le convenzioni i18n predefinite di Rails?

Edit:

ho voluto provare e l'esempio del flusso di lavoro indirizzo di tigrish menzionato in un commento qui sotto qui, piuttosto che come un altro commento qui sotto la sua risposta.Si prega di scusarmi se non mi sembra di avere i punti che sono fatti, o se sono solo ingenua:

Punto 1: si ha un "nome" generico attributo per modelli ActiveRecord, e tutti hanno solo punto al dizionario generico per nome:

dictionary: 
    name: &name Name 

activerecord: 
    attributes: 
    name: *name 
    user: 
     name: *name 
    product: 
     name: *name 

Punto 2: nome per il modello utente ha solo bisogno di essere cambiato. Altri nomi rimangono gli stessi.

Opzione 1: mantenere i nomi dei campi del modello uguali sul back-end e modificare solo la traduzione del front-end a cui punta.

dictionary: 
    name: &name Name 
    full_name: &full_name Full Name 

activerecord: 
    attributes: 
    name: *name 
    user: 
     name: *full_name 
    product: 
     name: *name 

Opzione 2: Modificare il nome del campo modello User pure. Ciò richiederebbe la modifica di qualsiasi riferimento a questa chiave nel codice e una migrazione change_table/rename_column.

dictionary: 
    name: &name Name 
    full_name: &full_name Full Name 

activerecord: 
    attributes: 
    name: *name 
    user: 
     full_name: *full_name 
    product: 
     name: *name 

Opzione 3: Se vuoi essere molto approfondita, refactoring le informazioni contenute in un "nome" in per separare i campi del database/Activemodel, che avrebbero bisogno di nuove voci del dizionario e una migrazione. Si può decidere sui vostri punti di vista come si vorrebbe un "nome completo" alla visualizzazione:

dictionary: 
    name: &name Name 
    name_prefix: &name_prefix Prefix 
    first_name: &first_name First 
    middle_name: &middle_name Middle 
    last_name: &last_name Last 
    name_suffix: &name_suffix Suffix 

activerecord: 
    attributes: 
    name: *name 
    user: 
     name_prefix: *name_prefix 
     first_name: *first_name 
     middle_name: *middle_name 
     last_name: *last_name 
     name_suffix: *name_suffix 
    product: 
     name: *name 

Punto 3: chiunque, per qualsiasi motivo ha bisogno di un cambiamento di traduzione, Marketing in questo caso. Seguirò l'esempio del Punto 2 Opzione 1

Opzione 1: i nomi dei campi modello sono gli stessi, basta cambiare la traduzione del front-end.

dictionary: 
    name: &name Name 
    full_name: &full_name Full Name 
    funky_name: &funky_name Ur Phunky Phresh Naym 

activerecord: 
    attributes: 
    name: *name 
    user: 
     name: *full_name 
    product: 
     name: *name 
sessions: # Sign up page keys 
    new: 
    name: *funky_name 

Opzione 2: "nome Funky" ha bisogno disperatamente di essere salvati nel database, anche, per qualche motivo. Chiamiamolo a username se nessuno obietta (o funky_name se per qualche motivo insiste Marketing).

dictionary: 
    name: &name Name 
    full_name: &full_name Full Name 
    funky_name: &funky_name Ur Phunky Phresh Naym 

activerecord: 
    attributes: 
    name: *name 
    user: 
     name: *full_name 
     username: *funky_name 
    product: 
     name: *name 
sessions: # Sign up page keys 
    new: 
    name: *name 
    funky_name: *funky_name 

Giusto, quindi ammetto che ho poca idea di quello che sto facendo, però, io sono disposto a essere abbattuto al pubblico al fine di capire il motivo per cui questo modo di lavorare con i18n in Haml è una cattiva idea in un'app Rails. Difficile da leggere? Incubo di manutenzione? E 'davvero considerato' hacking il formato del file 'se io uso (quello che penso sia) una funzionalità del linguaggio?

Grazie ancora a Tigrish per avermi portato a tirar fuori tutto questo.

risposta

9

TLDNR; Non modificare il formato del file, migliorare gli helper delle guide e aiutare a stabilire una struttura di chiavi standardizzata!

TLDR;

Non voglio piovere sulla tua parata, ma ho qualche problema con questa tecnica. Il dilemma su dove usare la scorciatoia a punti e come differisce la struttura chiave degli aiutanti di rotaie può essere un po 'sconcertante.

Da quello che ho capito, la domanda è fondamentalmente su RIPRISTINO i file locali e utilizzando una funzione del linguaggio YAML per ottenere ciò.

In primo luogo, gli ancoraggi sono garantiti per funzionare solo per YAML, quindi questa soluzione non può essere applicata in modo generico a I18n. Questa tecnica probabilmente non è fattibile se si utilizza un back-end diverso. Che si tratti di SQL, Redis o Json, non sono a conoscenza di nessuno di loro che abbia funzionalità di tipo symlinking. E questo è senza andare troppo nel fatto che sotto il cofano, le traduzioni sono di fatto duplicate.

Il secondo problema più grande che ho riguarda la linguistica. Il tuo esempio dimostra che tutti questi termini sono esattamente uguali nel contesto e nel significato. Sfortunatamente questo è sempre il caso in esempi estremamente semplici.

Indubbiamente, man mano che la tua app cresce o mentre aggiungi altre lingue, scoprirai che l'attributo "nome" di una persona deve essere distinto dall'attributo "nome" di un libro che in inglese chiameremo "titolo" "- OK, questo esempio è davvero contorto;) ma come si mescolano in sempre più lingue questa situazione si verifica frequentemente e idealmente, vogliamo un modo generico di gestirlo.

Penso che in gran parte, la complessità provenga dagli aiutanti dei binari che si sono evoluti con diversi valori predefiniti senza che esistesse una convenzione per le strutture chiave.

Tornando al tuo esempio citi 2 cose che ritengo siano davvero distinte: activerecord attribuisce traduzioni che utilizzano gli helper delle rotaie e visualizzano le traduzioni che usano la scorciatoia a punti.

Lasciate che vi faccia un esempio di un flusso di lavoro che è super frequente:

  1. Si crea una maschera con il campo "Nome" per l'utente in questa situazione, si desidera utilizzare il "nome" generico attributo traduzioni (label_tag dovrebbe usare qualcosa come: 'attributes.name'). Questo è il caso più semplice e più DRY per farti funzionare rapidamente, traducendo in massa gli attributi semplici.
  2. Poco dopo decidi che il "nome" dell'utente deve essere tradotto come "nome completo" per questo modello solo in modo da creare una nuova traduzione con una priorità più alta nella chiamata di ricerca label_tag (ad esempio: "activerecord.attributes.users .name '))
  3. In seguito, il responsabile del marketing ha la brillante idea di visualizzare l'etichetta di questo campo come "inserisci il tuo nome originale funky" in questa pagina (e solo in questa pagina). Non stiamo più descrivendo l'attributo del nome, stiamo descrivendo una particolare visione di questo modulo; questo è il punto in cui il collegamento a punti arriva convertendo: '. form.name' in qualcosa di simile a ': users.new.form.name'.

Non c'è modo di gestire questa situazione con un "dizionario" condiviso. Certo, il nostro file locale sarebbe DRY, ma i nostri problemi linguistici/di traduzione sono molto diversi dalle preoccupazioni degli sviluppatori qui (purtroppo).

Per quanto riguarda i lati positivi, possiamo chiarire meglio il tipo di contenuto che stiamo descrivendo e rifletterlo nelle nostre strutture chiave e nei nostri strumenti - che per me è la via da seguire!:)

+1

Grazie per aver dedicato del tempo a scrivere una risposta così dettagliata, soprattutto perché si trattava di una domanda a cui hai risposto che mi ha spinto a riflettere su questo. Ho pensato ai dizionari perché su progetti che ho lavorato a quelle società di traduzione usate, ci sono sempre state "memorie di traduzione", che presumo siano "dizionari riutilizzabili di qualche tipo". Ammetto di non avere idea se questa idea sia compatibile con altri backend i18n di Rails, ma nel tuo flusso di lavoro, non aggiungerei solo voci di dizionario per "nome completo" e "nome fresco funky" e basta che le chiavi appropriate facciano riferimento ad esso? –

+0

Per quanto ne so, l'uso più comune della memoria di traduzione è che un traduttore capisca come alcune parole debbano essere tradotte per essere coerenti. Es: quando si mostra un pannello di controllo, dovrebbe essere chiamato "preferenze" o "impostazioni" o "pannello di controllo" ecc ... Per me, questo è più uno strumento per i traduttori rispetto a qualcosa che gli sviluppatori dovrebbero usare per ridurre i loro file locali. Ancora una volta, il percorso per essere concisi sta nello sviluppo di default standardizzati per I18n. – tigrish

+0

Per rispondere alla domanda: "nome completo", non si spera che non si debbano creare nuove voci per loro. Ciò significherebbe cambiare le visualizzazioni e potenzialmente interrompere l'utilizzo degli helper integrati. Idealmente, avremmo bisogno solo di creare traduzioni con le chiavi corrette affinché abbiano la precedenza nei posti giusti. – tigrish

4

Ho appena rilasciare una gemma chiamata i18n-recursive-ricerca che permette una definizione di contenere riferimenti incorporati ad altre definizioni introducendo la speciale incorporato marcatore $ {}

https://github.com/annkissam/i18n-recursive-lookup

Con esso si poteva refactoring tuo esempio a:

dictionary: 
    email: Email 
    name: Name 
    password: Password 
    confirmation: Confirmation 

activerecord: 
    attributes: 
    user: 
     email: ${dictionary.email} 
     name: ${dictionary.name} 
     password: ${dictionary.password} 
     password_confirmation: ${dictionary.confirmation} 
    models: 
    user: User 
users: 
    fields: 
    email: ${dictionary.email} 
    name: ${dictionary.name} 
    password: ${dictionary.password} 
    confirmation: ${dictionary.confirmation} 
sessions: 
    new: 
    email: ${dictionary.email} 
    password: ${dictionary.password} 

la cosa bella è che, una volta compilate le traduzioni vengono scritti di nuovo al deposito di traduzione in modo che tutti interpolazione/ricerca ricorsiva accade una volta.

So che questo potrebbe non rispondere alle domande più filosofiche su quale sia il modo "giusto" per asciugare le traduzioni, ma ho pensato che fosse un'alternativa migliore all'uso dell'hack YML di riferimento dell'etichetta &.

+0

Mi piace perché fa in modo che quando i contesti producono realmente parole/frasi diverse, puoi fare la cosa giusta nella lingua desiderata. Il mio caso d'uso sarebbe per "galloni". Io chiamo questa unità di volume da qualche parte, ma ho alcune traduzioni che dicono "galloni" esplicitamente e volevo ASCIUGARLA. – ZiggyTheHamster

0

Miglioramento della refactiring file YAML, in particolare per coloro che hanno molti modelli:

ru: 
    dictionary: 
    name: &name "Имя" 
    title_ru: &title_ru "Заголовок (ru)" 
    title_en: &title_en "Заголовок (en)" 
    content_ru: &content_ru "Содержание (ru)" 
    content_en: &content_en "Содержание (en)" 
    role: &role "Роль" 
    created_at: &created_at "Создано в" 
    updated_at: &updated_at "Обновлено в" 
    published: &published "Опубликовано" 

    nomination: &nomination 
     name: *name 
     title_ru: *title_ru 
     title_en: *title_en 

    post: &post 
     content_ru: *content_ru 
     content_en: *content_en 
     published: *published 

    dates: &dates 
     created_at: *created_at 
     updated_at: *updated_at 

    activerecord: 
    attributes: 
     article: 
     <<: *nomination 
     <<: *post 
     <<: *dates 

     user: 
     <<: *dates 
     role: *role 
     email: "Электропочта" 

userful link

0

Ho appena rilasciato una gemma chiamata dry_i18n: https://rubygems.org/gems/dry_i18n

Ho creato questo gioiello in ordine per risolvere il problema che chiedi. Con questa gemma potrai persino riutilizzare le chiavi con interpolazioni e annidarle.

Spero sia utile.