Skip to content

Commit

Permalink
Merge pull request #1 from ioncache/OWP-582
Browse files Browse the repository at this point in the history
Allow for falling back to a default language for translations when none exist for the current language
  • Loading branch information
abendigo authored Apr 11, 2017
2 parents 1cadd14 + 5b13dc6 commit 100a7ce
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 22 deletions.
22 changes: 22 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
language: node_js
sudo: required
dist: trusty
node_js: stable
addons:
firefox: latest
apt:
sources:
- google-chrome
packages:
- google-chrome-stable
before_script:
- npm install -g bower polylint web-component-tester
- bower install
- polylint
script:
- xvfb-run wct
- if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then wct -s default; fi
env:
global:
- secure: DitCRBZSh4YLwnI3LjD1ukbftNDIx6RrUjEYwHi+RMt+OCAkKiY4N0FI9PujlGEnt7tNdaD0CTzLSu+R2vpNeMaqsrjyFKzLfWH8rFRQ1dHCvaqZ1upV92yadzqLW6dhFMMre1OzhMoU0r/4b7hUV93UYAxUZU70WYzJTSjKvv+1ul97UVLMThmulvMBDrOx8cA06SF3oRfZwdxRj7zc8knUZvRmub41exfVonEVYjXdhOstHGLvXBXxmUBOjaTdNNaIT4KvvwMMmMqyQpnoB1uZimTLAy4y4ogpnf9HttPHTSZSTdWI2avk75nlqQCFFCcBier0NWT3phgkQt0CKrKs62w2RwjAIij2/ZVhsUiGLezIuOilG3k3+UYzXHb86KtLMie573XfAsX6cC/DYozJB7NfPA79MOwa/BuzTlyDJdZfKKm8+6FCmh7xQj0OcXHdqqxzTZu40bXwjz32TLDNnkHBdJNjTQrBm//TTQsxZ8BiXiw2tg4r7vXMIr3NjiRLQSLuAiHHQ2MnryhJuvAeBf1cqgjZXxy4mG6ctdus7Fc8nl9GSkY/5VmT4BMGwxbUcdd5/EDf750jwgE/sXzYABABYXd1cwvYPwT5oPsIMOs3hUC5mls+DlTk6Y57EtezsGuvA+EWeyg0rRzuv/u3rfJtOvYV7I7kA9xe/ZU=
- secure: hSCnfwhOhq23wOyRk3vBz4Gz+KBYRaCsekoW9leSQ5LRt7QYF6gESoaiqQaqQ6aL0FX4tW6DCxGStFhwvOcR8EU9J1dz04Xku21bf3haLEFGTpOyDtQwisxw2TKp6ki95FIaBsx6435UvLXn77M3c4X5YW+1N+GKfZ62A/RqP12u6q8c2Sooe70V5E4J7oQS+CW20CvdcfrlEoHgJ89hF7hyu1A5GEj0Y4TJMsNfgqBC7t3k0YMIZ8yEgXRyzxsamKVFaa69U8435Wokol4zcgyVtirXZyKyqVLGk5j5dcUlzlwx4+dpoETrtTsUcIvLyxQ/SxsqBKr3j4u8CMAmKSRkMrDI/Pf6c4Q4H9N+CVOv+VW/TAqD/CnncI9eGaTJ3Ba2HZUMmHImPgBD1a6DqHvaFLbU5J9MHWvwCRBcOwQTAVqaOppgOvmu/mpwNnq9+NJFrwR6aTDgovYzi4TMA9DdoB7O3L6fvwYjqMYRahfukBPSYX5da4DHiQV0P6wEr/Sdub/ERQSgWqXLE6e/jpl4sXBY2rII4Ao3Tc/Xg9suwHjUKvmi8axOyfm0LjE9fmGj1bkFFPKU1JIAbGOaDInbpE6fMjbgpoOeqe6hxRxdrjDn5+/odQhhhUoGNk3YIKuLSeK82lW/ZMgH0/z/NubIQjchIuKDbLqmyX7ZZ2w=
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ thing! https://github.com/PolymerLabs/tedium/issues
-->

[![Build status](https://travis-ci.org/PolymerElements/app-localize-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/app-localize-behavior)


##Polymer.AppLocalizeBehavior

Expand Down
69 changes: 58 additions & 11 deletions app-localize-behavior.html
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,24 @@
* If the element is using `pathToResources` to load an external resources
* file, fired when the file has been loaded.
*
* @event app-resources-loaded
* @event app-localize-resources-loaded
*/

/**
* If the element is using `pathToResources` to load an external resources
* file, fired when the file cannot be loaded due to an error.
*
* @event app-resources-error
* @event app-localize-resources-error
*/

properties: {
/**
* Fallback language to use if a string cannot be found in the desired language
*/
defaultLanguage: {
type: String
},

/**
* The language used for translation.
*/
Expand Down Expand Up @@ -156,6 +163,24 @@
value: function() { return {} }
},

/**
* If true, will use the langauge in the defaultLanguage property
* when the translation does not exist for that key.
*/
useDefaultLanguageIfMissing: {
type: Boolean,
value: false
},

/**
* If true, will use the provided key when
* the translation does not exist for that key.
*/
useKeyIfMissing: {
type: Boolean,
value: false
},

/**
* Translates a string to the current `language`. Any parameters to the
* string should be passed in order, as follows:
Expand All @@ -170,6 +195,11 @@
loadResources: function(path) {
var proto = this.constructor.prototype;

// In the event proto not have __localizationCache object, create it.
if(proto['__localizationCache'] === undefined) {
proto['__localizationCache'] = {requests: {}, messages: {}, ajax: null};
}

// If the global ajax object has not been initialized, initialize and cache it.
var ajax = proto.__localizationCache.ajax;
if (!ajax) {
Expand Down Expand Up @@ -210,30 +240,47 @@

// Cache the key/value pairs for the same language, so that we don't
// do extra work if we're just reusing strings across an application.
var messageKey = key + resources[language][key];
var msg = proto.__localizationCache.messages[messageKey];
var translatedValue = resources[language][key];

// fallback to using the translation from the default language
// if enabled
if (
!translatedValue &&
this.useDefaultLanguageIfMissing &&
this.defaultLanguage &&
resources[this.defaultLanguage]
) {
translatedValue = resources[this.defaultLanguage][key];
}

if (!translatedValue) {
return this.useKeyIfMissing ? key : '';
}

var messageKey = key + translatedValue;
var translatedMessage = proto.__localizationCache.messages[messageKey];

if (!msg) {
msg = new IntlMessageFormat(resources[language][key], language, formats);
proto.__localizationCache.messages[messageKey] = msg;
if (!translatedMessage) {
translatedMessage = new IntlMessageFormat(translatedValue, language, formats);
proto.__localizationCache.messages[messageKey] = translatedMessage;
}

var args = {};
for (var i = 1; i < arguments.length; i+=2) {
for (var i = 1; i < arguments.length; i += 2) {
args[arguments[i]] = arguments[i+1];
}

return msg.format(args);
return translatedMessage.format(args);
};
},

__onRequestResponse: function(event) {
this.resources = event.response;
this.fire('app-resources-loaded');
this.fire('app-localize-resources-loaded');
},

__onRequestError: function(event) {
this.fire('app-resources-error');
this.fire('app-localize-resources-error');
}
}

Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "app-localize-behavior",
"version": "0.9.2",
"version": "0.10.2",
"description": "A behavior to help with internationalizating apps",
"authors": [
"The Polymer Authors"
Expand Down
2 changes: 1 addition & 1 deletion demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</head>

<body unresolved>
<x-translate></x-translate>
<x-translate use-key-if-missing></x-translate>
<x-local-translate></x-local-translate>
</body>
</html>
1 change: 1 addition & 0 deletions demo/x-translate.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ <h4>{{localize('header_1')}}</h4>
<div class="snippet">
<div class="demo">
<div>{{localize('greeting')}}</div>
<div>{{localize('missing')}}</div>
<div>{{localize('intro', 'name', 'Batman')}}</div>
<div>{{localize('cats', 'numCats', 10000, 'pctBlack', 0.42)}}</div>
<div>{{localize('sale', 'start', 150, 'time', 15, 'price', 10)}}</div>
Expand Down
41 changes: 32 additions & 9 deletions test/basic.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@
</template>
</test-fixture>

<test-fixture id="missing">
<template>
<x-translate use-key-if-missing></x-translate>
</template>
</test-fixture>

<test-fixture id="basic2">
<template>
<x-translate></x-translate>
Expand Down Expand Up @@ -86,12 +92,24 @@

assert.equal(app.language, 'en');
assert.equal(app.$.output.innerHTML, 'hello');
assert.equal(app.$.missing.innerHTML, '');

app.language = 'fr';
assert.equal(app.language, 'fr');
assert.equal(app.$.output.innerHTML, 'bonjour');
});

test('can handle missing keys', function() {
var app = fixture('missing');

assert.equal(app.language, 'en');
assert.equal(app.$.missing.innerHTML, 'missing');

app.language = 'fr';
assert.equal(app.language, 'fr');
assert.equal(app.$.missing.innerHTML, 'missing');
});

test('can translate a string with a parameter', function() {
var app = fixture('interpolated');

Expand All @@ -107,8 +125,13 @@
var app = fixture('l10n');

app.language = 'fr';
assert.equal(app.$.output.innerHTML, 'Tout est à 10,00&nbsp;$US');

// Note: In French, on Edge and everything else, format.js seems to
// behave differently - in not-edge, the result is "10 $US", in Edge
// it's just 10$. This isn't something we control, so check the string
// is mostly right.
assert.equal(app.$.output.innerHTML.indexOf('Tout est à 10,00&nbsp;$'), 0);

app.language = 'en';
assert.equal(app.$.output.innerHTML, 'Everything is $10.00');

Expand Down Expand Up @@ -150,7 +173,7 @@
// Keep the tests independent by resetting the internal cache.
resetRequestsCache(app);

app.addEventListener('app-resources-loaded', function() {
app.addEventListener('app-localize-resources-loaded', function() {
assert.equal(app.language, 'en');
assert.equal(app.$.output.innerHTML, 'hello');

Expand All @@ -170,7 +193,7 @@
// Keep the tests independent by resetting the internal cache.
resetRequestsCache(app);

app.addEventListener('app-resources-loaded', function() {
app.addEventListener('app-localize-resources-loaded', function() {
assert.equal(app.language, 'en');
assert.equal(app.$.output.innerHTML, 'my name is batman. i have 3 cats.');

Expand All @@ -192,7 +215,7 @@
resetRequestsCache(app1);
resetRequestsCache(app2);

app1.addEventListener('app-resources-loaded', function() {
app1.addEventListener('app-localize-resources-loaded', function() {
assert.equal(app1.language, 'en');
assert.equal(app2.language, 'en');
assert.equal(app1.localize('greeting'), 'hello');
Expand Down Expand Up @@ -232,7 +255,7 @@
assert.equal(0, Object.keys(getRequestsCache(app3)).length);

// Once the first file has been loaded, it should be the only thing in the cache.
app1.addEventListener('app-resources-loaded', function() {
app1.addEventListener('app-localize-resources-loaded', function() {
assert.equal(1, Object.keys(getRequestsCache(app1)).length, 'there is 1 request cached in app1');
assert.equal(1, Object.keys(getRequestsCache(app2)).length, 'there is 1 request cached in app2');
assert.equal(1, Object.keys(getRequestsCache(app3)).length, 'there is 1 request cached in app3');
Expand All @@ -242,7 +265,7 @@
assert.equal(app1.resources['fr']['greeting'], 'bonjour');

// Loading the second file should not make an iron-ajax request, and re-use the one in the cache.
app2.addEventListener('app-resources-loaded', function() {
app2.addEventListener('app-localize-resources-loaded', function() {
assert.equal(1, Object.keys(getRequestsCache(app1)).length, 'there is 1 request cached in app1');
assert.equal(1, Object.keys(getRequestsCache(app2)).length, 'there is 1 request cached in app2');
assert.equal(1, Object.keys(getRequestsCache(app3)).length, 'there is 1 request cached in app3');
Expand All @@ -252,7 +275,7 @@
assert.equal(app2.resources['fr']['greeting'], 'bonjour');

// Loading the third file should not make an iron-ajax request, and re-use the one in the cache.
app3.addEventListener('app-resources-loaded', function() {
app3.addEventListener('app-localize-resources-loaded', function() {
assert.equal(1, Object.keys(getRequestsCache(app1)).length, 'there is 1 request cached in app1');
assert.equal(1, Object.keys(getRequestsCache(app2)).length, 'there is 1 request cached in app2');
assert.equal(1, Object.keys(getRequestsCache(app3)).length, 'there is 1 request cached in app3');
Expand Down Expand Up @@ -287,7 +310,7 @@
var path2 = app1.resolveUrl('locales2.json');

// Once the first file has been loaded, it should be the only thing in the cache.
app1.addEventListener('app-resources-loaded', function() {
app1.addEventListener('app-localize-resources-loaded', function() {
assert.equal(1, Object.keys(getRequestsCache(app1)).length, 'there is 1 request cached in app1');
assert.equal(1, Object.keys(getRequestsCache(app2)).length, 'there is 1 request cached in app2');

Expand All @@ -296,7 +319,7 @@
assert.equal(app1.resources['fr']['greeting'], 'bonjour');

// Loading a different file should make a different ajax request.
app2.addEventListener('app-resources-loaded', function() {
app2.addEventListener('app-localize-resources-loaded', function() {
assert.equal(2, Object.keys(getRequestsCache(app1)).length, 'there are 2 requests cached in app1');
assert.equal(2, Object.keys(getRequestsCache(app2)).length, 'there are 2 requests cached in app2');

Expand Down
1 change: 1 addition & 0 deletions test/x-translate.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<dom-module id="x-translate">
<template>
<div id="output">{{localize('greeting')}}</div>
<div id="missing">{{localize('missing')}}</div>
</template>

<script>
Expand Down

0 comments on commit 100a7ce

Please sign in to comment.