Support for globalization

This commit is contained in:
Amir Jafarian 2016-07-22 15:26:07 -04:00
parent f1ed1ee023
commit 4ce5b5d3a0
17 changed files with 208 additions and 133 deletions

3
.gitignore vendored
View File

@ -12,3 +12,6 @@ docs/man
npm-debug.log
.project
test/memory.json
intl/*
!intl/en/

View File

@ -3,6 +3,9 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
var SG = require('strong-globalize');
SG.SetRootDir(__dirname);
exports.ModelBuilder = exports.LDL = require('./lib/model-builder.js').ModelBuilder;
exports.DataSource = exports.Schema = require('./lib/datasource.js').DataSource;
exports.ModelBaseClass = require('./lib/model.js');

62
intl/en/messages.json Normal file
View File

@ -0,0 +1,62 @@
{
"4c78325cedbb826db3a05bf5df0e8546": "You must provide an {{id}} when replacing!",
"a0cf0e09c26df14283223e84e6a10f00": "Could not update attributes. {{Object}} with {{id}} {0} does not exist!",
"e54d944c2a2c85a23caa86027ae307cf": "Cannot migrate models not attached to this datasource: {0}",
"e6161ae8459c79d810e2aa9d21282a39": "You must provide an {{id}} when updating attributes!",
"fca4d12faff1035d9d0438d73432571b": "Duplicate entry for {0}.{1}",
"09483e03b91c8bd58732a74b3ef1ec13": "Invalid date: {0}",
"0e88a84c6bc2638fbcc5d3ea95181f99": "Unknown property: {0}",
"416dfbb7b823f51c9f3800be81060b41": "No instance with {{id}} {0} found for {1}",
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}} requires the {{id}} argument",
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}} requires the {{id}} argument",
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}} requires the {{id}} argument",
"a829dee089c912e68c18920ba015400c": "WARNING: {{id}} property cannot be changed from {0} to {1} for model:{2} in {{'loaded'}} operation hook",
"a984a076c59e451948b2bcf7a393d860": "WARNING: {{id}} property cannot be changed from {0} to {1} for model:{2} in {{'before save'}} operation hook",
"db03083e9a768388fdbee865249ac67a": "Ignoring validation errors in {{updateOrCreate()}}:",
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "Unknown \"{0}\" {{id}} \"{1}\".",
"f6e8c96c93b9c7687d6c172b3695e898": "{{id}} property ({0}) cannot be updated from {1} to {2}",
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "No model specified for {{polymorphic}} {0}: {1}",
"0c4eb8b6c2ff6e51d7e195eee346ced9": "Table '{0}' does not exist.",
"2f4af31c144bbfab1bbf479866acd820": "\nWARNING: {{LoopBack}} connector \"{0}\" is not installed as any of the following modules:\n\n {1}\n\nTo fix, run:\n\n {{npm install {2} --save}}\n",
"6111399276924ffa3bc9a410cdfcb2e5": "No {{id}} name {0}",
"791ab3031a73ede03f7d6299a85e8289": "Timeout in connecting after {0} ms",
"7b277018e43d41bc445731092b91547d": "Not connected",
"a2487abefef4259c2131d96cdb8543b1": "Connection fails: {0}\nIt will be retried for the next request.",
"b15b20280211ad258d92947f05b6e4a5": "The connector has not been initialized.",
"ddf0aa14803f1c84f4a97f3803f7471c": "Class name required",
"e0e9504e137a3c3339144b51ed76fef2": "Connector is not defined correctly: it should create `{{connector}}` member of dataSource",
"ec42dca074f1818c447f7ad16e2d01af": "{0} is not provided by the attached connector",
"ba0fd8106eb54de4d003a844206431fd": "Model hook \"{0}\" is deprecated, use Operation hooks instead. {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
"280f4550f90e133118955ec6f6f72830": "Discriminator type {0} specified but no model exists with such name",
"83abbb3ad105947dccbb21b4cf41e98f": "{{Relation.modelTo}} is not defined for relation {0} and is no polymorphic",
"eb56c2b0c30cf006e2df00a549ec9c2c": "Relation \"{0}\" is not defined for {1} model",
"514985b2327f061ffb1c932f6b909979": "Model {0} is not defined.",
"8091838319a5cc7d6a34af2f2a616ce9": "Property name should not be \"{{constructor}}\" in Model: {0}",
"da02dd6c53d4148320eeb31718a7aebe": "Invalid type for property {0}",
"da751a8a748adbde5b55fa83b707b4e2": "Property names containing dot(s) are not supported. Model: {0}, property: {1}",
"881e4b0cb86ed59549248ee540a9fd10": "Property name \"{{constructor}}\" is not allowed in {0} data",
"bdb11cc1c780c9ccac33c316cfdc9d82": "Type not defined for property {0}.{1}",
"cd930369e86cdd222f7bd117c6f9fa94": "Unknown default value provider {0}",
"cfee4d8149316d9a647c0885cf3cafaf": "Property names containing dot(s) are not supported. Model: {0}, dynamic property: {1}",
"0c0b867aca0973ba26e887d3337cc4ec": "{{Polymorphic}} model not found: `{0}` not set",
"2f062cbecdf24245731bddc77714c814": "Could not find \"{0}\" relation for {1}",
"3cde8cc9bca22c67278b202ab0720106": "No instance with id {0} found for {1}",
"6502a117987610380b9068ef98b1b0ee": "No record found in {0} for ({1}.{2} ,{3}.{4})",
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "{{HasOne}} relation cannot create more than one instance of {0}",
"7e9530c0399289be0ee601a604be71ff": "{{BelongsTo}} relation {0} is empty",
"7faa840eb6ce11250a141deb42a6c489": "Unknown relation {{scope}}: {0}",
"89afd3a9249f5a8d3edda07d84ca049d": "{{Polymorphic}} model not found: `{0}`",
"a004f310d315e592843776fab964eaeb": "{{Polymorphic}} relations need a through model",
"a25e41a39c60c4702e55d0c3936576a1": "Key mismatch: {0}.{1}: {2}, {3}.{4}: {5}",
"a327355560d495454fba2c1aad6bdf09": "Unknown scope method: {0}",
"e08ab0e1ab55f26c357061447b635905": "No relation found in {0} for ({1}.{2},{3}.{4})",
"e55937649d8d7a11706b8cec22d02eae": "{{HasOne}} relation {0} is empty",
"2c4904377a87fdab502118719cc0d266": "{{Transaction}} is not supported",
"ecb7aa804bf54c682999d20d6436104c": "The {{transaction}} is not active: {0}",
"89bf6d92731fe7bd2146ce8d0bec205c": "Invalid argument, must be a string, {{regex}} literal, or {{RegExp}} object",
"8c5ab01638c1ac1d58168c6346a8481a": "Invalid {{regex}} flags: {0}",
"a6c18a7f4390cd3d59a2a7a047ae2aab": "Run \"{{npm install loopback-datasource-juggler}} {0}\" command ",
"b138294f132edfe1eb2a8211150c7238": "Unexpected `undefined` in query",
"8a39126103a157f501affa070367a1b0": "The {0} instance is not valid. Details: {1}."
}

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
var g = require('strong-globalize')();
var util = require('util');
var Connector = require('loopback-connector').Connector;
var geo = require('../geo');
@ -217,7 +218,7 @@ Memory.prototype._createSync = function(model, data, fn) {
}
if (this.collection(model)[id])
return fn(new Error('Duplicate entry for ' + model + '.' + idName));
return fn(new Error(g.f('Duplicate entry for %s.%s', model, idName)));
this.collection(model)[id] = serialize(data);
fn(null, id);
@ -711,7 +712,7 @@ Memory.prototype.update =
Memory.prototype.updateAttributes = function updateAttributes(model, id, data, options, cb) {
if (!id) {
var err = new Error('You must provide an id when updating attributes!');
var err = new Error(g.f('You must provide an {{id}} when updating attributes!'));
if (cb) {
return cb(err);
} else {
@ -730,14 +731,14 @@ Memory.prototype.updateAttributes = function updateAttributes(model, id, data, o
if (modelData) {
this.save(model, data, options, cb);
} else {
cb(new Error('Could not update attributes. Object with id ' + id + ' does not exist!'));
cb(new Error(g.f('Could not update attributes. {{Object}} with {{id}} %s does not exist!', id)));
}
};
Memory.prototype.replaceById = function(model, id, data, options, cb) {
var self = this;
if (!id) {
var err = new Error('You must provide an id when replacing!');
var err = new Error(g.f('You must provide an {{id}} when replacing!'));
return process.nextTick(function() { cb(err); });
}
// Do not modify the data object passed in arguments
@ -828,8 +829,8 @@ Memory.prototype.automigrate = function(models, cb) {
if (invalidModels.length) {
return process.nextTick(function() {
cb(new Error('Cannot migrate models not attached to this datasource: ' +
invalidModels.join(' ')));
cb(new Error(g.f('Cannot migrate models not attached to this datasource: %s',
invalidModels.join(' '))));
});
}

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
var g = require('strong-globalize')();
var util = require('util');
var Connector = require('loopback-connector').Connector;
var utils = require('../utils');
@ -108,7 +109,7 @@ Transient.prototype.update =
Transient.prototype.updateAttributes = function updateAttributes(model, id, data, cb) {
if (!id) {
var err = new Error('You must provide an id when updating attributes!');
var err = new Error(g.f('You must provide an {{id}} when updating attributes!'));
if (cb) {
return cb(err);
} else {

View File

@ -11,6 +11,7 @@ module.exports = DataAccessObject;
/*!
* Module dependencies
*/
var g = require('strong-globalize')();
var async = require('async');
var jutil = require('./jutil');
var ValidationError = require('./validations').ValidationError;
@ -89,7 +90,7 @@ function applyStrictCheck(model, strict, data, inst, cb) {
if (props[key]) {
result[key] = data[key];
} else if (strict === 'throw') {
cb(new Error('Unknown property: ' + key));
cb(new Error(g.f('Unknown property: %s', key)));
return;
} else if (strict === 'validate') {
inst.__unknownProperties.push(key);
@ -533,8 +534,8 @@ DataAccessObject.upsert = function(data, options, cb) {
return cb(new ValidationError(inst), inst);
} else {
// TODO(bajtos) Remove validateUpsert:undefined in v3.0
console.warn('Ignoring validation errors in updateOrCreate():');
console.warn(' %s', new ValidationError(inst).message);
g.warn('Ignoring validation errors in {{updateOrCreate()}}:');
g.warn(' %s', new ValidationError(inst).message);
// continue with updateOrCreate
}
}
@ -1049,7 +1050,7 @@ DataAccessObject.exists = function exists(id, options, cb) {
});
} else {
process.nextTick(function() {
cb(new Error('Model::exists requires the id argument'));
cb(new Error(g.f('{{Model::exists}} requires the {{id}} argument')));
});
}
return cb.promise;
@ -1111,7 +1112,7 @@ DataAccessObject.findById = function findById(id, filter, options, cb) {
return cb.promise;
} else if (id == null || id === '') {
process.nextTick(function() {
cb(new Error('Model::findById requires the id argument'));
cb(new Error(g.f('{{Model::findById}} requires the {{id}} argument')));
});
} else {
var query = byIdQuery(this, id);
@ -1184,7 +1185,7 @@ function convertNullToNotFoundError(ctx, cb) {
var modelName = ctx.method.sharedClass.name;
var id = ctx.getArgByName('id');
var msg = 'Unknown "' + modelName + '" id "' + id + '".';
var msg = g.f('Unknown "%s" {{id}} "%s".', modelName, id);
var error = new Error(msg);
error.statusCode = error.status = 404;
cb(error);
@ -1242,7 +1243,7 @@ DataAccessObject._normalize = function(filter) {
}
var err = null;
if ((typeof filter !== 'object') || Array.isArray(filter)) {
err = new Error(util.format('The query filter %j is not an object', filter));
err = new Error(g.f(util.format('The query filter %j is not an {{object}}', filter)));
err.statusCode = 400;
throw err;
}
@ -1250,14 +1251,14 @@ DataAccessObject._normalize = function(filter) {
var limit = Number(filter.limit || 100);
var offset = Number(filter.skip || filter.offset || 0);
if (isNaN(limit) || limit <= 0 || Math.ceil(limit) !== limit) {
err = new Error(util.format('The limit parameter %j is not valid',
filter.limit));
err = new Error(g.f(util.format('The {{limit}} parameter %j is not valid',
filter.limit)));
err.statusCode = 400;
throw err;
}
if (isNaN(offset) || offset < 0 || Math.ceil(offset) !== offset) {
err = new Error(util.format('The offset/skip parameter %j is not valid',
filter.skip || filter.offset));
err = new Error(g.f(util.format('The {{offset/skip}} parameter %j is not valid',
filter.skip || filter.offset)));
err.statusCode = 400;
throw err;
}
@ -1288,7 +1289,7 @@ DataAccessObject._normalize = function(filter) {
if (dir === 'ASC' || dir === 'DESC') {
token = parts[0] + ' ' + dir;
} else {
err = new Error(util.format('The order %j has invalid direction', token));
err = new Error(g.f(util.format('The {{order}} %j has invalid direction', token)));
err.statusCode = 400;
throw err;
}
@ -1324,7 +1325,7 @@ DataAccessObject._normalize = function(filter) {
function DateType(arg) {
var d = new Date(arg);
if (isNaN(d.getTime())) {
throw new Error('Invalid date: ' + arg);
throw new Error(g.f('Invalid date: %s', arg));
}
return d;
}
@ -1365,7 +1366,7 @@ DataAccessObject._coerce = function(where) {
var err;
if (typeof where !== 'object' || Array.isArray(where)) {
err = new Error(util.format('The where clause %j is not an object', where));
err = new Error(g.f(util.format('The where clause %j is not an {{object}}', where)));
err.statusCode = 400;
throw err;
}
@ -1380,7 +1381,7 @@ DataAccessObject._coerce = function(where) {
self._coerce(clauses[k]);
}
} else {
err = new Error(util.format('The %s operator has invalid clauses %j', p, clauses));
err = new Error(g.f(util.format('The %s operator has invalid clauses %j', p, clauses)));
err.statusCode = 400;
throw err;
}
@ -1439,14 +1440,14 @@ DataAccessObject._coerce = function(where) {
case 'inq':
case 'nin':
if (!Array.isArray(val)) {
err = new Error(util.format('The %s property has invalid clause %j', p, where[p]));
err = new Error(g.f(util.format('The %s property has invalid clause %j', p, where[p])));
err.statusCode = 400;
throw err;
}
break;
case 'between':
if (!Array.isArray(val) || val.length !== 2) {
err = new Error(util.format('The %s property has invalid clause %j', p, where[p]));
err = new Error(g.f(util.format('The %s property has invalid clause %j', p, where[p])));
err.statusCode = 400;
throw err;
}
@ -1454,7 +1455,7 @@ DataAccessObject._coerce = function(where) {
case 'like':
case 'nlike':
if (!(typeof val === 'string' || val instanceof RegExp)) {
err = new Error(util.format('The %s property has invalid clause %j', p, where[p]));
err = new Error(g.f(util.format('The %s property has invalid clause %j', p, where[p])));
err.statusCode = 400;
throw err;
}
@ -2011,7 +2012,7 @@ DataAccessObject.deleteById = function deleteById(id, options, cb) {
return cb.promise;
} else if (id == null || id === '') {
process.nextTick(function() {
cb(new Error('Model::deleteById requires the id argument'));
cb(new Error(g.f('{{Model::deleteById}} requires the {{id}} argument')));
});
return cb.promise;
}
@ -2022,7 +2023,7 @@ DataAccessObject.deleteById = function deleteById(id, options, cb) {
if (err) return cb(err);
var deleted = info && info.count > 0;
if (Model.settings.strictDelete && !deleted) {
err = new Error('No instance with id ' + id + ' found for ' + Model.modelName);
err = new Error(g.f('No instance with {{id}} %s found for %s', id, Model.modelName));
err.code = 'NOT_FOUND';
err.statusCode = 404;
return cb(err);
@ -2485,7 +2486,7 @@ DataAccessObject.prototype.remove =
if (err) return cb(err, false);
var deleted = info && info.count > 0;
if (Model.settings.strictDelete && !deleted) {
err = new Error('No instance with id ' + id + ' found for ' + Model.modelName);
err = new Error(g.f('No instance with {{id}} %s found for %s', id, Model.modelName));
err.code = 'NOT_FOUND';
err.statusCode = 404;
return cb(err, false);
@ -2509,7 +2510,7 @@ DataAccessObject.prototype.remove =
if (err) return cb(err);
var deleted = info && info.count > 0;
if (Model.settings.strictDelete && !deleted) {
err = new Error('No instance with id ' + id + ' found for ' + Model.modelName);
err = new Error(g.f('No instance with {{id}} %s found for %s', id, Model.modelName));
err.code = 'NOT_FOUND';
err.statusCode = 404;
return cb(err);
@ -2654,8 +2655,8 @@ DataAccessObject.replaceById = function(id, data, options, cb) {
var hookState = {};
if (id !== data[pkName]) {
var err = new Error('id property (' + pkName + ') ' +
'cannot be updated from ' + id + ' to ' + data[pkName]);
var err = new Error(g.f('{{id}} property (%s) ' +
'cannot be updated from %s to %s', pkName, id, data[pkName]));
err.statusCode = 400;
process.nextTick(function() { cb(err); });
return cb.promise;
@ -2674,9 +2675,8 @@ DataAccessObject.replaceById = function(id, data, options, cb) {
if (ctx.instance[pkName] !== id && !Model._warned.cannotOverwritePKInBeforeSaveHook) {
Model._warned.cannotOverwritePKInBeforeSaveHook = true;
console.warn('WARNING: id property cannot be changed from ' +
id + ' to ' + inst[pkName] + ' for model:' + Model.modelName +
' in \'before save\' operation hook');
g.warn('WARNING: {{id}} property cannot be changed from %s to %s for model:%s ' +
'in {{\'before save\'}} operation hook', id, inst[pkName], Model.modelName);
}
data = inst.toObject(false);
@ -2732,9 +2732,9 @@ DataAccessObject.replaceById = function(id, data, options, cb) {
if (ctx.data[pkName] !== id && !Model._warned.cannotOverwritePKInLoadedHook) {
Model._warned.cannotOverwritePKInLoadedHook = true;
console.warn('WARNING: id property cannot be changed from ' +
id + ' to ' + ctx.data[pkName] + ' for model:' + Model.modelName +
' in \'loaded\' operation hook');
g.warn('WARNING: {{id}} property cannot be changed from %s to %s for model:%s in ' +
'{{\'loaded\'}} operation hook',
id, ctx.data[pkName], Model.modelName);
}
inst.__persisted = true;
@ -2841,8 +2841,8 @@ function(data, options, cb) {
for (var i = 0, n = idNames.length; i < n; i++) {
var idName = idNames[i];
if (data[idName] !== undefined && !idEquals(data[idName], inst[idName])) {
var err = new Error('id property (' + idName + ') ' +
'cannot be updated from ' + inst[idName] + ' to ' + data[idName]);
var err = new Error(g.f('{{id}} property (%s) ' +
'cannot be updated from %s to %s'), idName, inst[idName], data[idName]);
err.statusCode = 400;
process.nextTick(function() {
cb(err);

View File

@ -20,6 +20,7 @@ var util = require('util');
var assert = require('assert');
var async = require('async');
var traverse = require('traverse');
var g = require('strong-globalize')();
if (process.env.DEBUG === 'loopback') {
// For back-compatibility
@ -237,8 +238,8 @@ DataSource._resolveConnector = function(name, loader) {
var connector = tryModules(names, loader);
var error = null;
if (!connector) {
error = util.format('\nWARNING: LoopBack connector "%s" is not installed ' +
'as any of the following modules:\n\n %s\n\nTo fix, run:\n\n npm install %s --save\n',
error = g.f('\nWARNING: {{LoopBack}} connector "%s" is not installed ' +
'as any of the following modules:\n\n %s\n\nTo fix, run:\n\n {{npm install %s --save}}\n',
name, names.join('\n'), names[names.length - 1]);
}
return {
@ -316,16 +317,15 @@ DataSource.prototype.setup = function(name, settings) {
this._setupConnector();
// we have an connector now?
if (!this.connector) {
throw new Error('Connector is not defined correctly: ' +
'it should create `connector` member of dataSource');
throw new Error(g.f('Connector is not defined correctly: ' +
'it should create `{{connector}}` member of dataSource'));
}
this.connected = !err; // Connected now
if (this.connected) {
this.emit('connected');
} else {
// The connection fails, let's report it and hope it will be recovered in the next call
console.error('Connection fails: ', err,
'\nIt will be retried for the next request.');
console.error(g.f('Connection fails: %s\nIt will be retried for the next request.', err));
this.emit('error', err);
this.connecting = false;
}
@ -458,7 +458,7 @@ DataSource.prototype.defineRelations = function(modelClass, relations) {
var targetModel, polymorphicName;
if (r.polymorphic && r.type !== 'belongsTo' && !r.model) {
throw new Error('No model specified for polymorphic ' + r.type + ': ' + rn);
throw new Error(g.f('No model specified for {{polymorphic}} %s: %s', r.type, rn));
}
if (r.polymorphic) {
@ -597,7 +597,7 @@ DataSource.prototype.define = function defineClass(className, properties, settin
var args = slice.call(arguments);
if (!className) {
throw new Error('Class name required');
throw new Error(g.f('Class name required'));
}
if (args.length === 1) {
properties = {};
@ -817,8 +817,8 @@ DataSource.prototype.automigrate = function(models, cb) {
if (invalidModels.length) {
process.nextTick(function() {
cb(new Error('Cannot migrate models not attached to this datasource: ' +
invalidModels.join(' ')));
cb(new Error(g.f('Cannot migrate models not attached to this datasource: %s',
invalidModels.join(' '))));
});
return cb.promise;
}
@ -872,8 +872,8 @@ DataSource.prototype.autoupdate = function(models, cb) {
if (invalidModels.length) {
process.nextTick(function() {
cb(new Error('Cannot migrate models not attached to this datasource: ' +
invalidModels.join(' ')));
cb(new Error(g.f('Cannot migrate models not attached to this datasource: %s',
invalidModels.join(' '))));
});
return cb.promise;
}
@ -1316,7 +1316,7 @@ DataSource.prototype.discoverSchemas = function(modelName, options, cb) {
var columns = results[0];
if (!columns || columns.length === 0) {
cb(new Error('Table \'' + modelName + '\' does not exist.'));
cb(new Error(g.f('Table \'%s\' does not exist.', modelName)));
return cb.promise;
}
@ -1716,7 +1716,7 @@ DataSource.prototype.log = function(sql, t) {
*/
DataSource.prototype.freeze = function freeze() {
if (!this.connector) {
throw new Error('The connector has not been initialized.');
throw new Error(g.f('The connector has not been initialized.'));
}
if (this.connector.freezeDataSource) {
this.connector.freezeDataSource();
@ -1779,7 +1779,7 @@ DataSource.prototype.idColumnName = function(modelName) {
*/
DataSource.prototype.idName = function(modelName) {
if (!this.getModelDefinition(modelName).idName) {
console.error('No id name', this.getModelDefinition(modelName));
g.error('No {{id}} name %s', this.getModelDefinition(modelName));
}
return this.getModelDefinition(modelName).idName();
};
@ -1968,7 +1968,7 @@ DataSource.prototype.enableRemote = function(operation) {
if (op) {
op.remoteEnabled = true;
} else {
throw new Error(operation + ' is not provided by the attached connector');
throw new Error(g.f('%s is not provided by the attached connector', operation));
}
};
@ -1997,7 +1997,7 @@ DataSource.prototype.disableRemote = function(operation) {
if (op) {
op.remoteEnabled = false;
} else {
throw new Error(operation + ' is not provided by the attached connector');
throw new Error(g.f('%s is not provided by the attached connector', operation));
}
};
@ -2129,7 +2129,7 @@ DataSource.prototype.ready = function(obj, args) {
var params = [].slice.call(args);
var cb = params.pop();
if (typeof cb === 'function') {
cb(new Error('Timeout in connecting after ' + timeout + ' ms'));
cb(new Error(g.f('Timeout in connecting after %s ms', timeout)));
}
}, timeout);
@ -2151,7 +2151,7 @@ DataSource.prototype.ping = function(cb) {
self.discoverModelProperties('dummy', {}, cb);
} else {
process.nextTick(function() {
var err = self.connected ? null : new Error('Not connected');
var err = self.connected ? null : new Error(g.f('Not connected'));
cb(err);
});
}

View File

@ -4,6 +4,7 @@
// License text available at https://opensource.org/licenses/MIT
var deprecated = require('depd')('loopback-datasource-juggler');
var g = require('strong-globalize')();
/*!
* Module exports
@ -94,7 +95,7 @@ function deprecateHook(ctor, prefixes, capitalizedName) {
var hookName = candidateNames.filter(function(hook) { return !!ctor[hook]; })[0];
if (!hookName) return; // just to be sure, this should never happen
if (ctor.modelName) hookName = ctor.modelName + '.' + hookName;
deprecated('Model hook "' + hookName + '" is deprecated, ' +
deprecated(g.f('Model hook "%s" is deprecated, ' +
'use Operation hooks instead. ' +
'http://docs.strongloop.com/display/LB/Operation+hooks');
'{{http://docs.strongloop.com/display/LB/Operation+hooks}}', hookName));
}

View File

@ -4,6 +4,7 @@
// License text available at https://opensource.org/licenses/MIT
var async = require('async');
var g = require('strong-globalize')();
var utils = require('./utils');
var List = require('./list');
var includeUtils = require('./include_utils');
@ -284,8 +285,7 @@ Inclusion.include = function(objects, include, options, cb) {
var relation = relations[relationName];
if (!relation) {
cb(new Error('Relation "' + relationName + '" is not defined for ' +
self.modelName + ' model'));
cb(new Error(g.f('Relation "%s" is not defined for %s model', relationName, self.modelName)));
return;
}
var polymorphic = relation.polymorphic;
@ -296,8 +296,8 @@ Inclusion.include = function(objects, include, options, cb) {
//}
if (!relation.modelTo) {
if (!relation.polymorphic) {
cb(new Error('Relation.modelTo is not defined for relation' +
relationName + ' and is no polymorphic'));
cb(new Error(g.f('{{Relation.modelTo}} is not defined for relation %s and is no polymorphic',
relationName)));
return;
}
}
@ -738,8 +738,8 @@ Inclusion.include = function(objects, include, options, cb) {
var Model = lookupModel(relation.modelFrom.dataSource.modelBuilder.
models, modelType);
if (!Model) {
callback(new Error('Discriminator type "' + modelType +
' specified but no model exists with such name'));
callback(new Error(g.f('Discriminator type %s specified but no model exists with such name',
modelType)));
return;
}
relation.applyScope(null, typeFilter);

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
var g = require('strong-globalize')();
var util = require('util');
var Any = require('./types').Types.Any;
@ -18,7 +19,7 @@ function List(items, itemType, parent) {
try {
items = JSON.parse(items);
} catch (e) {
var err = new Error(util.format('could not create List from JSON string: %j', items));
var err = new Error(g.f(util.format('could not create List from {{JSON}} string: %j', items)));
err.statusCode = 400;
throw err;
}
@ -29,7 +30,7 @@ function List(items, itemType, parent) {
items = items || [];
if (!Array.isArray(items)) {
var err = new Error(util.format('Items must be an array: %j', items));
var err = new Error(g.f(util.format('Items must be an array: %j', items)));
err.statusCode = 400;
throw err;
}

View File

@ -7,6 +7,7 @@
* Module dependencies
*/
var g = require('strong-globalize')();
var inflection = require('inflection');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
@ -125,7 +126,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
var pathName = httpOptions.path || pluralName;
if (!className) {
throw new Error('Class name required');
throw new Error(g.f('Class name required'));
}
if (args.length === 1) {
properties = {};
@ -178,7 +179,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
return new ModelConstructor(data, options);
}
if (ModelClass.settings.unresolved) {
throw new Error('Model ' + ModelClass.modelName + ' is not defined.');
throw new Error(g.f('Model %s is not defined.', ModelClass.modelName));
}
ModelBaseClass.apply(this, arguments);
};
@ -248,14 +249,13 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
// Throw error for properties with unsupported names
if (/\./.test(p)) {
throw new Error('Property names containing dot(s) are not supported. ' +
'Model: ' + className + ', property: ' + p);
throw new Error(g.f('Property names containing dot(s) are not supported. ' +
'Model: %s, property: %s', className, p));
}
// Warn if property name is 'constructor'
if (p === 'constructor') {
deprecated('Property name should not be "constructor" in Model: ' +
className);
deprecated(g.f('Property name should not be "{{constructor}}" in Model: %s', className));
}
}
@ -418,7 +418,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
var prop = properties[propertyName];
var DataType = prop.type;
if (!DataType) {
throw new Error('Invalid type for property ' + propertyName);
throw new Error(g.f('Invalid type for property %s', propertyName));
}
if (prop.required) {
@ -527,7 +527,7 @@ ModelBuilder.prototype.define = function defineClass(className, properties, sett
function DateType(arg) {
var d = new Date(arg);
if (isNaN(d.getTime())) {
throw new Error('Invalid date: ' + arg);
throw new Error(g.f('Invalid date: %s', arg));
}
return d;
}

View File

@ -12,6 +12,7 @@ module.exports = ModelBaseClass;
* Module dependencies
*/
var g = require('strong-globalize')();
var util = require('util');
var jutil = require('./jutil');
var List = require('./list');
@ -68,7 +69,7 @@ ModelBaseClass.prototype._initProperties = function(data, options) {
if (typeof data !== 'undefined' &&
typeof (data.constructor) !== 'function') {
throw new Error('Property name "constructor" is not allowed in ' + ctor.modelName + ' data');
throw new Error(g.f('Property name "{{constructor}}" is not allowed in %s data', ctor.modelName));
}
if (data instanceof ctor) {
@ -232,13 +233,14 @@ ModelBaseClass.prototype._initProperties = function(data, options) {
// Throw error for properties with unsupported names
if (/\./.test(p)) {
throw new Error(
throw new Error(g.f(
'Property names containing dot(s) are not supported. ' +
'Model: ' + this.constructor.modelName + ', dynamic property: ' +
p);
'Model: %s, dynamic property: %s',
this.constructor.modelName, p
));
}
} else if (strict === 'throw') {
throw new Error('Unknown property: ' + p);
throw new Error(g.f('Unknown property: %s', p));
} else if (strict === 'validate') {
this.__unknownProperties.push(p);
}
@ -302,7 +304,7 @@ ModelBaseClass.prototype._initProperties = function(data, options) {
break;
default:
// TODO Support user-provided functions via a registry of functions
console.warn('Unknown default value provider ' + defn);
g.warn('Unknown default value provider %s', defn);
}
// FIXME: We should coerce the value
// will implement it after we refactor the PropertyDefinition
@ -362,7 +364,7 @@ ModelBaseClass.getPropertyType = function(propName) {
return null;
}
if (!prop.type) {
throw new Error('Type not defined for property ' + this.modelName + '.' + propName);
throw new Error(g.f('Type not defined for property %s.%s', this.modelName, propName));
// return null;
}
return prop.type.name;

View File

@ -12,6 +12,7 @@ var async = require('async');
var utils = require('./utils');
var i8n = require('inflection');
var defineScope = require('./scope.js').defineScope;
var g = require('strong-globalize')();
var mergeQuery = utils.mergeQuery;
var idEquals = utils.idEquals;
var ModelBaseClass = require('./model.js');
@ -176,7 +177,7 @@ RelationDefinition.prototype.defineMethod = function(name, fn) {
var method;
if (definition.multiple) {
var scope = this.modelFrom.scopes[this.name];
if (!scope) throw new Error('Unknown relation scope: ' + this.name);
if (!scope) throw new Error(g.f('Unknown relation {{scope}}: %s', this.name));
method = scope.defineMethod(name, function() {
var relation = new relationClass(definition, this);
return fn.apply(relation, arguments);
@ -301,7 +302,7 @@ Relation.prototype.callScopeMethod = function(methodName) {
if (rel && typeof rel[methodName] === 'function') {
return rel[methodName].apply(rel, args);
} else {
throw new Error('Unknown scope method: ' + methodName);
throw new Error(g.f('Unknown scope method: %s', methodName));
}
};
@ -543,7 +544,7 @@ function lookupModelTo(modelFrom, modelTo, params, singularize) {
modelTo = lookupModel(modelFrom.dataSource.modelBuilder.models, modelToName) || modelTo;
}
if (typeof modelTo !== 'function') {
throw new Error('Could not find "' + params.as + '" relation for ' + modelFrom.modelName);
throw new Error(g.f('Could not find "%s" relation for %s', params.as, modelFrom.modelName));
}
}
return modelTo;
@ -784,7 +785,7 @@ HasMany.prototype.findById = function(fkId, options, cb) {
return cb(err);
}
if (!inst) {
err = new Error('No instance with id ' + fkId + ' found for ' + modelTo.modelName);
err = new Error(g.f('No instance with {{id}} %s found for %s', fkId, modelTo.modelName));
err.statusCode = 404;
return cb(err);
}
@ -792,9 +793,8 @@ HasMany.prototype.findById = function(fkId, options, cb) {
if (inst[fk] != null && idEquals(inst[fk], modelInstance[pk])) {
cb(null, inst);
} else {
err = new Error('Key mismatch: ' + modelFrom.modelName + '.' + pk +
': ' + modelInstance[pk] +
', ' + modelTo.modelName + '.' + fk + ': ' + inst[fk]);
err = new Error(g.f('Key mismatch: %s.%s: %s, %s.%s: %s',
modelFrom.modelName, pk, modelInstance[pk], modelTo.modelName, fk, inst[fk]));
err.statusCode = 400;
cb(err);
}
@ -929,10 +929,10 @@ HasManyThrough.prototype.findById = function(fkId, options, cb) {
self.exists(fkId, options, function(err, exists) {
if (err || !exists) {
if (!err) {
err = new Error('No relation found in ' + modelThrough.modelName +
' for (' + self.definition.modelFrom.modelName + '.' +
modelInstance[pk] + ',' +
modelTo.modelName + '.' + fkId + ')');
err = new Error(g.f('No relation found in %s' +
' for (%s.%s,%s.%s)',
modelThrough.modelName, self.definition.modelFrom.modelName,
modelInstance[pk], modelTo.modelName, fkId));
err.statusCode = 404;
}
return cb(err);
@ -942,7 +942,7 @@ HasManyThrough.prototype.findById = function(fkId, options, cb) {
return cb(err);
}
if (!inst) {
err = new Error('No instance with id ' + fkId + ' found for ' + modelTo.modelName);
err = new Error(g.f('No instance with id %s found for %s', fkId, modelTo.modelName));
err.statusCode = 404;
return cb(err);
}
@ -974,10 +974,9 @@ HasManyThrough.prototype.destroyById = function(fkId, options, cb) {
self.exists(fkId, options, function(err, exists) {
if (err || !exists) {
if (!err) {
err = new Error('No record found in ' + modelThrough.modelName +
' for (' + self.definition.modelFrom.modelName + '.' +
modelInstance[pk] + ' ,' +
modelTo.modelName + '.' + fkId + ')');
err = new Error(g.f('No record found in %s for (%s.%s ,%s.%s)',
modelThrough.modelName, self.definition.modelFrom.modelName,
modelInstance[pk], modelTo.modelName, fkId));
err.statusCode = 404;
}
return cb(err);
@ -1355,7 +1354,7 @@ BelongsTo.prototype.update = function(targetModelData, options, cb) {
if (inst instanceof ModelBaseClass) {
inst.updateAttributes(targetModelData, options, cb);
} else {
cb(new Error('BelongsTo relation ' + definition.name + ' is empty'));
cb(new Error(g.f('{{BelongsTo}} relation %s is empty', definition.name)));
}
});
return cb.promise;
@ -1381,7 +1380,7 @@ BelongsTo.prototype.destroy = function(options, cb) {
cb && cb(err, targetModel);
});
} else {
cb(new Error('BelongsTo relation ' + definition.name + ' is empty'));
cb(new Error(g.f('{{BelongsTo}} relation %s is empty', definition.name)));
}
});
return cb.promise;
@ -1450,12 +1449,12 @@ BelongsTo.prototype.related = function(condOrRefresh, options, cb) {
if (discriminator) {
var modelToName = modelInstance[discriminator];
if (typeof modelToName !== 'string') {
throw new Error('Polymorphic model not found: `' + discriminator + '` not set');
throw new Error(g.f('{{Polymorphic}} model not found: `%s` not set', discriminator));
}
modelToName = modelToName.toLowerCase();
modelTo = lookupModel(modelFrom.dataSource.modelBuilder.models, modelToName);
if (!modelTo) {
throw new Error('Polymorphic model not found: `' + modelToName + '`');
throw new Error(g.f('{{Polymorphic}} model not found: `%s`', modelToName));
}
}
@ -1489,10 +1488,9 @@ BelongsTo.prototype.related = function(condOrRefresh, options, cb) {
self.resetCache(inst);
cb(null, inst);
} else {
err = new Error('Key mismatch: ' +
self.definition.modelFrom.modelName + '.' + fk +
': ' + modelInstance[fk] +
', ' + modelTo.modelName + '.' + pk + ': ' + inst[pk]);
err = new Error(g.f('Key mismatch: %s.%s: %s, %s.%s: %s',
self.definition.modelFrom.modelName, fk, modelInstance[fk],
modelTo.modelName, pk, inst[pk]));
err.statusCode = 400;
cb(err);
}
@ -1552,7 +1550,7 @@ RelationDefinition.hasAndBelongsToMany = function hasAndBelongsToMany(modelFrom,
var models = modelFrom.dataSource.modelBuilder.models;
if (!params.through) {
if (params.polymorphic) throw new Error('Polymorphic relations need a through model');
if (params.polymorphic) throw new Error(g.f('{{Polymorphic}} relations need a through model'));
var name1 = modelFrom.modelName + modelTo.modelName;
var name2 = modelTo.modelName + modelFrom.modelName;
params.through = lookupModel(models, name1) || lookupModel(models, name2) ||
@ -1721,9 +1719,9 @@ HasOne.prototype.create = function(targetModelData, options, cb) {
self.resetCache(targetModel);
cb && cb(err, targetModel);
} else {
cb && cb(new Error(
'HasOne relation cannot create more than one instance of ' +
modelTo.modelName));
cb && cb(new Error(g.f(
'{{HasOne}} relation cannot create more than one instance of %s',
modelTo.modelName)));
}
});
return cb.promise;
@ -1743,7 +1741,7 @@ HasOne.prototype.update = function(targetModelData, options, cb) {
delete targetModelData[fk];
targetModel.updateAttributes(targetModelData, cb);
} else {
cb(new Error('HasOne relation ' + definition.name + ' is empty'));
cb(new Error(g.f('{{HasOne}} relation %s is empty', definition.name)));
}
});
return cb.promise;
@ -1761,7 +1759,7 @@ HasOne.prototype.destroy = function(options, cb) {
if (targetModel instanceof ModelBaseClass) {
targetModel.destroy(options, cb);
} else {
cb(new Error('HasOne relation ' + definition.name + ' is empty'));
cb(new Error(g.f('{{HasOne}} relation %s is empty', definition.name)));
}
});
return cb.promise;
@ -1898,10 +1896,9 @@ HasOne.prototype.related = function(condOrRefresh, options, cb) {
self.resetCache(inst);
cb(null, inst);
} else {
err = new Error('Key mismatch: ' +
self.definition.modelFrom.modelName + '.' + pk +
': ' + modelInstance[pk] +
', ' + modelTo.modelName + '.' + fk + ': ' + inst[fk]);
err = new Error(g.f('Key mismatch: %s.%s: %s, %s.%s: %s',
self.definition.modelFrom.modelName, pk, modelInstance[pk],
modelTo.modelName, fk, inst[fk]));
err.statusCode = 400;
cb(err);
}
@ -3169,7 +3166,7 @@ ReferencesMany.prototype.findById = function(fkId, options, cb) {
var inst = instances[0];
if (!inst) {
err = new Error('No instance with id ' + fkId + ' found for ' + modelTo.modelName);
err = new Error(g.f('No instance with {{id}} %s found for %s', fkId, modelTo.modelName));
err.statusCode = 404;
return cb(err);
}
@ -3178,9 +3175,9 @@ ReferencesMany.prototype.findById = function(fkId, options, cb) {
if (utils.findIndexOf(ids, inst[pk], idEquals) > -1) {
cb(null, inst);
} else {
err = new Error('Key mismatch: ' + modelFrom.modelName + '.' + fk +
': ' + modelInstance[fk] +
', ' + modelTo.modelName + '.' + pk + ': ' + inst[pk]);
err = new Error(g.f('Key mismatch: %s.%s: %s, %s.%s: %s',
modelFrom.modelName, fk, modelInstance[fk],
modelTo.modelName, pk, inst[pk]));
err.statusCode = 400;
cb(err);
}

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
var g = require('strong-globalize')();
var debug = require('debug')('loopback:connector:transaction');
var uuid = require('node-uuid');
var utils = require('./utils');
@ -94,7 +95,7 @@ TransactionMixin.beginTransaction = function(options, cb) {
});
} else {
process.nextTick(function() {
var err = new Error('Transaction is not supported');
var err = new Error(g.f('{{Transaction}} is not supported'));
cb(err);
});
}
@ -115,7 +116,7 @@ if (Transaction) {
// Report an error if the transaction is not active
if (!self.connection) {
process.nextTick(function() {
cb(new Error('The transaction is not active: ' + self.id));
cb(new Error(g.f('The {{transaction}} is not active: %s', self.id)));
});
return cb.promise;
}
@ -149,7 +150,7 @@ if (Transaction) {
// Report an error if the transaction is not active
if (!self.connection) {
process.nextTick(function() {
cb(new Error('The transaction is not active: ' + self.id));
cb(new Error(g.f('The {{transaction}} is not active: %s', self.id)));
});
return cb.promise;
}

View File

@ -22,6 +22,7 @@ exports.hasRegExpFlags = hasRegExpFlags;
exports.idEquals = idEquals;
exports.findIndexOf = findIndexOf;
var g = require('strong-globalize')();
var traverse = require('traverse');
var assert = require('assert');
var Promise = require('bluebird');
@ -30,9 +31,9 @@ function safeRequire(module) {
try {
return require(module);
} catch (e) {
console.log('Run "npm install loopback-datasource-juggler ' + module +
'" command to use loopback-datasource-juggler using ' + module +
' database engine');
g.log('Run "{{npm install loopback-datasource-juggler}} %s" command ',
'to use {{loopback-datasource-juggler}} using %s database engine',
module, module);
process.exit(1);
}
}
@ -313,7 +314,7 @@ function removeUndefined(query, handleUndefined) {
this.update(null);
break;
case 'throw':
throw new Error('Unexpected `undefined` in query');
throw new Error(g.f('Unexpected `undefined` in query'));
break;
case 'ignore':
default:
@ -518,8 +519,8 @@ function toRegExp(regex) {
var isRegExp = regex instanceof RegExp;
if (!(isString || isRegExp))
return new Error('Invalid argument, must be a string, regex literal, or ' +
'RegExp object');
return new Error(g.f('Invalid argument, must be a string, {{regex}} literal, or ' +
'{{RegExp}} object'));
if (isRegExp)
return regex;
@ -538,7 +539,7 @@ function toRegExp(regex) {
var hasInvalidFlags = invalidFlags.length > 0;
if (hasInvalidFlags)
return new Error('Invalid regex flags: ' + invalidFlags);
return new Error(g.f('Invalid {{regex}} flags: %s', invalidFlags));
// strip regex delimiter forward slashes
var expression = regex.substr(1, regex.lastIndexOf('/') - 1);

View File

@ -3,6 +3,7 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
var g = require('strong-globalize')();
var util = require('util');
var extend = util._extend;
@ -767,7 +768,7 @@ function ValidationError(obj) {
this.name = 'ValidationError';
var context = obj && obj.constructor && obj.constructor.modelName;
this.message = util.format(
this.message = g.f(
'The %s instance is not valid. Details: %s.',
context ? '`' + context + '`' : 'model',
formatErrors(obj.errors, obj.toJSON()) || '(unknown)'

View File

@ -46,6 +46,7 @@
"loopback-connector": "^2.1.0",
"node-uuid": "^1.4.2",
"qs": "^3.1.0",
"strong-globalize": "^2.5.8",
"traverse": "^0.6.6"
},
"license": "MIT"