title: Refactoring Ruby on Rails i18n YAML files using dictionaries
body: <p><a href="https://stackoverflow.com/q/10282857/567863">This</a> StackOverflow question gave me food for thought on what is a good structure for Rails i18n files, so I thought I'd share another structure for refactoring Rails i18n yml files for your consideration/criticism.  </p>
  
  <p>Given that I would like to</p>
  
  <ol>
  <li>keep the default app structure so I can use shorthand "lazy" lookups like <code>t('.some_translation')</code> in my views, as well as have an idea where translations are used in the app,</li>
  <li>avoid as much string repetition as possible, in particular with words that are not just the same, but also have identical contexts/meanings,</li>
  <li>only have to change a key once to have it reflected everywhere it's referenced,</li>
  </ol>
  
  <p>for a <strong>config/locales/en.yml</strong> file that looks something like this:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>I can see that there is significant repetition, and that the context of words like "Email" and "Password" are unambiguous and have the same meaning in their respective views.  It would be a bit annoying to have to go and change them all if I decide to change "Email" to "e-mail", so I'd like to refactor the strings to reference a dictionary of some sort.  So, how about adding a dictionary hash to the top of the file with some <code>&amp;</code> anchors like this:</p>
  
  <pre><code>dictionary:
    email: &amp;email Email
    name: &amp;name Name
    password: &amp;password Password
    confirmation: &amp;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
  </code></pre>
  
  <p>You could still continue to use static strings (eg "User" above), but whenever you get more than one instance of exactly the same word/phrase in your views, you could refactor it out to the dictionary.  If the dictionary translation of a key in the base language doesn't make sense for a target language, then just change out the referenced value in the target language to a static string or add it as an extra entry to the target language's dictionary.  I'm sure each language's dictionary could be refactored out into another file if they get too big and unwieldy (as long as it then gets reimported at the top of the translation file so the references work).</p>
  
  <p>This way of structuring i18n yaml files seems to work well with some local test apps I tried it on.  I'm hoping the wonderful <a href="http://www.localeapp.com/" rel="noreferrer">Localeapp</a> will provide support for this kind of anchoring/referencing in the future.  But anyway, all this dictionary talk can't possibly be an original idea, so are there other issues with anchor referencing in YAML, or maybe just with the whole "dictionary" concept in general?  Or is it just better to just rip out the default backend entirely and replace it with <a href="http://redis.io/" rel="noreferrer">Redis</a> or something if you have needs beyond Rails default i18n conventions?</p>
  
  <p><strong>Edit</strong>:</p>
  
  <p>I wanted to try and address tigrish's workflow example mentioned in a comment below up here, rather than as another comment below his answer.  Please excuse me if I don't seem to be getting the points being made or if I'm just naive:</p>
  
  <p><strong>Point 1</strong>: you have a general "name" attribute for ActiveRecord models, and they all just point to the generic dictionary for name:</p>
  
  <pre><code>dictionary:
    name: &amp;name Name
  
  activerecord:
    attributes:
      name: *name
      user:
        name: *name
      product:
        name: *name
  </code></pre>
  
  <p><strong>Point 2</strong>: Name for User model only needs to be changed.  Other names stay the same.</p>
  
  <p><em>Option 1</em>: Keep the model field names the same on the backend and just change the front end translation it points to.</p>
  
  <pre><code>dictionary:
    name: &amp;name Name
    full_name: &amp;full_name Full Name
  
  activerecord:
    attributes:
      name: *name
      user:
        name: *full_name
      product:
        name: *name
  </code></pre>
  
  <p><em>Option 2</em>: Change the User model field name as well.  This would require changing any references to this key in the code, and a <code>change_table</code>/<code>rename_column</code> migration.</p>
  
  <pre><code>dictionary:
    name: &amp;name Name
    full_name: &amp;full_name Full Name
  
  activerecord:
    attributes:
      name: *name
      user:
        full_name: *full_name
      product:
        name: *name
  </code></pre>
  
  <p><em>Option 3</em>: If you want to be very thorough, refactor the information contained in a "name" out in to separate database/Activemodel fields, which would need new dictionary entries and a migration.  You can decide on your views how you would want a "full name" to display:</p>
  
  <pre><code>dictionary:
    name: &amp;name Name
    name_prefix: &amp;name_prefix Prefix
    first_name: &amp;first_name First
    middle_name: &amp;middle_name Middle
    last_name: &amp;last_name Last
    name_suffix: &amp;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
  </code></pre>
  
  <p><strong>Point 3</strong>: Anyone for any reason needs a translation change, Marketing in this case.  I'll follow on from Point 2 Option 1's example</p>
  
  <p><em>Option 1</em>: Model field names same, just change the front end translation.</p>
  
  <pre><code>dictionary:
    name: &amp;name Name
    full_name: &amp;full_name Full Name
    funky_name: &amp;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
  </code></pre>
  
  <p><em>Option 2</em>: "Funky name" desperately needs to be saved to the database, too, for some reason.  Let's call it a <code>username</code> if no one objects (or <code>funky_name</code> if for some reason Marketing insists).</p>
  
  <pre><code>dictionary:
    name: &amp;name Name
    full_name: &amp;full_name Full Name
    funky_name: &amp;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
  </code></pre>
  
  <p>Right, so I admit that I have little idea what I'm doing, however, I'm willing to be shot down publicly in order to understand why this way of working with i18n in Haml is a bad idea in a Rails app.  Difficult to read?  Maintenance nightmare?  Is it really considered 'hacking the file format' if I use (what I think is) a feature of the language?</p>
  
  <p>Thanks again to tigrish for driving me to get all this out.</p>