Solution 1:

I've found that the best overall strategy is to somewhat reproduce the file structure so that given any translation, I can immediately find where it was called from. This gives me some kind of context for making the translation.

The majority of application translations are found in views, so my biggest top level namespace is usually views.

I create sub namespaces for the controller name and the action name or partial being used ex :

  • views.users.index.title
  • views.articles._sidebar.header

Both of these examples should make it obvious what part of my app we're translating and which file to look in to find it.

You mention navigation and buttons, if they are to be generic, then they belong in the views.application namespace just as do their view counterparts :

  • views.application._main_nav.links.about_us - a link in our app's main navigation partial
  • views.application.buttons.save
  • views.application.buttons.create - I have a bunch of these buttons ready to be used when needed

Flash messages are generated from the controller, so their top level namespace is... controllers! :)

We apply the same logic as we do to views :

  • controllers.users.create.flash.success|alert|notice

Again if you wanted to provide generic flash messages like "Operation successful", you would write something like this :

  • controllers.application.create.flash.notice

Finally, keys can be anything that is valid YAML, but please stick to using periods . as separators and underscores _ between words as a matter of convention.

The only thing left to sort out now, is getting rails' translations into its own namespace to clean up our top level :)

Solution 2:

I know that an answer has already been accepted, but this question provided me with some food for thought and I thought I'd share another structure for Rails i18n yml files for your consideration/criticism.

Given that I would like to

  1. keep the default app structure so I can use shorthand "lazy" lookups like t('.some_translation') in my views,
  2. avoid as much string repetition as possible, in particular with words that are not just the same, but also have identical contexts/meanings,
  3. only have to change a key once to have it reflected everywhere it's referenced,

for a config/locales/en.yml file that looks something like this:

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

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 & anchors like this:

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

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.

This way of structuring i18n yaml files seemed to work well with some local test apps I tried it on. I'm hoping the wonderful Localeapp 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 Redis or something?