25

このStackOverflowの質問は、Rails i18nファイルの適切な構造について考えるための材料を与えてくれたので、検討/批評のためにRailsi18nymlファイルをリファクタリングするための別の構造を共有したいと思いました。

私がしたいことを考えると

  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

かなりの繰り返しがあり、「Eメール」や「パスワード」などの単語の文脈は明確であり、それぞれの見方で同じ意味を持っていることがわかります。「Email」を「e-mail」に変更することにした場合、すべてを変更しなければならないのは少し面倒なので、ある種の辞書を参照するように文字列をリファクタリングしたいと思います。&したがって、次のようなアンカーを使用して、ファイルの先頭に辞書ハッシュを追加するのはどうでしょうか。

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:何らかの理由で、「ファンキーな名前」もデータベースに保存する必要があります。username誰も反対しない場合(またはfunky_name何らかの理由でマーケティングが主張する場合)、それをaと呼びましょう。

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 ヘルパーを改善し、標準化されたキー構造の確立を支援してください!

TLDR;

パレードに雨を降らせたくないのですが、このテクニックにはいくつか問題があります。ドット ショートカットをどこで使用するか、および Rails ヘルパーのキー構造がどのように異なるかというジレンマは、少し不可解な場合があります。

私が理解しているように、問題は基本的に、ロケール ファイルを DRY し、YAML 言語の機能を使用してこれを実現することです。

まず、アンカーは YAML でのみ機能することが保証されているため、このソリューションを一般的に I18n に適用することはできません。別のバックエンドを使用している場合、この手法はおそらく実行できません。SQL であれ、Redis であれ、Json であれ、シンボリック リンク機能を持っているものはありません。そしてそれは、ボンネットの下で翻訳が実際に複製されているという事実にあまり深く入り込むことはありません.

私が抱えている 2 番目の大きな問題は、言語学に関するものです。あなたの例は、これらすべての用語が文脈と意味において完全に等しいことを示しています。残念ながら、これは非常に単純な例の場合にのみ当てはまります。

間違いなく、アプリが成長したり、言語を追加したりすると、人の「名前」属性は、英語で「タイトル」と呼ばれる書籍の「名前」属性とは区別する必要があることに気付くでしょう。この例は本当に複雑です ;) しかし、より多くの言語を混在させると、この状況が頻繁に発生し、理想的には、これを処理する一般的な方法が必要になります。

複雑さの大部分は、主要な構造の慣習がなく、さまざまなデフォルトで進化した Rails ヘルパーによるものだと思います。

あなたの例に戻ると、私が本当に異なると思う2つのことについて言及しています。レールヘルパーを使用する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}

良い点は、一度コンパイルされた翻訳が翻訳ストアに書き戻されるため、すべての補間/再帰ルックアップが 1 回行われることです。

これは、翻訳を DRY する「正しい」方法についてのより哲学的な質問には答えないかもしれませんが、& ラベル参照 YML ハックを使用するよりも良い代替手段だと思いました。

于 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 に答える