|
@@ -19,37 +19,70 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
THE SOFTWARE.
|
|
|
*/
|
|
|
-(function() {
|
|
|
- var I18n, findTemplate, getPath, isBinding, isTranslatedAttribute, pluralForm;
|
|
|
+(function(window) {
|
|
|
+ var I18n, assert, findTemplate, get, set, isBinding, lookupKey, pluralForm;
|
|
|
|
|
|
- isTranslatedAttribute = /(.+)Translation$/;
|
|
|
+ get = Ember.Handlebars.get || Ember.Handlebars.getPath || Ember.getPath;
|
|
|
+ set = Ember.set;
|
|
|
|
|
|
- getPath = Ember.Handlebars.getPath || Ember.getPath;
|
|
|
+ function warn(msg) { Ember.Logger.warn(msg); }
|
|
|
|
|
|
if (typeof CLDR !== "undefined" && CLDR !== null) pluralForm = CLDR.pluralForm;
|
|
|
|
|
|
if (pluralForm == null) {
|
|
|
- Ember.Logger.warn("CLDR.pluralForm not found. Em.I18n will not support count-based inflection.");
|
|
|
+ warn("CLDR.pluralForm not found. Em.I18n will not support count-based inflection.");
|
|
|
}
|
|
|
|
|
|
+ lookupKey = function(key, hash) {
|
|
|
+ var firstKey, idx, remainingKeys;
|
|
|
+
|
|
|
+ if (hash[key] != null) { return hash[key]; }
|
|
|
+
|
|
|
+ if ((idx = key.indexOf('.')) !== -1) {
|
|
|
+ firstKey = key.substr(0, idx);
|
|
|
+ remainingKeys = key.substr(idx + 1);
|
|
|
+ hash = hash[firstKey];
|
|
|
+ if (hash) { return lookupKey(remainingKeys, hash); }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ assert = Ember.assert != null ? Ember.assert : window.ember_assert;
|
|
|
+
|
|
|
findTemplate = function(key, setOnMissing) {
|
|
|
- var result;
|
|
|
- Ember.assert("You must provide a translation key string, not %@".fmt(key), typeof key === 'string');
|
|
|
- result = I18n.translations[key];
|
|
|
+ assert("You must provide a translation key string, not %@".fmt(key), typeof key === 'string');
|
|
|
+ var result = lookupKey(key, I18n.translations);
|
|
|
+
|
|
|
if (setOnMissing) {
|
|
|
if (result == null) {
|
|
|
result = I18n.translations[key] = I18n.compile("Missing translation: " + key);
|
|
|
+ warn("Missing translation: " + key);
|
|
|
}
|
|
|
}
|
|
|
- if ((result != null) && !$.isFunction(result)) {
|
|
|
+
|
|
|
+ if ((result != null) && !jQuery.isFunction(result)) {
|
|
|
result = I18n.translations[key] = I18n.compile(result);
|
|
|
}
|
|
|
+
|
|
|
return result;
|
|
|
};
|
|
|
|
|
|
+ function eachTranslatedAttribute(object, fn) {
|
|
|
+ var isTranslatedAttribute = /(.+)Translation$/,
|
|
|
+ isTranslatedAttributeMatch;
|
|
|
+
|
|
|
+ for (var key in object) {
|
|
|
+ isTranslatedAttributeMatch = key.match(isTranslatedAttribute);
|
|
|
+ if (isTranslatedAttributeMatch) {
|
|
|
+ fn.call(object, isTranslatedAttributeMatch[1], I18n.t(object[key]));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
I18n = {
|
|
|
compile: Handlebars.compile,
|
|
|
+
|
|
|
translations: {},
|
|
|
+
|
|
|
template: function(key, count) {
|
|
|
var interpolatedKey, result, suffix;
|
|
|
if ((count != null) && (pluralForm != null)) {
|
|
@@ -59,72 +92,92 @@ THE SOFTWARE.
|
|
|
}
|
|
|
return result != null ? result : result = findTemplate(key, true);
|
|
|
},
|
|
|
+
|
|
|
t: function(key, context) {
|
|
|
var template;
|
|
|
if (context == null) context = {};
|
|
|
template = I18n.template(key, context.count);
|
|
|
return template(context);
|
|
|
},
|
|
|
+
|
|
|
+ TranslateableProperties: Em.Mixin.create({
|
|
|
+ init: function() {
|
|
|
+ var result = this._super.apply(this, arguments);
|
|
|
+ eachTranslatedAttribute(this, function(attribute, translation) {
|
|
|
+ set(this, attribute, translation);
|
|
|
+ });
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }),
|
|
|
+
|
|
|
TranslateableAttributes: Em.Mixin.create({
|
|
|
didInsertElement: function() {
|
|
|
- var attribute, isTranslatedAttributeMatch, key, path, result, translatedValue;
|
|
|
- result = this._super.apply(this, arguments);
|
|
|
- for (key in this) {
|
|
|
- path = this[key];
|
|
|
- isTranslatedAttributeMatch = key.match(isTranslatedAttribute);
|
|
|
- if (isTranslatedAttributeMatch) {
|
|
|
- attribute = isTranslatedAttributeMatch[1];
|
|
|
- translatedValue = I18n.t(path);
|
|
|
- this.$().attr(attribute, translatedValue);
|
|
|
- }
|
|
|
- }
|
|
|
+ var result = this._super.apply(this, arguments);
|
|
|
+ eachTranslatedAttribute(this, function(attribute, translation) {
|
|
|
+ this.$().attr(attribute, translation);
|
|
|
+ });
|
|
|
return result;
|
|
|
}
|
|
|
})
|
|
|
};
|
|
|
|
|
|
- // SC.I18n = I18n;
|
|
|
-
|
|
|
- Em.I18n = I18n;
|
|
|
-
|
|
|
Ember.I18n = I18n;
|
|
|
|
|
|
isBinding = /(.+)Binding$/;
|
|
|
|
|
|
+ // CRUFT: in v2, which requires Ember 1.0+, Ember.uuid will always be
|
|
|
+ // available, so this function can be cleaned up.
|
|
|
+ var uniqueElementId = (function(){
|
|
|
+ var id = Ember.uuid || 0;
|
|
|
+ return function() {
|
|
|
+ var elementId = 'i18n-' + id++;
|
|
|
+ return elementId;
|
|
|
+ };
|
|
|
+ })();
|
|
|
+
|
|
|
Handlebars.registerHelper('t', function(key, options) {
|
|
|
- var attrs, context, elementID, result, tagName, view;
|
|
|
+ var attrs, context, data, elementID, result, tagName, view;
|
|
|
context = this;
|
|
|
attrs = options.hash;
|
|
|
- view = options.data.view;
|
|
|
+ data = options.data;
|
|
|
+ view = data.view;
|
|
|
tagName = attrs.tagName || 'span';
|
|
|
delete attrs.tagName;
|
|
|
- elementID = "i18n-" + (jQuery.uuid++);
|
|
|
+ elementID = uniqueElementId();
|
|
|
+
|
|
|
Em.keys(attrs).forEach(function(property) {
|
|
|
- var bindPath, currentValue, invoker, isBindingMatch, observer, propertyName;
|
|
|
+ var bindPath, currentValue, invoker, isBindingMatch, normalized, normalizedPath, observer, propertyName, root, _ref;
|
|
|
isBindingMatch = property.match(isBinding);
|
|
|
+
|
|
|
if (isBindingMatch) {
|
|
|
propertyName = isBindingMatch[1];
|
|
|
bindPath = attrs[property];
|
|
|
- currentValue = getPath(bindPath);
|
|
|
+ currentValue = get(context, bindPath, options);
|
|
|
attrs[propertyName] = currentValue;
|
|
|
invoker = null;
|
|
|
+ normalized = Ember.Handlebars.normalizePath(context, bindPath, data);
|
|
|
+ _ref = [normalized.root, normalized.path], root = _ref[0], normalizedPath = _ref[1];
|
|
|
+
|
|
|
observer = function() {
|
|
|
var elem, newValue;
|
|
|
- newValue = getPath(context, bindPath);
|
|
|
- elem = view.$("#" + elementID);
|
|
|
- if (elem.length === 0) {
|
|
|
- Em.removeObserver(context, bindPath, invoker);
|
|
|
+ if (view.get('state') !== 'inDOM') {
|
|
|
+ Em.removeObserver(root, normalizedPath, invoker);
|
|
|
return;
|
|
|
}
|
|
|
+ newValue = get(context, bindPath, options);
|
|
|
+ elem = view.$("#" + elementID);
|
|
|
attrs[propertyName] = newValue;
|
|
|
return elem.html(I18n.t(key, attrs));
|
|
|
};
|
|
|
+
|
|
|
invoker = function() {
|
|
|
return Em.run.once(observer);
|
|
|
};
|
|
|
- return Em.addObserver(context, bindPath, invoker);
|
|
|
+
|
|
|
+ return Em.addObserver(root, normalizedPath, invoker);
|
|
|
}
|
|
|
});
|
|
|
+
|
|
|
result = '<%@ id="%@">%@</%@>'.fmt(tagName, elementID, I18n.t(key, attrs), tagName);
|
|
|
return new Handlebars.SafeString(result);
|
|
|
});
|
|
@@ -133,12 +186,14 @@ THE SOFTWARE.
|
|
|
var attrs, result;
|
|
|
attrs = options.hash;
|
|
|
result = [];
|
|
|
+
|
|
|
Em.keys(attrs).forEach(function(property) {
|
|
|
var translatedValue;
|
|
|
translatedValue = I18n.t(attrs[property]);
|
|
|
return result.push('%@="%@"'.fmt(property, translatedValue));
|
|
|
});
|
|
|
+
|
|
|
return new Handlebars.SafeString(result.join(' '));
|
|
|
});
|
|
|
|
|
|
-}).call(this);
|
|
|
+}).call(undefined, this);
|