jamesarosen/ember-i18n — pull request #155 by RSSchermer (2014-10-19 11:17:58+00:00)
Title: Lazy helper lookups

Pull request implementing lazy lookups for the `{{t}}` helper, as per https://github.com/jamesarosen/ember-i18n/issues/154.

There is good news and there is bad news. The good news is that `options.data.view.get('renderedName')` seems to work pretty well for determining the template name.

* It is only defined for top level templates, not for other views or components.
* When including a partial view, the `renderedName` remains the name of the including view, not the included partial view. This could actually be considered useful.
* I was afraid that `renderedName` might actually be based on the route name, rather than the template name, but this is not true. When explicitly changing the template rendered by a route, the `renderedName` becomes the name of that template:

```javascript
// routes/resource/index.js
import Ember from 'ember';

export default Ember.Route.extend({
renderTemplate: function() {
this.render('test');
}
});
// The renderedName of this route's view will now be 'test', not 'resource.index'
```

However, there's also bad news. When using the `{{t}}` inside another view helper, `options.data.view` will be the view of that helper. As mentioned `renderedName` is only defined for top level route views, so it will return `undefined`:

```handlebars

{{#link-to 'resource.index'}}
{{t '.resource-link'}}
{{/link-to}}
```

One way around this is to loop up through the parent views of `options.data.view` until a view is found that does have a `renderedName` property. There is however a further problem with this: Ember's public API seems to treat all the top level route template views as one single view with `renderedName = 'application'`:

```javascript
var view = options.data.view;
var parentView = view.get('parentView');

while (!view.get('renderedName') && parentView) {
view = parentView;
parentView = view.get('parentView');
}
view.get('renderedName') // Always returns 'application'
```

However, Ember's private API does respect the route template views as separate parent views:

```javascript
var view = options.data.view;
var parentView = view.get('_parentView');

while (!view.get('renderedName') && parentView) {
view = parentView;
parentView = view.get('_parentView');
}
view.get('renderedName') // Will correctly return 'test' when the {{t}} helper is used in templates/test.hbs
```

This seems to work perfectly. I've tested this with a largish Ember app I'm working on and didn't get any unexpected results. It does however use Ember's private API. I'm not sure why this difference between `parentView` and `_parentView` exists. Maybe we could ask the person responsible for this API, but I have no idea who that is.

On the subject of testing: I added 2 simple unit tests. I think this may also benefit from integration tests to verify that using it in a certain template produces the right `renderedName`, but I don't know how I'd go about that with the current test setup. Maybe along the lines of how ember cli addons do it with a dummy app, making ember cli a dependency. I think that might be a pretty be refactor though, not sure if you'd wanna go there.

This doesn't work with translatable attributes yet, but I think I could probably use that same looping up through `_parentView` to get that working.