ember-intl
Version:
Ember toolbox for internationalization.
194 lines (148 loc) • 5.04 kB
JavaScript
/* global requirejs */
/**
* Copyright 2015, Yahoo! Inc.
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
import Ember from 'ember';
import getOwner from 'ember-getowner-polyfill';
import IntlMessageFormat from 'intl-messageformat';
import IntlRelativeFormat from 'intl-relativeformat';
import extend from '../utils/extend';
import isArrayEqual from '../utils/is-equal';
const { assert, computed, makeArray, get, set, RSVP, Service, Evented, Logger:logger } = Ember;
const TRANSLATION_PATH_CAPTURE = /\/translations\/(.+)$/;
function formatterProxy(formatType) {
return function (value, options = {}, formats = null) {
const owner = getOwner(this);
const formatter = owner.lookup(`ember-intl@formatter:format-${formatType}`);
if (typeof options.format === 'string') {
options = extend(this.getFormat(formatType, options.format), options);
}
if (!options.locale) {
options.locale = get(this, '_locale');
}
if (!formats) {
formats = get(this, 'formats');
}
return formatter.format(value, options, formats);
};
}
const IntlService = Service.extend(Evented, {
_locale: null,
locale: computed('_locale', {
set() {
throw new Error('Use `setLocale` to change the application locale');
},
get() {
return get(this, '_locale');
}
}),
adapter: computed({
get() {
return getOwner(this).lookup('ember-intl@adapter:default');
}
}),
formats: computed({
get() {
const formats = getOwner(this).resolveRegistration('formats:main');
if (Ember.Object.detect(formats)) {
return formats.create();
}
return formats;
}
}),
formatHtmlMessage: formatterProxy('html-message'),
formatRelative: formatterProxy('relative'),
formatMessage: formatterProxy('message'),
formatNumber: formatterProxy('number'),
formatTime: formatterProxy('time'),
formatDate: formatterProxy('date'),
t(key, options, formats) {
const translation = this.findTranslationByKey(key, options && options.locale);
return this.formatMessage(translation, options, formats);
},
exists(key, optionalLocales) {
let locales = optionalLocales;
const adapter = get(this, 'adapter');
if (!optionalLocales) {
locales = get(this, '_locale');
}
assert(`ember-intl: locale is unset, cannot lookup '${key}'`, locales);
return makeArray(locales).some((locale) => {
return adapter.has(locale, key);
});
},
getLocalesByTranslations() {
return Object.keys(requirejs.entries).reduce((translations, module) => {
const match = module.match(TRANSLATION_PATH_CAPTURE);
if (match) {
translations.addObject(match[1]);
}
return translations;
}, Ember.A());
},
/**
* A utility method for registering CLDR data for
* intl-messageformat and intl-relativeformat. This data is derived
* from formatjs-extract-cldr-data
*
* @method addLocaleData
* @param {Object} locale data
* @public
*/
addLocaleData(data) {
IntlMessageFormat.__addLocaleData(data);
IntlRelativeFormat.__addLocaleData(data);
},
addTranslation(locale, key, value) {
return this.translationsFor(locale).then((localeInstance) => {
return localeInstance.addTranslation(key, value);
});
},
addTranslations(locale, payload) {
return this.translationsFor(locale).then((localeInstance) => {
return localeInstance.addTranslations(payload);
});
},
createLocale(locale, payload) {
logger.warn('`createLocale` is deprecated, use `addTranslations`');
return this.addTranslations(locale, payload);
},
setLocale(locales) {
if (!locales) { return; }
const proposed = makeArray(locales);
const current = get(this, '_locale');
if (!isArrayEqual(proposed, current)) {
this.propertyWillChange('locale');
set(this, '_locale', proposed);
this.propertyDidChange('locale');
this.trigger('localeChanged');
}
},
getFormat(formatType, format) {
const formats = get(this, 'formats');
if (formats && formatType && typeof format === 'string') {
return get(formats, `${formatType}.${format}`);
}
return {};
},
translationsFor(locale) {
const result = get(this, 'adapter').translationsFor(locale);
return RSVP.cast(result).then(function(localeInstance) {
if (typeof localeInstance === 'undefined') {
throw new Error(`'locale' must be a string or a locale instance`);
}
return localeInstance;
});
},
findTranslationByKey(key, locales) {
locales = locales || get(this, '_locale');
const translation = get(this, 'adapter').findTranslationByKey(makeArray(locales), key);
if (typeof translation === 'undefined') {
const missingMessage = getOwner(this).resolveRegistration('util:intl/missing-message');
return missingMessage.call(this, key, locales);
}
return translation;
}
});
export default IntlService;