Skip to content

Instantly share code, notes, and snippets.

@krainboltgreene
Created June 4, 2012 06:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krainboltgreene/2866752 to your computer and use it in GitHub Desktop.
Save krainboltgreene/2866752 to your computer and use it in GitHub Desktop.
accounts_controller:
sign_out:
en: "Sign Out"
index_action:
no_ideas:
en: "You have no ideas, why don't you make some?"
es: "Usted no tiene ninguna idea, ¿por qué no hacer algo?"
posts_controller:
find_posts:
en: "Find Posts"
insufficient_funds:
en: "You don't have sufficient funds."
jp: "あなたが十分な資金を持っていません。"
en:
accounts_controller:
sign_out: "Sign Out"
index_action:
no_ideas: "You have no ideas, why don't you make some?"
posts_controller:
find_posts: "Find Posts"
insufficient_funds: "You don't have sufficient funds."
es:
accounts_controller:
index_action:
no_ideas: "Usted no tiene ninguna idea, ¿por qué no hacer algo?"
jp:
insufficient_funds: "あなたが十分な資金を持っていません。"
{
"accounts_controller": {
"sign_out": {
"en": "Sign Out"
},
"index": {
"no_ideas": {
"en": "You have no ideas, why don't you make some?",
"es": "Usted no tiene ninguna idea, ¿por qué no hacer algo?"
}
}
},
"posts_controller": {
"find_posts": {
"en": "Find Posts"
}
},
"insuficient_funds": {
"en": "You don't have sufficient funds.",
"jp": "あなたが十分な資金を持っていません。"
}
}
{
"en": {
"accounts_controller": {
"sign_out": "Sign Out",
"index_action": {
"no_ideas": "You have no ideas, why don't you make some?"
}
},
"posts_controller": {
"find_posts": "Find Posts"
},
"insufficient_funds": "You don't have sufficient funds."
},
"jp": {
"insufficient_funds": "あなたが十分な資金を持っていません。"
},
"es": {
"accounts_controller": {
"index_action": {
"no_ideas": "Usted no tiene ninguna idea, ¿por qué no hacer algo?"
}
}
}
}
@krainboltgreene
Copy link
Author

I posit that locale-as-root for i18n translation trees is an anti-pattern. There must be at least two key elements present to formally distinguish an actual anti-pattern from a simple bad habit, bad practice, or bad idea:

  • Some repeated pattern of action, process or structure that initially appears to be beneficial, but ultimately produces more bad consequences than beneficial results, and
  • An alternative solution exists that is clearly documented, proven in actual practice and repeatable.

Here I've provided two examples, in both JSON and YAML, that describe both the common practice way of building i18n locale trees. Here are the problems presented from this form of structure:

  • Changes to one tree must invariably be made to all trees. This leads to a situation where you need to make 1+n changes, where n is the number of locales supported.
  • It is not immediately obvious which which locales are missing which structure, requiring human matching and searching.
  • The common pattern does not lend itself to database representations of the structure and can lead to worse indexing.
  • Adding sub-locales (en-us, en-br, etc) requires duplicating the entire tree.

@lancejpollard
Copy link

Interesting take, not sure I agree though. Both ways have pros and cons. It seems like it can be solved by having a precompiler.

The method you're proposing does have the following characteristics:

  • decreases duplication
  • prevents having to port changes in one tree to all trees
  • is not immediately obvious if all the locales have filled out all the properties (run into this a lot myself)

(not quite sure what you mean by your last point about not lending to database representation)

However, it also means you have to bundle all your locales into one huge bundle. That's the main reason they keep it separate from what I see. If you're in the US you only need english, no spanish/japanese/etc. That would be unnecessary download overhead. Also, if I'm developing the en-us locale, I don't want to be distracted by japanese characters right below.

So it seems a workaround to get the benefits of both would be: prevent the "one large bundle", while also decreasing code duplication and all the things you mentioned. The system would accomplish this by transforming your new version to the original rails version. This way you can write it how you like, while getting the benefit of having separate locales. (But there's still the issue that it's confusing to have 10 or 20 different languages in a row for each attribute).

To get around the problem of not knowing if you've ported all fields to the other language (or handled changes in the locale structure), there should be a hidden file that keeps track of the state of the locales, and when one is changed, you run a command and it transforms the fields in the other locales. This is something like how the asset manifest.json works in Rails 3 (and Tower). It's also how paperclip knows how to update your already-updated thumbnails if you've later changed your styles definition (it stores your thumbnail styles in a hidden/tmp file somewhere). You can do this automatically by defining a "template" locale file, which is watched for changes, and when changed updates all of the implementation locales.

@krainboltgreene
Copy link
Author

(not quite sure what you mean by your last point about not lending to database representation)

Representing the locales structure in a document database does not work if you have language as root. You end up with a finite list of root documents (languages) and infinite key/values. The other way you have infinite documents (the identifiers) with finite key/values (the locales and their respective text).

However, it also means you have to bundle all your locales into one huge bundle.

This happens anyways, you always have to bundle the entire thing into a single structure (with multiple root nodes). In this case, however, you can have infinite root nodes. I always suggest having global, controller specific, and controller+action specific.

But there's still the issue that it's confusing to have 10 or 20 different languages in a row for each attribute

I'm not sure that's an issue, I would have to ask a translator. You could always have a default be a specific language:

{
  "posts_controller": "Red Light"
}

instead of

{
  "posts_controller": { "en": "Red Light" }
}

I think ultimately a preprocessor is overkill. Having simple json files with the end nodes identifying the language would require less work and ultimately less magic.

@krainboltgreene
Copy link
Author

Oh, and example of the database version is things like Copycopter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment