Skip to content

Commit 4ce5b5d

Browse files
committed
Support for globalization
1 parent f1ed1ee commit 4ce5b5d

File tree

17 files changed

+208
-133
lines changed

17 files changed

+208
-133
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ docs/man
1212
npm-debug.log
1313
.project
1414
test/memory.json
15+
intl/*
16+
!intl/en/
17+

index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
// This file is licensed under the MIT License.
44
// License text available at https://opensource.org/licenses/MIT
55

6+
var SG = require('strong-globalize');
7+
SG.SetRootDir(__dirname);
8+
69
exports.ModelBuilder = exports.LDL = require('./lib/model-builder.js').ModelBuilder;
710
exports.DataSource = exports.Schema = require('./lib/datasource.js').DataSource;
811
exports.ModelBaseClass = require('./lib/model.js');

intl/en/messages.json

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"4c78325cedbb826db3a05bf5df0e8546": "You must provide an {{id}} when replacing!",
3+
"a0cf0e09c26df14283223e84e6a10f00": "Could not update attributes. {{Object}} with {{id}} {0} does not exist!",
4+
"e54d944c2a2c85a23caa86027ae307cf": "Cannot migrate models not attached to this datasource: {0}",
5+
"e6161ae8459c79d810e2aa9d21282a39": "You must provide an {{id}} when updating attributes!",
6+
"fca4d12faff1035d9d0438d73432571b": "Duplicate entry for {0}.{1}",
7+
"09483e03b91c8bd58732a74b3ef1ec13": "Invalid date: {0}",
8+
"0e88a84c6bc2638fbcc5d3ea95181f99": "Unknown property: {0}",
9+
"416dfbb7b823f51c9f3800be81060b41": "No instance with {{id}} {0} found for {1}",
10+
"5ec8efeb715a2c34b440f2d76e2cf87d": " {0}",
11+
"6c3234937d69763fc7f6bcafccc59bbc": "{{Model::deleteById}} requires the {{id}} argument",
12+
"6eb6fd4fbd73394000bc25f5776fd20c": "{{Model::exists}} requires the {{id}} argument",
13+
"7bbbdece4eea90e42aa5c0bce295e503": "{{Model::findById}} requires the {{id}} argument",
14+
"a829dee089c912e68c18920ba015400c": "WARNING: {{id}} property cannot be changed from {0} to {1} for model:{2} in {{'loaded'}} operation hook",
15+
"a984a076c59e451948b2bcf7a393d860": "WARNING: {{id}} property cannot be changed from {0} to {1} for model:{2} in {{'before save'}} operation hook",
16+
"db03083e9a768388fdbee865249ac67a": "Ignoring validation errors in {{updateOrCreate()}}:",
17+
"e4434de4bb8f5a3cd1d416e4d80d7e0b": "Unknown \"{0}\" {{id}} \"{1}\".",
18+
"f6e8c96c93b9c7687d6c172b3695e898": "{{id}} property ({0}) cannot be updated from {1} to {2}",
19+
"0be2d39d225b1d8b2a0f92ad5c65c9ac": "No model specified for {{polymorphic}} {0}: {1}",
20+
"0c4eb8b6c2ff6e51d7e195eee346ced9": "Table '{0}' does not exist.",
21+
"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",
22+
"6111399276924ffa3bc9a410cdfcb2e5": "No {{id}} name {0}",
23+
"791ab3031a73ede03f7d6299a85e8289": "Timeout in connecting after {0} ms",
24+
"7b277018e43d41bc445731092b91547d": "Not connected",
25+
"a2487abefef4259c2131d96cdb8543b1": "Connection fails: {0}\nIt will be retried for the next request.",
26+
"b15b20280211ad258d92947f05b6e4a5": "The connector has not been initialized.",
27+
"ddf0aa14803f1c84f4a97f3803f7471c": "Class name required",
28+
"e0e9504e137a3c3339144b51ed76fef2": "Connector is not defined correctly: it should create `{{connector}}` member of dataSource",
29+
"ec42dca074f1818c447f7ad16e2d01af": "{0} is not provided by the attached connector",
30+
"ba0fd8106eb54de4d003a844206431fd": "Model hook \"{0}\" is deprecated, use Operation hooks instead. {{http://docs.strongloop.com/display/LB/Operation+hooks}}",
31+
"280f4550f90e133118955ec6f6f72830": "Discriminator type {0} specified but no model exists with such name",
32+
"83abbb3ad105947dccbb21b4cf41e98f": "{{Relation.modelTo}} is not defined for relation {0} and is no polymorphic",
33+
"eb56c2b0c30cf006e2df00a549ec9c2c": "Relation \"{0}\" is not defined for {1} model",
34+
"514985b2327f061ffb1c932f6b909979": "Model {0} is not defined.",
35+
"8091838319a5cc7d6a34af2f2a616ce9": "Property name should not be \"{{constructor}}\" in Model: {0}",
36+
"da02dd6c53d4148320eeb31718a7aebe": "Invalid type for property {0}",
37+
"da751a8a748adbde5b55fa83b707b4e2": "Property names containing dot(s) are not supported. Model: {0}, property: {1}",
38+
"881e4b0cb86ed59549248ee540a9fd10": "Property name \"{{constructor}}\" is not allowed in {0} data",
39+
"bdb11cc1c780c9ccac33c316cfdc9d82": "Type not defined for property {0}.{1}",
40+
"cd930369e86cdd222f7bd117c6f9fa94": "Unknown default value provider {0}",
41+
"cfee4d8149316d9a647c0885cf3cafaf": "Property names containing dot(s) are not supported. Model: {0}, dynamic property: {1}",
42+
"0c0b867aca0973ba26e887d3337cc4ec": "{{Polymorphic}} model not found: `{0}` not set",
43+
"2f062cbecdf24245731bddc77714c814": "Could not find \"{0}\" relation for {1}",
44+
"3cde8cc9bca22c67278b202ab0720106": "No instance with id {0} found for {1}",
45+
"6502a117987610380b9068ef98b1b0ee": "No record found in {0} for ({1}.{2} ,{3}.{4})",
46+
"6fcc2ff0db7a4f490f5e0ce9e24691f3": "{{HasOne}} relation cannot create more than one instance of {0}",
47+
"7e9530c0399289be0ee601a604be71ff": "{{BelongsTo}} relation {0} is empty",
48+
"7faa840eb6ce11250a141deb42a6c489": "Unknown relation {{scope}}: {0}",
49+
"89afd3a9249f5a8d3edda07d84ca049d": "{{Polymorphic}} model not found: `{0}`",
50+
"a004f310d315e592843776fab964eaeb": "{{Polymorphic}} relations need a through model",
51+
"a25e41a39c60c4702e55d0c3936576a1": "Key mismatch: {0}.{1}: {2}, {3}.{4}: {5}",
52+
"a327355560d495454fba2c1aad6bdf09": "Unknown scope method: {0}",
53+
"e08ab0e1ab55f26c357061447b635905": "No relation found in {0} for ({1}.{2},{3}.{4})",
54+
"e55937649d8d7a11706b8cec22d02eae": "{{HasOne}} relation {0} is empty",
55+
"2c4904377a87fdab502118719cc0d266": "{{Transaction}} is not supported",
56+
"ecb7aa804bf54c682999d20d6436104c": "The {{transaction}} is not active: {0}",
57+
"89bf6d92731fe7bd2146ce8d0bec205c": "Invalid argument, must be a string, {{regex}} literal, or {{RegExp}} object",
58+
"8c5ab01638c1ac1d58168c6346a8481a": "Invalid {{regex}} flags: {0}",
59+
"a6c18a7f4390cd3d59a2a7a047ae2aab": "Run \"{{npm install loopback-datasource-juggler}} {0}\" command ",
60+
"b138294f132edfe1eb2a8211150c7238": "Unexpected `undefined` in query",
61+
"8a39126103a157f501affa070367a1b0": "The {0} instance is not valid. Details: {1}."
62+
}

lib/connectors/memory.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// This file is licensed under the MIT License.
44
// License text available at https://opensource.org/licenses/MIT
55

6+
var g = require('strong-globalize')();
67
var util = require('util');
78
var Connector = require('loopback-connector').Connector;
89
var geo = require('../geo');
@@ -217,7 +218,7 @@ Memory.prototype._createSync = function(model, data, fn) {
217218
}
218219

219220
if (this.collection(model)[id])
220-
return fn(new Error('Duplicate entry for ' + model + '.' + idName));
221+
return fn(new Error(g.f('Duplicate entry for %s.%s', model, idName)));
221222

222223
this.collection(model)[id] = serialize(data);
223224
fn(null, id);
@@ -711,7 +712,7 @@ Memory.prototype.update =
711712

712713
Memory.prototype.updateAttributes = function updateAttributes(model, id, data, options, cb) {
713714
if (!id) {
714-
var err = new Error('You must provide an id when updating attributes!');
715+
var err = new Error(g.f('You must provide an {{id}} when updating attributes!'));
715716
if (cb) {
716717
return cb(err);
717718
} else {
@@ -730,14 +731,14 @@ Memory.prototype.updateAttributes = function updateAttributes(model, id, data, o
730731
if (modelData) {
731732
this.save(model, data, options, cb);
732733
} else {
733-
cb(new Error('Could not update attributes. Object with id ' + id + ' does not exist!'));
734+
cb(new Error(g.f('Could not update attributes. {{Object}} with {{id}} %s does not exist!', id)));
734735
}
735736
};
736737

737738
Memory.prototype.replaceById = function(model, id, data, options, cb) {
738739
var self = this;
739740
if (!id) {
740-
var err = new Error('You must provide an id when replacing!');
741+
var err = new Error(g.f('You must provide an {{id}} when replacing!'));
741742
return process.nextTick(function() { cb(err); });
742743
}
743744
// Do not modify the data object passed in arguments
@@ -828,8 +829,8 @@ Memory.prototype.automigrate = function(models, cb) {
828829

829830
if (invalidModels.length) {
830831
return process.nextTick(function() {
831-
cb(new Error('Cannot migrate models not attached to this datasource: ' +
832-
invalidModels.join(' ')));
832+
cb(new Error(g.f('Cannot migrate models not attached to this datasource: %s',
833+
invalidModels.join(' '))));
833834
});
834835
}
835836

lib/connectors/transient.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// This file is licensed under the MIT License.
44
// License text available at https://opensource.org/licenses/MIT
55

6+
var g = require('strong-globalize')();
67
var util = require('util');
78
var Connector = require('loopback-connector').Connector;
89
var utils = require('../utils');
@@ -108,7 +109,7 @@ Transient.prototype.update =
108109

109110
Transient.prototype.updateAttributes = function updateAttributes(model, id, data, cb) {
110111
if (!id) {
111-
var err = new Error('You must provide an id when updating attributes!');
112+
var err = new Error(g.f('You must provide an {{id}} when updating attributes!'));
112113
if (cb) {
113114
return cb(err);
114115
} else {

lib/dao.js

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module.exports = DataAccessObject;
1111
/*!
1212
* Module dependencies
1313
*/
14+
var g = require('strong-globalize')();
1415
var async = require('async');
1516
var jutil = require('./jutil');
1617
var ValidationError = require('./validations').ValidationError;
@@ -89,7 +90,7 @@ function applyStrictCheck(model, strict, data, inst, cb) {
8990
if (props[key]) {
9091
result[key] = data[key];
9192
} else if (strict === 'throw') {
92-
cb(new Error('Unknown property: ' + key));
93+
cb(new Error(g.f('Unknown property: %s', key)));
9394
return;
9495
} else if (strict === 'validate') {
9596
inst.__unknownProperties.push(key);
@@ -533,8 +534,8 @@ DataAccessObject.upsert = function(data, options, cb) {
533534
return cb(new ValidationError(inst), inst);
534535
} else {
535536
// TODO(bajtos) Remove validateUpsert:undefined in v3.0
536-
console.warn('Ignoring validation errors in updateOrCreate():');
537-
console.warn(' %s', new ValidationError(inst).message);
537+
g.warn('Ignoring validation errors in {{updateOrCreate()}}:');
538+
g.warn(' %s', new ValidationError(inst).message);
538539
// continue with updateOrCreate
539540
}
540541
}
@@ -1049,7 +1050,7 @@ DataAccessObject.exists = function exists(id, options, cb) {
10491050
});
10501051
} else {
10511052
process.nextTick(function() {
1052-
cb(new Error('Model::exists requires the id argument'));
1053+
cb(new Error(g.f('{{Model::exists}} requires the {{id}} argument')));
10531054
});
10541055
}
10551056
return cb.promise;
@@ -1111,7 +1112,7 @@ DataAccessObject.findById = function findById(id, filter, options, cb) {
11111112
return cb.promise;
11121113
} else if (id == null || id === '') {
11131114
process.nextTick(function() {
1114-
cb(new Error('Model::findById requires the id argument'));
1115+
cb(new Error(g.f('{{Model::findById}} requires the {{id}} argument')));
11151116
});
11161117
} else {
11171118
var query = byIdQuery(this, id);
@@ -1184,7 +1185,7 @@ function convertNullToNotFoundError(ctx, cb) {
11841185

11851186
var modelName = ctx.method.sharedClass.name;
11861187
var id = ctx.getArgByName('id');
1187-
var msg = 'Unknown "' + modelName + '" id "' + id + '".';
1188+
var msg = g.f('Unknown "%s" {{id}} "%s".', modelName, id);
11881189
var error = new Error(msg);
11891190
error.statusCode = error.status = 404;
11901191
cb(error);
@@ -1242,22 +1243,22 @@ DataAccessObject._normalize = function(filter) {
12421243
}
12431244
var err = null;
12441245
if ((typeof filter !== 'object') || Array.isArray(filter)) {
1245-
err = new Error(util.format('The query filter %j is not an object', filter));
1246+
err = new Error(g.f(util.format('The query filter %j is not an {{object}}', filter)));
12461247
err.statusCode = 400;
12471248
throw err;
12481249
}
12491250
if (filter.limit || filter.skip || filter.offset) {
12501251
var limit = Number(filter.limit || 100);
12511252
var offset = Number(filter.skip || filter.offset || 0);
12521253
if (isNaN(limit) || limit <= 0 || Math.ceil(limit) !== limit) {
1253-
err = new Error(util.format('The limit parameter %j is not valid',
1254-
filter.limit));
1254+
err = new Error(g.f(util.format('The {{limit}} parameter %j is not valid',
1255+
filter.limit)));
12551256
err.statusCode = 400;
12561257
throw err;
12571258
}
12581259
if (isNaN(offset) || offset < 0 || Math.ceil(offset) !== offset) {
1259-
err = new Error(util.format('The offset/skip parameter %j is not valid',
1260-
filter.skip || filter.offset));
1260+
err = new Error(g.f(util.format('The {{offset/skip}} parameter %j is not valid',
1261+
filter.skip || filter.offset)));
12611262
err.statusCode = 400;
12621263
throw err;
12631264
}
@@ -1288,7 +1289,7 @@ DataAccessObject._normalize = function(filter) {
12881289
if (dir === 'ASC' || dir === 'DESC') {
12891290
token = parts[0] + ' ' + dir;
12901291
} else {
1291-
err = new Error(util.format('The order %j has invalid direction', token));
1292+
err = new Error(g.f(util.format('The {{order}} %j has invalid direction', token)));
12921293
err.statusCode = 400;
12931294
throw err;
12941295
}
@@ -1324,7 +1325,7 @@ DataAccessObject._normalize = function(filter) {
13241325
function DateType(arg) {
13251326
var d = new Date(arg);
13261327
if (isNaN(d.getTime())) {
1327-
throw new Error('Invalid date: ' + arg);
1328+
throw new Error(g.f('Invalid date: %s', arg));
13281329
}
13291330
return d;
13301331
}
@@ -1365,7 +1366,7 @@ DataAccessObject._coerce = function(where) {
13651366

13661367
var err;
13671368
if (typeof where !== 'object' || Array.isArray(where)) {
1368-
err = new Error(util.format('The where clause %j is not an object', where));
1369+
err = new Error(g.f(util.format('The where clause %j is not an {{object}}', where)));
13691370
err.statusCode = 400;
13701371
throw err;
13711372
}
@@ -1380,7 +1381,7 @@ DataAccessObject._coerce = function(where) {
13801381
self._coerce(clauses[k]);
13811382
}
13821383
} else {
1383-
err = new Error(util.format('The %s operator has invalid clauses %j', p, clauses));
1384+
err = new Error(g.f(util.format('The %s operator has invalid clauses %j', p, clauses)));
13841385
err.statusCode = 400;
13851386
throw err;
13861387
}
@@ -1439,22 +1440,22 @@ DataAccessObject._coerce = function(where) {
14391440
case 'inq':
14401441
case 'nin':
14411442
if (!Array.isArray(val)) {
1442-
err = new Error(util.format('The %s property has invalid clause %j', p, where[p]));
1443+
err = new Error(g.f(util.format('The %s property has invalid clause %j', p, where[p])));
14431444
err.statusCode = 400;
14441445
throw err;
14451446
}
14461447
break;
14471448
case 'between':
14481449
if (!Array.isArray(val) || val.length !== 2) {
1449-
err = new Error(util.format('The %s property has invalid clause %j', p, where[p]));
1450+
err = new Error(g.f(util.format('The %s property has invalid clause %j', p, where[p])));
14501451
err.statusCode = 400;
14511452
throw err;
14521453
}
14531454
break;
14541455
case 'like':
14551456
case 'nlike':
14561457
if (!(typeof val === 'string' || val instanceof RegExp)) {
1457-
err = new Error(util.format('The %s property has invalid clause %j', p, where[p]));
1458+
err = new Error(g.f(util.format('The %s property has invalid clause %j', p, where[p])));
14581459
err.statusCode = 400;
14591460
throw err;
14601461
}
@@ -2011,7 +2012,7 @@ DataAccessObject.deleteById = function deleteById(id, options, cb) {
20112012
return cb.promise;
20122013
} else if (id == null || id === '') {
20132014
process.nextTick(function() {
2014-
cb(new Error('Model::deleteById requires the id argument'));
2015+
cb(new Error(g.f('{{Model::deleteById}} requires the {{id}} argument')));
20152016
});
20162017
return cb.promise;
20172018
}
@@ -2022,7 +2023,7 @@ DataAccessObject.deleteById = function deleteById(id, options, cb) {
20222023
if (err) return cb(err);
20232024
var deleted = info && info.count > 0;
20242025
if (Model.settings.strictDelete && !deleted) {
2025-
err = new Error('No instance with id ' + id + ' found for ' + Model.modelName);
2026+
err = new Error(g.f('No instance with {{id}} %s found for %s', id, Model.modelName));
20262027
err.code = 'NOT_FOUND';
20272028
err.statusCode = 404;
20282029
return cb(err);
@@ -2485,7 +2486,7 @@ DataAccessObject.prototype.remove =
24852486
if (err) return cb(err, false);
24862487
var deleted = info && info.count > 0;
24872488
if (Model.settings.strictDelete && !deleted) {
2488-
err = new Error('No instance with id ' + id + ' found for ' + Model.modelName);
2489+
err = new Error(g.f('No instance with {{id}} %s found for %s', id, Model.modelName));
24892490
err.code = 'NOT_FOUND';
24902491
err.statusCode = 404;
24912492
return cb(err, false);
@@ -2509,7 +2510,7 @@ DataAccessObject.prototype.remove =
25092510
if (err) return cb(err);
25102511
var deleted = info && info.count > 0;
25112512
if (Model.settings.strictDelete && !deleted) {
2512-
err = new Error('No instance with id ' + id + ' found for ' + Model.modelName);
2513+
err = new Error(g.f('No instance with {{id}} %s found for %s', id, Model.modelName));
25132514
err.code = 'NOT_FOUND';
25142515
err.statusCode = 404;
25152516
return cb(err);
@@ -2654,8 +2655,8 @@ DataAccessObject.replaceById = function(id, data, options, cb) {
26542655
var hookState = {};
26552656

26562657
if (id !== data[pkName]) {
2657-
var err = new Error('id property (' + pkName + ') ' +
2658-
'cannot be updated from ' + id + ' to ' + data[pkName]);
2658+
var err = new Error(g.f('{{id}} property (%s) ' +
2659+
'cannot be updated from %s to %s', pkName, id, data[pkName]));
26592660
err.statusCode = 400;
26602661
process.nextTick(function() { cb(err); });
26612662
return cb.promise;
@@ -2674,9 +2675,8 @@ DataAccessObject.replaceById = function(id, data, options, cb) {
26742675

26752676
if (ctx.instance[pkName] !== id && !Model._warned.cannotOverwritePKInBeforeSaveHook) {
26762677
Model._warned.cannotOverwritePKInBeforeSaveHook = true;
2677-
console.warn('WARNING: id property cannot be changed from ' +
2678-
id + ' to ' + inst[pkName] + ' for model:' + Model.modelName +
2679-
' in \'before save\' operation hook');
2678+
g.warn('WARNING: {{id}} property cannot be changed from %s to %s for model:%s ' +
2679+
'in {{\'before save\'}} operation hook', id, inst[pkName], Model.modelName);
26802680
}
26812681

26822682
data = inst.toObject(false);
@@ -2732,9 +2732,9 @@ DataAccessObject.replaceById = function(id, data, options, cb) {
27322732

27332733
if (ctx.data[pkName] !== id && !Model._warned.cannotOverwritePKInLoadedHook) {
27342734
Model._warned.cannotOverwritePKInLoadedHook = true;
2735-
console.warn('WARNING: id property cannot be changed from ' +
2736-
id + ' to ' + ctx.data[pkName] + ' for model:' + Model.modelName +
2737-
' in \'loaded\' operation hook');
2735+
g.warn('WARNING: {{id}} property cannot be changed from %s to %s for model:%s in ' +
2736+
'{{\'loaded\'}} operation hook',
2737+
id, ctx.data[pkName], Model.modelName);
27382738
}
27392739

27402740
inst.__persisted = true;
@@ -2841,8 +2841,8 @@ function(data, options, cb) {
28412841
for (var i = 0, n = idNames.length; i < n; i++) {
28422842
var idName = idNames[i];
28432843
if (data[idName] !== undefined && !idEquals(data[idName], inst[idName])) {
2844-
var err = new Error('id property (' + idName + ') ' +
2845-
'cannot be updated from ' + inst[idName] + ' to ' + data[idName]);
2844+
var err = new Error(g.f('{{id}} property (%s) ' +
2845+
'cannot be updated from %s to %s'), idName, inst[idName], data[idName]);
28462846
err.statusCode = 400;
28472847
process.nextTick(function() {
28482848
cb(err);

0 commit comments

Comments
 (0)