UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

240 lines (237 loc) 6.69 kB
import { EventHandler } from '../../core/event-handler.js'; import { Asset } from '../asset/asset.js'; import { DEFAULT_LOCALE_FALLBACKS, DEFAULT_LOCALE } from './constants.js'; import { getLang, replaceLang, getPluralFn, findAvailableLocale } from './utils.js'; import { I18nParser } from './i18n-parser.js'; class I18n extends EventHandler { set assets(value) { const index = {}; for(let i = 0, len = value.length; i < len; i++){ const id = value[i] instanceof Asset ? value[i].id : value[i]; index[id] = true; } let i = this._assets.length; while(i--){ const id = this._assets[i]; if (!index[id]) { this._app.assets.off(`add:${id}`, this._onAssetAdd, this); const asset = this._app.assets.get(id); if (asset) { this._onAssetRemove(asset); } this._assets.splice(i, 1); } } for(const id in index){ const idNum = parseInt(id, 10); if (this._assets.indexOf(idNum) !== -1) continue; this._assets.push(idNum); const asset = this._app.assets.get(idNum); if (!asset) { this._app.assets.once(`add:${idNum}`, this._onAssetAdd, this); } else { this._onAssetAdd(asset); } } } get assets() { return this._assets; } set locale(value) { if (this._locale === value) { return; } let lang = getLang(value); if (lang === 'in') { lang = 'id'; value = replaceLang(value, lang); if (this._locale === value) { return; } } const old = this._locale; this._locale = value; this._lang = lang; this._pluralFn = getPluralFn(this._lang); this.fire(I18n.EVENT_CHANGE, value, old); } get locale() { return this._locale; } static findAvailableLocale(desiredLocale, availableLocales) { return findAvailableLocale(desiredLocale, availableLocales); } findAvailableLocale(desiredLocale) { if (this._translations[desiredLocale]) { return desiredLocale; } const lang = getLang(desiredLocale); return this._findFallbackLocale(desiredLocale, lang); } getText(key, locale) { let result = key; let lang; if (!locale) { locale = this._locale; lang = this._lang; } let translations = this._translations[locale]; if (!translations) { if (!lang) { lang = getLang(locale); } locale = this._findFallbackLocale(locale, lang); translations = this._translations[locale]; } if (translations && translations.hasOwnProperty(key)) { result = translations[key]; if (Array.isArray(result)) { result = result[0]; } if (result === null || result === undefined) { result = key; } } return result; } getPluralText(key, n, locale) { let result = key; let lang; let pluralFn; if (!locale) { locale = this._locale; lang = this._lang; pluralFn = this._pluralFn; } else { lang = getLang(locale); pluralFn = getPluralFn(lang); } let translations = this._translations[locale]; if (!translations) { locale = this._findFallbackLocale(locale, lang); lang = getLang(locale); pluralFn = getPluralFn(lang); translations = this._translations[locale]; } if (translations && translations[key] && pluralFn) { const index = pluralFn(n); result = translations[key][index]; if (result === null || result === undefined) { result = key; } } return result; } addData(data) { let parsed; try { parsed = this._parser.parse(data); } catch (err) { console.error(err); return; } for(let i = 0, len = parsed.length; i < len; i++){ const entry = parsed[i]; const locale = entry.info.locale; const messages = entry.messages; if (!this._translations[locale]) { this._translations[locale] = {}; const lang = getLang(locale); if (!this._availableLangs[lang]) { this._availableLangs[lang] = locale; } } Object.assign(this._translations[locale], messages); this.fire('data:add', locale, messages); } } removeData(data) { let parsed; try { parsed = this._parser.parse(data); } catch (err) { console.error(err); return; } for(let i = 0, len = parsed.length; i < len; i++){ const entry = parsed[i]; const locale = entry.info.locale; const translations = this._translations[locale]; if (!translations) continue; const messages = entry.messages; for(const key in messages){ delete translations[key]; } if (Object.keys(translations).length === 0) { delete this._translations[locale]; delete this._availableLangs[getLang(locale)]; } this.fire('data:remove', locale, messages); } } destroy() { this._translations = null; this._availableLangs = null; this._assets = null; this._parser = null; this.off(); } _findFallbackLocale(locale, lang) { let result = DEFAULT_LOCALE_FALLBACKS[locale]; if (result && this._translations[result]) { return result; } result = DEFAULT_LOCALE_FALLBACKS[lang]; if (result && this._translations[result]) { return result; } result = this._availableLangs[lang]; if (result && this._translations[result]) { return result; } return DEFAULT_LOCALE; } _onAssetAdd(asset) { asset.on('load', this._onAssetLoad, this); asset.on('change', this._onAssetChange, this); asset.on('remove', this._onAssetRemove, this); asset.on('unload', this._onAssetUnload, this); if (asset.resource) { this._onAssetLoad(asset); } } _onAssetLoad(asset) { this.addData(asset.resource); } _onAssetChange(asset) { if (asset.resource) { this.addData(asset.resource); } } _onAssetRemove(asset) { asset.off('load', this._onAssetLoad, this); asset.off('change', this._onAssetChange, this); asset.off('remove', this._onAssetRemove, this); asset.off('unload', this._onAssetUnload, this); if (asset.resource) { this.removeData(asset.resource); } this._app.assets.once(`add:${asset.id}`, this._onAssetAdd, this); } _onAssetUnload(asset) { if (asset.resource) { this.removeData(asset.resource); } } constructor(app){ super(); this.locale = DEFAULT_LOCALE; this._translations = {}; this._availableLangs = {}; this._app = app; this._assets = []; this._parser = new I18nParser(); } } I18n.EVENT_CHANGE = 'change'; export { I18n };