ruby-on-rails - tutorial - rails multi language
Refactorización de archivos Ruby on Rails i18n YAML utilizando diccionarios (4)
This pregunta de StackOverflow me sirvió para reflexionar sobre cuál es una buena estructura para los archivos Rails i18n, así que pensé en compartir otra estructura para refactorizar archivos Rails i18n yml para su consideración / crítica.
Dado que me gustaría
- 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, - 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,
- 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 y 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 usando cadenas estáticas (por ejemplo, "Usuario" más arriba), pero cada vez 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 y cuando 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 charla 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 a continuación aquí, 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 motivo 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émosle 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, admito que tengo poca idea de lo que estoy haciendo; sin embargo, estoy dispuesto a que me derriben 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.
Acabo de lanzar una gema llamada dry_i18n: https://rubygems.org/gems/dry_i18n
Creé esta gema para resolver el problema que pediste. Con esta gema podrás incluso reutilizar las claves con interpolaciones y anidarlas.
Espero que sea útil.
Acabo de lanzar una gema llamada i18n-recursive-lookup que permite que una definición contenga referencias incrustadas a otras definiciones mediante la introducción del 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 compiladas, 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 sobre cuál es la forma "correcta" de SECAR las traducciones, pero pensé que es una mejor alternativa al uso del & Yack de referencia de etiqueta 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: "Электропочта"
link usuario
TLDNR; ¡No hackee su formato de archivo, mejore los ayudantes de rieles 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 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 funcionan para YAML, por lo que esta solución no se puede aplicar de forma genérica 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 algún tipo 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 rieles que han evolucionado con diferentes valores predeterminados sin que exista una convención para las 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 rieles y las traducciones que usan el atajo de punto.
Permítame darle un ejemplo de un flujo de trabajo que es muy frecuente:
- 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 ponerlo en funcionamiento rápidamente, y traducir en masa atributos simples.
- 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'' ))
- Más tarde aún, el encargado de marketing tiene la brillante 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 a las de nuestros desarrolladores aquí (lamentablemente).
En el lado positivo, podemos aclarar qué tipo de contenido estamos describiendo y reflejarlo en nuestras estructuras clave y en nuestras herramientas, ¡para mí es el camino a seguir! :)