diff --git a/.gitignore b/.gitignore index 6e610ce..befbc02 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ generated-instructions*.json checkstyle.xml loopback-boot-*.tgz /test/sandbox/ +intl/* +!intl/en/ diff --git a/index.js b/index.js index 7ac2f51..e3e4975 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,10 @@ // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT +// Strong globalize +var SG = require('strong-globalize'); +SG.SetRootDir(__dirname); + var ConfigLoader = require('./lib/config-loader'); var compile = require('./lib/compiler'); var execute = require('./lib/executor'); diff --git a/intl/en/messages.json b/intl/en/messages.json new file mode 100644 index 0000000..c0e92c4 --- /dev/null +++ b/intl/en/messages.json @@ -0,0 +1,25 @@ +{ + "ec551b6f2fafd8d40af801ebe5bb09f6": "Discarding {{middleware}} instructions, {{loopback}} client does not support {{middleware}}.", + "1e5fea50eef843cbffd1d438494912c8": "Cannot resolve path \"{0}\"", + "34319676975b1abf107da7a056abb434": "Invalid normalization format - \"{0}\"", + "46e3ab0ef1149ce0a171b5fac2612ea3": "{{Middleware}} \"{0}\" not found: {1}", + "79e93b2a95e969788590c14e26bb2c1b": "The data in {{model-config.json}} is in the unsupported 1.x format.", + "978a25819e71602cad691dbe7ba17592": "{0} config must be a valid JSON object", + "be2dcdab7aa493ed8d77287eb45cfec8": "cannot require directory contents without directory name", + "2634623ad4b2c5902f6c6bb25e68b733": "WARNING: Main {{config}} file \"{0}.json\" is missing", + "4ed668e9187650d898acf97707df445a": "The {{phase}} \"{0}\" is not defined in the main config.", + "6de7e97f033f2cf477297b3d05a93608": "The {{middleware}} \"{0}\" in phase \"{1}\"is not defined in the main config.", + "94a0c7d5ab6462f7892b90c63f316f42": "invalid array: {0}", + "ec34cc58612cb654742e4cd0a57aca78": "Cannot apply {0}: {1}", + "0b91d122f6459c8bbe7865be0936fc4a": "{{app.restBasePath}} is required", + "1cda77c9954be299bb7154f73cb6ab74": "{{instructions.middleware.phases}} must be an {{array}}", + "22549489736fb0d7eba5a4b08977505f": "{{app.host}} must be a {{string}}", + "4c581cc529a7aeda620d5c4b4ef5cfa8": "{{app.restApiRoot}} must start with \"/\"", + "6037512314fac9d12af6c654a3804823": "Built-in model {0} should have been defined", + "69746d336c89bf4bb371a6c2fe56304d": "{0} does not resolve to a valid value, returned as {1}. \"{2}\" must be resolvable in Environment variable or by app.get().", + "70654dc6eb565613a33344efed3de998": "Failed loading boot script: {0}\n{1}", + "b078ccd043437a258581e387f93dc1a5": "The `{{app}}` is powered by an incompatible {{loopback}} version {0}. Supported versions: {1}", + "e8d29edfb313cfe64f5c96cc7d3d5b4b": "When using {{loopback-boot}} with {{loopback}} <1.9, the {{loopback}} module must be available for `{{require('loopback')}}`.", + "f48405e7c61c3d665b601c9ba41da424": "{{app.port}} must be a {{string}} or {{number}}", + "fa2a7d5137c8891693f9515d48f5b7d7": "{{app.restApiRoot}} must be a {{string}}" +} diff --git a/lib/bundler.js b/lib/bundler.js index cb0552a..41ba1a1 100644 --- a/lib/bundler.js +++ b/lib/bundler.js @@ -7,6 +7,7 @@ var fs = require('fs'); var path = require('path'); var commondir = require('commondir'); var cloneDeep = require('lodash').cloneDeep; +var g = require('strong-globalize')(); /** * Add boot instructions to a browserify bundler. @@ -85,9 +86,9 @@ function bundleInstructions(instructions, bundler) { var hasMiddleware = instructions.middleware.phases.length || instructions.middleware.middleware.length; if (hasMiddleware) { - console.warn( - 'Discarding middleware instructions,' + - ' loopback client does not support middleware.'); + g.warn( + 'Discarding {{middleware}} instructions,' + + ' {{loopback}} client does not support {{middleware}}.'); } delete instructions.middleware; diff --git a/lib/compiler.js b/lib/compiler.js index 70a2379..cf289ba 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -12,6 +12,7 @@ var ConfigLoader = require('./config-loader'); var debug = require('debug')('loopback:boot:compiler'); var Module = require('module'); var _ = require('lodash'); +var g = require('strong-globalize')(); var FILE_EXTENSION_JSON = '.json'; @@ -120,7 +121,7 @@ module.exports = function compile(options) { function assertIsValidConfig(name, config) { if (config) { assert(typeof config === 'object', - name + ' config must be a valid JSON object'); + g.f('%s config must be a valid JSON object', name)); } } @@ -135,7 +136,8 @@ function assertIsValidModelConfig(config) { if (unsupported) { throw new Error( - 'The data in model-config.json is in the unsupported 1.x format.'); + g.f('The data in {{model-config.json}}' + + ' is in the unsupported 1.x format.')); } } } @@ -149,7 +151,7 @@ function assertIsValidModelConfig(config) { */ function findScripts(dir, extensions) { - assert(dir, 'cannot require directory contents without directory name'); + assert(dir, g.f('cannot require directory contents without directory name')); var files = tryReadDir(dir); extensions = extensions || _.keys(require.extensions); @@ -357,7 +359,7 @@ function findModelDefinitions(rootDir, sources) { function resolveAppPath(rootDir, relativePath, resolveOptions) { var resolvedPath = tryResolveAppPath(rootDir, relativePath, resolveOptions); if (resolvedPath === undefined && !resolveOptions.optional) { - var err = new Error('Cannot resolve path "' + relativePath + '"'); + var err = new Error(g.f('Cannot resolve path "%s"', relativePath)); err.code = 'PATH_NOT_FOUND'; throw err; } @@ -482,7 +484,7 @@ function buildMiddlewareInstructions(rootDir, config) { // if a non-optional middleware is not resolvable, it will throw // at resolveAppPath() and not reach here if (!resolved.sourceFile) { - return console.log('Middleware "%s" not found: %s', + return g.log('{{Middleware}} "%s" not found: %s', middleware, resolved.optional ); @@ -812,8 +814,8 @@ function normalizeMixinName(str, options) { return normalization(str); } - var err = new Error('Invalid normalization format - "' + - normalization + '"'); + var err = new Error(g.f('Invalid normalization format - "%s"', + normalization)); err.code = 'INVALID_NORMALIZATION_FORMAT'; throw err; } diff --git a/lib/config-loader.js b/lib/config-loader.js index 1f5ab6a..ca922d2 100644 --- a/lib/config-loader.js +++ b/lib/config-loader.js @@ -8,6 +8,7 @@ var fs = require('fs'); var path = require('path'); var debug = require('debug')('loopback:boot:config-loader'); var assert = require('assert'); +var g = require('strong-globalize')(); var ConfigLoader = exports; @@ -96,7 +97,7 @@ function findConfigFiles(appRootDir, env, name) { var master = ifExists(name + '.json'); if (!master && (ifExistsWithAnyExt(name + '.local') || ifExistsWithAnyExt(name + '.' + env))) { - console.warn('WARNING: Main config file "' + name + '.json" is missing'); + g.warn('WARNING: Main {{config}} file "%s.json" is missing', name); } if (!master) return []; @@ -153,21 +154,21 @@ function mergeConfigurations(configObjects, mergeFn) { function mergeDataSourceConfig(target, config, fileName) { var err = mergeObjects(target, config); if (err) { - throw new Error('Cannot apply ' + fileName + ': ' + err); + throw new Error(g.f('Cannot apply %s: %s', fileName, err)); } } function mergeModelConfig(target, config, fileName) { var err = mergeObjects(target, config); if (err) { - throw new Error('Cannot apply ' + fileName + ': ' + err); + throw new Error(g.f('Cannot apply %s: %s', fileName, err)); } } function mergeAppConfig(target, config, fileName) { var err = mergeObjects(target, config); if (err) { - throw new Error('Cannot apply ' + fileName + ': ' + err); + throw new Error(g.f('Cannot apply %s: %s', fileName, err)); } } @@ -177,16 +178,16 @@ function mergeMiddlewareConfig(target, config, fileName) { if (phase in target) { err = mergePhaseConfig(target[phase], config[phase], phase); } else { - err = 'The phase "' + phase + '" is not defined in the main config.'; + err = g.f('The {{phase}} "%s" is not defined in the main config.', phase); } if (err) - throw new Error('Cannot apply ' + fileName + ': ' + err); + throw new Error(g.f('Cannot apply %s: %s', fileName, err)); } } function mergeNamedItems(arr1, arr2, key) { - assert(Array.isArray(arr1), 'invalid array: ' + arr1); - assert(Array.isArray(arr2), 'invalid array: ' + arr2); + assert(Array.isArray(arr1), g.f('invalid array: %s', arr1)); + assert(Array.isArray(arr2), g.f('invalid array: %s', arr2)); key = key || 'name'; var result = [].concat(arr1); for (var i = 0, n = arr2.length; i < n; i++) { @@ -236,8 +237,8 @@ function mergePhaseConfig(target, config, phase) { err = mergeObjects(targetMiddleware, configMiddleware); } } else { - err = 'The middleware "' + mw + '" in phase "' + phase + '"' + - 'is not defined in the main config.'; + err = g.f('The {{middleware}} "%s" in phase "%s"' + + 'is not defined in the main config.', mw, phase); } if (err) return err; } @@ -246,7 +247,7 @@ function mergePhaseConfig(target, config, phase) { function mergeComponentConfig(target, config, fileName) { var err = mergeObjects(target, config); if (err) { - throw new Error('Cannot apply ' + fileName + ': ' + err); + throw new Error(g.f('Cannot apply %s: %s', fileName, err)); } } diff --git a/lib/executor.js b/lib/executor.js index 4059618..17fc02d 100644 --- a/lib/executor.js +++ b/lib/executor.js @@ -9,6 +9,7 @@ var debug = require('debug')('loopback:boot:executor'); var async = require('async'); var path = require('path'); var format = require('util').format; +var g = require('strong-globalize')(); /** * Execute bootstrap instructions gathered by `boot.compile`. @@ -72,9 +73,10 @@ function patchAppLoopback(app) { app.loopback = require('loopback'); } catch (err) { if (err.code === 'MODULE_NOT_FOUND') { - console.error( - 'When using loopback-boot with loopback <1.9, ' + - 'the loopback module must be available for `require(\'loopback\')`.'); + g.error( + 'When using {{loopback-boot}} with {{loopback}} <1.9, ' + + 'the {{loopback}} module must be available ' + + 'for `{{require(\'loopback\')}}`.'); } throw err; } @@ -89,8 +91,8 @@ function assertLoopBackVersion(app) { // while loopback-boot treats pre-releases the same way as regular versions var version = (loopback.version || '1.0.0').replace(/-.*$/, ''); if (!semver.satisfies(version, RANGE)) { - var msg = format( - 'The `app` is powered by an incompatible loopback version %s. ' + + var msg = g.f( + 'The `{{app}}` is powered by an incompatible {{loopback}} version %s. ' + 'Supported versions: %s', loopback.version || '(unknown)', RANGE); @@ -117,7 +119,7 @@ function setHost(app, instructions) { app.get('host'); if (host !== undefined) { - assert(typeof host === 'string', 'app.host must be a string'); + assert(typeof host === 'string', g.f('{{app.host}} must be a {{string}}')); app.set('host', host); } } @@ -141,7 +143,7 @@ function setPort(app, instructions) { if (port !== undefined) { var portType = typeof port; assert(portType === 'string' || portType === 'number', - 'app.port must be a string or number'); + g.f('{{app.port}} must be a {{string}} or {{number}}')); app.set('port', port); } } @@ -156,11 +158,11 @@ function setApiRoot(app, instructions) { app.get('restApiRoot') || '/api'; - assert(restApiRoot !== undefined, 'app.restBasePath is required'); + assert(restApiRoot !== undefined, g.f('{{app.restBasePath}} is required')); assert(typeof restApiRoot === 'string', - 'app.restApiRoot must be a string'); + g.f('{{app.restApiRoot}} must be a {{string}}')); assert(/^\//.test(restApiRoot), - 'app.restApiRoot must start with "/"'); + g.f('{{app.restApiRoot}} must start with "/"')); app.set('restApiRoot', restApiRoot); } @@ -230,12 +232,12 @@ function defineModels(app, instructions) { if (!data.definition) { model = registry.getModel(name); if (!model) { - throw new Error('Cannot configure unknown model ' + name); + throw new Error(g.f('Cannot configure unknown model %s', name)); } debug('Configuring existing model %s', name); } else if (isBuiltinLoopBackModel(app, data)) { model = registry.getModel(name); - assert(model, 'Built-in model ' + name + ' should have been defined'); + assert(model, g.f('Built-in model %s should have been defined', name)); debug('Configuring built-in LoopBack model %s', name); } else { debug('Creating new model %s %j', name, data.definition); @@ -295,7 +297,7 @@ function runScripts(app, list, callback) { }); } } catch (err) { - console.error('Failed loading boot script: %s\n%s', filepath, err.stack); + g.error('Failed loading boot script: %s\n%s', filepath, err.stack); throw err; } }); @@ -326,7 +328,7 @@ function setupMiddleware(app, instructions) { // Phases can be empty var phases = instructions.middleware.phases || []; assert(Array.isArray(phases), - 'instructions.middleware.phases must be an array'); + g.f('{{instructions.middleware.phases}} must be an {{array}}')); var middleware = instructions.middleware.middleware; assert(Array.isArray(middleware), @@ -375,7 +377,7 @@ function getUpdatedConfigObject(app, config, opts) { // it will now return `undefined`, for the use case of // dynamic datasources url:`undefined` to fallback to other parameters configVariable = undefined; - console.warn('%s does not resolve to a valid value, returned as %s. ' + + g.warn('%s does not resolve to a valid value, returned as %s. ' + '"%s" must be resolvable in Environment variable or by app.get().', param, configVariable, varName); debug('Dynamic Configuration: Cannot resolve variable for `%s`, ' + diff --git a/package.json b/package.json index 6c83b00..27eb0ed 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "debug": "^2.0.0", "lodash": "^3.6.0", "semver": "^4.1.0", + "strong-globalize": "^2.6.2", "toposort": "^0.2.10" }, "devDependencies": {