mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
i18n enable runtime node files
This commit is contained in:
parent
7d41781fb4
commit
6d4c64fcd5
@ -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);
|
||||
|
8
nodes/core/locales/en-US/messages.json
Normal file
8
nodes/core/locales/en-US/messages.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"inject": {
|
||||
"repeat": "repeat = __repeat__",
|
||||
"crontab": "crontab = __crontab__",
|
||||
"stopped": "stopped",
|
||||
"failed": "Inject failed: __error__"
|
||||
}
|
||||
}
|
40
red/i18n.js
40
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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 = /^<script[^>]* data-lang=['"](.+?)['"]/i;
|
||||
regExp = /(<script[^>]* 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<node.types.length;i++) {
|
||||
@ -153,13 +188,38 @@ function loadNodeConfig(fileInfo) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fs.stat(path.join(path.dirname(file),"locales"),function(err,stat) {
|
||||
if (!err) {
|
||||
node.namespace = node.id;
|
||||
i18n.registerMessageCatalog(node.id,
|
||||
path.join(path.dirname(file),"locales"),
|
||||
path.basename(file,".js")+".json")
|
||||
.then(function() {
|
||||
resolve(node);
|
||||
});
|
||||
} else {
|
||||
node.namespace = node.module;
|
||||
resolve(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
resolve(node);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//function getAPIForNode(node) {
|
||||
// var red = {
|
||||
// nodes: RED.nodes,
|
||||
// library: RED.library,
|
||||
// credentials: RED.credentials,
|
||||
// events: RED.events,
|
||||
// log: RED.log,
|
||||
//
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
|
||||
/**
|
||||
* Loads the specified node into the runtime
|
||||
@ -180,7 +240,20 @@ function loadNodeSet(node) {
|
||||
var loadPromise = null;
|
||||
var r = require(node.file);
|
||||
if (typeof r === "function") {
|
||||
var promise = r(require('../../red'));
|
||||
|
||||
var red = {};
|
||||
for (var i in RED) {
|
||||
if (RED.hasOwnProperty(i) && !/^(init|start|stop)$/.test(i)) {
|
||||
var propDescriptor = Object.getOwnPropertyDescriptor(RED,i);
|
||||
Object.defineProperty(red,i,propDescriptor);
|
||||
}
|
||||
}
|
||||
red["_"] = function() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
args[0] = node.namespace+":"+args[0];
|
||||
return red.i18n._.apply(null,args);
|
||||
}
|
||||
var promise = r(red);
|
||||
if (promise != null && typeof promise.then === "function") {
|
||||
loadPromise = promise.then(function() {
|
||||
node.enabled = true;
|
||||
@ -269,10 +342,43 @@ function addFile(file) {
|
||||
}
|
||||
}
|
||||
|
||||
function loadNodeHelp(node,lang) {
|
||||
var dir = path.dirname(node.template);
|
||||
var base = path.basename(node.template);
|
||||
var localePath = path.join(dir,"locales",lang,base);
|
||||
try {
|
||||
// TODO: make this async
|
||||
var content = fs.readFileSync(localePath, "utf8")
|
||||
return content;
|
||||
} catch(err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getNodeHelp(node,lang) {
|
||||
if (!node.help[lang]) {
|
||||
var help = loadNodeHelp(node,lang);
|
||||
if (help == null) {
|
||||
var langParts = lang.split("-");
|
||||
if (langParts.length == 2) {
|
||||
help = loadNodeHelp(node,langParts[0]);
|
||||
}
|
||||
}
|
||||
if (help) {
|
||||
node.help[lang] = help;
|
||||
} else {
|
||||
node.help[lang] = node.help["en-US"];
|
||||
}
|
||||
|
||||
}
|
||||
return node.help[lang];
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: init,
|
||||
load: load,
|
||||
addModule: addModule,
|
||||
addFile: addFile,
|
||||
loadNodeSet: loadNodeSet
|
||||
loadNodeSet: loadNodeSet,
|
||||
getNodeHelp: getNodeHelp
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ function getLocalNodeFiles(dir) {
|
||||
}
|
||||
} else if (stats.isDirectory()) {
|
||||
// Ignore /.dirs/, /lib/ /node_modules/
|
||||
if (!/^(\..*|lib|icons|node_modules|test)$/.test(fn)) {
|
||||
if (!/^(\..*|lib|icons|node_modules|test|locales)$/.test(fn)) {
|
||||
result = result.concat(getLocalNodeFiles(path.join(dir,fn)));
|
||||
} else if (fn === "icons") {
|
||||
events.emit("node-icon-dir",path.join(dir,fn));
|
||||
@ -196,6 +196,13 @@ function getNodeFiles(_defaultNodesDir,disableNodePathScan) {
|
||||
var nodeFiles = getLocalNodeFiles(path.resolve(defaultNodesDir));
|
||||
//console.log(nodeFiles);
|
||||
|
||||
var defaultLocalesPath = path.resolve(path.join(defaultNodesDir,"core","locales"));
|
||||
events.emit("node-locales-dir", {
|
||||
namespace:"node-red",
|
||||
dir: defaultLocalesPath,
|
||||
file: "messages.json"
|
||||
});
|
||||
|
||||
if (settings.userDir) {
|
||||
dir = path.join(settings.userDir,"nodes");
|
||||
nodeFiles = nodeFiles.concat(getLocalNodeFiles(dir));
|
||||
|
@ -23,6 +23,8 @@ var settings;
|
||||
|
||||
var Node;
|
||||
|
||||
var loader;
|
||||
|
||||
var nodeConfigCache = null;
|
||||
var moduleConfigs = {};
|
||||
var nodeList = [];
|
||||
@ -30,8 +32,9 @@ var nodeConstructors = {};
|
||||
var nodeTypeToId = {};
|
||||
var moduleNodes = {};
|
||||
|
||||
function init(_settings) {
|
||||
function init(_settings,_loader) {
|
||||
settings = _settings;
|
||||
loader = _loader;
|
||||
if (settings.available()) {
|
||||
moduleConfigs = loadNodeConfigs();
|
||||
} else {
|
||||
@ -323,7 +326,7 @@ function registerNodeConstructor(type,constructor) {
|
||||
events.emit("type-registered",type);
|
||||
}
|
||||
|
||||
function getAllNodeConfigs() {
|
||||
function getAllNodeConfigs(lang) {
|
||||
if (!nodeConfigCache) {
|
||||
var result = "";
|
||||
var script = "";
|
||||
@ -332,6 +335,7 @@ function getAllNodeConfigs() {
|
||||
var config = moduleConfigs[getModule(id)].nodes[getNode(id)];
|
||||
if (config.enabled && !config.err) {
|
||||
result += config.config;
|
||||
result += loader.getNodeHelp(config,lang||"en-US")
|
||||
//script += config.script;
|
||||
}
|
||||
}
|
||||
@ -345,7 +349,7 @@ function getAllNodeConfigs() {
|
||||
return nodeConfigCache;
|
||||
}
|
||||
|
||||
function getNodeConfig(id) {
|
||||
function getNodeConfig(id,lang) {
|
||||
var config = moduleConfigs[getModule(id)];
|
||||
if (!config) {
|
||||
return null;
|
||||
@ -353,6 +357,8 @@ function getNodeConfig(id) {
|
||||
config = config.nodes[getNode(id)];
|
||||
if (config) {
|
||||
var result = config.config;
|
||||
result += loader.getNodeHelp(config,lang||"en-US")
|
||||
|
||||
//if (config.script) {
|
||||
// result += '<script type="text/javascript">'+config.script+'</script>';
|
||||
//}
|
||||
|
@ -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;
|
||||
|
@ -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("<script type=\"text/x-red\" data-template-name=\"test-node-1\"></script>\n<script type=\"text/x-red\" data-help-name=\"test-node-1\"></script>\n<script type=\"text/javascript\">RED.nodes.registerType('test-node-1',{});</script>\n<style></style>\n<p>this should be filtered out</p>\n<script type=\"text/x-red\" data-template-name=\"test-node-2\"></script>\n<script type=\"text/x-red\" data-help-name=\"test-node-2\"></script>\n<script type=\"text/javascript\">RED.nodes.registerType('test-node-2',{});</script>\n<style></style>\n");
|
||||
nodeConfigs.should.equal("<script type=\"text/x-red\" data-template-name=\"test-node-1\"></script>\n\n<script type=\"text/javascript\">RED.nodes.registerType('test-node-1',{});</script>\n<style></style>\n<p>this should be filtered out</p>\n<script type=\"text/x-red\" data-help-name=\"test-node-1\"></script><script type=\"text/x-red\" data-template-name=\"test-node-2\"></script>\n\n<script type=\"text/javascript\">RED.nodes.registerType('test-node-2',{});</script>\n<style></style>\n<script type=\"text/x-red\" data-help-name=\"test-node-2\"></script>");
|
||||
|
||||
var nodeId = list[0].id;
|
||||
var nodeConfig = typeRegistry.getNodeConfig(nodeId);
|
||||
nodeConfig.should.equal("<script type=\"text/x-red\" data-template-name=\"test-node-1\"></script>\n<script type=\"text/x-red\" data-help-name=\"test-node-1\"></script>\n<script type=\"text/javascript\">RED.nodes.registerType('test-node-1',{});</script>\n<style></style>\n<p>this should be filtered out</p>\n");
|
||||
nodeConfig.should.equal("<script type=\"text/x-red\" data-template-name=\"test-node-1\"></script>\n\n<script type=\"text/javascript\">RED.nodes.registerType('test-node-1',{});</script>\n<style></style>\n<p>this should be filtered out</p>\n<script type=\"text/x-red\" data-help-name=\"test-node-1\"></script>");
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user