25

这个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

您仍然可以继续使用静态字符串(例如上面的“用户”),但是只要您在视图中获得多个完全相同的单词/短语的实例,您就可以将其重构到字典中。如果基础语言中的键的字典翻译对目标语言没有意义,那么只需将目标语言中的引用值更改为静态字符串或将其作为额外条目添加到目标语言的字典中。我敢肯定,如果每种语言的字典变得太大且笨拙,可以将它们重构到另一个文件中(只要它在翻译文件的顶部重新导入,以便参考工作)。

这种构建 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 中使用 i18n 的方式在 Rails 应用程序中是一个坏主意。难以阅读?维护噩梦?如果我使用(我认为是)该语言的一个特性,它真的被认为是“破解文件格式”吗?

再次感谢 tigrish 驱使我完成这一切。

4

4 回答 4

12

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

TLDR;

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

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

首先,锚点只能真正保证适用于 YAML,因此该解决方案不能普遍应用于 I18n。如果您使用不同的后端,此技术可能不可行。无论是 SQL、Redis 还是 Json,我都不知道它们中的任何一个具有任何类型的符号链接功能。这并没有过多地考虑在引擎盖下,翻译实际上是重复的。

我遇到的第二个也是更大的问题是关于语言学的。您的示例说明所有这些术语在上下文和含义上完全相同。不幸的是,只有在极其简单的示例中才会出现这种情况。

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

我认为在很大程度上,复杂性来自于随着不同默认值而演变的rails helpers,而没有关键结构的约定。

回到您的示例,您提到了我认为非常不同的两件事:使用 rails 助手的 activerecord 属性翻译和使用点快捷方式的查看翻译。

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

  1. 在这种情况下,您使用用户的“名称”字段创建一个表单,您希望使用通用的“名称”属性翻译(label_tag 应该使用类似:'attributes.name')。这是最简单、最干燥的案例,可让您快速启动并运行,批量翻译简单属性。
  2. 过了一会儿,您决定只需要将此模型的用户“姓名”翻译为“全名”,因此您创建了一个在 label_tag 的查找调用中具有更高优先级的新翻译(例如:'activerecord.attributes.users.name' ))
  3. 再后来,营销人员有了一个绝妙的主意,即在此页面上(并且仅在此页面上)将此字段的标签显示为“输入您的时髦新名称”。我们不再描述 name 属性,我们描述的是这种形式的特定视图;这就是点快捷方式将 :'.form.name' 转换为类似 ':users.new.form.name' 的地方。

我们无法使用共享的“字典”来处理这种情况。当然,我们的语言环境文件将是 DRY,但我们的语言/翻译问题与我们在这里的开发人员问题大不相同(遗憾的是)。

从好的方面来说,我们可以更清楚地了解我们正在描述什么样的内容,并在我们的关键结构和工具中反映出来——对我来说,这就是前进的方向!:)

于 2012-06-21T18:10:34.843 回答
5

我刚刚发布了一个名为 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}

好消息是,一旦编译,翻译就会被写回翻译存储,这样所有的插值/递归查找都会发生一次。

我知道这可能无法回答有关干燥翻译的“正确”方法是什么的更多哲学问题,但我认为这是使用 & 标签参考 YML hack 的更好选择。

于 2013-04-19T18:38:10.430 回答
1

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

有用的链接

于 2016-03-19T00:18:14.213 回答
0

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

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

我希望它是有用的。

于 2016-06-12T13:57:07.400 回答