diff --git a/.gitignore b/.gitignore
index 77abb30b2..5415d9f4f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,5 @@ flows*.json
nodes/node-red-nodes/
node_modules
public
+locales/zz-ZZ
+nodes/core/locales/zz-ZZ
diff --git a/locales/zz-ZZ/editor.json b/locales/zz-ZZ/editor.json
deleted file mode 100644
index a30fe6815..000000000
--- a/locales/zz-ZZ/editor.json
+++ /dev/null
@@ -1,142 +0,0 @@
-{
- "workspace": {
- "label": {
- "name": "[G'Nameฏูİı|]"
- }
- },
- "menu": {
- "label": {
- "sidebar": "[G'Sidebarฏูİı|]",
- "displayStatus": "[G'Display node statusฏูİı|]",
- "import": "[G'Importฏูİı|]",
- "export": "[G'Exportฏูİı|]",
- "clipboard": "[G'Clipboardฏูİı|]",
- "library": "[G'Libraryฏูİı|]",
- "configurationNodes": "[G'Configuration nodesฏูİı|]",
- "subflows": "[G'Subflowsฏูİı|]",
- "createSubflow": "[G'Create subflowฏูİı|]",
- "selectionToSubflow": "[G'Selection to subflowฏูİı|]",
- "workspaces": "[G'Workspacesฏูİı|]",
- "add": "[G'Addฏูİı|]",
- "rename": "[G'Renameฏูİı|]",
- "delete": "[G'Deleteฏูİı|]",
- "keyboardShortcuts": "[G'Keyboard Shortcutsฏูİı|]",
- "login": "[G'Loginฏูİı|]",
- "logout": "[G'Logoutฏูİı|]"
- }
- },
- "notification": {
- "nodeAdded": "[G'Node added to palette:ฏูİı|]",
- "nodeAdded_plural": "[G'Nodes added to paletteฏูİı|]",
- "nodeRemoved": "[G'Node removed from palette:ฏูİı|]",
- "nodeRemoved_plural": "[G'Nodes removed from palette:ฏูİı|]",
- "nodeEnabled": "[G'Node enabled:ฏูİı|]",
- "nodeEnabled_plural": "[G'Nodes enabled:ฏูİı|]",
- "nodeDisabled": "[G'Node disabled:ฏูİı|]",
- "nodeDisabled_plural": "[G'Nodes disabled:ฏูİı|]",
- "lostConnectionError": "[G'Error: Lost connection to serverฏูİı|]",
- "importUnrecognised": "[G'Imported unrecognised ฏูİı|]",
- "loggedInAs": "[G'Logged in as ฏูİı|]",
- "invalidFilename": "[G'Invalid filenameฏูİı|]",
- "savedType": "[G'Saved __type__ฏูİı|]",
- "saveFailed": "[G'Save failed: ฏูİı|]",
- "noNodesSelected": "[G'Cannot create subflow: no nodes selectedฏูİı|]",
- "multipleInputsToSelection": "[G'Cannot create subflow: multiple inputs to selectionฏูİı|]",
- "cannotAddSubflowToItself": "[G'Error: Cannot add subflow to itselfฏูİı|]",
- "cannotAddCircularReference": "[G'Error: Cannot add subflow - circular reference detectedฏูİı|]",
- "nodeCopied": "[G'__count__ node copiedฏูİı|]",
- "nodeCopied_plural": "[G'__count__ nodes copiedฏูİı|]",
- "undeployedChanges": "[G'Warning: node has undeployed changesฏูİı|]",
- "nodeActionDisabled": "[G'Warning: node actions disabled within subflowฏูİı|]",
- "error": "[G'Error: ฏูİı|]"
- },
- "error": {
- "apiSubflowOnly": "[G'this api is subflow only. called with:ฏูİı|]",
- "invalidFlow": "[G'Invalid flow: ฏูİı|]",
- "cannotAddSubflowToItself": "[G'Cannot add subflow to itselfฏูİı|]",
- "cannotAddCircularReference": "[G'Cannot add subflow - circular reference detectedฏูİı|]"
- },
- "dialog": {
- "cancel": "[G'Cancelฏูİı|]",
- "login": "[G'Loginฏูİı|]",
- "loginFailed": "[G'Login failedฏูİı|]",
- "ok": "[G'Okฏูİı|]",
- "delete": "[G'Deleteฏูİı|]",
- "close": "[G'Closeฏูİı|]",
- "nodes": "[G' Nodes:ฏูİı|]",
- "selectToCopy": "[G'Select the text above and copy to the clipboard with Ctrl-C.ฏูİı|]",
- "pasteNodesHere": "[G'Paste nodes hereฏูİı|]",
- "importNodes": "[G'Import nodesฏูİı|]",
- "exportNodesClipboard": "[G'Export nodes to clipboardฏูİı|]",
- "renameSheet": "[G'Rename sheetฏูİı|]",
- "confirmDelete": "[G'Confirm deleteฏูİı|]"
- },
- "deploy": {
- "deploy": "[G'Deployฏูİı|]",
- "full": "[G'Fullฏูİı|]",
- "modifiedFlows": "[G'Modified Flowsฏูİı|]",
- "modifiedNodes": "[G'Modified Nodesฏูİı|]",
- "fullDesc": "[G'Deploys everything in the workspaceฏูİı|]",
- "modifiedFlowsDesc": "[G'Only deploys flows that contain changed nodesฏูİı|]",
- "modifiedNodesDesc": "[G'Only deploys nodes that have changedฏูİı|]",
- "confirmDeploy": "[G'Confirm deployฏูİı|]",
- "cancelDeploy": "[G'Cancelฏูİı|]",
- "undeployedChanges": "[G'You have undeployed changes.\n\nLeaving this page will lose these changes.ฏูİı|]",
- "successfulDeploy": "[G'Successfully Deployedฏูİı|]",
- "error": "[G'Error: ฏูİı|]",
- "noResponseError": "[G'no response from serverฏูİı|]"
- },
- "editor": {
- "savedNodes": "[G'Saved nodesฏูİı|]",
- "configEdit": "[G'editฏูİı|]",
- "configAdd": "[G'addฏูİı|]",
- "configDelete": "[G'Deleteฏูİı|]",
- "editFlow": "[G'Edit flow ฏูİı|]",
- "nodesUse": "[G'__count__ node uses this configฏูİı|]",
- "nodesUse_plural": "[G'__count__ nodes use this configฏูİı|]",
- "addNewConfig": "[G'Add new __type__ config nodeฏูİı|]",
- "editConfig": "[G'Edit __type__ config nodeฏูİı|]",
- "addNewType": "[G'Add new __type__...ฏูİı|]",
- "subflow": "[G'Subflow: ฏูİı|]",
- "subflowInstances": "[G'There is __count__ instance of this subflowฏูİı|]",
- "subflowInstances_plural": "[G'There are __count__ instances of this subflowฏูİı|]"
- },
- "keyboard": {
- "selectAll": "[G'Select all nodesฏูİı|]",
- "selectAllConnected": "[G'Select all connected nodesฏูİı|]",
- "addRemoveNode": "[G'Add/remove node from selectionฏูİı|]",
- "deleteSelected": "[G'Delete selected nodes or linkฏูİı|]",
- "importNode": "[G'Import nodesฏูİı|]",
- "exportNode": "[G'Export selected nodesฏูİı|]",
- "toggleSidebar": "[G'Toggle sidebarฏูİı|]",
- "deleteNode": "[G'Delete selected nodes or linkฏูİı|]",
- "copyNode": "[G'Copy selected nodesฏูİı|]",
- "cutNode": "[G'Cut selected nodesฏูİı|]",
- "pasteNode": "[G'Paste nodesฏูİı|]"
- },
- "library": {
- "openLibrary": "[G'Open Library...ฏูİı|]",
- "saveToLibrary": "[G'Save to Library...ฏูİı|]",
- "typeLibrary": "[G'__type__ libraryฏูİı|]",
- "unnamedType": "[G'Unnamed __type__ฏูİı|]",
- "saveToLibrary": "[G'Save to Libraryฏูİı|]",
- "exportToLibrary": "[G'Export nodes to libraryฏูİı|]"
- },
- "palette": {
- "noInfo": "[G'no information availableฏูİı|]",
- "popOverError": "[G'Error generating pop-over label for '__type__'.ฏูİı|]"
- },
- "tabInfo": {
- "node": "[G'Nodeฏูİı|]",
- "type": "[G'Typeฏูİı|]",
- "id": "[G'IDฏูİı|]",
- "subflow": "[G'Subflowฏูİı|]",
- "name": "[G'nameฏูİı|]",
- "instances": "[G'instancesฏูİı|]",
- "properties": "[G'Propertiesฏูİı|]",
- "blank": "[G'blankฏูİı|]"
- },
- "workspaces": {
- "subflow": "[G'Subflow: ฏูİı|]"
- }
-}
diff --git a/locales/zz-ZZ/runtime.json b/locales/zz-ZZ/runtime.json
deleted file mode 100644
index c3b3a3528..000000000
--- a/locales/zz-ZZ/runtime.json
+++ /dev/null
@@ -1,91 +0,0 @@
-{
- "runtime": {
- "welcome": "[G'Welcome to Node-REDฏูİı|]",
- "version": "[G'__component__ version: __version__ฏูİı|]",
- "paths": {
- "settings": "[G'Settings file : __path__ฏูİı|]"
- }
- },
-
- "server": {
- "loading": "[G'Loading palette nodesฏูİı|]",
- "errors": "[G'Failed to register __count__ node typeฏูİı|]",
- "errors_plural": "[G'Failed to register __count__ node typesฏูİı|]",
- "errors-help": "[G'Run with -v for detailsฏูİı|]",
- "missing-modules": "[G'Missing node modules:ฏูİı|]",
- "removing-modules": "[G'Removing modules from configฏูİı|]",
- "added-types": "[G'Added node types:ฏูİı|]",
- "removed-types": "[G'Removed node types:ฏูİı|]",
- "install": {
- "invalid": "[G'Invalid module nameฏูİı|]",
- "installing": "[G'Installing module: __name__ฏูİı|]",
- "installed": "[G'Installed module: __name__ฏูİı|]",
- "install-failed": "[G'Install failedฏูİı|]",
- "install-failed-long": "[G'Installation of module __name__ failed:ฏูİı|]",
- "install-failed-not-found": "[G'$t(install-failed-long) module not foundฏูİı|]",
-
- "uninstalling": "[G'Uninstalling module: __name__ฏูİı|]",
- "uninstall-failed": "[G'Uninstall failedฏูİı|]",
- "uninstall-failed-long": "[G'Uninstall of module __name__ failed:ฏูİı|]",
- "uninstalled": "[G'Uninstalled module: __name__ฏูİı|]"
- }
- },
-
- "api": {
- "flows": {
- "error-save": "[G'Error saving flows: __message__ฏูİı|]"
- },
- "library": {
- "error-load-entry": "[G'Error loading library entry '__path__': __message__ฏูİı|]",
- "error-save-entry": "[G'Error saving library entry '__path__': __message__ฏูİı|]",
- "error-load-flow": "[G'Error loading flow '__path__': __message__ฏูİı|]",
- "error-save-flow": "[G'Error saving flow '__path__': __message__ฏูİı|]"
- },
- "nodes": {
- "enabled": "[G'Enabled node types:ฏูİı|]",
- "disabled": "[G'Disabled node types:ฏูİı|]",
- "error-enable": "[G'Failed to enable node:ฏูİı|]"
- }
- },
-
- "comms": {
- "error": "[G'Communication channel error: __message__ฏูİı|]",
- "error-server": "[G'Communication server error: __message__ฏูİı|]",
- "error-send": "[G'Communication send error: __message__ฏูİı|]"
- },
-
- "nodes": {
- "credentials": {
- "error":"[G'Error loading credentials: __message__ฏูİı|]",
- "not-registered": "[G'Credential type '__type__' is not registeredฏูİı|]"
- },
- "flows": {
- "registered-missing": "[G'Missing type registered: __type__ฏูİı|]",
- "error": "[G'Error loading flows: __message__ฏูİı|]",
- "starting-modified-nodes": "[G'Starting modified nodesฏูİı|]",
- "starting-modified-flows": "[G'Starting modified flowsฏูİı|]",
- "starting-flows": "[G'Starting flowsฏูİı|]",
- "started-modified-nodes": "[G'Started modified nodesฏูİı|]",
- "started-modified-flows": "[G'Started modified flowsฏูİı|]",
- "started-flows": "[G'Started flowsฏูİı|]",
- "stopping-modified-nodes": "[G'Stopping modified nodesฏูİı|]",
- "stopping-modified-flows": "[G'Stopping modified flowsฏูİı|]",
- "stopping-flows": "[G'Stopping flowsฏูİı|]",
- "stopped-modified-nodes": "[G'Stopped modified nodesฏูİı|]",
- "stopped-modified-flows": "[G'Stopped modified flowsฏูİı|]",
- "stopped-flows": "[G'Stopped flowsฏูİı|]",
- "stopped": "[G'Stoppedฏูİı|]",
- "missing-types": "[G'Waiting for missing types to be registered:ฏูİı|]"
-
- }
- },
-
- "storage": {
- "localfilesystem": {
- "user-dir": "[G'User directory : __path__ฏูİı|]",
- "flows-file": "[G'Flows file : __path__ฏูİı|]",
- "create": "[G'Creating new flow fileฏูİı|]"
- }
- }
-
-}
diff --git a/red/api/locales.js b/red/api/locales.js
index 6fc2069ce..9f49d4bda 100644
--- a/red/api/locales.js
+++ b/red/api/locales.js
@@ -19,8 +19,12 @@ module.exports = {
get: function(req,res) {
var namespace = req.params[0];
namespace = namespace.replace(/\.json$/,"");
- var lang = req.query["lang"]||"en-US"; // TODO: determine requested lang
- var catalog = i18n.catalog(namespace,lang);
- res.json(catalog||{});
+ var lang = i18n.determineLangFromHeaders(req.acceptedLanguages);
+ var prevLang = i18n.i.lng();
+ i18n.i.setLng(lang, function(){
+ var catalog = i18n.catalog(namespace,lang);
+ res.json(catalog||{});
+ });
+ i18n.i.setLng(prevLang);
}
}
diff --git a/red/i18n.js b/red/i18n.js
index 1165a854b..5f5941f4a 100644
--- a/red/i18n.js
+++ b/red/i18n.js
@@ -101,12 +101,29 @@ function getCatalog(namespace,lang) {
return result;
}
+function determineLangFromHeaders(acceptedLanguages){
+ var lang = "en-US";
+
+ var supportedLanguages = ['en-US', 'es', 'fr', 'it', 'de', 'pt-BR', 'zh', 'zh-TW', 'ko', 'ja', 'zz-ZZ']; // TODO: pull this value from settings
+ for (var i=0;i