diff --git a/nodes/core/core/20-inject.js b/nodes/core/core/20-inject.js index 2459175bb..4ae1ead97 100644 --- a/nodes/core/core/20-inject.js +++ b/nodes/core/core/20-inject.js @@ -1,5 +1,5 @@ /** - * Copyright 2013, 2014 IBM Corp. + * Copyright 2013, 2015 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,12 +32,12 @@ module.exports = function(RED) { if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) { this.repeat = this.repeat * 1000; - if (RED.settings.verbose) { this.log("repeat = "+this.repeat); } + if (RED.settings.verbose) { this.log(RED._("inject.repeat",this)); } this.interval_id = setInterval( function() { node.emit("input",{}); }, this.repeat ); } else if (this.crontab) { - if (RED.settings.verbose) { this.log("crontab = "+this.crontab); } + if (RED.settings.verbose) { this.log(RED._("inject.crontab",this)); } this.cronjob = new cron.CronJob(this.crontab, function() { node.emit("input",{}); @@ -68,10 +68,10 @@ module.exports = function(RED) { InjectNode.prototype.close = function() { if (this.interval_id != null) { clearInterval(this.interval_id); - if (RED.settings.verbose) { this.log("inject: repeat stopped"); } + if (RED.settings.verbose) { this.log(RED._("inject.stopped")); } } else if (this.cronjob != null) { this.cronjob.stop(); - if (RED.settings.verbose) { this.log("inject: cronjob stopped"); } + if (RED.settings.verbose) { this.log(RED._("inject.stopped")); } delete this.cronjob; } } @@ -84,7 +84,7 @@ module.exports = function(RED) { res.send(200); } catch(err) { res.send(500); - node.error("Inject failed:"+err); + node.error(RED._("inject.failed",{error:err})); } } else { res.send(404); diff --git a/nodes/core/locales/en-US/messages.json b/nodes/core/locales/en-US/messages.json new file mode 100644 index 000000000..87b8cc1ca --- /dev/null +++ b/nodes/core/locales/en-US/messages.json @@ -0,0 +1,8 @@ +{ + "inject": { + "repeat": "repeat = __repeat__", + "crontab": "crontab = __crontab__", + "stopped": "stopped", + "failed": "Inject failed: __error__" + } +} diff --git a/red/i18n.js b/red/i18n.js index 9bc5bfa53..e4a7018a4 100644 --- a/red/i18n.js +++ b/red/i18n.js @@ -19,15 +19,21 @@ var when = require("when"); var path = require("path"); var fs = require("fs"); +var defaultLang = "en-US"; + var resourceMap = { - "messages": path.resolve(__dirname+"/../locales") + "messages": { + basedir: path.resolve(__dirname+"/../locales"), + file:"messages.json" + } } +var resourceCache = {} - -function registerMessageCatalog(namespace,dir) { +function registerMessageCatalog(namespace,dir,file) { return when.promise(function(resolve,reject) { - resourceMap[namespace] = dir; + resourceMap[namespace] = { basedir:dir, file:file}; i18n.loadNamespace(namespace,function() { + //console.log(namespace,dir); resolve(); }); }); @@ -36,13 +42,16 @@ function registerMessageCatalog(namespace,dir) { var MessageFileLoader = { fetchOne: function(lng, ns, callback) { if (resourceMap[ns]) { - var file = path.join(resourceMap[ns],lng,"messages.json"); + var file = path.join(resourceMap[ns].basedir,lng,resourceMap[ns].file); fs.readFile(file,"utf8",function(err,content) { if (err) { callback(err); } else { try { - callback(null, JSON.parse(content.replace(/^\uFEFF/, ''))); + //console.log(">>",ns,file); + resourceCache[ns] = resourceCache[ns]||{}; + resourceCache[ns][lng] = JSON.parse(content.replace(/^\uFEFF/, '')); + callback(null, resourceCache[ns][lng]); } catch(e) { callback(e); } @@ -70,10 +79,26 @@ function init() { }); } +function getCatalog(namespace,lang) { + var result = null; + if (resourceCache.hasOwnProperty(namespace)) { + result = resourceCache[namespace][lang]; + if (!result) { + var langParts = lang.split("-"); + if (langParts.length == 2) { + result = getCatalog(namespace,langParts[0]); + } + } + } + return result; +} + var obj = module.exports = { init: init, - registerMessageCatalog: registerMessageCatalog + registerMessageCatalog: registerMessageCatalog, + catalog: getCatalog, + i: i18n } obj['_'] = function() { @@ -81,5 +106,6 @@ obj['_'] = function() { //if (def) { // opts.defaultValue = def; //} + //console.log(arguments); return i18n.t.apply(null,arguments); } diff --git a/red/nodes/registry/index.js b/red/nodes/registry/index.js index 655c10429..2450ab7fe 100644 --- a/red/nodes/registry/index.js +++ b/red/nodes/registry/index.js @@ -26,8 +26,8 @@ var settings; function init(_settings) { settings = _settings; - registry.init(settings); loader.init(settings); + registry.init(settings,loader); } //TODO: defaultNodesDir/disableNodePathScan are to make testing easier. // When the tests are componentized to match the new registry structure, diff --git a/red/nodes/registry/loader.js b/red/nodes/registry/loader.js index cb35a575e..d136c7a22 100644 --- a/red/nodes/registry/loader.js +++ b/red/nodes/registry/loader.js @@ -18,16 +18,26 @@ var when = require("when"); var fs = require("fs"); var path = require("path"); +var events = require("../../events"); var localfilesystem = require("./localfilesystem"); var registry = require("./registry"); +var RED; var settings; +var i18n = require("../../i18n"); + +events.on("node-locales-dir", function(info) { + i18n.registerMessageCatalog(info.namespace,info.dir,info.file); +}); function init(_settings) { settings = _settings; localfilesystem.init(settings); + + RED = require('../../red'); + } function load(defaultNodesDir,disableNodePathScan) { @@ -133,6 +143,7 @@ function loadNodeConfig(fileInfo) { node.types = []; node.err = err.toString(); } + resolve(node); } else { var types = []; @@ -143,8 +154,32 @@ function loadNodeConfig(fileInfo) { types.push(match[2]); } node.types = types; - node.config = content; + var langRegExp = /^]* data-lang=['"](.+?)['"]/i; + regExp = /(]* data-help-name=[\s\S]*?<\/script>)/gi; + match = null; + var mainContent = ""; + var helpContent = {}; + var index = 0; + while((match = regExp.exec(content)) !== null) { + mainContent += content.substring(index,regExp.lastIndex-match[1].length); + index = regExp.lastIndex; + var help = content.substring(regExp.lastIndex-match[1].length,regExp.lastIndex); + + var lang = "en-US"; + if ((match = langRegExp.exec(help)) !== null) { + lang = match[1]; + } + if (!helpContent.hasOwnProperty(lang)) { + helpContent[lang] = ""; + } + + helpContent[lang] += help; + } + mainContent += content.substring(index); + + node.config = mainContent; + node.help = helpContent; // TODO: parse out the javascript portion of the template //node.script = ""; for (var i=0;i'; //} diff --git a/red/red.js b/red/red.js index 98a7cc7b9..53cd0891d 100644 --- a/red/red.js +++ b/red/red.js @@ -20,6 +20,7 @@ var library = require("./api/library"); var comms = require("./comms"); var log = require("./log"); var util = require("./util"); +var i18n = require("./i18n"); var fs = require("fs"); var settings = require("./settings"); var credentials = require("./nodes/credentials"); @@ -56,6 +57,7 @@ var RED = { credentials: credentials, events: events, log: log, + i18n: i18n, comms: comms, settings:settings, util: util, @@ -75,4 +77,7 @@ var RED = { get httpNode() { return server.nodeApp }, get server() { return server.server } }; + +//RED["_"] = i18n._; + module.exports = RED; diff --git a/test/red/nodes/registry/index_spec.js b/test/red/nodes/registry/index_spec.js index 696e19064..5db18b668 100644 --- a/test/red/nodes/registry/index_spec.js +++ b/test/red/nodes/registry/index_spec.js @@ -160,14 +160,16 @@ describe('red/nodes/registry/index', function() { list[0].should.have.property("enabled",true); list[0].should.not.have.property("err"); - eventEmitSpy.callCount.should.equal(2); + eventEmitSpy.callCount.should.equal(3); eventEmitSpy.firstCall.args[0].should.be.equal("node-icon-dir"); eventEmitSpy.firstCall.args[1].should.be.equal( resourcesDir + "NestedDirectoryNode" + path.sep + "NestedNode" + path.sep + "icons"); - eventEmitSpy.secondCall.args[0].should.be.equal("type-registered"); - eventEmitSpy.secondCall.args[1].should.be.equal("nested-node-1"); + eventEmitSpy.secondCall.args[0].should.be.equal("node-locales-dir"); + + eventEmitSpy.thirdCall.args[0].should.be.equal("type-registered"); + eventEmitSpy.thirdCall.args[1].should.be.equal("nested-node-1"); done(); }).catch(function(e) { @@ -284,11 +286,11 @@ describe('red/nodes/registry/index', function() { var nodeConfigs = typeRegistry.getNodeConfigs(); // TODO: this is brittle... - nodeConfigs.should.equal("\n\n\n\n

this should be filtered out

\n\n\n\n\n"); + nodeConfigs.should.equal("\n\n\n\n

this should be filtered out

\n\n\n\n\n"); var nodeId = list[0].id; var nodeConfig = typeRegistry.getNodeConfig(nodeId); - nodeConfig.should.equal("\n\n\n\n

this should be filtered out

\n"); + nodeConfig.should.equal("\n\n\n\n

this should be filtered out

\n"); done(); }).catch(function(e) { done(e); @@ -548,14 +550,18 @@ describe('red/nodes/registry/index', function() { list[1].should.have.property("err"); - eventEmitSpy.callCount.should.equal(2); + eventEmitSpy.callCount.should.equal(3); + + eventEmitSpy.firstCall.args[0].should.be.equal("node-locales-dir"); - eventEmitSpy.firstCall.args[0].should.be.equal("node-icon-dir"); - eventEmitSpy.firstCall.args[1].should.be.equal( + + eventEmitSpy.secondCall.args[0].should.be.equal("node-icon-dir"); + eventEmitSpy.secondCall.args[1].should.be.equal( resourcesDir + "TestNodeModule" + path.sep+ "node_modules" + path.sep + "TestNodeModule" + path.sep + "icons"); - eventEmitSpy.secondCall.args[0].should.be.equal("type-registered"); - eventEmitSpy.secondCall.args[1].should.be.equal("test-node-mod-1"); + + eventEmitSpy.thirdCall.args[0].should.be.equal("type-registered"); + eventEmitSpy.thirdCall.args[1].should.be.equal("test-node-mod-1"); done(); }).catch(function(e) {