Skip to content

Commit

Permalink
feat(t-attribute): fallback on missing key
Browse files Browse the repository at this point in the history
if a missing key is provided to the T-Attribute, the original
value (text/innerhtml) is kept and a warning logged to the console

fixes issue #267
  • Loading branch information
zewa666 committed May 5, 2018
1 parent 71099bc commit 976157b
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 18 deletions.
3 changes: 3 additions & 0 deletions doc/article/en-US/i18n-with-aurelia.md
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,9 @@ property plugin `instance.setup` function parameter.
</source-code>
</code-listing>

> Passing the option `skipTranslationOnMissingKey` during plugin initialization, will keep your original contents in place and instead add a warning in the console
about trying to update an element without a matching key.

Any element in your views that has one of those attributes, will be translated when the locale is changed.

<code-listing heading="Attribute based translation with the TCustomAttribute">
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"url": "https://github.com/aurelia/i18n/issues"
},
"scripts": {
"build": "gulp build",
"precommit": "gulp lint",
"test": "karma start"
},
Expand Down
34 changes: 21 additions & 13 deletions src/i18n.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*eslint no-cond-assign: 0*/
import * as LogManager from 'aurelia-logging';
import i18next from 'i18next';
import {DOM, PLATFORM} from 'aurelia-pal';
import {EventAggregator} from 'aurelia-event-aggregator';
import {BindingSignaler} from 'aurelia-templating-resources';
import { DOM, PLATFORM } from 'aurelia-pal';
import { EventAggregator } from 'aurelia-event-aggregator';
import { BindingSignaler } from 'aurelia-templating-resources';

export class I18N {
static inject = [EventAggregator, BindingSignaler];
Expand All @@ -27,6 +27,7 @@ export class I18N {

setup(options?): Promise<any> {
const defaultOptions = {
skipTranslationOnMissingKey: false,
compatibilityAPI: 'v1',
compatibilityJSON: 'v1',
lng: 'en',
Expand All @@ -53,7 +54,7 @@ export class I18N {
}

setLocale(locale): Promise<any> {
return new Promise( resolve => {
return new Promise(resolve => {
let oldLocale = this.getLocale();
this.i18next.changeLanguage(locale, (err, tr) => {
this.ea.publish('i18n:locale:changed', { oldValue: oldLocale, newValue: locale });
Expand All @@ -76,7 +77,7 @@ export class I18N {
let comparer = nf.format(10000 / 3);

let thousandSeparator = comparer[1];
let decimalSeparator = comparer[5];
let decimalSeparator = comparer[5];

if (thousandSeparator === '.') {
thousandSeparator = '\\.';
Expand Down Expand Up @@ -190,18 +191,25 @@ export class I18N {
// convert to camelCase
const attrCC = attr.replace(/-([a-z])/g, function(g) { return g[1].toUpperCase(); });
const reservedNames = ['prepend', 'append', 'text', 'html'];
const i18nLogger = LogManager.getLogger('i18n');

if (reservedNames.indexOf(attr) > -1 &&
node.au &&
node.au.controller &&
node.au.controller.viewModel &&
attrCC in node.au.controller.viewModel) {
const i18nLogger = LogManager.getLogger('i18n');
node.au &&
node.au.controller &&
node.au.controller.viewModel &&
attrCC in node.au.controller.viewModel) {
i18nLogger.warn(`Aurelia I18N reserved attribute name\n
[${reservedNames.join(', ')}]\n
Your custom element has a bindable named ${attr} which is a reserved word.\n
If you'd like Aurelia I18N to translate your bindable instead, please consider giving it another name.`);
}

if (this.i18next.options.skipTranslationOnMissingKey &&
this.tr(key, params) === key) {
i18nLogger.warn(`Couldn't find translation for key: ${key}`);
return;
}

//handle various attributes
//anything other than text,prepend,append or html will be added as an attribute on the element.
switch (attr) {
Expand Down Expand Up @@ -254,9 +262,9 @@ If you'd like Aurelia I18N to translate your bindable instead, please consider g
break;
default: //normal html attribute
if (node.au &&
node.au.controller &&
node.au.controller.viewModel &&
attrCC in node.au.controller.viewModel) {
node.au.controller &&
node.au.controller.viewModel &&
attrCC in node.au.controller.viewModel) {
node.au.controller.viewModel[attrCC] = this.tr(key, params);
} else {
node.setAttribute(attr, this.tr(key, params));
Expand Down
1 change: 1 addition & 0 deletions test/unit/relative.time.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ describe('testing relative time support', () => {
signaler.signal('aurelia-relativetime-signal');
expect(elem.innerHTML).toBe('1 second ago');

component.dispose();
done();
}, 1000);
});
Expand Down
34 changes: 34 additions & 0 deletions test/unit/skiptranslation.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { StageComponent } from 'aurelia-testing';
import { bootstrap } from 'aurelia-bootstrapper';

import { bootstrapTestEnvironment } from './staging-helpers';

describe('staged tests', () => {
it('should keep original value instead of fallback to key, when defined via options', done => {
const target = 'fallback-target';
const component = StageComponent
.withResources('test/unit/mocks/rt-vm')
.inView('<h5 id=' + target + ' t="hello">Hello!</h5>')
.boundTo({ mydate: new Date() });

bootstrapTestEnvironment(component, {
resources: {
en: {
translation: {
hello: undefined
}
}
},
skipTranslationOnMissingKey: true
});

component.create(bootstrap)
.then(() => {
const elem = document.getElementById(target);
expect(elem.innerHTML).toBe('Hello!');

component.dispose();
done();
});
});
});
8 changes: 4 additions & 4 deletions test/unit/staging-helpers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Backend } from '../../src/aurelia-i18n-loader';

export function bootstrapTestEnvironment(component, resources) {
export function bootstrapTestEnvironment(component, config) {
component.bootstrap((aurelia) => {
aurelia.use
.standardConfiguration()
Expand All @@ -10,11 +10,11 @@ export function bootstrapTestEnvironment(component, resources) {
// register backend plugin
instance.i18next.use(Backend.with(aurelia.loader));

return instance.setup({

return instance.setup(Object.assign({
backend: { // <-- configure backend settings
loadPath: './locales/{{lng}}/{{ns}}.json' // <-- XHR settings for where to get the files from
},
resources,
interpolation: {
prefix: '{{',
suffix: '}}'
Expand All @@ -24,7 +24,7 @@ export function bootstrapTestEnvironment(component, resources) {
defaultNS: 'translation',
fallbackLng: 'en',
debug: false
});
}, config));
});
});
}
7 changes: 6 additions & 1 deletion test/unit/t-attribute.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@ describe('t-attribute', () => {
.inView(`<div t.bind="integer" id=${target}></div>`)
.boundTo({ integer: 1 });

bootstrapTestEnvironment(component, {en: { translation: { '1': expectedValue}}});
bootstrapTestEnvironment(component, {
resources: {
en: { translation: { '1': expectedValue } }
}
});

component.create(bootstrap)
.then(() => {
const elem = document.getElementById(target);
expect(elem.innerHTML).toBe(expectedValue);

component.dispose();
done();
});
});
Expand Down

0 comments on commit 976157b

Please sign in to comment.