Expose i18n in editor

This commit is contained in:
Nick O'Leary 2015-05-06 22:14:00 +01:00
parent 008bc98070
commit a7900940da
12 changed files with 133 additions and 38 deletions

View File

@ -93,6 +93,7 @@ module.exports = function(grunt) {
// Ensure editor source files are concatenated in
// the right order
"editor/js/main.js",
"editor/js/i18n.js",
"editor/js/settings.js",
"editor/js/user.js",
"editor/js/comms.js",

44
editor/js/i18n.js Normal file
View File

@ -0,0 +1,44 @@
/**
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
RED.i18n = (function() {
return {
init: function(done) {
i18n.init({
resGetPath: 'locales/__ns__?lang=__lng__',
dynamicLoad: false,
ns: {
namespaces: ["editor","node-red"],
defaultNs: "editor"
},
fallbackLng: ['en']
},function() {
done();
});
RED["_"] = function() {
return i18n.t.apply(null,arguments);
}
},
loadCatalog: function(namespace,done) {
i18n.loadNamespace(namespace,done);
}
}
})();

View File

@ -16,10 +16,10 @@
var RED = (function() {
function loadSettings() {
RED.settings.init(loadNodeList);
function loadLocales() {
RED.i18n.init(loadEditor);
}
function loadNodeList() {
$.ajax({
headers: {
@ -29,7 +29,23 @@ var RED = (function() {
url: 'nodes',
success: function(data) {
RED.nodes.setNodeList(data);
loadNodes();
var nsCount = 0;
for(var i=0;i<data.length;i++) {
var ns = data[i];
if (ns.module != "node-red") {
nsCount++;
RED.i18n.loadCatalog(ns.id, function() {
nsCount--;
if (nsCount === 0) {
loadNodes();
}
});
}
}
if (nsCount === 0) {
loadNodes();
}
}
});
}
@ -43,6 +59,9 @@ var RED = (function() {
url: 'nodes',
success: function(data) {
$("body").append(data);
$("body").i18n();
$(".palette-spinner").hide();
$(".palette-scroll").show();
$("#palette-search").show();
@ -135,21 +154,6 @@ var RED = (function() {
RED.view.status(statusEnabled);
}
function loadLocales() {
i18n.init({
ns: {
namespaces: ["editor"],
defaultNs: "editor"
},
fallbackLng: ['en-US']
},function() {
RED["_"] = function() {
return i18n.t.apply(null,arguments);
}
loadEditor();
});
}
function loadEditor() {
RED.menu.init({id:"btn-sidemenu",
options: [

View File

@ -107,6 +107,7 @@ RED.nodes = (function() {
registerNodeType: function(nt,def) {
nodeDefinitions[nt] = def;
if (def.category != "subflows") {
def.set = nodeSets[typeToId[nt]];
nodeSets[typeToId[nt]].added = true;
// TODO: too tightly coupled into palette UI
}
@ -134,6 +135,19 @@ RED.nodes = (function() {
}
function addNode(n) {
var ns;
if (n._def.set.module === "node-red") {
ns = "node-red";
} else {
ns = n._def.set.id;
}
n["_"] = function() {
var args = Array.prototype.slice.call(arguments, 0);
if (args[0].indexOf(":") === -1) {
args[0] = ns+":"+args[0];
}
return RED._.apply(null,args);
}
if (n._def.category == "config") {
configNodes[n.id] = n;
RED.sidebar.config.refresh();

View File

@ -574,13 +574,21 @@ RED.editor = (function() {
$( "#dialog" ).dialog("option","buttons",buttons);
}
$("#dialog-form").html($("script[data-template-name='"+type+"']").html());
var ns;
if (node._def.set.module === "node-red") {
ns = "node-red";
} else {
ns = node._def.set.id;
}
$("#dialog-form").find('[data-i18n]').each(function() {
var current = $(this).attr("data-i18n");
if (current.indexOf(":") === -1) {
$(this).attr("data-i18n",ns+":"+current);
}
});
$('<input type="text" style="display: none;" />').appendTo("#dialog-form");
prepareEditDialog(node,node._def,"node-input");
$("#dialog").i18n();
$( "#dialog" ).dialog("option","title","Edit "+type+" node").dialog( "open" );
}
@ -603,6 +611,21 @@ RED.editor = (function() {
}
$("#dialog-config-form").html($("script[data-template-name='"+type+"']").html());
var ns;
if (node_def.set.module === "node-red") {
ns = "node-red";
} else {
ns = node_def.set.id;
}
$("#dialog-config-form").find('[data-i18n]').each(function() {
var current = $(this).attr("data-i18n");
if (current.indexOf(":") === -1) {
$(this).attr("data-i18n",ns+":"+current);
}
});
prepareEditDialog(configNode,node_def,"node-config-input");
var buttons = $( "#node-config-dialog" ).dialog("option","buttons");
@ -652,6 +675,8 @@ RED.editor = (function() {
}
$( "#node-config-dialog" ).dialog("option","buttons",buttons);
$("#node-config-dialog").i18n();
$( "#node-config-dialog" )
.dialog("option","node-adding",adding)
.dialog("option","node-property",name)

View File

@ -152,7 +152,7 @@
<div id="node-dialog-rename-workspace" class="hide">
<form class="form-horizontal">
<div class="form-row">
<label for="node-input-workspace-name" ><i class="fa fa-tag"></i> Name:</label>
<label for="node-input-workspace-name" ><i class="fa fa-tag"></i> <span data-i18n="workspace.label.name"></span>:</label>
<input type="text" id="node-input-workspace-name">
</div>
</form>

View File

@ -1,3 +1,7 @@
{
"foo": "fred"
"workspace": {
"label": {
"name": "Name"
}
}
}

View File

@ -16,7 +16,7 @@
<script type="text/x-red" data-template-name="inject">
<div class="form-row node-input-payload">
<label for="node-input-payloadType"><i class="fa fa-envelope"></i> Payload</label>
<label for="node-input-payloadType"><i class="fa fa-envelope"></i> <span data-i18n="inject.payload"></span></label>
<select id="node-input-payloadType" style="width:73%">
<option value="date">timestamp</option>
<option value="string">string</option>

View File

@ -3,6 +3,8 @@
"repeat": "repeat = __repeat__",
"crontab": "crontab = __crontab__",
"stopped": "stopped",
"failed": "Inject failed: __error__"
"failed": "Inject failed: __error__",
"payload": "Payload"
}
}

View File

@ -86,7 +86,7 @@ function init(adminApp,storage) {
adminApp.get("/nodes/:mod/:set",needsPermission("nodes.read"),nodes.getSet);
adminApp.put("/nodes/:mod/:set",needsPermission("nodes.write"),nodes.putSet);
adminApp.get(/^\/locales\/(.+?)\/(.*).json$/,needsPermission("nodes.read"),locales.get);
adminApp.get(/locales\/(.+)\/?$/,needsPermission("nodes.read"),locales.get);
// Library
library.init(adminApp);

View File

@ -17,13 +17,10 @@ var i18n = require("../i18n");
module.exports = {
get: function(req,res) {
var lang = req.params[0];
var namespace = req.params[1];
var namespace = req.params[0];
namespace = namespace.replace(/\.json$/,"");
var lang = "en-US"; // TODO: determine requested lang
var catalog = i18n.catalog(namespace,lang);
if (catalog) {
res.json(catalog);
} else {
res.send(404);
}
res.json(catalog||{});
}
}

View File

@ -37,7 +37,6 @@ function registerMessageCatalog(namespace,dir,file) {
return when.promise(function(resolve,reject) {
resourceMap[namespace] = { basedir:dir, file:file};
i18n.loadNamespace(namespace,function() {
//console.log(namespace,dir);
resolve();
});
});
@ -47,14 +46,16 @@ var MessageFileLoader = {
fetchOne: function(lng, ns, callback) {
if (resourceMap[ns]) {
var file = path.join(resourceMap[ns].basedir,lng,resourceMap[ns].file);
//console.log(file);
fs.readFile(file,"utf8",function(err,content) {
if (err) {
callback(err);
} else {
try {
//console.log(">>",ns,file);
//console.log(">>",ns,file,lng);
resourceCache[ns] = resourceCache[ns]||{};
resourceCache[ns][lng] = JSON.parse(content.replace(/^\uFEFF/, ''));
//console.log(resourceCache[ns][lng]);
callback(null, resourceCache[ns][lng]);
} catch(e) {
callback(e);
@ -84,6 +85,8 @@ function init() {
}
function getCatalog(namespace,lang) {
//console.log("+",namespace,lang);
//console.log(resourceCache[namespace][lang]);
var result = null;
if (resourceCache.hasOwnProperty(namespace)) {
result = resourceCache[namespace][lang];
@ -94,6 +97,7 @@ function getCatalog(namespace,lang) {
}
}
}
//console.log(result);
return result;
}