ember-i18n
Advanced tools
Comparing version 2.9.0 to 3.0.0-beta.1
{ | ||
"name": "ember-i18n", | ||
"version": "2.9.0", | ||
"version": "3.0.0-beta.1", | ||
"description": "I18n support for Ember.js", | ||
@@ -9,3 +9,3 @@ "main": [ "lib/i18n.js" ], | ||
"handlebars": "^1.0", | ||
"ember": ">=1.0 <1.9" | ||
"ember": "^1.0" | ||
}, | ||
@@ -12,0 +12,0 @@ "scripts": { |
@@ -0,4 +1,17 @@ | ||
## 3.0.0 (In Beta) | ||
* Drop support for `CLDR.js` in favor of the included | ||
`i18n-plurals.js` | ||
* Always use custom compiler; drop support for | ||
I18N_COMPILE_WITHOUT_HANDLEBARS; drop support for using | ||
the Handlebars compiler if full Handlebars is available. | ||
* `{{t}}` helper obeys Ember-1-style argument quoting; | ||
unquoted arguments, including the key itself, are bound | ||
references | ||
* `{{t}}` helper no longer supports passing a `tagName` | ||
* Drop support for `I18N_TRANSLATE_HELPER_SPAN` flag | ||
## 2.9.0 2014-10-20 | ||
* Ember 2.9+ is not compatible with Ember 1.9+ | ||
* Ember-I18n 2.9+ is not compatible with Ember 1.9+ | ||
* Use `Ember.$.isFunction` instead of `jQuery.isFunction` | ||
@@ -5,0 +18,0 @@ * Deprecate use of `tagName` in the `{{t}}` helper |
@@ -224,3 +224,3 @@ (function(globals) { | ||
if (count == null) { throw new Error("Ember.I18n.pluralForm requires a count"); } | ||
language = language || Ember.I18n.locale || (globals.CLDR && globals.CLDR.defaultLanguage); | ||
language = language || Ember.I18n.locale; | ||
if (language == null) { throw new Error("Ember.I18n.pluralForm requires a language"); } | ||
@@ -227,0 +227,0 @@ language = language.replace(/^(\w\w\w?)-?.*/, "$1"); |
147
lib/i18n.js
(function(window) { | ||
var I18n, assert, findTemplate, get, set, isBinding, lookupKey, | ||
var I18n, assert, findTemplate, get, set, lookupKey, | ||
PlainHandlebars, EmHandlebars, keyExists; | ||
@@ -7,8 +7,6 @@ | ||
EmHandlebars = Ember.Handlebars; | ||
get = EmHandlebars.get; | ||
get = Ember.get; | ||
set = Ember.set; | ||
assert = Ember.assert; | ||
function warn(msg) { Ember.Logger.warn(msg); } | ||
lookupKey = function(key, hash) { | ||
@@ -58,3 +56,4 @@ var firstKey, idx, remainingKeys; | ||
if (isTranslatedAttributeMatch) { | ||
fn.call(object, isTranslatedAttributeMatch[1], I18n.t(object[key])); | ||
var translation = object[key] == null ? null : I18n.t(object[key]); | ||
fn.call(object, isTranslatedAttributeMatch[1], translation); | ||
} | ||
@@ -64,40 +63,10 @@ } | ||
var compileImplementation; | ||
function compileTemplate(template) { | ||
if (compileImplementation === undefined) { | ||
compileImplementation = selectCompileImplementation(); | ||
} | ||
return compileImplementation(template); | ||
return function(data) { | ||
return template.replace(/\{\{(.*?)\}\}/g, function(i, match) { | ||
return data[match]; | ||
}); | ||
}; | ||
} | ||
function selectCompileImplementation() { | ||
var flag = Ember.ENV.I18N_COMPILE_WITHOUT_HANDLEBARS; | ||
if (flag === true) { | ||
return function compileWithoutHandlebars(template) { | ||
return function (data) { | ||
return template.replace(/\{\{(.*?)\}\}/g, function(i, match) { | ||
return data[match]; | ||
}); | ||
}; | ||
}; | ||
} | ||
if (flag === undefined) { | ||
warn("Ember.I18n will no longer include Handlebars compilation by default in the future; instead, it will supply its own default compiler. Set Ember.ENV.I18N_COMPILE_WITHOUT_HANDLEBARS to true to opt-in now."); | ||
} | ||
if (typeof PlainHandlebars.compile === 'function') { | ||
return function compileWithHandlebars(template) { | ||
return PlainHandlebars.compile(template); | ||
}; | ||
} else { | ||
return function cannotCompileTemplate() { | ||
throw new Ember.Error('The default Ember.I18n.compile function requires the full Handlebars. Either include the full Handlebars or override Ember.I18n.compile.'); | ||
}; | ||
} | ||
} | ||
I18n = Ember.Evented.apply({ | ||
@@ -130,3 +99,3 @@ pluralForm: undefined, | ||
if (context == null) context = {}; | ||
template = I18n.template(key, context.count); | ||
template = I18n.template(key, get(context, 'count')); | ||
return template(context); | ||
@@ -168,93 +137,6 @@ }, | ||
isBinding = /(.+)Binding$/; | ||
// Generate a universally unique id | ||
var _uuid = 0; | ||
function uniqueElementId() { | ||
var i = ++_uuid; | ||
return 'i18n-' + i; | ||
} | ||
var TranslationView = Ember._MetamorphView.extend({ | ||
translationKey: null, | ||
wrappingTagName: Ember.computed(function(propertyName, newValue) { | ||
if (arguments.length > 1 && newValue != null) { return newValue; } | ||
var useSpanByDefault; | ||
if (Ember.FEATURES.hasOwnProperty('I18N_TRANSLATE_HELPER_SPAN')) { | ||
useSpanByDefault = Ember.FEATURES.I18N_TRANSLATE_HELPER_SPAN; | ||
} else { | ||
Ember.deprecate('The {{t}} helper will no longer use a <span> tag in future versions of Ember.I18n. Set Ember.FEATURES.I18N_TRANSLATE_HELPER_SPAN to false to quiet these warnings and maintain older behavior.'); | ||
useSpanByDefault = true; | ||
} | ||
return useSpanByDefault ? 'span' : null; | ||
}), | ||
render: function(buffer) { | ||
var wrappingTagName = this.get('wrappingTagName'); | ||
var text = Ember.I18n.t(this.get('translationKey'), this.get('context')); | ||
if (wrappingTagName) { buffer.push('<' + wrappingTagName + ' id="' + uniqueElementId() + '">'); } | ||
buffer.push(text); | ||
if (wrappingTagName) { buffer.push('</' + wrappingTagName + '>'); } | ||
} | ||
EmHandlebars.registerBoundHelper('t', function(key, options) { | ||
return new PlainHandlebars.SafeString(I18n.t(key, options.hash)); | ||
}); | ||
EmHandlebars.registerHelper('t', function(key, options) { | ||
var context = this; | ||
var data = options.data; | ||
var attrs = options.hash; | ||
var tagName = attrs.tagName; | ||
delete attrs.tagName; | ||
if (options.types[0] !== 'STRING') { | ||
warn("Ember.I18n t helper called with unquoted key: %@. In the future, this will be treated as a bound property, not a string literal.".fmt(key)); | ||
} | ||
Ember.deprecate('Passing a tagName to the {{t}} helper is deprecated and will be removed in v3.0.', tagName == null); | ||
var translationView = TranslationView.create({ | ||
context: attrs, | ||
translationKey: key, | ||
wrappingTagName: tagName | ||
}); | ||
Ember.keys(attrs).forEach(function(property) { | ||
var isBindingMatch = property.match(isBinding); | ||
if (!isBindingMatch) { return; } | ||
var propertyName = isBindingMatch[1]; | ||
var bindPath = attrs[property]; | ||
var currentValue = get(context, bindPath, options); | ||
attrs[propertyName] = currentValue; | ||
var invoker = null; | ||
var normalized = EmHandlebars.normalizePath(context, bindPath, data); | ||
var _ref = [normalized.root, normalized.path], root = _ref[0], normalizedPath = _ref[1]; | ||
var observer = function() { | ||
if (translationView.$() == null) { | ||
Ember.removeObserver(root, normalizedPath, invoker); | ||
return; | ||
} | ||
attrs[propertyName] = get(context, bindPath, options); | ||
translationView.rerender(); | ||
}; | ||
invoker = function() { | ||
Ember.run.scheduleOnce('afterRender', observer); | ||
}; | ||
return Ember.addObserver(root, normalizedPath, invoker); | ||
}); | ||
data.view.appendChild(translationView); | ||
}); | ||
var attrHelperFunction = function(options) { | ||
@@ -277,7 +159,2 @@ var attrs, result; | ||
if (typeof CLDR !== "undefined") { | ||
Ember.deprecate("CLDR.js has been deprecated; use Ember-I18n's i18n-plurals.js instead."); | ||
Ember.I18n.pluralForm = CLDR.pluralForm; | ||
} | ||
}).call(undefined, this); |
{ | ||
"name": "ember-i18n", | ||
"version": "2.9.0", | ||
"version": "3.0.0-beta.1", | ||
"licence": "APLv2", | ||
@@ -5,0 +5,0 @@ "description": "Internationalization for Ember", |
@@ -7,6 +7,6 @@ ## Ember-I18n | ||
Ember-I18n 2.x (the current stable branch) requires | ||
Ember-I18n requires | ||
* Ember v1.0 - v1.8. **Note: v1.9 and above will be supported in Ember-I18n v3.x.** | ||
* Handlebars v1.x | ||
* Ember v1.x | ||
* Handlebars-runtime v1.x - v2.x | ||
* jQuery v1.7 - v2.x | ||
@@ -22,7 +22,2 @@ | ||
Set `Ember.ENV.I18N_COMPILE_WITHOUT_HANDLEBARS = true;` before including | ||
ember-i18n to use the new translation compiler that does not depend on the full | ||
Handlebars. The older Handlebars-based compiler has been deprecated and | ||
will be removed in a future release. | ||
If you want to support inflection based on `count`, you will | ||
@@ -33,18 +28,2 @@ also need to include Ember-I18n's pluralization support (`lib/i18n-plurals.js`) | ||
#### New: I18N_TRANSLATE_HELPER_SPAN | ||
In previous versions of Ember-I18n, the `{{t}}` helper emitted a `<span>` tag | ||
by default; the tag name could be changed, but the tag could not be removed. | ||
Ember-I18n now uses Metamorph tags so it no longer requires a wrapping tag. | ||
Emitting a `<span>` is still the default for backwards-compatibility reasons, | ||
but this will change in the next major release. If you wish to opt to | ||
tagless translations, set | ||
```js | ||
Ember.FEATURES.I18N_TRANSLATE_HELPER_SPAN = false; | ||
``` | ||
The examples below assume this feature flag is set to `true` (the default). | ||
### Examples | ||
@@ -72,3 +51,3 @@ | ||
<script id="metamorph-28-start"></script> | ||
<span id="i18n-123">Edit User</span> | ||
Edit User | ||
<script id="metamorph-28-end"></script> | ||
@@ -78,13 +57,2 @@ </h2> | ||
#### Emit directly into the h2: | ||
```html | ||
{{t "user.edit.title" tagName="h2"}} | ||
``` | ||
yields | ||
```html | ||
<script id="metamorph-28-start"></script> | ||
<h2 id="i18n-123">Edit User</h2> | ||
<script id="metamorph-28-end"></script> | ||
``` | ||
#### Set interpolated values directly: | ||
@@ -98,3 +66,3 @@ ```html | ||
<script id="metamorph-28-start"></script> | ||
<span id="i18n-123">All 2 Followers</span> | ||
All 2 Followers | ||
<script id="metamorph-28-end"></script> | ||
@@ -112,3 +80,3 @@ </h2> | ||
<script id="metamorph-28-start"></script> | ||
<span id="i18n-123">All 2 Followers</span> | ||
All 2 Followers | ||
<script id="metamorph-28-end"></script> | ||
@@ -115,0 +83,0 @@ </h2> |
@@ -27,8 +27,6 @@ var fs = require('fs'), | ||
outputPath = 'spec/suite.html', | ||
withoutHandlebars = (process.env.WITHOUT_HANDLEBARS === 'true'), | ||
templateData = { | ||
emberVersion: versionFor('ember'), | ||
jQueryVersion: versionFor('jquery'), | ||
handlebarsVersion: versionFor('handlebars'), | ||
withoutHandlebars: withoutHandlebars | ||
handlebarsVersion: versionFor('handlebars') | ||
}; | ||
@@ -35,0 +33,0 @@ fs.writeFileSync(outputPath, compiledTemplate(templateData)); |
@@ -12,2 +12,3 @@ #!/usr/bin/env node | ||
"ember-beta": "http://builds.emberjs.com/beta/ember.js", | ||
"ember-canary": "http://builds.emberjs.com/canary/ember.js", | ||
@@ -19,3 +20,4 @@ "jquery-1.9.1": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js", | ||
"handlebars-1.1.0": "https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.1.0/handlebars.js", | ||
"handlebars-1.3.0": "https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.3.0/handlebars.js" | ||
"handlebars-1.3.0": "https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.3.0/handlebars.js", | ||
"handlebars-2.0.0": "https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.js" | ||
}; | ||
@@ -22,0 +24,0 @@ |
@@ -6,3 +6,3 @@ describe('Ember.I18n.eachTranslatedAttribute', function() { | ||
spy = sinon.spy(); | ||
var object = { aKey: 'a value', titleTranslation: 'foo.bar' }; | ||
var object = { aKey: 'a value', titleTranslation: 'foo.bar', aNullTranslation: null }; | ||
Ember.I18n.eachTranslatedAttribute(object, spy); | ||
@@ -18,2 +18,6 @@ }); | ||
}); | ||
it('calls the callback with null if the translation key is null', function() { | ||
expect(spy.calledWithExactly('aNull', null)).to.equal(true); | ||
}); | ||
}); |
@@ -10,7 +10,3 @@ describe('TranslateableProperties', function() { | ||
}); | ||
describe('TranslateableProperties update', function() { | ||
it('translates ___Translation attributes on the object and updates them when set', function() { | ||
it('updates translations when the upstream value changes', function() { | ||
var subject = Ember.Object.extend(Ember.I18n.TranslateableProperties).create({ | ||
@@ -17,0 +13,0 @@ titleTranslation: 'foo.bar' |
describe('{{t}}', function() { | ||
var warn; | ||
beforeEach(function() { | ||
// compatibility mode: | ||
Ember.FEATURES.I18N_TRANSLATE_HELPER_SPAN = true; | ||
warn = sinon.spy(Ember.Logger, 'warn'); | ||
}); | ||
afterEach(function() { | ||
warn.restore(); | ||
}); | ||
it('outputs simple translated strings', function() { | ||
@@ -23,39 +11,35 @@ var view = this.renderTemplate('{{t "foo.bar"}}'); | ||
it('emits a warning on unquoted keys', function() { | ||
it('supports bound keys', function() { | ||
var view = this.renderTemplate('{{t view.key}}', { key: 'foo.bar' }); | ||
var view = this.renderTemplate('{{t foo.bar}}'); | ||
Ember.run(function() { | ||
expect(warn.callCount).to.equal(1); | ||
expect(warn.lastCall.args[0]).to.match(/unquoted/); | ||
expect(warn.lastCall.args[0]).to.match(/foo\.bar/); | ||
expect(view.$().text()).to.equal('A Foobar'); | ||
}); | ||
}); | ||
it('interpolates values', function() { | ||
var view = this.renderTemplate('{{t "bars.all" count="597"}}'); | ||
Ember.run(view, 'set', 'key', 'foo.save.disabled'); | ||
Ember.run(function() { | ||
expect(view.$().text()).to.equal('All 597 Bars'); | ||
expect(view.$().text()).to.equal('Saving Foo...'); | ||
}); | ||
}); | ||
it('interpolates bindings', function() { | ||
var view = this.renderTemplate('{{t "bars.all" countBinding="view.count"}}', { count: 3 }); | ||
it('interpolates literal values', function() { | ||
var view = this.renderTemplate('{{t "bars.all" count="597"}}'); | ||
Ember.run(function() { | ||
expect(view.$().text()).to.equal('All 3 Bars'); | ||
expect(view.$().text()).to.equal('All 597 Bars'); | ||
}); | ||
}); | ||
it('responds to updates on bound properties', function() { | ||
var view = this.renderTemplate('{{t "bars.all" countBinding="view.count"}}', { count: 3 }); | ||
it('interpolates bound values', function() { | ||
var view = this.renderTemplate('{{t "foos" countBinding="view.count"}}', { count: 1 }); | ||
Ember.run(function() { | ||
view.set('count', 4); | ||
expect(view.$().text()).to.equal('One Foo'); | ||
}); | ||
Ember.run(view, 'set', 'count', 4); | ||
Ember.run(function() { | ||
expect(view.$().text()).to.equal('All 4 Bars'); | ||
expect(view.$().text()).to.equal('All 4 Foos'); | ||
}); | ||
@@ -87,28 +71,2 @@ }); | ||
}); | ||
it('handles interpolations from contextual keywords', function() { | ||
var view = this.renderTemplate('{{t "foo.bar.named" nameBinding="view.favouriteBeer" }}', { | ||
favouriteBeer: 'IPA' | ||
}); | ||
Ember.run(function() { | ||
expect(view.$().text()).to.equal('A Foobar named IPA'); | ||
}); | ||
}); | ||
it('responds to updates on bound keyword properties', function() { | ||
var view = this.renderTemplate('{{t "foo.bar.named" nameBinding="view.favouriteBeer"}}', { | ||
favouriteBeer: 'Lager' | ||
}); | ||
expect(view.$().text()).to.equal('A Foobar named Lager'); | ||
Ember.run(function() { | ||
view.set('favouriteBeer', 'IPA'); | ||
}); | ||
Ember.run(function() { | ||
expect(view.$().text()).to.equal('A Foobar named IPA'); | ||
}); | ||
}); | ||
}); | ||
@@ -115,0 +73,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
57192
31
1060
3
2
166