UNPKG

spincycle

Version:

A reactive message router and object manager that lets clients subscribe to object property changes on the server

163 lines (144 loc) 4.89 kB
<!doctype html> <link rel="import" href="../polymer/polymer.html"> <script> var Polymer = Polymer || {}; Polymer.CarbonI18nBehaviorLocales = Polymer.CarbonI18nBehaviorLocales || { /** * Adds the translations for a locale * * @param {String} localname Name of the element for which the translations * are registered, e.g. `x-hello` * @param {String} locale Name of the locale for the translations, e.g. `de` * @param {String} translations Translations for the given locale, e.g. { hello: `Hallo` } */ add: function(localName, locale, translations) { this[localName] = this[localName] || {}; this[localName][locale.toLowerCase()] = translations; } }; // Private shared database of all elements that use CarbonI18nBehavior var carbonI18nBehaviorElements = []; // Locale used by existing elements, so that they stay in-sync. // FIXME: This is weird, we probably should have *one* place configuring this locale explicitly, and then distributing it to all attached elements. var carbonI18nBehaviorElementsLocale = null; // When true: we're currently mass-updating the locales. var localeChangeInProgress = false; /** * Adds internationalization support to an element * * @polymerBehavior Polymer.CarbonI18nBehavior * @demo demo/index.html */ Polymer.CarbonI18nBehavior = { properties: { /** * The currently selected locale. * * The default value is the language of the browser (`navigator.language`). */ locale: { type: String, value: function() { // Work out a reasonable default // See http://gu.illau.me/posts/the-problem-of-user-language-lists-in-javascript/ for a discussion return carbonI18nBehaviorElementsLocale || navigator.language || navigator.userLanguage || navigator.browserLanguage || navigator.systemLanguage; }, observer: '_onLocaleChanged' }, /** * The locale to use when a specific element has no translations available in the selected `locale`. * * The default value is `en`. */ fallbackLocale: { type: String, value: 'en' }, /** Exposes all translations */ i18n: { type: Object, computed: '_computeI18n(locale, fallbackLocale)' } }, attached: function() { carbonI18nBehaviorElements.push(this); }, detached: function() { var i = carbonI18nBehaviorElements.indexOf(this); if (i >= 0) { carbonI18nBehaviorElements.splice(i, 1); } if (carbonI18nBehaviorElements.length === 0) { // Last one to go, reset the default // XXX: This is mostly for testing the components, re-triggering the default locale selection. carbonI18nBehaviorElementsLocale = null; } }, /** * Returns localized text with replaced placeholders * * @param {Object} i18n Polymer data binding requires the parameter * to trigger a reload whenever the locale changes. * @param {String} key Key under which the translation is stored */ i18nFormat: function(i18n, key) { var args = Array.prototype.slice.call(arguments, 2); return this._format(i18n[key], args); }, _computeI18n: function(locale, fallbackLocale) { var elementLocales = Polymer.CarbonI18nBehaviorLocales[this.localName]; if (!elementLocales) { throw new Error('No translations defined for element "' + this.localName + '". Check that you imported ' + this.localName + '.<locale>.js imports.'); } /** * Join strings for the given locale and all "parent" locales. */ function mergeLocales(result, locale) { while (locale) { var maybeAvailableLocales = elementLocales[locale.toLowerCase()]; if (result) { // Object.assign modifies the target, so we better merge things into a new empty object result = Object.assign({}, maybeAvailableLocales, result); } locale = locale.substring(0, locale.lastIndexOf('-')); } return result; }; // Combine all locales ... var result = mergeLocales({}, locale); // ... and now add the fallback locales return mergeLocales(result, fallbackLocale); }, /** * Inform other elements with the behavior about the changed locale */ _onLocaleChanged: function(locale) { if (!locale) { return; } if (!localeChangeInProgress) { localeChangeInProgress = true; try { // Remember the value for new elements as default carbonI18nBehaviorElementsLocale = locale; // Tell all other elements about it. carbonI18nBehaviorElements.forEach(function(el) { if (el !== this) { el.locale = locale; } }.bind(this)); } finally { localeChangeInProgress = false; } } }, /** * Simple version of formatf */ _format: function(format, args) { return format.replace(/{(\d+)}/g, function(match, number) { return typeof args[number] != 'undefined' ? args[number] : match; }); } }; </script>