Refactorización de archivos Ruby on Rails i18n YAML utilizando diccionarios

Esta pregunta de StackOverflow me hizo reflexionar sobre cuál es una buena estructura para los archivos Rails i18n, así que pensé que compartiría otra estructura para refactorizar archivos Rails i18n yml para su consideración / crítica.

Dado que me gustaría

  1. mantener la estructura predeterminada de la aplicación para que pueda usar búsquedas abreviadas “perezosas” como t('.some_translation') en mis vistas, así como tener una idea de dónde se usan las traducciones en la aplicación,
  2. evite tanta repetición de cadenas como sea posible, en particular con palabras que no son solo lo mismo, sino que también tienen contextos / significados idénticos,
  3. solo tiene que cambiar una tecla una vez para que se refleje en todos los lugares a los que se hace referencia,

para un archivo config / locales / en.yml que se parece a esto:

 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 

Puedo ver que hay una repetición significativa, y que el contexto de palabras como “Correo electrónico” y “Contraseña” son inequívocos y tienen el mismo significado en sus respectivas vistas. Sería un poco molesto tener que ir a cambiarlos a todos si decido cambiar “Correo electrónico” a “correo electrónico”, así que me gustaría refactorizar las cadenas para hacer referencia a un diccionario de algún tipo. Entonces, ¿qué hay de agregar un hash de diccionario a la parte superior del archivo con algunos & anclajes como este:

 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 

Aún puede seguir utilizando cadenas estáticas (por ejemplo, “Usuario” más arriba), pero siempre que obtenga más de una instancia de exactamente la misma palabra / frase en sus vistas, puede refactorizarla al diccionario. Si la traducción del diccionario de una clave en el idioma base no tiene sentido para un idioma de destino, simplemente cambie el valor referenciado en el idioma de destino a una cadena estática o agréguelo como una entrada adicional al diccionario del idioma de destino. Estoy seguro de que el diccionario de cada idioma se puede adaptar a otro archivo si es demasiado grande y difícil de manejar (siempre que se reimporte en la parte superior del archivo de traducción para que funcionen las referencias).

Esta forma de estructurar archivos i18n yaml parece funcionar bien con algunas aplicaciones de prueba locales en las que lo probé. Espero que la maravillosa Localeapp proporcione soporte para este tipo de anclaje / referencia en el futuro. Pero, de todos modos, toda esta conversación sobre el diccionario no puede ser una idea original, así que ¿hay otros problemas con las referencias de anclaje en YAML, o tal vez con el concepto general del “diccionario” en general? ¿O es mejor simplemente extraer el backend predeterminado por completo y reemplazarlo con Redis o algo así si tiene necesidades más allá de las convenciones i18n predeterminadas de Rails?

Editar :

Quería tratar de abordar el ejemplo de flujo de trabajo de Tigrish mencionado en un comentario aquí abajo, en lugar de otro comentario debajo de su respuesta. Por favor, discúlpeme si parece que no estoy obteniendo los puntos o si soy un ingenuo:

Punto 1 : tiene un atributo de “nombre” general para los modelos ActiveRecord, y todos ellos solo apuntan al diccionario genérico para el nombre:

 dictionary: name: &name Name activerecord: attributes: name: *name user: name: *name product: name: *name 

Punto 2 : El nombre para el modelo de usuario solo necesita ser cambiado. Otros nombres siguen siendo los mismos.

Opción 1 : Mantenga los nombres de los campos del modelo iguales en el backend y solo cambie la traducción de la parte delantera a la que apunta.

 dictionary: name: &name Name full_name: &full_name Full Name activerecord: attributes: name: *name user: name: *full_name product: name: *name 

Opción 2 : cambiar también el nombre del campo del modelo de usuario. Esto requeriría cambiar cualquier referencia a esta clave en el código y una migración 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 

Opción 3 : si desea ser muy cuidadoso, refactorice la información contenida en un “nombre” para separar los campos de la base de datos / Módulo de activación, que necesitarían nuevas entradas de diccionario y una migración. Puede decidir en sus vistas cómo desea que aparezca un “nombre completo”:

 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 : Cualquier persona por cualquier razón necesita un cambio de traducción, Marketing en este caso. Seguiré del ejemplo de la Opción 1 del Punto 2

Opción 1 : modelo de nombre de campo igual, solo cambia la traducción del extremo frontal.

 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 

Opción 2 : el “nombre funky” necesita desesperadamente ser guardado en la base de datos, también, por alguna razón. Llamémoslo un username si nadie se opone (o funky_name si por alguna razón el 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 

Bien, entonces admito que tengo poca idea de lo que estoy haciendo, sin embargo, estoy dispuesto a ser derribado públicamente para comprender por qué esta forma de trabajar con i18n en Haml es una mala idea en una aplicación de Rails. ¿Dificultad para leer? ¿Pesadilla de mantenimiento? ¿Realmente se considera ‘hackear el formato de archivo’ si uso (lo que creo que es) una característica del lenguaje?

Gracias de nuevo a Tigrish por impulsarme a sacar todo esto.

TLDNR; ¡No hackee su formato de archivo, mejore los ayudantes de Rails y ayude a establecer una estructura de claves estandarizada!

TLDR;

No quiero llover en tu desfile, pero tengo algunos problemas con esta técnica. El dilema de dónde usar el atajo de punto y cómo difiere la estructura de las llaves de los ayudantes de Rails puede ser un poco desconcertante.

Como lo entiendo, la pregunta es básicamente acerca de SECAR sus archivos de configuración regional y usar una característica del lenguaje YAML para lograr esto.

En primer lugar, se garantiza que los anclajes solo funcionarán para YAML, por lo que esta solución no se puede aplicar genéricamente a I18n. Esta técnica probablemente no sea factible si utiliza un backend diferente. Ya sea SQL, Redis o Json, no conozco a ninguno de ellos que tenga alguna clase de funcionalidad de vinculación. Y eso es sin entrar demasiado en el hecho de que bajo el capó, las traducciones de hecho se duplican.

El segundo y más grande problema que tengo es sobre lingüística. Su ejemplo sostiene que todos estos términos son exactamente iguales en contexto y en significado. Desafortunadamente, esto solo es así en ejemplos extremadamente simples.

Sin lugar a dudas, a medida que su aplicación crezca o a medida que agregue idiomas adicionales, encontrará que el atributo “nombre” de una persona tiene que ser distinto de decir el atributo “nombre” de un libro, que en inglés llamaremos “título”. este ejemplo es realmente complicado;) pero a medida que mezcla cada vez más idiomas, esta situación ocurre con frecuencia e idealmente, queremos una forma genérica de tratarla.

Creo que, en gran parte, la complejidad proviene de los ayudantes de Rails que han evolucionado con diferentes valores predeterminados sin que exista una convención para estructuras clave.

Volviendo a su ejemplo, menciona 2 cosas que creo que son realmente distintas: las traducciones de atributos de registro de registro que usan los ayudantes de Rails y las traducciones que usan el atajo de punto.

Déjame darte un ejemplo de un flujo de trabajo que es muy frecuente:

  1. Si creas un formulario con el campo “Nombre” del usuario en esta situación, querrás usar las traducciones de atributo “nombre” genérico (label_tag debería usar algo como: ‘attributes.name’). Este es el caso más simple y DRYest para que pueda comenzar a trabajar rápidamente, traduciendo en masa atributos simples.
  2. Poco después, usted decide que el “nombre” del Usuario solo debe traducirse como “nombre completo” para este modelo, de modo que cree una nueva traducción que tenga una mayor prioridad en la llamada de búsqueda de label_tag (por ejemplo: ‘activerecord.attributes.users.name’ ))
  3. Más tarde, el encargado de marketing tiene la shiny idea de mostrar la etiqueta de este campo como “ingrese su nombre nuevo y original” en esta página (y solo en esta página). Ya no estamos describiendo el atributo de nombre, estamos describiendo una vista particular de este formulario; aquí es donde el atajo de punto viene al convertir: ‘. form.name’ a algo como ‘: users.new.form.name’.

No hay forma de que podamos manejar esta situación con un “diccionario” compartido. Claro que nuestro archivo de configuración regional sería DRY, pero nuestras preocupaciones lingüísticas / de traducción son muy diferentes de las de nuestros desarrolladores aquí (lamentablemente).

En el lado positivo, podemos aclarar qué tipo de contenido estamos describiendo y reflejar eso en nuestras estructuras clave y en nuestras herramientas, ¡ese es el camino a seguir para mí! 🙂

Acabo de lanzar una gem llamada i18n-recursive-lookup que permite que una definición contenga referencias incrustadas a otras definiciones al introducir el marcador incrustado especial $ {}

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

Usándolo puedes refactorizar tu ejemplo para:

 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} 

Lo bueno es que, una vez comstackdas, las traducciones se vuelven a escribir en el almacén de traducción para que toda la búsqueda interpolada / recursiva ocurra una vez.

Sé que esto podría no responder a las preguntas más filosóficas acerca de cuál es la forma “correcta” de SECAR las traducciones, pero pensé que es una mejor alternativa a usar la etiqueta & Yack de referencia de YML.

Mejora de la refacción de archivos YAML, especialmente para aquellos que tienen muchos modelos:

 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: "Электропочта" 

Enlace de usuario

Acabo de lanzar una gem llamada dry_i18n: https://rubygems.org/gems/dry_i18n

Creé esta gem para resolver el problema que pediste. Con esta gem podrás reutilizar incluso las claves con interpolaciones y anidarlas.

Espero que sea útil.

Intereting Posts