使用词典重构Ruby on Rails i18n YAML文件

这个 StackOverflow问题给了我一些关于Rails i18n文件的良好结构的思考,所以我想我会分享另一个结构来重构Rails i18n yml文件供您考虑/批评。

鉴于我想

  1. 保持默认的应用程序结构,这样我就可以在我的视图中使用像t('.some_translation')这样的简写“懒惰”查找,并且知道在应用程序中使用翻译的地方,
  2. 避免尽可能多的字符串重复,特别是使用不仅相同的单词,但也有相同的上下文/含义,
  3. 只需更改一次密钥就可以反映出它引用的所有地方,

对于config / locales / en.yml文件,看起来像这样:

 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 

我可以看到存在重大的重复,并且诸如“电子邮件”和“密码”之类的词语的上下文是明确的并且在它们各自的视图中具有相同的含义。 如果我决定将“电子邮件”更改为“电子邮件”,那么必须去更改它们会有点烦人,所以我想重构字符串以引用某种字典。 那么,如何将字典哈希添加到文件的顶部,其中包含一些&锚点:

 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 

您仍然可以继续使用静态字符串(例如上面的“User”),但是只要您在视图中获得完全相同的单词/短语的多个实例,就可以将其重构为字典。 如果基本语言中的键的字典翻译对目标语言没有意义,则只需将目标语言中的引用值更改为静态字符串,或将其作为额外条目添加到目标语言的字典中。 我确信每个语言的字典都可以重构成另一个文件,如果它们变得太大而且不实用(只要它在翻译文件的顶部重新导入,这样引用就可以了)。

这种结构化i18n yaml文件的方式似乎适用于我尝试过的一些本地测试应用程序。 我希望美妙的Localeapp将来会为这种锚定/引用提供支持。 但无论如何,所有这些词典谈话都不可能是一个原创的想法,那么在YAML中是否存在锚定引用的其他问题,或者可能只是整个“词典”概念? 或者,如果你有超出Rails默认i18n约定的需求,那么完全删除默认后端并用Redis替换它会更好吗?

编辑

我想尝试解决下面评论中提到的tigrish的工作流程示例,而不是作为他答案下面的另一条评论。 如果我似乎没有得到积分或者我只是天真,请原谅我:

第1点 :您有一个ActiveRecord模型的通用“名称”属性,它们都只是指向通用字典的名称:

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

第2点 :仅需要更改用户模型的名称。 其他名字保持不变。

选项1 :在后端保持模型字段名称相同,只需更改它指向的前端转换。

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

选项2 :同时更改用户模型字段名称。 这需要更改代码中对此键的任何引用,以及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 

选项3 :如果您想要非常彻底,请将“名称”中包含的信息重构为单独的数据库/ Activemodel字段,这些字段需要新的字典条目和迁移。 您可以决定如何显示“全名”的视图:

 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 

第3点 :任何人因任何原因需要翻译,在这种情况下营销。 我将从第2点选项1的例子开始

选项1 :模型字段名称相同,只需更改前端翻译。

 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 

选项2 :由于某种原因,迫切需要将“Funky name”保存到数据库中。 如果没有人反对,我们称之为username (如果由于某种原因营销坚持,则称为funky_name )。

 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 

是的,所以我承认我不知道自己在做什么,但是,我愿意公开拍摄,以便了解为什么在Haml中使用这种方式在Haml中使用i18n是一个坏主意。 难以阅读? 维修噩梦? 如果我使用(我认为是)语言的一个特征,它真的被认为是“黑客文件格式”吗?

再次感谢tigrish让我把这一切都拿出来。

TLDNR; 不要破解您的文件格式,改进rails帮助程序并帮助建立标准化的密钥结构!

TLDR;

不想在你的游行中下雨,但我对这种技术有一些问题。 在哪里使用点快捷方式以及铁轨助手的键结构如何不同的困境可能有点令人费解。

据我了解,问题基本上是关于干燥你的语言环境文件和使用YAML语言的function来实现这一点。

首先,锚点只能保证适用于YAML,所以这个解决方案不能一般地应用于I18n。 如果使用不同的后端,此技术可能不可行。 无论是SQL,Redis还是Json,我都不知道它们中有任何一种具有任何类型的符号链接function。 而且,在引擎盖下,翻译实际上是重复的事实并没有太多。

我遇到的第二个也是更大的问题是关于语言学。 您的示例表明所有这些术语在上下文和含义上完全相同。 不幸的是,这只是非常简单的例子。

毫无疑问,随着您的应用程序的增长或添加其他语言,您会发现Person的“name”属性必须与Book的“name”属性不同,在英语中我们称之为“title” – 好的,这个例子真的很复杂;)但是当你混合使用越来越多的语言时,这种情况确实经常发生,理想情况下,我们需要一种处理它的通用方法。

我认为在很大程度上,复杂性来自使用不同默认值的rails帮助程序,而没有关键结构的约定。

回到你的例子,你提到了我认为非常不同的两件事:activerecord属性翻译使用rails助手和使用点快捷键的视图翻译。

让我举一个超常频繁的工作流程示例:

  1. 在这种情况下,您使用用户的“名称”字段创建表单,您希望使用通用的“名称”属性转换(label_tag应使用类似:’attributes.name’)。 这是最简单的DRYest案例,可以帮助您快速启动和运行,批量转换简单属性。
  2. 不久之后,您决定只为此模型将用户的“名称”翻译为“全名”,以便您在label_tag的查询调用中创建一个具有更高优先级的新翻译(例如:’activerecord.attributes.users.name’ ))
  3. 后来,营销人员有一个绝妙的想法,就是在这个页面上显示这个字段的标签为“输入你时髦的新名字”(仅在这个页面上)。 我们不再描述name属性了,我们正在描述这种forms的特定视图; 这是点快捷方式转换为:’。form.name’的地方,如’:users.new.form.name’。

我们无法用共享的“字典”处理这种情况。 当然我们的语言环境文件是干的,但我们的语言/翻译问题与我们的开发人员关注的问题有很大不同(遗憾的是)。

从好的方面来说,我们可以更清楚地了解我们正在描述的内容,并在我们的关键结构和工具中反映出来 – 对我而言,这是前进的方向! 🙂

我只是发布一个名为i18n-recursive-lookup的gem,它允许定义通过引入特殊的嵌入式标记$ {}来包含对其他定义的嵌入式引用

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

使用它你可以将你的例子重构为:

 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} 

好消息是,一旦编译,翻译就会被写回翻译商店,以便所有插值/递归查找都会发生一次。

我知道这可能无法回答关于干燥翻译的“正确”方法的更多哲学问题,但我认为这是使用&label参考YML hack的更好的替代方法。

改进重新格式化YAML文件,特别是对于那些有很多模型的人:

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

用户链接

我刚刚发布了一个叫做dry_i18n的gem: https ://rubygems.org/gems/dry_i18n

我创建了这个gem来解决你要求的问题。 有了这个gem,你甚至可以重复使用带插值的键并嵌套它们。

我希望它有用。