Skip to content

Commit

Permalink
add fallback locale support
Browse files Browse the repository at this point in the history
  • Loading branch information
martinandert committed Mar 27, 2015
1 parent 5b95052 commit 38d575b
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 7 deletions.
49 changes: 42 additions & 7 deletions index.js
Expand Up @@ -19,13 +19,32 @@ function isFunction(val) {
return typeof val === 'function' || Object.prototype.toString.call(val) === '[object Function]';
}

function isPlainObject(val) {
return Object.prototype.toString.call(val) === '[object Object]';
}

function isSymbol(key) {
return isString(key) && key[0] === ':';
}

function hasOwnProp(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}

function getEntry(translations, keys) {
return keys.reduce(function(result, key) {
if (isPlainObject(result) && hasOwnProp(result, key)) {
return result[key];
} else {
return null;
}
}, translations);
}

function Counterpart() {
this._registry = {
locale: 'en',
fallbackLocale: null,
scope: null,
translations: {},
interpolations: {},
Expand Down Expand Up @@ -54,6 +73,16 @@ Counterpart.prototype.setLocale = function(value) {
return previous;
};

Counterpart.prototype.getFallbackLocale = function() {
return this._registry.fallbackLocale;
};

Counterpart.prototype.setFallbackLocale = function(value) {
var previous = this._registry.fallbackLocale;
this._registry.fallbackLocale = value;
return previous;
};

Counterpart.prototype.getSeparator = function() {
return this._registry.separator;
};
Expand Down Expand Up @@ -105,20 +134,26 @@ Counterpart.prototype.translate = function(key, options) {
var separator = options.separator || this._registry.separator;
delete options.separator;

var fallbackLocale = options.fallbackLocale || this._registry.fallbackLocale;
delete options.fallbackLocale;

var keys = this._normalizeKeys(locale, scope, key, separator);

var entry = keys.reduce(function(result, key) {
if (Object.prototype.toString.call(result) === '[object Object]' && Object.prototype.hasOwnProperty.call(result, key)) {
return result[key];
} else {
return null;
}
}, this._registry.translations);
var entry = getEntry(this._registry.translations, keys);

if (entry === null && options.fallback) {
entry = this._fallback(locale, scope, key, options.fallback, options);
}

if (entry === null && fallbackLocale && locale !== fallbackLocale) {
var fallbackKeys = this._normalizeKeys(fallbackLocale, scope, key, separator);
entry = getEntry(this._registry.translations, fallbackKeys);

if (entry) {
locale = fallbackLocale;
}
}

if (entry === null) {
entry = 'missing translation: ' + keys.join(separator);
}
Expand Down
58 changes: 58 additions & 0 deletions spec.js
Expand Up @@ -275,6 +275,33 @@ describe('translate', function() {
assert.matches(instance.translate('missing', { fallback: [':also_missing', ':foo.missed'] }), /missing translation/);
});
});

describe('with a global `fallbackLocale` present', function() {
it('returns the entry of the fallback locale', function() {
instance.registerTranslations('de', { bar: { baz: 'bam' } });
instance.registerTranslations('de', { hello: 'Hallo %(name)s!' });

assert.equal(instance.translate('baz', { locale: 'foo', scope: 'bar' }), 'missing translation: foo.bar.baz');
assert.equal(instance.translate('hello', { locale: 'foo', name: 'Martin' }), 'missing translation: foo.hello');

var previousFallbackLocale = instance.setFallbackLocale('de');

assert.equal(instance.translate('baz', { locale: 'foo', scope: 'bar' }), 'bam');
assert.equal(instance.translate('hello', { locale: 'foo', name: 'Martin' }), 'Hallo Martin!');

instance.setFallbackLocale(previousFallbackLocale);
});
});

describe('with a `fallbackLocale` provided as option', function() {
it('returns the entry of the fallback locale', function() {
instance.registerTranslations('en', { bar: { baz: 'bam' } });
instance.registerTranslations('en', { hello: 'Hello, %(name)s!' });

assert.equal(instance.translate('baz', { locale: 'foo', scope: 'bar', fallbackLocale: 'en' }), 'bam');
assert.equal(instance.translate('hello', { locale: 'foo', fallbackLocale: 'en', name: 'Martin' }), 'Hello, Martin!');
});
});
});
});

Expand Down Expand Up @@ -345,6 +372,37 @@ describe('translate', function() {
});
});

describe('#getFallbackLocale', function() {
it('is a function', function() {
assert.isFunction(instance.getFallbackLocale);
});

it('returns the fallback locale stored in the registry', function() {
assert.equal(instance.getFallbackLocale(), instance._registry.fallbackLocale);
});

it('returns null by default', function() {
assert.strictEqual(instance.getFallbackLocale(), null);
});
});

describe('#setFallbackLocale', function() {
it('is a function', function() {
assert.isFunction(instance.setFallbackLocale);
});

it('sets the fallback locale stored in the registry', function() {
instance.setFallbackLocale('foo');
assert.equal(instance._registry.fallbackLocale, 'foo');
});

it('returns the previous fallback locale that was stored in the registry', function() {
var current = instance.getFallbackLocale();
var previous = instance.setFallbackLocale(current + 'x');
assert.equal(previous, current);
});
});

describe('#withLocale', function() {
it('is a function', function() {
assert.isFunction(instance.withLocale);
Expand Down

0 comments on commit 38d575b

Please sign in to comment.