mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Allow editor language to be chosen in editor settings
This gets stored in localStorage of the browser which is not ideal. This is because we load language catalogs before we load user preferences - so if this was stored in the runtime, the editor wouldn't know the user's preference until it was too late to apply it. This is likely good enough for now - may need to do something more convoluted later on.
This commit is contained in:
parent
c2aa8a206a
commit
493687b5bb
@ -25,8 +25,8 @@ var auth = require("../auth");
|
|||||||
var nodes = require("../admin/nodes"); // TODO: move /icons into here
|
var nodes = require("../admin/nodes"); // TODO: move /icons into here
|
||||||
var needsPermission;
|
var needsPermission;
|
||||||
var runtimeAPI;
|
var runtimeAPI;
|
||||||
var log = require("@node-red/util").log; // TODO: separate module
|
var log = require("@node-red/util").log;
|
||||||
var i18n = require("@node-red/util").i18n; // TODO: separate module
|
var i18n = require("@node-red/util").i18n;
|
||||||
|
|
||||||
var apiUtil = require("../util");
|
var apiUtil = require("../util");
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ var sshkeys = require("./sshkeys");
|
|||||||
var theme = require("./theme");
|
var theme = require("./theme");
|
||||||
var clone = require("clone");
|
var clone = require("clone");
|
||||||
|
|
||||||
|
var i18n = require("@node-red/util").i18n
|
||||||
|
|
||||||
function extend(target, source) {
|
function extend(target, source) {
|
||||||
var keys = Object.keys(source);
|
var keys = Object.keys(source);
|
||||||
var i = keys.length;
|
var i = keys.length;
|
||||||
@ -53,12 +55,14 @@ module.exports = {
|
|||||||
user: req.user
|
user: req.user
|
||||||
}
|
}
|
||||||
runtimeAPI.settings.getRuntimeSettings(opts).then(function(result) {
|
runtimeAPI.settings.getRuntimeSettings(opts).then(function(result) {
|
||||||
|
result.editorTheme = result.editorTheme||{};
|
||||||
var themeSettings = theme.settings();
|
var themeSettings = theme.settings();
|
||||||
if (themeSettings) {
|
if (themeSettings) {
|
||||||
// result.editorTheme may already exist with the palette
|
// result.editorTheme may already exist with the palette
|
||||||
// disabled. Need to merge that into the receive settings
|
// disabled. Need to merge that into the receive settings
|
||||||
result.editorTheme = extend(clone(themeSettings),result.editorTheme||{});
|
result.editorTheme = extend(clone(themeSettings),result.editorTheme);
|
||||||
}
|
}
|
||||||
|
result.editorTheme.languages = i18n.availableLanguages("editor");
|
||||||
res.json(result);
|
res.json(result);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -42,7 +42,9 @@
|
|||||||
"defaultDir": "Default",
|
"defaultDir": "Default",
|
||||||
"ltr": "Left-to-right",
|
"ltr": "Left-to-right",
|
||||||
"rtl": "Right-to-left",
|
"rtl": "Right-to-left",
|
||||||
"auto": "Contextual"
|
"auto": "Contextual",
|
||||||
|
"language": "Language",
|
||||||
|
"browserDefault": "Browser default"
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"show": "Show sidebar"
|
"show": "Show sidebar"
|
||||||
|
@ -21,7 +21,8 @@ RED.i18n = (function() {
|
|||||||
return {
|
return {
|
||||||
init: function(options, done) {
|
init: function(options, done) {
|
||||||
apiRootUrl = options.apiRootUrl||"";
|
apiRootUrl = options.apiRootUrl||"";
|
||||||
i18n.init({
|
var preferredLanguage = localStorage.getItem("editor-language");
|
||||||
|
var opts = {
|
||||||
resGetPath: apiRootUrl+'locales/__ns__?lng=__lng__',
|
resGetPath: apiRootUrl+'locales/__ns__?lng=__lng__',
|
||||||
dynamicLoad: false,
|
dynamicLoad: false,
|
||||||
load:'current',
|
load:'current',
|
||||||
@ -32,7 +33,11 @@ RED.i18n = (function() {
|
|||||||
fallbackLng: ['en-US'],
|
fallbackLng: ['en-US'],
|
||||||
useCookie: false,
|
useCookie: false,
|
||||||
returnObjectTrees: true
|
returnObjectTrees: true
|
||||||
},function() {
|
};
|
||||||
|
if (preferredLanguage) {
|
||||||
|
opts.lng = preferredLanguage;
|
||||||
|
}
|
||||||
|
i18n.init(opts,function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
RED["_"] = function() {
|
RED["_"] = function() {
|
||||||
|
@ -104,6 +104,10 @@ RED.userSettings = (function() {
|
|||||||
|
|
||||||
var viewSettings = [
|
var viewSettings = [
|
||||||
{
|
{
|
||||||
|
options: [
|
||||||
|
{setting:"editor-language",local: true, label:"menu.label.view.language",options:function(done){ done([{val:'',text:RED._('menu.label.view.browserDefault')}].concat(RED.settings.theme("languages"))) }},
|
||||||
|
]
|
||||||
|
},{
|
||||||
title: "menu.label.view.grid",
|
title: "menu.label.view.grid",
|
||||||
options: [
|
options: [
|
||||||
{setting:"view-show-grid",oldSetting:"menu-menu-item-view-show-grid",label:"menu.label.view.showGrid",toggle:true,onchange:"core:toggle-show-grid"},
|
{setting:"view-show-grid",oldSetting:"menu-menu-item-view-show-grid",label:"menu.label.view.showGrid",toggle:true,onchange:"core:toggle-show-grid"},
|
||||||
@ -136,14 +140,40 @@ RED.userSettings = (function() {
|
|||||||
currentEditorSettings.view = currentEditorSettings.view || {};
|
currentEditorSettings.view = currentEditorSettings.view || {};
|
||||||
|
|
||||||
viewSettings.forEach(function(section) {
|
viewSettings.forEach(function(section) {
|
||||||
$('<h3></h3>').text(RED._(section.title)).appendTo(pane);
|
if (section.title) {
|
||||||
|
$('<h3></h3>').text(RED._(section.title)).appendTo(pane);
|
||||||
|
}
|
||||||
section.options.forEach(function(opt) {
|
section.options.forEach(function(opt) {
|
||||||
var initialState = currentEditorSettings.view[opt.setting];
|
var initialState;
|
||||||
|
if (opt.local) {
|
||||||
|
initialState = localStorage.getItem(opt.setting);
|
||||||
|
} else {
|
||||||
|
initialState = currentEditorSettings.view[opt.setting];
|
||||||
|
}
|
||||||
var row = $('<div class="user-settings-row"></div>').appendTo(pane);
|
var row = $('<div class="user-settings-row"></div>').appendTo(pane);
|
||||||
var input;
|
var input;
|
||||||
if (opt.toggle) {
|
if (opt.toggle) {
|
||||||
input = $('<label for="user-settings-'+opt.setting+'"><input id="user-settings-'+opt.setting+'" type="checkbox"> '+RED._(opt.label)+'</label>').appendTo(row).find("input");
|
input = $('<label for="user-settings-'+opt.setting+'"><input id="user-settings-'+opt.setting+'" type="checkbox"> '+RED._(opt.label)+'</label>').appendTo(row).find("input");
|
||||||
input.prop('checked',initialState);
|
input.prop('checked',initialState);
|
||||||
|
} else if (opt.options) {
|
||||||
|
$('<label for="user-settings-'+opt.setting+'">'+RED._(opt.label)+'</label>').appendTo(row);
|
||||||
|
var select = $('<select id="user-settings-'+opt.setting+'"></select>').appendTo(row);
|
||||||
|
if (typeof opt.options === 'function') {
|
||||||
|
opt.options(function(options) {
|
||||||
|
options.forEach(function(opt) {
|
||||||
|
var val = opt;
|
||||||
|
var text = opt;
|
||||||
|
if (typeof opt !== 'string') {
|
||||||
|
val = opt.val;
|
||||||
|
text = opt.text;
|
||||||
|
}
|
||||||
|
$('<option>').val(val).text(text).appendTo(select);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
select.val(initialState)
|
||||||
|
} else {
|
||||||
|
// TODO: support other option types
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$('<label for="user-settings-'+opt.setting+'">'+RED._(opt.label)+'</label>').appendTo(row);
|
$('<label for="user-settings-'+opt.setting+'">'+RED._(opt.label)+'</label>').appendTo(row);
|
||||||
$('<input id="user-settings-'+opt.setting+'" type="'+(opt.type||"text")+'">').appendTo(row).val(initialState);
|
$('<input id="user-settings-'+opt.setting+'" type="'+(opt.type||"text")+'">').appendTo(row).val(initialState);
|
||||||
@ -155,16 +185,20 @@ RED.userSettings = (function() {
|
|||||||
|
|
||||||
function setSelected(id, value) {
|
function setSelected(id, value) {
|
||||||
var opt = allSettings[id];
|
var opt = allSettings[id];
|
||||||
var currentEditorSettings = RED.settings.get('editor') || {};
|
if (opt.local) {
|
||||||
currentEditorSettings.view = currentEditorSettings.view || {};
|
localStorage.setItem(opt.setting,value);
|
||||||
currentEditorSettings.view[opt.setting] = value;
|
} else {
|
||||||
RED.settings.set('editor', currentEditorSettings);
|
var currentEditorSettings = RED.settings.get('editor') || {};
|
||||||
var callback = opt.onchange;
|
currentEditorSettings.view = currentEditorSettings.view || {};
|
||||||
if (typeof callback === 'string') {
|
currentEditorSettings.view[opt.setting] = value;
|
||||||
callback = RED.actions.get(callback);
|
RED.settings.set('editor', currentEditorSettings);
|
||||||
}
|
var callback = opt.onchange;
|
||||||
if (callback) {
|
if (typeof callback === 'string') {
|
||||||
callback.call(opt,value);
|
callback = RED.actions.get(callback);
|
||||||
|
}
|
||||||
|
if (callback) {
|
||||||
|
callback.call(opt,value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function toggle(id) {
|
function toggle(id) {
|
||||||
@ -202,6 +236,10 @@ RED.userSettings = (function() {
|
|||||||
var editorSettingsChanged = false;
|
var editorSettingsChanged = false;
|
||||||
viewSettings.forEach(function(section) {
|
viewSettings.forEach(function(section) {
|
||||||
section.options.forEach(function(opt) {
|
section.options.forEach(function(opt) {
|
||||||
|
if (opt.local) {
|
||||||
|
allSettings[opt.setting] = opt;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (opt.oldSetting) {
|
if (opt.oldSetting) {
|
||||||
var oldValue = RED.settings.get(opt.oldSetting);
|
var oldValue = RED.settings.get(opt.oldSetting);
|
||||||
if (oldValue !== undefined && oldValue !== null) {
|
if (oldValue !== undefined && oldValue !== null) {
|
||||||
|
32
packages/node_modules/@node-red/util/lib/i18n.js
vendored
32
packages/node_modules/@node-red/util/lib/i18n.js
vendored
@ -50,10 +50,21 @@ function registerMessageCatalogs(catalogs) {
|
|||||||
function registerMessageCatalog(namespace,dir,file) {
|
function registerMessageCatalog(namespace,dir,file) {
|
||||||
return initPromise.then(function() {
|
return initPromise.then(function() {
|
||||||
return new Promise((resolve,reject) => {
|
return new Promise((resolve,reject) => {
|
||||||
resourceMap[namespace] = { basedir:dir, file:file};
|
resourceMap[namespace] = { basedir:dir, file:file, lngs: []};
|
||||||
i18n.loadNamespaces(namespace,function() {
|
fs.readdir(dir,function(err, files) {
|
||||||
resolve();
|
if (err) {
|
||||||
});
|
resolve();
|
||||||
|
} else {
|
||||||
|
files.forEach(function(f) {
|
||||||
|
if (fs.existsSync(path.join(dir,f,file))) {
|
||||||
|
resourceMap[namespace].lngs.push(f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
i18n.loadNamespaces(namespace,function() {
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -163,11 +174,24 @@ function getCatalog(namespace,lang) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of languages a given catalog is available in.
|
||||||
|
* @name availableLanguages
|
||||||
|
* @function
|
||||||
|
* @memberof @node-red/util_i18n
|
||||||
|
*/
|
||||||
|
function availableLanguages(namespace) {
|
||||||
|
if (resourceMap.hasOwnProperty(namespace)) {
|
||||||
|
return resourceMap[namespace].lngs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var obj = module.exports = {
|
var obj = module.exports = {
|
||||||
init: init,
|
init: init,
|
||||||
registerMessageCatalog: registerMessageCatalog,
|
registerMessageCatalog: registerMessageCatalog,
|
||||||
registerMessageCatalogs: registerMessageCatalogs,
|
registerMessageCatalogs: registerMessageCatalogs,
|
||||||
catalog: getCatalog,
|
catalog: getCatalog,
|
||||||
|
availableLanguages: availableLanguages,
|
||||||
/**
|
/**
|
||||||
* The underlying i18n library for when direct access is really needed
|
* The underlying i18n library for when direct access is really needed
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user