UNPKG

ember-intl

Version:

Ember toolbox for internationalization.

235 lines (182 loc) 6.45 kB
/* jshint node: true */ 'use strict'; /** * Copyright 2015, Yahoo! Inc. * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. */ var serialize = require('serialize-javascript'); var stringify = require('json-stable-stringify'); var WatchedDir = require('broccoli-source').WatchedDir; var Funnel = require('broccoli-funnel'); var existsSync = require('exists-sync'); var stew = require('broccoli-stew'); var walkSync = require('walk-sync'); var path = require('path'); var _ = require('lodash'); var fs = require('fs'); var utils = require('./lib/utils'); var mergeTrees = require('broccoli-merge-trees'); var CldrWriter = require('./lib/broccoli/cldr-writer'); var TranslationReducer = require('./lib/broccoli/translation-reducer'); module.exports = { name: 'ember-intl', opts: null, included: function(app) { this._super.included.apply(this, arguments); // see: https://github.com/ember-cli/ember-cli/issues/3718 if (typeof app.import !== 'function' && app.app) { app = app.app; } this.app = app; this.opts = this.intlConfig(this.app.env); var translationFolder = this.opts.inputPath; this.hasTranslationDir = existsSync(path.join(app.project.root, translationFolder)); this.projectLocales = this.findLocales(); this.trees = this.trees || {}; this.trees.projectTranslations = new WatchedDir(translationFolder); this.trees.addonTranslations = this.findIntlAddons().map(function(addon) { return new Funnel(addon.path, { srcDir: addon.translationPath, destDir: '__addon__' + addon.name }); }, this); this.trees.translationTree = this.createTranslationTree(); return this.app; }, treeForApp: function(tree) { var trees = [tree]; if (this.hasTranslationDir && !this.opts.publicOnly) { trees.push(this.reduceTranslations({ filename: function filename(key) { return key + '.js'; }, wrapEntry: function wrapEntry(obj) { return 'export default ' + stringify(obj) + ';'; } })); } if (tree && this.projectLocales.length) { var cldrTree = new CldrWriter([tree], { destDir: 'cldrs', locales: this.projectLocales, prelude: '/*jslint eqeq: true*/\n', wrapEntry: function wrapEntry(result) { return 'export default ' + serialize(result) + ';'; } }); trees.push(cldrTree); } return mergeTrees(trees, { overwrite: true }); }, treeForPublic: function() { var publicTree = this._super.treeForPublic.apply(this, arguments); var trees = []; if (publicTree) { trees.push(publicTree); } if (!this.opts.disablePolyfill) { var appOptions = this.app.options || {}; trees.push(require('./lib/broccoli/intl-polyfill')({ locales: this.projectLocales, destDir: _.get(appOptions, 'app.intl') || 'assets/intl' })); } if (this.hasTranslationDir && this.opts.publicOnly) { trees.push(this.reduceTranslations()); } return mergeTrees(trees, { overwrite: true }); }, log: function(msg) { this.ui.writeLine('[ember-intl] ' + msg); }, readConfig: function(environment) { var project = this.app.project; var configPath = path.join(project.root, project.configPath(), '..', 'ember-intl.js'); if (fs.existsSync(configPath)) { return require(configPath)(environment); } return {}; }, intlConfig: function(environment) { var deprecatedConfig = this.app.project.config(environment)['intl']; var addonConfig = _.assign(this.readConfig(), deprecatedConfig || {}); if (deprecatedConfig) { this.log('DEPRECATION: intl configuration should be moved into config/ember-intl.js'); this.log('Run `ember g ember-intl-config` to create a default config'); } var defaults = { locales: null, baseLocale: null, publicOnly: false, disablePolyfill: false, inputPath: 'translations', outputPath: 'translations' }; if (addonConfig.defaultLocale) { this.log('DEPRECATION: defaultLocale is deprecated in favor of baseLocale'); this.log('Please update config/ember-intl.js or config/environment.js'); addonConfig.baseLocale = addonConfig.defaultLocale; } addonConfig = _.assign(defaults, addonConfig); if (addonConfig.locales) { addonConfig.locales = _.castArray(addonConfig.locales).filter(function(locale) { return typeof locale === 'string'; }).map(function(locale) { return locale.toLocaleLowerCase(); }); } return addonConfig; }, findLocales: function() { var locales = []; if (this.hasTranslationDir) { locales = locales.concat(walkSync(path.join(this.app.project.root, this.opts.inputPath)).map(function(filename) { return path.basename(filename, path.extname(filename)); })); } if (this.opts.locales) { locales = locales.concat(this.opts.locales); } locales = locales.concat(locales.filter(function(locale) { if (utils.isSupportedLocale(locale)) { return true; } this.log('\'' + locale + '\' is not a valid locale name'); return false; }, this)); return utils.unique(locales).filter(function(locale) { return locale !== 'subdirectory' }); }, findIntlAddons: function(tree) { var addons = this.app.project.addonPackages; return Object.keys(addons).map(function(key) { var addon = addons[key]; var pkg = require(path.join(addon.path, 'package.json')); return { name: key, translationPath: pkg['ember-addon'].translationPath || 'translations', path: addon.path }; }).filter(function(addon) { return fs.existsSync(path.join(addon.path, addon.translationPath)); }); }, createTranslationTree: function() { var trees = []; trees.push(this.trees.projectTranslations); if (this.trees.addonTranslations) { trees = trees.concat(this.trees.addonTranslations); } return mergeTrees(trees); }, reduceTranslations: function(opts) { if (!opts) { opts = {}; } var addon = this; return new TranslationReducer(this.trees.translationTree, _.assign({}, this.opts, opts, { log: function() { return addon.log.apply(addon, arguments); } })); } };