Reconfiguration des fichiers Ruby on Rails I18N YAML à l'aide de dictionnaires
cette question de StackOverflow m'a donné matière à réflexion sur ce qui est une bonne structure pour les Rails i18n fichiers, donc j'ai pensé que je partagerais une autre structure pour le remaniement des Rails i18n fichiers yml pour votre considération/critique.
étant donné que je voudrais
- garder la structure par défaut de l'application afin que je puisse utiliser la sténographie "lazy" comme
t('.some_translation')
dans mes vues, ainsi que d'avoir une idée où les traductions sont utilisées dans l'application, - éviter autant de répétition de chaîne que possible, en particulier avec des mots qui ne sont pas identiques, mais qui ont aussi des contextes/significations identiques,
- il suffit de changer une clé une seule fois pour qu'elle se reflète partout où elle est référencée,
pour un config/locales/fr.YML fichier qui ressemble à quelque chose comme ceci:
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
je peux voyez qu'il y a une répétition significative, et que le contexte de mots comme "Email" et "mot de passe" sont sans ambiguïté et ont le même sens dans leurs vues respectives. Il serait un peu ennuyeux d'avoir à aller changer tous si je décide de changer de "Courriel" pour "e-mail", donc j'aimerais refactoriser les cordes pour faire référence à un dictionnaire de la sorte. Alors, que diriez-vous d'ajouter un hachage de dictionnaire en haut du fichier avec quelques ancres &
comme ceci:
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
vous pouvez toujours continuer à utiliser des chaînes statiques (par exemple" Utilisateur " ci-dessus), mais chaque fois que vous obtenez plus d'une instance de exactement le même mot/phrase dans vos vues, vous pouvez le remanier vers le dictionnaire. Si la traduction du dictionnaire d'une clé dans la langue de base n'a pas de sens pour une langue cible, alors il suffit de changer la valeur référencée dans la langue cible en une chaîne statique ou de l'ajouter comme entrée supplémentaire au dictionnaire de la langue cible. Je suis sûr que chaque langue le dictionnaire peut être refactorisé dans un autre fichier s'il devient trop gros et lourd (Tant qu'il est réimporté en haut du fichier de traduction pour que les références fonctionnent).
cette façon de structurer les fichiers i18n yaml semble bien fonctionner avec certaines applications de test locales sur lesquelles je l'ai essayé. J'espère que le merveilleux Localeapp fournira un soutien pour ce genre d'ancrage / référencement à l'avenir. Mais de toute façon, tous ces dictionnaires ne peuvent pas peut-être une idée originale, alors y a-t-il d'autres problèmes avec le référencement d'ancre dans YAML, ou peut-être juste avec l'ensemble du "dictionnaire" concept en général? Ou est-ce qu'il est juste préférable de simplement enlever le backend par défaut et le remplacer par Redis ou quelque chose si vous avez des besoins au-delà des conventions i18n de Rails par défaut?
Modifier :
je voulais essayer d'adresser l'exemple de flux de travail de tigrish mentionné dans un commentaire ci-dessous, jusqu'ici, plutôt que comme un autre commentaire ci-dessous sa réponse. S'il vous plaît excusez-moi si Je ne semble pas obtenir les points étant fait ou si je suis juste naïf:
Point 1 : vous avez un attribut "name" général pour les modèles ActiveRecord, et ils tous pointent juste au dictionnaire générique pour le nom:
dictionary:
name: &name Name
activerecord:
attributes:
name: *name
user:
name: *name
product:
name: *name
Point 2 : le nom du modèle Utilisateur doit être changé. D'autres noms rester le même.
Option 1 : conserver les noms des champs model identiques sur le verso et juste changer la traduction de l'avant vers laquelle il pointe.
dictionary:
name: &name Name
full_name: &full_name Full Name
activerecord:
attributes:
name: *name
user:
name: *full_name
product:
name: *name
Option 2 : changez également le nom du champ User model. Il faudrait pour cela modifier toute référence à cette clé dans le code, ainsi qu'une migration 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
Option 3 : si vous voulez être très complet, modifiez l'information contenue dans un" nom " pour séparer les champs de base de données/Activemodel, qui auraient besoin de nouvelles entrées de dictionnaire et une migration. Vous pouvez décider sur vos vues comment vous voudriez qu'un" nom complet "s'affiche:
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
Point 3 : toute personne pour une raison quelconque a besoin d'un changement de traduction, Marketing dans ce cas. Je vais suivre de Point 2 L'exemple de L'Option 1
Option 1 : les noms des champs du modèle sont les mêmes, il suffit de changer la traduction de l'extrémité avant.
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
Option 2 : "Funky name" a désespérément besoin d'être sauvegardé dans la base de données, aussi, pour une raison quelconque. Appelons-le un username
si personne ne s'y oppose (ou funky_name
si pour une raison quelconque le Marketing insiste).
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
D'accord, donc j'admets que j'ai peu d'idée de ce que je fais, cependant, Je suis prêt à être abattu publiquement afin de comprendre pourquoi cette façon de travailler avec i18n dans Haml est une mauvaise idée dans une application Rails. Difficile à lire? Entretien cauchemar? Est-ce vraiment considéré comme 'hacking the file format' si j'utilise (ce que je pense être) une caractéristique de la langue?
merci encore à tigrish de m'avoir amené à sortir tout ça.
4 réponses
TLDNR; ne pas hacker votre format de fichier, améliorer les aides rails et aider à établir une structure de clé standardisée!
TLDR;
Je ne veux pas qu'il pleuve sur votre défilé, mais j'ai quelques problèmes avec cette technique. Le dilemme de savoir où utiliser le raccourci de points et comment la structure de la clé des assistants de rails diffère peut être un peu déroutant.
d'après ce que j'ai compris, la question est essentiellement de sécher vos fichiers locaux et utiliser une caractéristique du langage YAML pour y parvenir.
tout d'abord, les ancres ne sont vraiment garanties de fonctionner que pour YAML, donc cette solution ne peut pas être appliquée de manière générique à I18n. Cette technique n'est probablement pas réalisable si vous utilisez un support différent. Que ce soit SQL, Redis ou Json, Je ne suis pas au courant de l'un d'eux ayant une fonctionnalité de symlinking. Et cela sans entrer trop dans le fait que sous le capot, les traductions sont en fait dupliquées.
le deuxième et le plus gros problème que j'ai, c'est la linguistique. Votre exemple montre que tous ces termes sont exactement égaux dans leur contexte et dans leur signification. Malheureusement, ce n'est le cas que dans des exemples extrêmement simples.
sans aucun doute, au fur et à mesure que votre application se développe ou que vous ajoutez d'autres langues, vous constaterez que l'attribut" name " d'une personne doit être distinct de l'attribut "name" d'un livre que nous appellerons en anglais "title" - OK, cet exemple est mais comme vous mélangez dans de plus en plus de langues cette situation se produit fréquemment et idéalement, nous voulons une façon générique de traiter avec elle.
je pense qu'en grande partie, la complexité vient des helpers rails qui ont évolué avec différents défauts sans qu'il y ait une convention pour les structures clés.
pour revenir à votre exemple, vous mentionnez deux choses que je pense sont vraiment distincts : activerecord attribut traductions qui utilisez les helpers de rails et visualisez les traductions qui utilisent le raccourci à points.
Permettez-moi de vous donner un exemple d'un flux de travail qui est très fréquent:
- vous créez un formulaire avec le champ "Nom" de l'utilisateur dans cette situation, vous voulez utiliser les traductions génériques d'attribut " nom " (label_tag doit utiliser quelque chose comme :'attributs.nom"). C'est le cas le plus simple, le plus sec pour vous mettre en route rapidement, traduire en masse des attributs simples.
- un peu plus tard, vous décidez que le" nom "de L'utilisateur doit être traduit par" nom complet " pour ce modèle seulement afin de créer une nouvelle traduction qui a une priorité plus élevée dans l'appel de recherche de label_tag (par exemple :'activerecord.attributs.utilisateurs.nom'))
- plus tard encore, le gars du marketing a la brillante idée d'afficher l'étiquette de ce domaine comme "entrez votre nom frais funky" sur cette page (et seulement sur cette page). Nous ne décrivons plus l'attribut du nom., nous décrivons une vue particulière de cette forme; c'est là que le raccourci de points vient en conversion :'.form.Nom' to something like': users.new.form.nom".
il n'y a aucun moyen que nous puissions gérer cette situation avec un"dictionnaire" partagé. Bien sûr notre fichier local serait sec, mais nos préoccupations linguistiques/de traduction sont très différentes de nos préoccupations de développeur ici (malheureusement).
du côté positif, nous pouvons obtenir plus clair sur ce genre de contenu nous décrivons et reflétons cela dans nos structures clés et dans nos outils - c'est pour moi la voie à suivre! :)
je viens de publier une gemme appelée i18n-recursive-lookup qui permet à une définition de contenir des références intégrées à d'autres définitions en introduisant le marqueur spécial intégré $ {}
https://github.com/annkissam/i18n-recursive-lookup
en l'utilisant, vous pourriez reformuler votre exemple en:
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 bonne chose est qu'une fois compilées les traductions sont écrites de nouveau à la traduction stocker de façon à ce que toute interpolation/recherche récursive n'arrive qu'une fois.
je sais que cela pourrait ne pas répondre aux questions plus philosophiques sur ce que la "bonne" façon de sécher les traductions est, mais j'ai pensé que c'est une meilleure alternative à l'utilisation du hack YML de référence & label.
amélioration des fichiers YAML refactiring, en particulier pour ceux qui ont plusieurs modèles:
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: "Электропочта"
Divers lien
je viens de sortir une gemme appelée dry_i18n: https://rubygems.org/gems/dry_i18n
j'ai créé ce bijou afin de résoudre le problème que vous demandez. Avec ce bijou, vous pourrez même réutiliser des clés avec des interpolations et les emboîter.
j'espère que c'est utile.