diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1c437ba8c..d66631102 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [14, 16] + node-version: [16, 18] steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} @@ -30,7 +30,7 @@ jobs: run: | npm run test # - name: Publish to coveralls.io - # if: ${{ matrix.node-version == 14 }} + # if: ${{ matrix.node-version == 16 }} # uses: coverallsapp/github-action@v1.1.2 # with: # github-token: ${{ github.token }} diff --git a/.jshintrc b/.jshintrc index 719eecb49..0886c1dc0 100644 --- a/.jshintrc +++ b/.jshintrc @@ -15,5 +15,5 @@ "shadow": true, // allow variable shadowing (re-use of names...) "sub": true, // don't warn that foo['bar'] should be written as foo.bar "proto": true, // allow setting of __proto__ in node < v0.12, - "esversion": 6 // allow es6 + "esversion": 11 // allow es11(ES2020) } diff --git a/CHANGELOG.md b/CHANGELOG.md index 630d91b4b..6a82583bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,143 @@ +#### 3.1.0-beta.2: Beta Release + +Editor + + - NEW: Add change icon to tabs (#4068) @knolleary + - NEW: Complete overhaul of Group UX (#4079) @knolleary + - NEW: Add link to node help in node edit dialog footer (#4065) @knolleary + - NEW: Added editor feature for connecting multiple nodes to single node (#4051) @sonntam + - NEW: Increase workspace size to 8000x8000 (#4094) @knolleary + - Ensure node buttons are redrawn when flow lock state is changed (#4091) @knolleary + - Prevent loops being created with junction nodes (#4087) @knolleary + - Prevent opening locked node's edit dialog (#4069) @knolleary + - Reverse direction of tab scroll to expected direction (#4064) @knolleary + - Add cancel operation to editableList (#4077) @HiroyasuNishiyama + - Apply Mermaid diagram for project settings UI (#4054) @kazuhitoyokoi + - Add tooltip for show/hide button on info sidebar (#4050) @kazuhitoyokoi + - Fix align nodes on locked tab (#4072) @HiroyasuNishiyama + - Fix importing connected link nodes into a subflow (#4082) @knolleary + - Fix to add empty marker to empty group (#4060) @HiroyasuNishiyama + - Fix image URLs for v3.0 tour (#4053) @kazuhitoyokoi + - Show scrollbar in notification dialog only when needed (#4048) @kazuhitoyokoi + - Update-monaco-and-typings (#4089) @Steve-Mcl + - Update jquery UI (#4088) @knolleary + - Support i18n of lock/unlock buttons in flow property UI (#4049) @kazuhitoyokoi + - Translation kr (#3895) @hae-iotplatform + - Translation zhcn (!!请懂中文的帮忙review) (#3952) @cliyr + - Add French translation of nodes (#3964) @GogoVega + - Add French translation (#3962) @GogoVega + - Portuguese Brazilian (pt-BR) translation (#3804) @FabsMuller + + +Runtime + + - NEW: Generate stable ids for subflow instance internal nodes (#4093) @knolleary + - NEW: Change default file name to flows.json in project feature (#4073) @kazuhitoyokoi + - NEW: Deprecate synchronous access to jsonata (#4090) @knolleary + - Add Node 18 to test matrix (#4084) @knolleary + - Bump minimum nodejs version supported to match documented value (#4086) @knolleary + - Update monaco docs link in settings.js (#4075) @Steve-Mcl + - Remove duplicated messages in the message catalog (#4066) @kazuhitoyokoi + - Ensure errors in preDeliver callback are handled (#3911) @knolleary + - Fix "EADDRINUSE" error (#4046) @bggbr + +Nodes + + - Link Call: Clear link-call timeouts when node is closed (#4085) @knolleary + - Join: ensure inflight status is cleared when in auto mode (#4083) @knolleary + - File Out: Fix extra newline append for multipart file write (#3915) @dceejay + - Add validators for complete and link call nodes (#4056) @kazuhitoyokoi + +#### 3.1.0-beta.1: Beta Release + +Editor + + - NEW: Locking Flows (#3938) @knolleary + - NEW: Improve UX around hiding flows via context menu (#3930) @knolleary + - NEW: Add support for inline image in markdown editor by drag and drop of an image file (#4006) @HiroyasuNishiyama + - NEW: Add support for mermaid diagram to markdown editor (#4007) @HiroyasuNishiyama + - NEW: Support uri fragments for nodes and groups including edit support (#3870) @knolleary + - NEW: Add global environment variable feature (#3941) @HiroyasuNishiyama + + - Remember compact/pretty flow export user choice (#3974) @Steve-Mcl + - fix .red-ui-notification class (#4035) @xiaobinqt + - Fix border radius on Modules list header (#4038) @bonanitech + - fix workspace reference error in case of empty tabs (#4029) @HiroyasuNishiyama + - Disable delete tab menu when single tab exists (#4030) @HiroyasuNishiyama + - Disable hide all menu if all tabs hidden (#4031) @HiroyasuNishiyama + - fix hide subflow tooltip (#4033) @HiroyasuNishiyama + - Fix disabled menu items in project feature (#4027) @kazuhitoyokoi + - Let themes change radialMenu text colors (#3995) @bonanitech + - Add Japanese translations for v3.0.3 (#4012) @kazuhitoyokoi + - Add Japanese translation for v3.1.0-beta.0 (#3997) @kazuhitoyokoi + - Add Japanese translation for v3.1.0-beta.0 (#3916) @kazuhitoyokoi + - Hide subflow category after deleting subflow (#3980) @kazuhitoyokoi + - Prevent dbl-click opening node edit dialog with text selected (#3970) @knolleary + - Handle replacing unknown node inside group or subflow (#3921) @knolleary + - Fix #3939, red border red-ui-typedInput-container (#3949) @Steveorevo + - i18n item URL copy notification & add Japanese message (#3946) @HiroyasuNishiyama + - add Japanese message for item url copy actions (#3947) @HiroyasuNishiyama + - Fix autocomplete entry for responseUrl (#3884) @knolleary + - Fix Japanese translation for JSONata editor (#3872) @HiroyasuNishiyama + - Fix search type with spaces (#3841) @Steve-Mcl + - Fix error hanndling of JSONata expression editor for extended functions (#3871) @HiroyasuNishiyama + - Add button type to the adding SSH key button (#3866) @kazuhitoyokoi + - Check radio button as default in project dialog (#3879) @kazuhitoyokoi + - Add $clone as supported function (#3874) @HiroyasuNishiyama + - Env var jsonata (#3807) @HiroyasuNishiyama + - Add Japanese translation for v3.0.2 (#3852) @kazuhitoyokoi + +Runtime + + - Force IPv4 name resolution to have priority (#4019) @dceejay + - Fix async loading of modules containing both nodes and plugins (#3999) @knolleary + - Use main branch as default in project feature (#4036) @kazuhitoyokoi + - Rename package var to avoid strict mode error (#4020) @knolleary + - Fix typos in settings.js (#4013) @ypid + - Ensure credentials object is removed before returning node in getFlow request (#3971) @knolleary + - Ignore commit error in project feature (#3987) @kazuhitoyokoi + - Update dependencies (#3969) @knolleary + - Add check that node sends object rather than primitive type (#3909) @knolleary + - Ensure key_path is quoted in GIT_SSH_COMMAND in case of spaces in pathname (#3912) @knolleary + - Fix nodesDir scan when node package has js/html in sub dir to package.json (#3867) @Steve-Mcl + - Fix file permissions (#3917) @kazuhitoyokoi + - ci: add minimum GitHub token permissions for workflows (#3907) @boahc077 + +Nodes + + - Catch: fix typo in catch.html (#3965) @we11adam + - Change: Fix change node overwriting msg with itself (#3899) @dceejay + - Comment node: Clarify where the text will appear (#4004) @dirkjanfaber + - CSV: change replace to replaceAll (#3990) @dceejay + - CSV node: check header properties for ' and " (#3920) @dceejay + - CSV: Fix for CSV undefined property (#3906) @dceejay + - Delay: let delay node handle both flush then reset (#3898) @dceejay + - Function: Limit number of ports in function node (#3886) @kazuhitoyokoi + - Function: Remove dot from variable name for external module in function node (#3880) @kazuhitoyokoi + - Function: add function node monaco types util and promisify (#3868) @Steve-Mcl + - HTTP In: Ensure msg.req.headers is enumerable (#3908) @knolleary + - HTTP Request: Support form-data arrays (#3991) @hardillb + - HTTP Request: Fix httprequest tests to be more lenient on error message (#3922) @knolleary + - HTTP Request: Add missing property to node object HTTPRequest (#3842) @hardillb + - HTTP Request/Response: Support sortable list on property UI of http request and http response nodes (#3857) @kazuhitoyokoi + - HTTP Response: Ensure statusCode is a number (#3894) @hardillb + - Inject: Allow Inject node to work with async context stores (#4021) @knolleary + - Join/Batch: Add count to join and batch node labels (#4028) @dceejay + - MQTT: Fix birth topic handling in MQTT node (#3905) @Steve-Mcl + - MQTT: Fix pull-down menus of MQTT configuration node (#3890) @kazuhitoyokoi + - MQTT: Prevent invalid mqtt birth topic crashing node-red (#3869) @Steve-Mcl + - MQTT: ensure sessionExpiry(Interval) is applied (#3840) @Steve-Mcl + - MQTT: Fix mqtt nodes not reconnecting on modified-flows deploy (#3992) @knolleary + - MQTT: fix single subscription mqtt node status (#3966) @Steve-Mcl + - Range: Add drop mode to range node (#3935) @dceejay + - Remove done from describe (#3873) @HiroyasuNishiyama + - Split node: avoid duplicate done call for buffer split (#4000) @knolleary + - Status: Fix typo in 25-status.html (#3981) @kazuhitoyokoi + - TCP Node: ensure newline substitution applies to whole message (#4009) @dceejay + - Template: Add information about environment variable to template node (#3882) @kazuhitoyokoi + - Trigger: Hide trigger node repeat send option if sending nothing (#4023) @dceejay + - Watch: fix watch node test on MacOS/ARM (#3942) @HiroyasuNishiyama + #### 3.0.2: Maintenance Release Editor diff --git a/Gruntfile.js b/Gruntfile.js index 2f81da923..44f4c97f6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -151,6 +151,7 @@ module.exports = function(grunt) { "packages/node_modules/@node-red/editor-client/src/js/font-awesome.js", "packages/node_modules/@node-red/editor-client/src/js/history.js", "packages/node_modules/@node-red/editor-client/src/js/validators.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/mermaid.js", "packages/node_modules/@node-red/editor-client/src/js/ui/utils.js", "packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js", "packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js", @@ -169,6 +170,7 @@ module.exports = function(grunt) { "packages/node_modules/@node-red/editor-client/src/js/ui/diagnostics.js", "packages/node_modules/@node-red/editor-client/src/js/ui/diff.js", "packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/env-var.js", "packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js", "packages/node_modules/@node-red/editor-client/src/js/ui/statusBar.js", "packages/node_modules/@node-red/editor-client/src/js/ui/view.js", @@ -224,7 +226,7 @@ module.exports = function(grunt) { "node_modules/jsonata/jsonata-es5.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js", "packages/node_modules/@node-red/editor-client/src/vendor/ace/ace.js", - "packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js", + "packages/node_modules/@node-red/editor-client/src/vendor/ace/ext-language_tools.js" ], // "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [ // // TODO: resolve relative resource paths in @@ -233,6 +235,9 @@ module.exports = function(grunt) { "packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [ "node_modules/jsonata/jsonata-es5.min.js", "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js" + ], + "packages/node_modules/@node-red/editor-client/public/vendor/mermaid/mermaid.min.js": [ + "node_modules/mermaid/dist/mermaid.min.js" ] } } @@ -403,7 +408,7 @@ module.exports = function(grunt) { { cwd: 'packages/node_modules/@node-red/editor-client/src', src: [ - 'types/node/*.ts', + 'types/node/**/*.ts', 'types/node-red/*.ts', ], expand: true, diff --git a/package.json b/package.json index a57de03c5..f53cad7c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red", - "version": "3.0.2", + "version": "3.1.0-beta.2", "description": "Low-code programming for event-driven applications", "homepage": "http://nodered.org", "license": "Apache-2.0", @@ -26,30 +26,30 @@ } ], "dependencies": { - "acorn": "8.7.1", + "acorn": "8.8.2", "acorn-walk": "8.2.0", - "ajv": "8.11.0", - "async-mutex": "0.3.2", + "ajv": "8.12.0", + "async-mutex": "0.4.0", "basic-auth": "2.0.1", "bcryptjs": "2.4.3", - "body-parser": "1.20.0", + "body-parser": "1.20.2", "cheerio": "1.0.0-rc.10", "clone": "2.1.2", - "content-type": "1.0.4", + "content-type": "1.0.5", "cookie": "0.5.0", "cookie-parser": "1.4.6", "cors": "2.8.5", "cronosjs": "1.7.1", "denque": "2.1.0", - "express": "4.18.1", + "express": "4.18.2", "express-session": "1.17.3", "form-data": "4.0.0", - "fs-extra": "10.1.0", - "got": "11.8.5", + "fs-extra": "11.1.1", + "got": "12.6.0", "hash-sum": "2.0.0", - "hpagent": "1.0.0", + "hpagent": "1.2.0", "https-proxy-agent": "5.0.1", - "i18next": "21.8.16", + "i18next": "21.10.0", "iconv-lite": "0.6.3", "is-utf8": "0.2.1", "js-yaml": "4.1.0", @@ -60,7 +60,7 @@ "memorystore": "1.6.7", "mime": "3.0.0", "moment": "2.29.4", - "moment-timezone": "0.5.34", + "moment-timezone": "0.5.43", "mqtt": "4.3.7", "multer": "1.4.5-lts.1", "mustache": "4.2.0", @@ -72,21 +72,21 @@ "passport": "0.6.0", "passport-http-bearer": "1.0.1", "passport-oauth2-client-password": "0.1.2", - "raw-body": "2.5.1", - "semver": "7.3.7", - "tar": "6.1.11", - "tough-cookie": "4.0.0", - "uglify-js": "3.16.3", - "uuid": "8.3.2", + "raw-body": "2.5.2", + "semver": "7.5.0", + "tar": "6.1.13", + "tough-cookie": "4.1.2", + "uglify-js": "3.17.4", + "uuid": "9.0.0", "ws": "7.5.6", - "xml2js": "0.4.23" + "xml2js": "0.5.0" }, "optionalDependencies": { - "bcrypt": "5.0.1" + "bcrypt": "5.1.0" }, "devDependencies": { - "dompurify": "2.3.10", - "grunt": "1.5.3", + "dompurify": "2.4.1", + "grunt": "1.6.1", "grunt-chmod": "~1.1.1", "grunt-cli": "~1.4.3", "grunt-concurrent": "3.0.0", @@ -108,17 +108,18 @@ "i18next-http-backend": "1.4.1", "jquery-i18next": "1.2.1", "jsdoc-nr-template": "github:node-red/jsdoc-nr-template", - "marked": "4.0.18", + "marked": "4.3.0", + "mermaid": "^9.4.3", "minami": "1.2.3", "mocha": "9.2.2", - "node-red-node-test-helper": "^0.3.0", - "nodemon": "2.0.19", + "node-red-node-test-helper": "^0.3.1", + "nodemon": "2.0.20", "proxy": "^1.0.2", - "sass": "1.54.2", + "sass": "1.62.1", "should": "13.2.3", "sinon": "11.1.2", "stoppable": "^1.1.0", - "supertest": "6.2.4" + "supertest": "6.3.3" }, "engines": { "node": ">=14" diff --git a/packages/node_modules/@node-red/editor-api/lib/admin/index.js b/packages/node_modules/@node-red/editor-api/lib/admin/index.js index 8406fa8e9..26eabe65b 100644 --- a/packages/node_modules/@node-red/editor-api/lib/admin/index.js +++ b/packages/node_modules/@node-red/editor-api/lib/admin/index.js @@ -14,8 +14,6 @@ * limitations under the License. **/ -var express = require("express"); - var nodes = require("./nodes"); var flows = require("./flows"); var flow = require("./flow"); @@ -37,18 +35,9 @@ module.exports = { plugins.init(runtimeAPI); diagnostics.init(settings, runtimeAPI); - var needsPermission = auth.needsPermission; - - var adminApp = express(); - - var defaultServerSettings = { - "x-powered-by": false - } - var serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{}); - for (var eOption in serverSettings) { - adminApp.set(eOption, serverSettings[eOption]); - } + const needsPermission = auth.needsPermission; + const adminApp = apiUtil.createExpressApp(settings) // Flows adminApp.get("/flows",needsPermission("flows.read"),flows.get,apiUtil.errorHandler); diff --git a/packages/node_modules/@node-red/editor-api/lib/editor/index.js b/packages/node_modules/@node-red/editor-api/lib/editor/index.js index f210d90fe..42be1f270 100644 --- a/packages/node_modules/@node-red/editor-api/lib/editor/index.js +++ b/packages/node_modules/@node-red/editor-api/lib/editor/index.js @@ -46,14 +46,15 @@ module.exports = { runtimeAPI = _runtimeAPI; needsPermission = auth.needsPermission; if (!settings.disableEditor) { - info.init(runtimeAPI); + info.init(settings, runtimeAPI); comms.init(server,settings,runtimeAPI); var ui = require("./ui"); ui.init(runtimeAPI); - var editorApp = express(); + const editorApp = apiUtil.createExpressApp(settings) + if (settings.requireHttps === true) { editorApp.enable('trust proxy'); editorApp.use(function (req, res, next) { @@ -86,7 +87,7 @@ module.exports = { //Projects var projects = require("./projects"); - projects.init(runtimeAPI); + projects.init(settings, runtimeAPI); editorApp.use("/projects",projects.app()); // Locales diff --git a/packages/node_modules/@node-red/editor-api/lib/editor/projects.js b/packages/node_modules/@node-red/editor-api/lib/editor/projects.js index ad505a46e..5d1b2ff26 100644 --- a/packages/node_modules/@node-red/editor-api/lib/editor/projects.js +++ b/packages/node_modules/@node-red/editor-api/lib/editor/projects.js @@ -14,9 +14,9 @@ * limitations under the License. **/ -var express = require("express"); var apiUtils = require("../util"); +var settings; var runtimeAPI; var needsPermission = require("../auth").needsPermission; @@ -77,11 +77,12 @@ function getProjectRemotes(req,res) { }) } module.exports = { - init: function(_runtimeAPI) { + init: function(_settings, _runtimeAPI) { + settings = _settings; runtimeAPI = _runtimeAPI; }, app: function() { - var app = express(); + var app = apiUtils.createExpressApp(settings) app.use(function(req,res,next) { runtimeAPI.projects.available().then(function(available) { diff --git a/packages/node_modules/@node-red/editor-api/lib/editor/settings.js b/packages/node_modules/@node-red/editor-api/lib/editor/settings.js index 5fa2476e1..200ddf2c2 100644 --- a/packages/node_modules/@node-red/editor-api/lib/editor/settings.js +++ b/packages/node_modules/@node-red/editor-api/lib/editor/settings.js @@ -18,9 +18,9 @@ var runtimeAPI; var sshkeys = require("./sshkeys"); module.exports = { - init: function(_runtimeAPI) { + init: function(settings, _runtimeAPI) { runtimeAPI = _runtimeAPI; - sshkeys.init(runtimeAPI); + sshkeys.init(settings, runtimeAPI); }, userSettings: function(req, res) { var opts = { diff --git a/packages/node_modules/@node-red/editor-api/lib/editor/sshkeys.js b/packages/node_modules/@node-red/editor-api/lib/editor/sshkeys.js index 6d1c62e11..08097571f 100644 --- a/packages/node_modules/@node-red/editor-api/lib/editor/sshkeys.js +++ b/packages/node_modules/@node-red/editor-api/lib/editor/sshkeys.js @@ -17,13 +17,15 @@ var apiUtils = require("../util"); var express = require("express"); var runtimeAPI; +var settings; module.exports = { - init: function(_runtimeAPI) { + init: function(_settings, _runtimeAPI) { runtimeAPI = _runtimeAPI; + settings = _settings; }, app: function() { - var app = express(); + const app = apiUtils.createExpressApp(settings); // List all SSH keys app.get("/", function(req,res) { diff --git a/packages/node_modules/@node-red/editor-api/lib/editor/theme.js b/packages/node_modules/@node-red/editor-api/lib/editor/theme.js index c21a7e6e7..c3e8f975e 100644 --- a/packages/node_modules/@node-red/editor-api/lib/editor/theme.js +++ b/packages/node_modules/@node-red/editor-api/lib/editor/theme.js @@ -19,6 +19,7 @@ var util = require("util"); var path = require("path"); var fs = require("fs"); var clone = require("clone"); +const apiUtil = require("../util") var defaultContext = { page: { @@ -27,8 +28,7 @@ var defaultContext = { tabicon: { icon: "red/images/node-red-icon-black.svg", colour: "#8f0000" - }, - version: require(path.join(__dirname,"../../package.json")).version + } }, header: { title: "Node-RED", @@ -40,6 +40,7 @@ var defaultContext = { vendorMonaco: "" } }; +var settings; var theme = null; var themeContext = clone(defaultContext); @@ -92,7 +93,8 @@ function serveFilesFromTheme(themeValue, themeApp, directory, baseDirectory) { } module.exports = { - init: function(settings, _runtimeAPI) { + init: function(_settings, _runtimeAPI) { + settings = _settings; runtimeAPI = _runtimeAPI; themeContext = clone(defaultContext); if (process.env.NODE_ENV == "development") { @@ -113,7 +115,15 @@ module.exports = { var url; themeSettings = {}; - themeApp = express(); + themeApp = apiUtil.createExpressApp(settings); + + const defaultServerSettings = { + "x-powered-by": false + } + const serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{}); + for (const eOption in serverSettings) { + themeApp.set(eOption, serverSettings[eOption]); + } if (theme.page) { diff --git a/packages/node_modules/@node-red/editor-api/lib/index.js b/packages/node_modules/@node-red/editor-api/lib/index.js index 56f52a222..d9f34eafd 100644 --- a/packages/node_modules/@node-red/editor-api/lib/index.js +++ b/packages/node_modules/@node-red/editor-api/lib/index.js @@ -37,7 +37,6 @@ var adminApp; var server; var editor; - /** * Initialise the module. * @param {Object} settings The runtime settings @@ -49,7 +48,7 @@ var editor; function init(settings,_server,storage,runtimeAPI) { server = _server; if (settings.httpAdminRoot !== false) { - adminApp = express(); + adminApp = apiUtil.createExpressApp(settings); var cors = require('cors'); var corsHandler = cors({ @@ -64,14 +63,6 @@ function init(settings,_server,storage,runtimeAPI) { } } - var defaultServerSettings = { - "x-powered-by": false - } - var serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{}); - for (var eOption in serverSettings) { - adminApp.set(eOption, serverSettings[eOption]); - } - auth.init(settings,storage); var maxApiRequestSize = settings.apiMaxLength || '5mb'; @@ -136,10 +127,11 @@ async function stop() { editor.stop(); } } + module.exports = { - init: init, - start: start, - stop: stop, + init, + start, + stop, /** * @memberof @node-red/editor-api diff --git a/packages/node_modules/@node-red/editor-api/lib/util.js b/packages/node_modules/@node-red/editor-api/lib/util.js index 621fd9e33..f1420235a 100644 --- a/packages/node_modules/@node-red/editor-api/lib/util.js +++ b/packages/node_modules/@node-red/editor-api/lib/util.js @@ -14,10 +14,9 @@ * limitations under the License. **/ +const express = require("express"); -var log = require("@node-red/util").log; // TODO: separate module -var i18n = require("@node-red/util").i18n; // TODO: separate module - +const { log, i18n } = require("@node-red/util"); module.exports = { errorHandler: function(err,req,res,next) { @@ -64,5 +63,17 @@ module.exports = { path: req.path, ip: (req.headers && req.headers['x-forwarded-for']) || (req.connection && req.connection.remoteAddress) || undefined } + }, + createExpressApp: function(settings) { + const app = express(); + + const defaultServerSettings = { + "x-powered-by": false + } + const serverSettings = Object.assign({},defaultServerSettings,settings.httpServerOptions||{}); + for (let eOption in serverSettings) { + app.set(eOption, serverSettings[eOption]); + } + return app } } diff --git a/packages/node_modules/@node-red/editor-api/package.json b/packages/node_modules/@node-red/editor-api/package.json index e2c53fe84..6d3ddb5af 100644 --- a/packages/node_modules/@node-red/editor-api/package.json +++ b/packages/node_modules/@node-red/editor-api/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-api", - "version": "3.0.2", + "version": "3.1.0-beta.2", "license": "Apache-2.0", "main": "./lib/index.js", "repository": { @@ -16,14 +16,14 @@ } ], "dependencies": { - "@node-red/util": "3.0.2", - "@node-red/editor-client": "3.0.2", + "@node-red/util": "3.1.0-beta.2", + "@node-red/editor-client": "3.1.0-beta.2", "bcryptjs": "2.4.3", - "body-parser": "1.20.0", + "body-parser": "1.20.2", "clone": "2.1.2", "cors": "2.8.5", "express-session": "1.17.3", - "express": "4.18.1", + "express": "4.18.2", "memorystore": "1.6.7", "mime": "3.0.0", "multer": "1.4.5-lts.1", @@ -35,6 +35,6 @@ "ws": "7.5.6" }, "optionalDependencies": { - "bcrypt": "5.0.1" + "bcrypt": "5.1.0" } } diff --git a/packages/node_modules/@node-red/editor-client/locales/de/editor.json b/packages/node_modules/@node-red/editor-client/locales/de/editor.json index 93a2f5946..f2955c266 100644 --- a/packages/node_modules/@node-red/editor-client/locales/de/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/de/editor.json @@ -1175,8 +1175,10 @@ "languages": { "de": "Deutsch", "en-US": "Englisch", + "fr": "Französisch", "ja": "Japanisch", "ko": "Koreanisch", + "pt-BR":"Portugiesisch", "ru": "Russisch", "zh-CN": "Chinesisch (Vereinfacht)", "zh-TW": "Chinesisch (Traditionell)" diff --git a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json index 5474d1a23..aae72ab3a 100644 --- a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json @@ -23,7 +23,11 @@ "position": "Position", "enable": "Enable", "disable": "Disable", - "upload": "Upload" + "upload": "Upload", + "lock": "Lock", + "unlock": "Unlock", + "locked": "Locked", + "unlocked": "Unlocked" }, "type": { "string": "string", @@ -53,22 +57,30 @@ "confirmDelete": "Confirm delete", "delete": "Are you sure you want to delete '__label__'?", "dropFlowHere": "Drop the flow here", + "dropImageHere": "Drop the image here", "addFlow": "Add flow", "addFlowToRight": "Add flow to the right", + "closeFlow": "Close flow", "hideFlow": "Hide flow", "hideOtherFlows": "Hide other flows", - "showAllFlows": "Show all flows", + "showAllFlows": "Show all flows (__count__ hidden)", "hideAllFlows": "Hide all flows", "hiddenFlows": "List __count__ hidden flow", "hiddenFlows_plural": "List __count__ hidden flows", - "showLastHiddenFlow": "Show last hidden flow", + "showLastHiddenFlow": "Reopen hidden flow", "listFlows": "List flows", "listSubflows": "List subflows", "status": "Status", "enabled": "Enabled", "disabled": "Disabled", "info": "Description", - "selectNodes": "Click nodes to select" + "selectNodes": "Click nodes to select", + "enableFlow": "Enable flow", + "disableFlow": "Disable flow", + "lockFlow": "Lock flow", + "unlockFlow": "Unlock flow", + "moveToStart": "Move flow to start", + "moveToEnd": "Move flow to end" }, "menu": { "label": { @@ -101,6 +113,7 @@ "displayStatus": "Show node status", "displayConfig": "Configuration nodes", "import": "Import", + "importExample": "Import Example Flow", "export": "Export", "search": "Search flows", "searchInput": "search your flows", @@ -498,6 +511,7 @@ "addRemoveNode": "Add/remove node from selection", "editSelected": "Edit selected node", "deleteSelected": "Delete selected nodes or link", + "deleteReconnect": "Delete and Reconnect", "importNode": "Import nodes", "exportNode": "Export nodes", "nudgeNode": "Move selected nodes (1px)", @@ -684,9 +698,11 @@ "empty": "empty", "globalConfig": "Global Configuration Nodes", "triggerAction": "Trigger action", + "find": "Find in workspace", + "copyItemUrl": "Copy item url", + "copyURL2Clipboard": "Copied url to clipboard", "showFlow": "Show", - "hideFlow": "Hide", - "find": "Find in workspace" + "hideFlow": "Hide" }, "help": { "name": "Help", @@ -987,7 +1003,10 @@ "quote": "Quote", "link": "Link", "horizontal-rule": "Horizontal rule", - "toggle-preview": "Toggle preview" + "toggle-preview": "Toggle preview", + "mermaid": { + "summary": "Mermaid Diagram" + } }, "bufferEditor": { "title": "Buffer editor", @@ -1182,8 +1201,10 @@ "languages": { "de": "German", "en-US": "English", + "fr": "French", "ja": "Japanese", "ko": "Korean", + "pt-BR":"Portuguese", "ru": "Russian", "zh-CN": "Chinese(Simplified)", "zh-TW": "Chinese(Traditional)" @@ -1209,5 +1230,10 @@ "node": "Node", "junction": "Junction", "linkNodes": "Link Nodes" + }, + "env-var": { + "environment": "Environment", + "header": "Global Environment Variables", + "revert": "Revert" } } diff --git a/packages/node_modules/@node-red/editor-client/locales/fr/editor.json b/packages/node_modules/@node-red/editor-client/locales/fr/editor.json new file mode 100644 index 000000000..a80c9160e --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/fr/editor.json @@ -0,0 +1,1238 @@ +{ + "common": { + "label": { + "name": "Nom", + "ok": "Ok", + "done": "Terminer", + "cancel": "Annuler", + "delete": "Supprimer", + "close": "Fermer", + "load": "Ouvrir", + "save": "Sauver", + "import": "Importer", + "export": "Exporter", + "back": "Retour", + "next": "Suivant", + "clone": "Cloner", + "cont": "Continuer", + "style": "Style", + "line": "Bordure", + "fill": "Remplissage", + "label": "Etiquette", + "color": "Couleur", + "position": "Position", + "enable": "Activer", + "disable": "Désactiver", + "upload": "Charger", + "lock": "Verrouiller", + "unlock": "Déverrouiller", + "locked": "Verrouillé", + "unlocked": "Déverrouillé" + }, + "type": { + "string": "chaîne de caractères", + "number": "nombre", + "boolean": "booléen", + "array": "tableau", + "buffer": "tampon", + "object": "objet", + "jsonString": "chaîne JSON", + "undefined": "indéfini", + "null": "nul" + } + }, + "event": { + "loadPlugins": "Chargement des extensions", + "loadPalette": "Chargement de la palette", + "loadNodeCatalogs": "Chargement des catalogues de noeuds", + "loadNodes": "Chargement des noeuds __count__", + "loadFlows": "Chargement des flux", + "importFlows": "Ajout de flux à l'espace de travail", + "importError": "

Erreur lors de l'ajout du flux

__message__

", + "loadingProject": "Chargement du projet" + }, + "workspace": { + "defaultName": "Flux __number__", + "editFlow": "Modifier le flux : __name__", + "confirmDelete": "Confirmation de la suppression", + "delete": "Etes-vous sûr de vouloir supprimer '__label__'?", + "dropFlowHere": "Déposer le flux ici", + "dropImageHere": "Déposer l'image ici", + "addFlow": "Ajouter un flux", + "addFlowToRight": "Ajouter un flux à droite", + "closeFlow": "Fermer le flux", + "hideFlow": "Masquer le flux", + "hideOtherFlows": "Masquer les autres flux", + "showAllFlows": "Afficher tous les flux", + "hideAllFlows": "Masquer tous les flux", + "hiddenFlows": "Répertorier le flux masqué __count__", + "hiddenFlows_plural": "Répertorier les flux masqués __count__", + "showLastHiddenFlow": "Afficher le dernier flux masqué", + "listFlows": "Répertorier les flux", + "listSubflows": "Répertorier les sous-flux", + "status": "Statut", + "enabled": "Activé", + "disabled": "Désactivé", + "info": "Description", + "selectNodes": "Cliquer sur les noeuds pour sélectionner", + "enableFlow": "Activer le flux", + "disableFlow": "Désactiver le flux", + "lockFlow": "Verrouiller le flux", + "unlockFlow": "Déverrouiller le flux", + "moveToStart": "Déplacer le flux au début", + "moveToEnd": "Déplacer le flux vers la fin" + }, + "menu": { + "label": { + "view": { + "view": "Affichage", + "grid": "Grille", + "storeZoom": "Restaurer le niveau de zoom au chargement", + "storePosition": "Restaurer la position de défilement au chargement", + "showGrid": "Afficher la grille", + "snapGrid": "Aligner sur la grille", + "gridSize": "Taille de la grille", + "textDir": "Sens du texte", + "defaultDir": "Sens par défaut", + "ltr": "De gauche à droite", + "rtl": "De droite à gauche", + "auto": "Contextuel", + "language": "Langue", + "browserDefault": "Navigateur par défaut" + }, + "sidebar": { + "show": "Afficher la barre latérale" + }, + "palette": { + "show": "Afficher la palette" + }, + "edit": "Éditer", + "settings": "Paramètres", + "userSettings": "Paramètres de l'utilisateur", + "nodes": "Noeuds", + "displayStatus": "Afficher l'état du noeud", + "displayConfig": "Noeuds de configuration", + "import": "Importer", + "importExample": "Importer un exemple de flux", + "export": "Exporter", + "search": "Rechercher les flux", + "searchInput": "Rechercher vos flux", + "subflows": "Sous-flux", + "createSubflow": "Créer un sous-flux", + "selectionToSubflow": "Selection d'un sous-flux", + "flows": "Flux", + "add": "Ajouter", + "rename": "Renommer", + "delete": "Supprimer", + "keyboardShortcuts": "Raccourcis clavier", + "login": "Se connecter", + "logout": "Se déconnecter", + "editPalette": "Gérer la palette", + "other": "Autre", + "showTips": "Afficher les astuces", + "showWelcomeTours": "Afficher les visites guidées pour les nouvelles versions", + "help": "Site web de Node-RED", + "projects": "Projets", + "projects-new": "Nouveau projet", + "projects-open": "Ouvrir le projet", + "projects-settings": "Paramètres du projet", + "showNodeLabelDefault": "Afficher l'étiquette des noeuds nouvellement ajoutés", + "codeEditor": "Éditeur de code", + "groups": "Groupes", + "groupSelection": "Grouper cette sélection", + "ungroupSelection": "Dégrouper la sélection", + "groupMergeSelection": "Fusionner la sélection", + "groupRemoveSelection": "Supprimer du groupe", + "arrange": "Organiser", + "alignLeft": "Aligner à gauche", + "alignCenter": "Aligner au centre", + "alignRight": "Aligner à droite", + "alignTop": "Aligner en haut", + "alignMiddle": "Aligner au milieu", + "alignBottom": "Aligner en bas", + "distributeHorizontally": "Répartir horizontalement", + "distributeVertically": "Distribuer verticalement", + "moveToBack": "Déplacer vers l'arrière", + "moveToFront": "Déplacer vers l'avant", + "moveBackwards": "Reculer", + "moveForwards": "Avancer" + } + }, + "actions": { + "toggle-navigator": "Basculer de navigateur", + "zoom-out": "Dézoomer", + "zoom-reset": "Réinitialiser le zoom", + "zoom-in": "Agrandir", + "search-flows": "Rechercher le flux", + "search-prev": "Précédent", + "search-next": "Suivant", + "search-counter": "\"__term__\" __result__ de __count__" + }, + "user": { + "loggedInAs": "Connecté en tant que __name__", + "username": "Nom d'utilisateur", + "password": "Mot de passe", + "login": "Connexion", + "loginFailed": "Échec de la connexion", + "notAuthorized": "Pas autorisé", + "errors": { + "settings": "Vous devez être connecté pour accéder aux paramètres", + "deploy": "Vous devez être connecté pour déployer les modifications", + "notAuthorized": "Vous devez être connecté pour effectuer cette action" + } + }, + "notification": { + "state": { + "flowsStopped": "Flux arrêtés", + "flowsStarted": "Flux démarrés" + }, + "warning": "Attention : __message__", + "warnings": { + "undeployedChanges": "Le noeud a des modifications non déployées", + "nodeActionDisabled": "Actions de noeud désactivées", + "nodeActionDisabledSubflow": "Actions de noeud désactivées dans le sous-flux", + "missing-types": "

Flux arrêtés en raison de types de noeuds manquants.

", + "missing-modules": "

Flux arrêtés en raison de modules manquants.

", + "safe-mode": "

Flux arrêtés en mode sans échec.

Vous pouvez modifier vos flux et déployer les changements pour redémarrer.

", + "restartRequired": "Node-RED doit être redémarré pour mettre à jour les modules", + "credentials_load_failed": "

Les flux se sont arrêtés car les informations d'identification n'ont pas pu être déchiffrées.

Le fichier d'informations d'identification du flux est chiffré, mais la clé de chiffrement du projet est manquante ou invalide.

", + "credentials_load_failed_reset": "

Les informations d'identification n'ont pas pu être déchiffrées

Le fichier d'informations d'identification du flux est chiffré, mais la clé de chiffrement du projet est manquante ou invalide.

Le fichier d'informations d'identification du flux sera réinitialisé lors du prochain déploiement. Toutes les informations d'identification de flux existantes seront perdues.

", + "missing_flow_file": "

Fichier contenant les flux introuvable.

Le projet n'est pas configuré avec un fichier de flux.

", + "missing_package_file": "

Fichier de paquetage du projet introuvable.

Il manque au projet un fichier package.json.

", + "project_empty": "

Le projet est vide.

Voulez-vous créer un ensemble de fichiers de projet par défaut ?
Sinon, vous devrez ajouter manuellement des fichiers au projet (en dehors de l'éditeur).

", + "project_not_found": "

Le projet '__project__' est introuvable.

", + "git_merge_conflict": "

La fusion automatique des modifications a échoué.

Corriger les conflits non fusionnés, puis valider le résultat.

" + }, + "error": "Erreur : __message__", + "errors": { + "lostConnection": "Connexion avec le serveur perdue, reconnexion...", + "lostConnectionReconnect": "Connexion avec le serveur perdue, reconnexion dans __time__s.", + "lostConnectionTry": "Essayer maintenant", + "cannotAddSubflowToItself": "Impossible d'ajouter un sous-flux à lui-même", + "cannotAddCircularReference": "Impossible d'ajouter un sous-flux - référence circulaire détectée", + "unsupportedVersion": "

Utilisation d'une version non prise en charge de Node.js

Vous devez effectuer une mise à jour vers la dernière version de Node.js LTS

", + "failedToAppendNode": "

Échec du chargement du module '__module__'

__error__

" + }, + "project": { + "change-branch": "Changer pour une branche locale '__project__'", + "merge-abort": "Git fusion abandonnée", + "loaded": "Projet '__project__' chargé", + "updated": "Projet '__project__' mis à jour", + "pull": "Projet '__project__' rechargé", + "revert": "Projet '__project__' annulé", + "merge-complete": "Fusion Git terminée", + "setupCredentials": "Configuration des identifiants", + "setupProjectFiles": "Configuration des fichiers du projet", + "no": "Non merci", + "createDefault": "Créer des fichiers de projet par défaut", + "mergeConflict": "Afficher les conflits de fusion" + }, + "label": { + "manage-project-dep": "Gérer les dépendances du projet", + "setup-cred": "Configuration des identifiants", + "setup-project": "Configuration des fichiers du projet", + "create-default-package": "Créer un fichier de paquetage par défaut", + "no-thanks": "Non merci", + "create-default-project": "Créer des fichiers de projet par défaut", + "show-merge-conflicts": "Afficher les conflits de fusion", + "unknownNodesButton": "Rechercher les noeuds inconnus" + } + }, + "clipboard": { + "clipboard": "Presse-papiers", + "nodes": "Noeuds", + "node": "__count__ noeud", + "node_plural": "__count__ noeuds", + "configNode": "__count__ noeud de configuration", + "configNode_plural": "__count__ noeuds de configuration", + "group": "__count__ groupe", + "group_plural": "__count__ groupes", + "flow": "__count__ flux", + "flow_plural": "__count__ flux", + "subflow": "__count__ sous-flux", + "subflow_plural": "__count__ sous-flux", + "replacedNodes": "__count__ noeud remplacé", + "replacedNodes_plural": "__count__ noeuds remplacés", + "pasteNodes": "Coller le flux JSON ou", + "selectFile": "Sélectionner un fichier à importer", + "importNodes": "Importer des noeuds", + "exportNodes": "Exporter des noeuds", + "download": "Télécharger", + "importUnrecognised": "Importation d'un type inconnu :", + "importUnrecognised_plural": "Importation de plusieurs types inconnus :", + "importDuplicate": "Noeud en double importé :", + "importDuplicate_plural": "Noeuds en double importés :", + "nodesExported": "Noeuds exportés vers le presse-papiers", + "nodesImported": "Noeuds importés :", + "nodeCopied": "__count__ noeud copié", + "nodeCopied_plural": "__count__ noeuds copiés", + "groupCopied": "__count__ groupe copié", + "groupCopied_plural": "__count__ groupes copiés", + "groupStyleCopied": "Style de groupe copié", + "invalidFlow": "Flux invalide : __message__", + "recoveredNodes": "Noeuds récupérés", + "recoveredNodesInfo": "Les noeuds importés sur ce flux contiennent un mauvais identifiant de flux. Ces noeuds ont été ajoutés à ce flux afin que vous puissiez les restaurer ou les supprimer.", + "recoveredNodesNotification": "

Noeuds importés sans identifiant de flux valide

Ils ont été ajoutés à un nouveau flux appelé '__flowName__'.

", + "export": { + "selected": "noeuds sélectionnés", + "current": "flux actuel", + "all": "tous les flux", + "compact": "condensé", + "formatted": "formaté", + "copy": "Copier dans le presse-papier", + "export": "Exporter vers la bibliothèque", + "exportAs": "Exporter en tant que", + "overwrite": "Remplacer", + "exists": "

\"__file__\" existe déjà.

Voulez-vous le remplacer ?

" + }, + "import": { + "import": "Importer vers", + "importSelected": "Importation sélectionnée", + "importCopy": "Importer une copie", + "viewNodes": "Afficher les noeuds...", + "newFlow": "Nouveau flux", + "replace": "Remplacer", + "errors": { + "notArray": "L'entrée n'est pas un tableau JSON", + "itemNotObject": "L'entrée n'est pas un flux valide - l'élément '__index__' n'est pas un objet du noeud", + "missingId": "L'entrée n'est pas un flux valide - l'élément '__index__' n'a pas de propriété 'id'", + "missingType": "L'entrée n'est pas un flux valide - l'élément '__index__' n'a pas de propriété 'type'" + }, + "conflictNotification1": "Certains des noeuds que vous avez importés existent déjà dans votre espace de travail.", + "conflictNotification2": "Sélectionner les noeuds à importer et choisir s'il faut remplacer les noeuds existants ou en importer une copie." + }, + "copyMessagePath": "Chemin copié", + "copyMessageValue": "Valeur copiée", + "copyMessageValue_truncated": "Valeur tronquée (coupée) copiée" + }, + "deploy": { + "deploy": "Déployer", + "full": "Tout", + "fullDesc": "Déploie tout l'espace de travail", + "modifiedFlows": "Flux modifiés", + "modifiedFlowsDesc": "Déploie uniquement les flux contenant des noeuds modifiés", + "modifiedNodes": "Noeuds modifiés", + "modifiedNodesDesc": "Déploie uniquement les noeuds qui ont changés", + "startFlows": "Démarrer", + "startFlowsDesc": "Démarrer les flux", + "stopFlows": "Arrêter", + "stopFlowsDesc": "Arrêter les flux", + "restartFlows": "Redémarrer les flux", + "restartFlowsDesc": "Redémarrer les flux actuellement déployés", + "successfulDeploy": "Déployé avec succès", + "successfulRestart": "Flux redémarrés avec succès", + "deployFailed": "Échec du déploiement : __message__", + "unusedConfigNodes": "Vous avez des noeuds de configuration inutilisés.", + "unusedConfigNodesButton": "Rechercher les noeuds de configuration inutilisés", + "unknownNodesButton": "Rechercher les noeuds inconnus", + "invalidNodesButton": "Rechercher les noeuds invalides", + "errors": { + "noResponse": "Pas de réponse du serveur" + }, + "confirm": { + "button": { + "ignore": "Ignorer", + "confirm": "Confirmer", + "review": "Examiner les modifications", + "cancel": "Annuler", + "merge": "Fusionner", + "overwrite": "Ignorer et déployer" + }, + "undeployedChanges": "Vous avez des modifications non déployées.\n\nSi vous quittez cette page, ces modifications seront perdues.", + "improperlyConfigured": "L'espace de travail contient des noeuds qui ne sont pas correctement configurés :", + "unknown": "L'espace de travail contient des types de noeuds inconnus :", + "confirm": "Êtes-vous sûr de vouloir déployer ?", + "doNotWarn": "Ne plus m'avertir à ce sujet", + "conflict": "Le serveur exécute un ensemble de flux plus récent.", + "backgroundUpdate": "Les flux sur le serveur ont été mis à jour.", + "conflictChecking": "Vérifier si les modifications peuvent être fusionnées automatiquement", + "conflictAutoMerge": "Les modifications n'incluent aucun conflit et peuvent être fusionnées automatiquement.", + "conflictManualMerge": "Les changements incluent des conflits qui doivent être résolus avant de pouvoir être déployés.", + "plusNMore": "+ __count__ en plus" + } + }, + "eventLog": { + "title": "Journal des événements", + "view": "Afficher le journal" + }, + "diff": { + "unresolvedCount": "__count__ conflit non résolu", + "unresolvedCount_plural": "__count__ conflits non résolus", + "globalNodes": "noeuds globaux", + "flowProperties": "Propriétés du flux", + "type": { + "added": "ajouté", + "changed": "modifié", + "unchanged": "inchangé", + "deleted": "supprimé", + "flowDeleted": "flux supprimé", + "flowAdded": "flux ajouté", + "movedTo": "déplacé vers __id__", + "movedFrom": "déplacé depuis __id__" + }, + "nodeCount": "__count__ noeud", + "nodeCount_plural": "__count__ noeuds", + "local": "Changements locaux", + "remote": "Modifications à distance", + "reviewChanges": "Examiner les modifications", + "noBinaryFileShowed": "Impossible d'afficher le contenu du fichier binaire", + "viewCommitDiff": "Afficher les modifications de validation", + "compareChanges": "Comparer les modifications", + "saveConflict": "Enregistrer la résolution des conflits", + "conflictHeader": "__resolved__ sur __unresolved__ conflit(s) résolu(s)", + "commonVersionError": "La version commune ne contient pas de JSON valide :", + "oldVersionError": "L'ancienne version ne contient pas de JSON valide :", + "newVersionError": "La nouvelle version ne contient pas de JSON valide :" + }, + "subflow": { + "editSubflowInstance": "Modifier l'instance du sous-flux : __name__", + "editSubflow": "Modifier le modèle du sous-flux : __name__", + "edit": "Modifier le modèle du sous-flux", + "subflowInstances": "Il existe __count__ instance de ce modèle de sous-flux", + "subflowInstances_plural": "Il existe __count__ instances de ce modèle de sous-flux", + "editSubflowProperties": "modifier les propriétés", + "input": "entrées:", + "output": "sorties:", + "status": "statut du noeud", + "deleteSubflow": "supprimer le sous-flux", + "confirmDelete": "Voulez-vous vraiment supprimer ce sous-flux ?", + "info": "Description", + "category": "Catégorie", + "module": "Module", + "license": "Licence", + "licenseNone": "Aucune", + "licenseOther": "Autre", + "type": "Type de noeud", + "version": "Version", + "versionPlaceholder": "x.y.z", + "keys": "Mots clés", + "keysPlaceholder": "Mots clés séparés par des virgules", + "author": "Auteur", + "authorPlaceholder": "Votre nom ", + "desc": "Description", + "env": { + "restore": "Restaurer le sous-flux par défaut", + "remove": "Supprimer la variable d'environnement" + }, + "errors": { + "noNodesSelected": "Impossible de créer un sous-flux : aucun noeud sélectionné", + "multipleInputsToSelection": "Impossible de créer un sous-flux : plusieurs entrées pour la sélection" + } + }, + "group": { + "editGroup": "Modifier le groupe : __name__", + "errors": { + "cannotCreateDiffGroups": "Impossible de créer un groupe de noeuds provenant de différents groupes", + "cannotAddSubflowPorts": "Impossible d'ajouter des ports à un groupe de sous-flux" + } + }, + "editor": { + "configEdit": "Modifier", + "configAdd": "Ajouter", + "configUpdate": "Sauver", + "configDelete": "Supprimer", + "nodesUse": "__count__ noeud utilise cette configuration", + "nodesUse_plural": "__count__ noeuds utilisent cette configuration", + "addNewConfig": "Ajouter un nouveau noeud de configuration __type__", + "editNode": "Modifier le noeud __type__", + "editConfig": "Modifier le noeud de configuration __type__", + "addNewType": "Ajouter un nouveau __type__...", + "nodeProperties": "Propriétés du noeud", + "label": "Étiquette", + "color": "Couleur", + "portLabels": "Étiquettes des ports", + "labelInputs": "Entrées", + "labelOutputs": "Sorties", + "settingIcon": "Icône", + "default": "Par défaut", + "noDefaultLabel": "Aucune", + "defaultLabel": "Utiliser l'étiquette par défaut", + "searchIcons": "Icônes de recherche", + "useDefault": "Utilisation par défaut", + "description": "Description", + "show": "Afficher", + "hide": "Masquer", + "locale": "Sélectionner la langue", + "icon": "Icône", + "inputType": "Type d'entrée", + "selectType": "Sélectionner les types...", + "loadCredentials": "Chargement des identifiants du noeud", + "inputs": { + "input": "entrée", + "select": "sélection", + "checkbox": "case à cocher", + "spinner": "valeurs à défiler", + "none": "aucune", + "hidden": "masquer la propriété" + }, + "types": { + "str": "chaîne de caractères", + "num": "nombre", + "bool": "booléen", + "json": "JSON", + "bin": "tampon", + "env": "variable d'environnement", + "cred": "identifiant" + }, + "menu": { + "input": "entrée", + "select": "sélection", + "checkbox": "case à cocher", + "spinner": "valeurs à défiler", + "hidden": "étiquette seulement" + }, + "select": { + "label": "Etiquette", + "value": "Valeur" + }, + "spinner": { + "min": "Minimum", + "max": "Maximum" + }, + "errors": { + "scopeChange": "La modification de la portée la rendra indisponible pour les noeuds d'autres flux qui l'utilisent", + "invalidProperties": "Propriétés invalides :", + "credentialLoadFailed": "Échec du chargement des identifiants du noeud" + } + }, + "keyboard": { + "title": "Raccourcis clavier", + "keyboard": "Clavier", + "filterActions": "Actions de filtrage", + "shortcut": "raccourci", + "scope": "portée", + "unassigned": "Non attribué", + "global": "global", + "workspace": "espace de travail", + "selectAll": "Tout sélectionner", + "selectNone": "Ne rien sélectionner", + "selectAllConnected": "Sélectionner tous les éléments connectés", + "addRemoveNode": "Ajouter/supprimer un noeud de la sélection", + "editSelected": "Modifier le noeud sélectionné", + "deleteSelected": "Supprimer les noeuds ou le lien sélectionné(s)", + "deleteReconnect": "Supprimer et reconnecter", + "importNode": "Importer les noeuds", + "exportNode": "Exporter les noeuds", + "nudgeNode": "Déplacer les noeuds sélectionnés (1px)", + "moveNode": "Déplacer les noeuds sélectionnés (20px)", + "toggleSidebar": "Basculer la barre latérale", + "togglePalette": "Basculer la palette", + "copyNode": "Copier les noeuds sélectionnés", + "cutNode": "Couper les noeuds sélectionnés", + "pasteNode": "Coller les noeuds", + "copyGroupStyle": "Copier le style de groupe", + "pasteGroupStyle": "Coller le style de groupe", + "undoChange": "Annuler", + "redoChange": "Rétablir", + "searchBox": "Ouvrir le champ de recherche", + "managePalette": "Gérer la palette", + "actionList": "Liste d'action", + "splitWireWithLinks": "Ajouter des liens à la sélection" + }, + "library": { + "library": "Bibliothèque", + "openLibrary": "Ouvrir la bibliothèque...", + "saveToLibrary": "Enregistrer dans la bibliothèque...", + "typeLibrary": "__type__ bibliothèque", + "unnamedType": "Innomé __type__", + "exportedToLibrary": "Noeuds exportés vers la bibliothèque", + "dialogSaveOverwrite": "Une __libraryType__ appelée __libraryName__ existe déjà. Écraser ?", + "invalidFilename": "Nom de fichier non valide", + "savedNodes": "Noeuds enregistrés", + "savedType": "__type__ enregistré", + "saveFailed": "Échec de la sauvegarde : __message__", + "newFolder": "Nouveau dossier", + "types": { + "local": "Local", + "examples": "Exemples" + } + }, + "palette": { + "noInfo": "Pas d'information disponible", + "filter": "Filtrer les noeuds", + "search": "Rechercher les modules", + "addCategory": "Ajouter un nouveau...", + "label": { + "subflows": "sous-flux", + "network": "réseau", + "common": "commun", + "input": "entrée", + "output": "sortie", + "function": "fonction", + "sequence": "séquence", + "parser": "analyseur", + "social": "social", + "storage": "stockage", + "analysis": "analyse", + "advanced": "avancé" + }, + "actions": { + "collapse-all": "Réduire toutes les catégories", + "expand-all": "Développer toutes les catégories" + }, + "event": { + "nodeAdded": "Noeud ajouté à la palette :", + "nodeAdded_plural": "Noeuds ajoutés à la palette :", + "nodeRemoved": "Noeud supprimé de la palette :", + "nodeRemoved_plural": "Noeuds supprimés de la palette :", + "nodeEnabled": "Noeud activé :", + "nodeEnabled_plural": "Noeuds activés :", + "nodeDisabled": "Noeud désactivé :", + "nodeDisabled_plural": "Noeuds désactivés :", + "nodeUpgraded": "Les noeuds du module __module__ ont été mis à jour vers la version __version__", + "unknownNodeRegistered": "Erreur lors du chargement du noeud : " + }, + "editor": { + "title": "Gérer la palette", + "palette": "Palette", + "times": { + "seconds": "il y a quelques secondes", + "minutes": "il y a quelques minutes", + "minutesV": "il y a __count__ minutes", + "hoursV": "il y a __count__ heure", + "hoursV_plural": "il y a __count__ heures", + "daysV": "il y a __count__ jour", + "daysV_plural": "il y a __count__ jours", + "weeksV": "il y a __count__ semaine", + "weeksV_plural": "il y a __count__ semaines", + "monthsV": "il y a __count__ mois", + "monthsV_plural": "il y a __count__ mois", + "yearsV": "il y a __count__ an", + "yearsV_plural": "il y a __count__ ans", + "yearMonthsV": "il y a __y__ an, __count__ mois", + "yearMonthsV_plural": "il y a __y__ an, __count__ mois", + "yearsMonthsV": "il y a __y__ ans, __count__ mois", + "yearsMonthsV_plural": "il y a __y__ ans, __count__ mois" + }, + "nodeCount": "__label__ noeud", + "nodeCount_plural": "__label__ noeuds", + "moduleCount": "__count__ module disponible", + "moduleCount_plural": "__count__ modules disponibles", + "inuse": "en cours d'utilisation", + "enableall": "activer tout", + "disableall": "désactiver tout", + "enable": "activer", + "disable": "désactiver", + "remove": "supprimer", + "update": "mettre à jour vers __version__", + "updated": "mis à jour", + "install": "installer", + "installed": "installé", + "conflict": "conflit", + "conflictTip": "

Ce module ne peut pas être installé car il inclut un
type de noeud qui a déjà été installé

Conflits avec __module__

", + "loading": "Chargement des catalogues...", + "tab-nodes": "Noeuds", + "tab-install": "Installer", + "sort": "trier:", + "sortAZ": "a-z", + "sortRecent": "récent", + "more": "+ __count__ en plus", + "upload": "Charger le fichier tgz du module", + "refresh": "Actualiser la liste des modules", + "errors": { + "catalogLoadFailed": "

Échec du chargement du catalogue de noeuds.

Vérifier la console du navigateur pour plus d'informations

", + "installFailed": "

Échec lors de l'installation : __module__

__message__

Consulter le journal pour plus d'informations

", + "removeFailed": "

Échec lors de la suppression : __module__

__message__

Consulter le journal pour plus d'informations

", + "updateFailed": "

Échec lors de la mise à jour : __module__

__message__

Consulter le journal pour plus d'informations

", + "enableFailed": "

Échec lors de l'activation : __module__

__message__

Consulter le journal pour plus d'informations

", + "disableFailed": "

Échec lors de la désactivation : __module__

__message__

Consulter le journal pour plus d'informations

" + }, + "confirm": { + "install": { + "body": "

Installation de '__module__'

Avant l'installation, veuiller lire la documentation du noeud. Certains noeuds ont des dépendances qui ne peuvent pas être résolues automatiquement et peuvent nécessiter un redémarrage de Node-RED.

", + "title": "Installer les noeuds" + }, + "remove": { + "body": "

Suppression de '__module__'

La suppression du noeud le désinstallera de Node-RED. Le noeud peut continuer à utiliser des ressources jusqu'au redémarrage de Node-RED.

", + "title": "Supprimer les noeuds" + }, + "update": { + "body": "

Mise à jour de '__module__'

La mise à jour du noeud nécessitera un redémarrage de Node-RED pour terminer la mise à jour. Cela doit être fait manuellement.

", + "title": "Mettre à jour les noeuds" + }, + "cannotUpdate": { + "body": "Une mise à jour pour ce noeud est disponible, mais il n'est pas installé dans un emplacement que le gestionnaire de palette peut mettre à jour.

Veuiller vous référer à la documentation pour savoir comment mettre à jour ce noeud." + }, + "button": { + "review": "Ouvrir la documentation", + "install": "Installer", + "remove": "Supprimer", + "update": "Mettre à jour" + } + } + } + }, + "sidebar": { + "info": { + "name": "Information", + "tabName": "Nom", + "label": "info", + "node": "Noeud", + "type": "Type", + "group": "Groupe", + "module": "Module", + "id": "ID (identifiant)", + "status": "Statut", + "enabled": "Activé", + "disabled": "Désactivé", + "subflow": "Sous-flux", + "instances": "Instances", + "properties": "Propriétés", + "info": "Information", + "desc": "Description", + "blank": "vide", + "null": "nul", + "showMore": "afficher en plus", + "showLess": "afficher en moins", + "flow": "Flux", + "selection": "Sélection", + "nodes": "__count__ noeuds", + "flowDesc": "Description du flux", + "subflowDesc": "Description du sous-flux", + "nodeHelp": "Aide sur les noeuds", + "none": "Aucun", + "arrayItems": "__count__ éléments", + "showTips": "Vous pouvez ouvrir les astuces à partir du panneau des paramètres", + "outline": "Plan", + "empty": "vide", + "globalConfig": "Noeuds de configuration globale", + "triggerAction": "Déclencher une action", + "find": "Rechercher dans l'espace de travail", + "copyItemUrl": "Copier l'URL de l'élément", + "copyURL2Clipboard": "URL copiée dans le presse-papiers", + "showFlow": "Afficher", + "hideFlow": "Masquer" + }, + "help": { + "name": "Aide", + "label": "aide", + "search": "Aide à la recherche", + "nodeHelp": "Aide sur les noeuds", + "showHelp": "Afficher l'aide", + "showInOutline": "Afficher dans les grandes lignes", + "showTopics": "Afficher les sujets", + "noHelp": "Aucune rubrique d'aide sélectionnée", + "changeLog": "Journal des modifications" + }, + "config": { + "name": "Noeuds de configuration", + "label": "configuration", + "global": "Tous les flux", + "none": "aucun", + "subflows": "sous-flux", + "flows": "flux", + "filterAll": "tout", + "showAllConfigNodes": "Afficher tous les noeuds de configuration", + "filterUnused": "inutilisé", + "showAllUnusedConfigNodes": "Afficher tous les noeuds de configuration inutilisés", + "filtered": "__count__ caché(s)" + }, + "context": { + "name": "Données contextuelles", + "label": "contexte", + "none": "aucune sélection", + "refresh": "actualiser pour charger", + "empty": "vide", + "node": "Noeud", + "flow": "Flux", + "global": "Global", + "deleteConfirm": "Êtes-vous sûr de vouloir supprimer cet élément ?", + "autoRefresh": "Rafraîchir si la sélection change", + "refrsh": "Rafraîchir", + "delete": "Supprimer" + }, + "palette": { + "name": "Gestion des palettes", + "label": "palette" + }, + "project": { + "label": "projet", + "name": "Projet", + "description": "Description", + "dependencies": "Dépendances", + "settings": "Paramètres", + "noSummaryAvailable": "Aucun résumé disponible", + "editDescription": "Modifier la description du projet", + "editDependencies": "Modifier les dépendances du projet", + "noDescriptionAvailable": "Pas de description disponible", + "editReadme": "Modifier le fichier README.md", + "showProjectSettings": "Afficher les paramètres du projet", + "projectSettings": { + "title": "Paramètres du projet", + "edit": "modifier", + "none": "Vide", + "install": "installer", + "removeFromProject": "supprimer du projet", + "addToProject": "ajouter au projet", + "files": "Fichiers", + "flow": "Flux", + "credentials": "Identifiants", + "package": "Paquets", + "packageCreate": "Le fichier sera créé lorsque les modifications seront enregistrées", + "fileNotExist": "Le fichier n'existe pas", + "selectFile": "Choisir le dossier", + "invalidEncryptionKey": "Clé de chiffrement invalide", + "encryptionEnabled": "Chiffrement activé", + "encryptionDisabled": "Chiffrement désactivé", + "setTheEncryptionKey": "Définir la clé de chiffrement", + "resetTheEncryptionKey": "Réinitialiser la clé de chiffrement", + "changeTheEncryptionKey": "Changer la clé de chiffrement", + "currentKey": "Clé actuelle", + "newKey": "Nouvelle clé", + "credentialsAlert": "Cela supprimera tous les identifiants existants", + "versionControl": "Contrôle de version", + "branches": "Branches", + "noBranches": "Pas de branche", + "deleteConfirm": "Êtes-vous sûr de vouloir supprimer la branche locale '__name__' ? Ça ne peut pas être annulé.", + "unmergedConfirm": "La branche locale '__name__' contient des modifications non fusionnées qui seront perdues. Etes-vous sûr de vouloir la supprimer?", + "deleteUnmergedBranch": "Supprimer la branche non fusionnée", + "gitRemotes": "Git distant", + "addRemote": "Ajout distant", + "addRemote2": "Ajout distant", + "remoteName": "Nom distant", + "nameRule": "Doit contenir uniquement A-Z 0-9 _ -", + "url": "URL", + "urlRule": "https://, ssh:// ou file://", + "urlRule2": "Ne pas inclure le nom d'utilisateur/mot de passe dans l'URL", + "noRemotes": "Pas distant", + "deleteRemoteConfrim": "Êtes-vous sûr de vouloir supprimer '__name__' distant ?", + "deleteRemote": "Supprimer distant" + }, + "userSettings": { + "committerDetail": "Détails de l'auteur de la validation (commit)", + "committerTip": "Laisser vide pour utiliser la valeur par défaut du système", + "userName": "Nom d'utilisateur", + "email": "e-mail", + "workflow": "Flux de travail", + "workfowTip": "Choisisser votre flux de travail Git préféré", + "workflowManual": "Manuel", + "workflowManualTip": "Toutes les modifications doivent être validées manuellement dans la barre latérale 'historique'", + "workflowAuto": "Automatique", + "workflowAutoTip": "Les modifications sont validées automatiquement à chaque déploiement", + "sshKeys": "Clés SSH", + "sshKeysTip": "Vous permet de créer des connexions sécurisées aux référentiels Git distants.", + "add": "ajouter une clé", + "addSshKey": "Ajouter une clé SSH", + "addSshKeyTip": "Générer une nouvelle paire de clés publique/privée", + "name": "Nom", + "nameRule": "Doit contenir uniquement A-Z 0-9 _ -", + "passphrase": "Phrase de mot de passe", + "passphraseShort": "Phrase de mot de passe trop courte", + "optional": "Facultatif", + "cancel": "Annuler", + "generate": "Générer une clé", + "noSshKeys": "Pas de clé SSH", + "copyPublicKey": "Copier la clé publique dans le presse-papiers", + "delete": "Supprimer une clé", + "gitConfig": "Configuration Git", + "deleteConfirm": "Êtes-vous sûr de vouloir supprimer la clé SSH __nom__ ? Ça ne peut pas être annulé." + }, + "versionControl": { + "unstagedChanges": "Abandon des changements", + "stagedChanges": "Changement mis en place", + "unstageChange": "Ne pas mettre en place le changement", + "stageChange": "Mettre en place le changement", + "unstageAllChange": "Ne pas mettre en place tous les changements", + "stageAllChange": "Mettre en place tous les changements", + "commitChanges": "Valider les changements", + "resolveConflicts": "Résoudre les conflits", + "head": "En-tête", + "staged": "Mis en place", + "unstaged": "Non mis en place", + "local": "Local", + "remote": "Distant", + "revert": "Voulez-vous vraiment annuler les modifications apportées à '__file__' ? Ça ne peut pas être annulé.", + "revertChanges": "Rétablir les changements", + "localChanges": "Modifications locales", + "none": "Vide", + "conflictResolve": "Tous les conflits ont été résolus. Valider les modifications pour terminer la fusion.", + "localFiles": "Fichiers locaux", + "all": "tout", + "unmergedChanges": "Modifications non fusionnées", + "abortMerge": "Abandonner la fusion", + "commit": "Valider", + "changeToCommit": "Modifications à valider", + "commitPlaceholder": "Entrer votre message de validation", + "cancelCapital": "Annuler", + "commitCapital": "Valider", + "commitHistory": "Historique des validations", + "branch": "Branche :", + "moreCommits": "Davantage de validations", + "changeLocalBranch": "Changer de branche locale", + "createBranchPlaceholder": "Trouver où créer une branche", + "upstream": "en amont", + "localOverwrite": "Vous avez des modifications locales qui seraient écrasées en changeant la branche. Vous devez d'abord valider ou annuler ces modifications.", + "manageRemoteBranch": "Gérer une branche distante", + "unableToAccess": "Impossible d'accéder au référentiel distant", + "retry": "Recommencer", + "setUpstreamBranch": "Définir comme branche en amont", + "createRemoteBranchPlaceholder": "Trouver ou créer une branche distante", + "trackedUpstreamBranch": "La branche créée sera définie comme la branche en amont suivie.", + "selectUpstreamBranch": "La branche sera créée. Sélectionner ci-dessous pour la définir comme branche en amont suivie.", + "pushFailed": "L'envoi a échoué car la branche a des validations plus récentes. Tirer et fusionner d'abord, puis envoyer à nouveau.", + "push": "Envoyer", + "pull": "Tirer", + "unablePull": "

Impossible d'extraire les modifications à distance ; vos modifications locales non mises en place seraient écrasées.

Valider vos modifications et réessayer.

", + "showUnstagedChanges": "Afficher les modifications non mise en place", + "connectionFailed": "Impossible de se connecter au référentiel distant: ", + "pullUnrelatedHistory": "

Le réferentiel distant a un historique de validations sans rapport.

Êtes-vous sûr de vouloir extraire les modifications dans votre référentiel local ?

", + "pullChanges": "Tirer les changements", + "history": "Historique", + "projectHistory": "Historique du projet", + "daysAgo": "il y a __count__ jour", + "daysAgo_plural": "il y a __count__ jours", + "hoursAgo": "il y a __count__ heure", + "hoursAgo_plural": "il y a __count__ heures", + "minsAgo": "il y a __count__ minute", + "minsAgo_plural": "il y a __count__ minutes", + "secondsAgo": "Il y a quelques instants", + "notTracking": "Votre branche locale ne suit pas actuellement une branche distante.", + "statusUnmergedChanged": "Votre référentiel contient des modifications non fusionnées. Vous devez résoudre les conflits et valider le résultat.", + "repositoryUpToDate": "Votre référentiel est à jour.", + "commitsAhead": "Votre référentiel a __count__ validation d'avance sur le référentiel distant. Vous pouvez pousser cette validation maintenant.", + "commitsAhead_plural": "Votre référentiel a __count__ validations d'avance sur le référentiel distant. Vous pouvez pousser ces validations maintenant.", + "commitsBehind": "Votre référentiel a __count__ validation de retard sur le référentiel distant. Vous pouvez pousser cette validation maintenant.", + "commitsBehind_plural": "Votre référentiel a __count__ validations de retard sur le référentiel distant. Vous pouvez pousser ces validations maintenant.", + "commitsAheadAndBehind1": "Votre référentiel a __count__ validation derrière et ", + "commitsAheadAndBehind1_plural": "Votre référentiel est __count__ validations derrière et ", + "commitsAheadAndBehind2": "__count__ validation avant le référentiel distant. ", + "validationsAheadAndBehind2_plural": "__count__ commits avant le référentiel distant. ", + "commitsAheadAndBehind3": "Vous devez retirer la validation à distance avant de pousser la modification.", + "commitsAheadAndBehind3_plural": "Vous devez retirer les validations à distance avant de pousser les modifications.", + "refreshCommitHistory": "Actualiser l'historique des validations", + "refreshChanges": "Actualiser les modifications" + } + } + }, + "typedInput": { + "type": { + "str": "chaîne de caractères", + "num": "nombre", + "re": "expression régulière", + "bool": "booléen", + "json": "JSON", + "bin": "tampon", + "date": "horodatage", + "jsonata": "expression", + "env": "variable d'environnement", + "cred": "identifiant" + } + }, + "editableList": { + "add": "Ajouter", + "addTitle": "Ajouter un élément" + }, + "search": { + "history": "Historique des recherches", + "clear": "Tout effacer", + "empty": "Aucun résultat", + "addNode": "Ajouter un noeud...", + "options": { + "configNodes": "Noeuds de configuration", + "unusedConfigNodes": "Noeuds de configuration inutilisés", + "invalidNodes": "Noeuds invalides", + "uknownNodes": "Noeuds inconnus", + "unusedSubflows": "Sous-flux inutilisés", + "hiddenFlows": "Flux cachés", + "modifiedNodes": "Noeuds et flux modifiés", + "thisFlow": "Flux courant" + } + }, + "expressionEditor": { + "functions": "Fonctions", + "functionReference": "Fonction de référence", + "insert": "Insérer", + "title": "Éditeur d'expressions JSONata", + "test": "Test", + "data": "Exemple de message", + "result": "Résultat", + "format": "Format", + "compatMode": "Mode de compatibilité activé", + "compatModeDesc": "

Mode de compatibilité JSONata

L'expression actuelle semble toujours faire référence à msg et sera donc évaluée en mode de compatibilité. Veuiller mettre à jour l'expression pour ne pas utiliser msg car ce mode sera supprimé à l'avenir.

Lorsque la prise en charge de JSONata a été ajoutée pour la première fois à Node-RED, il fallait que l'expression référencie l'objet msg. Par exemple, msg.payload serait utilisé pour accéder à la charge utile.

Cela n'est plus nécessaire car l'expression sera évaluée directement par rapport au message. Pour accéder à la charge utile, l'expression doit être simplement charge utile.

", + "noMatch": "Aucun résultat correspondant", + "errors": { + "invalid-expr": "Expression JSONata non valide :\n __message__", + "invalid-msg": "Exemple de message JSON non valide :\n __message__", + "context-unsupported": "Impossible de tester les fonctions de contexte\n $flowContext ou $globalContext", + "env-unsupported": "Impossible de tester la fonction $env", + "moment-unsupported": "Impossible de tester la fonction $moment", + "clone-unsupported": "Impossible de tester la fonction $clone", + "eval": "Erreur lors de l'évaluation de l'expression :\n __message__" + } + }, + "monaco": { + "setTheme": "Définir le thème" + }, + "jsEditor": { + "title": "Éditeur JavaScript" + }, + "textEditor": { + "title": "Éditeur de texte" + }, + "jsonEditor": { + "title": "Éditeur JSON", + "format": "Format JSON", + "rawMode": "Modifier JSON", + "uiMode": "Afficher l'éditeur", + "rawMode-readonly": "JSON", + "uiMode-readonly": "Visualiser", + "insertAbove": "Insérer ci-dessus", + "insertBelow": "Insérer ci-dessous", + "addItem": "Ajouter un élément", + "copyPath": "Copier le chemin vers l'élément", + "expandItems": "Développer les éléments", + "collapseItems": "Réduire les éléments", + "duplicate": "Dupliquer", + "error": { + "invalidJSON": "JSON invalide : " + } + }, + "markdownEditor": { + "title": "Éditeur Markdown", + "expand": "Développer", + "format": "Formaté avec Markdown", + "heading1": "Rubrique 1", + "heading2": "Rubrique 2", + "heading3": "Rubrique 3", + "bold": "Gras", + "italic": "Italic", + "code": "Code", + "ordered-list": "Liste ordonnée", + "unordered-list": "Liste non ordonnée", + "quote": "Citation", + "link": "Lien", + "horizontal-rule": "Règle horizontale", + "toggle-preview": "Basculer l'aperçu", + "mermaid": { + "summary": "Diagramme Mermaid" + } + }, + "bufferEditor": { + "title": "Éditeur de tampon", + "modeString": "Gérer comme une chaîne UTF-8", + "modeArray": "Gérer en tant que tableau JSON", + "modeDesc": "

Éditeur de tampon

Le type de tampon est stocké sous la forme d'un tableau JSON de valeurs d'octets. L'éditeur tentera d'analyser la valeur saisie en tant que tableau JSON. S'il ne s'agit pas d'un JSON valide, il sera traité comme une chaîne UTF-8 et converti en un tableau de points de code de caractères individuels.

Par exemple, une valeur de Hello World sera converti en tableau JSON :

[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]

" + }, + "projects": { + "config-git": "Configurer le client Git", + "welcome": { + "hello": "Bonjour! Nous avons introduit des 'projets' dans Node-RED.", + "desc0": "Il s'agit d'une nouvelle façon pour vous de gérer vos fichiers de flux, cela inclut le contrôle de version de vos flux.", + "desc1": "Pour commencer, vous pouvez créer votre premier projet ou cloner un projet existant à partir d'un référentiel git.", + "desc2": "Si vous n'êtes pas sûr, vous pouvez ignorer ceci pour le moment. Vous pourrez toujours créer votre premier projet à partir du menu 'Projets' à tout moment.", + "create": "Créer un projet", + "clone": "Cloner un référentiel", + "openExistingProject": "Ouvrir un projet existant", + "not-right-now": "Pas maintenant" + }, + "git-config": { + "setup": "Configurer votre version du client Git", + "desc0": "Node-RED utilise l'outil open source Git pour le contrôle de version. Il suit les modifications apportées à vos fichiers de projet et vous permet de les transférer vers des référentiels distants.", + "desc1": "Lorsque vous validez un ensemble de modifications, Git enregistre l'auteur qui a effectué les modifications avec un nom d'utilisateur et une adresse e-mail. Le nom d'utilisateur peut être ce que vous voulez - il n'est pas nécessaire que ce soit votre vrai nom.", + "desc2": "Votre client Git est déjà configuré avec les détails ci-dessous.", + "desc3": "Vous pouvez modifier ces paramètres ultérieurement sous l'onglet 'Configuration Git' de la boîte de dialogue des paramètres.", + "username": "Nom d'utilisateur", + "email": "e-mail" + }, + "project-details": { + "create": "Créer votre projet", + "desc0": "Un projet est maintenu en tant que référentiel Git. Il est beaucoup plus facile de partager vos flux et de collaborer avec les autres grâce à ce référentiel.", + "desc1": "Vous pouvez créer plusieurs projets et basculer rapidement entre eux depuis l'éditeur.", + "desc2": "Pour commencer, votre projet a besoin d'un nom et facultativement d'une description.", + "already-exists": "Le projet existe déjà", + "must-contain": "Doit contenir uniquement A-Z 0-9 _ -", + "project-name": "Nom du projet", + "desc": "Description", + "opt": "Facultatif" + }, + "clone-project": { + "clone": "Cloner un projet", + "desc0": "Si vous avez déjà un dépôt Git contenant un projet, vous pouvez le cloner pour commencer.", + "already-exists": "Le projet existe déjà", + "must-contain": "Doit contenir uniquement A-Z 0-9 _ -", + "project-name": "Nom du projet", + "no-info-in-url": "Ne pas inclure le nom d'utilisateur/mot de passe dans l'URL", + "git-url": "URL du dépôt Git", + "protocols": "https://, ssh:// ou file://", + "auth-failed": "L'authentification a échoué", + "username": "Nom d'utilisateur", + "passwd": "Mot de passe", + "ssh-key": "Clé SSH", + "passphrase": "Phrase de mot de passe", + "ssh-key-desc": "Avant de pouvoir cloner un référentiel avec ssh, vous devez ajouter une clé SSH pour y accéder.", + "ssh-key-add": "Ajouter une clé ssh", + "credential-key": "Clé de chiffrement des identifiants", + "cant-get-ssh-key": "Erreur! Impossible d'obtenir le chemin de la clé SSH sélectionnée.", + "already-exists2": "Existe déjà", + "git-error": "Erreur git", + "connection-failed": "La connexion a échoué", + "not-git-repo": "Ce n'est pas un dépôt Git", + "repo-not-found": "Référentiel introuvable" + }, + "default-files": { + "create": "Créer vos fichiers de projet", + "desc0": "Un projet contient vos fichiers de flux, un fichier README et un fichier package.json.", + "desc1": "Il peut contenir tous les autres fichiers que vous souhaitez conserver dans le référentiel Git.", + "desc2": "Vos fichiers de flux et identifiants existants seront copiés dans le projet.", + "flow-file": "Fichier de flux", + "credentials-file": "Fichier d'identifiants" + }, + "encryption-config": { + "setup": "Configuration du chiffrage de votre fichier d'informations d'identification", + "desc0": "Votre fichier d'informations d'identification de flux peut être chiffré pour sécuriser son contenu.", + "desc1": "Si vous souhaitez stocker ces identifiants dans un référentiel Git public, vous devez les chiffrer en fournissant une phrase clé secrète.", + "desc2": "Votre fichier d'identifiants de flux n'est actuellement pas chiffré.", + "desc3": "Cela signifie que son contenu, tel que les mots de passe et les jetons d'accès, peut être lu par toute personne ayant accès au fichier.", + "desc4": "Si vous souhaitez stocker ces identifiants dans un référentiel Git public, vous devez les chiffrer en fournissant une phrase clé secrète.", + "desc5": "Votre fichier contenant les identifiants de flux est actuellement chiffré à l'aide de la propriété credentialSecret de votre fichier de paramètres comme clé.", + "desc6": "Votre fichier contenant les identifiants de flux est actuellement chiffré à l'aide d'une clé générée par le système. Vous devez fournir une nouvelle clé secrète pour ce projet.", + "desc7": "La clé sera stockée séparément de vos fichiers de projet. Vous devrez fournir la clé pour utiliser ce projet dans une autre instance de Node-RED.", + "credentials": "Identifiants", + "enable": "Activer le chiffrement", + "disable": "Désactiver le chiffrement", + "disabled": "Désactivé", + "copy": "Remplacer la clé existante", + "use-custom": "Utiliser la clé personnalisée", + "desc8": "Le fichier contenant les identifiants ne sera pas crypté et son contenu sera facilement lisible", + "create-project-files": "Créer des fichiers de projet", + "create-project": "Créer un projet", + "already-exists": "existe déjà", + "git-error": "Erreur Git", + "git-auth-error": "erreur d'authentification Git" + }, + "create-success": { + "success": "Vous avez créé avec succès votre premier projet !", + "desc0": "Vous pouvez maintenant continuer à utiliser Node-RED comme vous l'avez toujours fait.", + "desc1": "L'onglet 'info' dans la barre latérale vous montre quel est votre projet actif actuel. Le bouton à côté du nom peut être utilisé pour accéder à la vue des paramètres du projet.", + "desc2": "L'onglet 'historique' dans la barre latérale peut être utilisé pour afficher les fichiers qui ont changé dans votre projet et pour les valider. Il vous montre un historique complet de vos validations (commits) et vous permet de pousser vos modifications vers un référentiel distant." + }, + "create": { + "projects": "Projets", + "already-exists": "Le projet existe déjà", + "must-contain": "Doit contenir uniquement A-Z 0-9 _ -", + "no-info-in-url": "Ne pas inclure le nom d'utilisateur/mot de passe dans l'URL", + "open": "Projet ouvert", + "create": "Créer un projet", + "clone": "Cloner un référentiel", + "project-name": "Nom du projet", + "desc": "Description", + "opt": "Facultatif", + "flow-file": "Fichier de flux", + "credentials": "Identifiants", + "enable-encryption": "Activer le chiffrement", + "disable-encryption": "Désactiver le chiffrement", + "encryption-key": "Clé de chiffrement", + "desc0": "Une phrase pour sécuriser vos identifiants", + "desc1": "Le fichier contenant les identifiants ne sera pas crypté et son contenu sera facilement lisible", + "git-url": "URL du dépôt Git", + "protocols": "https://, ssh:// ou file://", + "auth-failed": "L'authentification a échoué", + "username": "Nom d'utilisateur", + "password": "Mot de passe", + "ssh-key": "Clé SSH", + "passphrase": "Phrase de mot de passe", + "desc2": "Avant de pouvoir cloner un référentiel sur ssh, vous devez ajouter une clé SSH pour y accéder.", + "add-ssh-key": "Ajouter une clé ssh", + "credentials-encryption-key": "Clé de chiffrement des identifiants", + "already-exists-2": "existe déjà", + "git-error": "erreur git", + "con-failed": "La connexion a échoué", + "not-git": "Ce n'est pas un dépôt git", + "no-resource": "Référentiel introuvable", + "cant-get-ssh-key-path": "Erreur! Impossible d'obtenir le chemin de la clé SSH sélectionnée.", + "unexpected_error": "Erreur inattendue", + "clearContext": "Effacer le contexte lors du changement de projet" + }, + "delete": { + "confirm": "Voulez-vous vraiment supprimer ce projet ?" + }, + "create-project-list": { + "search": "rechercher vos projets", + "current": "actuel" + }, + "require-clean": { + "confirm": "

Vous avez des modifications non déployées qui seront perdues.

Voulez-vous continuer ?

" + }, + "send-req": { + "auth-req": "Authentification requise pour le référentiel", + "username": "Nom d'utilisateur", + "password": "Mot de passe", + "passphrase": "Phrase de mot de passe", + "retry": "Recommencer", + "update-failed": "La mise à jour a échoué", + "unhandled": "Code d'erreur non géré", + "host-key-verify-failed": "

La vérification de la clé d'hôte a échoué.

La clé d'hôte du référentiel n'a pas pu être vérifiée. Veuillez mettre à jour votre fichier known_hosts et réessayer.

" + }, + "create-branch-list": { + "invalid": "Branche invalide", + "create": "Créer une branche", + "current": "Actuelle" + }, + "create-default-file-set": { + "no-active": "Impossible de créer un ensemble de fichiers par défaut sans projet actif", + "no-empty": "Impossible de créer un ensemble de fichiers par défaut sur un projet non vide", + "git-error": "Erreur Git" + }, + "errors": { + "no-username-email": "Votre client Git n'est pas configuré avec un nom d'utilisateur/e-mail.", + "unexpected": "Une erreur inattendue est apparue", + "code": "Code" + } + }, + "editor-tab": { + "properties": "Propriétés", + "envProperties": "Variables d'environnement", + "module": "Propriétés des modules", + "description": "Description", + "appearance": "Apparence", + "preview": "Aperçu de l'interface utilisateur", + "defaultValue": "Valeur par défaut" + }, + "tourGuide": { + "takeATour": "Aperçu", + "start": "Commencer", + "next": "Suivant", + "welcomeTours": "Visite de bienvenue" + }, + "diagnostics": { + "title": "Information système" + }, + "languages": { + "de": "Allemand", + "en-US": "Anglais", + "fr": "Français", + "ja": "Japonais", + "ko": "Coréen", + "pt-BR": "Portugais brésilien", + "ru": "Russe", + "zh-CN": "Chinois (Simplifié)", + "zh-TW": "Chinois (Traditionnel)" + }, + "validator": { + "errors": { + "invalid-json": "Données JSON invalides : __error__", + "invalid-json-prop": "__prop__: données JSON invalides : __error__", + "invalid-prop": "Expression de propriété non valide", + "invalid-prop-prop": "__prop__: expression de propriété invalide", + "invalid-num": "Numéro invalide", + "invalid-num-prop": "__prop__: numéro invalide", + "invalid-regexp": "Modèle d'entrée non valide", + "invalid-regex-prop": "__prop__: modèle d'entrée non valide", + "missing-required-prop": "__prop__: valeur de la propriété manquante", + "invalid-config": "__prop__: noeud de configuration invalide", + "missing-config": "__prop__: noeud de configuration manquant", + "validation-error": "__prop__: erreur de validation: __node__, __id__: __error__" + } + }, + "contextMenu": { + "insert": "Insérer", + "node": "Noeud", + "junction": "Jonction", + "linkNodes": "Liens entre les noeuds" + }, + "env-var": { + "environment": "Environment", + "header": "Variables d'environnement globales", + "revert": "Rétablir" + } +} diff --git a/packages/node_modules/@node-red/editor-client/locales/fr/infotips.json b/packages/node_modules/@node-red/editor-client/locales/fr/infotips.json new file mode 100755 index 000000000..449be751b --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/fr/infotips.json @@ -0,0 +1,23 @@ +{ + "info": { + "tip0": "Vous pouvez supprimer les noeuds ou les liens sélectionnés avec {{core:delete-selection}}", + "tip1": "Rechercher des noeuds à l'aide de {{core:search}}", + "tip2": "{{core:toggle-sidebar}} basculera l'affichage de cette barre latérale", + "tip3": "Vous pouvez gérer votre palette de noeuds avec {{core:manage-palette}}", + "tip4": "Vos noeuds de configuration de flux sont répertoriés dans le panneau de la barre latérale. Ils sont accessibles depuis le menu ou avec {{core:show-config-tab}}", + "tip5": "Activer ou désactiver ces conseils à partir de l'option dans les paramètres", + "tip6": "Déplacer les noeuds sélectionnés à l'aide des touches [gauche] [haut] [bas] et [droite]. Maintenir la touche [shift] enfoncée pour les pousser plus loin", + "tip7": "Faire glisser un noeud sur un fil le raccordera au lien", + "tip8": "Exporter les noeuds sélectionnés, ou l'onglet actuel avec {{core:show-export-dialog}}", + "tip9": "Importer un flux en faisant glisser son JSON dans l'éditeur, ou avec {{core:show-import-dialog}}", + "tip10": "[majuscule] [clic] et faites glisser sur un port de noeud pour déplacer tous les fils attachés ou seulement celui sélectionné", + "tip11": "Afficher l'onglet Infos avec {{core:show-info-tab}} ou l'onglet Débogage avec {{core:show-debug-tab}}", + "tip12": "[ctrl] [clic] dans l'espace de travail pour ouvrir la boîte de dialogue d'ajout rapide", + "tip13": "Maintenir la touche [ctrl] enfoncée lorsque vous [cliquez] sur un port de noeud pour activer le câblage rapide", + "tip14": "Maintenir la touche [shift] enfoncée lorsque vous [cliquez] sur un noeud pour sélectionner également tous ses noeuds connectés", + "tip15": "Maintenir la touche [ctrl] enfoncée lorsque vous [cliquez] sur un noeud pour l'ajouter ou le supprimer de la sélection actuelle", + "tip16": "Changer d'onglet de flux avec {{core:show-previous-tab}} et {{core:show-next-tab}}", + "tip17": "Vous pouvez confirmer vos modifications dans le panneau d'édition du noeud avec {{core:confirm-edit-tray}} ou les annuler avec {{core:cancel-edit-tray}}", + "tip18": "Appuyer sur {{core:edit-selected-node}} modifiera le premier noeud de la sélection actuelle" + } +} \ No newline at end of file diff --git a/packages/node_modules/@node-red/editor-client/locales/fr/jsonata.json b/packages/node_modules/@node-red/editor-client/locales/fr/jsonata.json new file mode 100755 index 000000000..8fd65bf72 --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/fr/jsonata.json @@ -0,0 +1,274 @@ +{ + "$string": { + "args": "arg[, prettify]", + "desc": "Convertit le paramètre `arg` en une chaîne de caractères en utilisant les règles de typage suivantes :\n\n - Les chaînes de caractères sont inchangées\n - Les fonctions sont converties en une chaîne vide\n - L'infini numérique et NaN renvoient une erreur car ils ne peuvent pas être représentés comme un Numéro JSON\n - Toutes les autres valeurs sont converties en une chaîne JSON à l'aide de la fonction `JSON.stringify`. Si `prettify` est vrai, alors le JSON \"prettified\" est produit. c'est-à-dire une ligne par champ et les lignes seront en retrait en fonction de la profondeur du champ." + }, + "$length": { + "args": "str", + "desc": "Renvoie le nombre de caractères dans la chaîne `str`. Une erreur est renvoyée si `str` n'est pas une chaîne de caractères." + }, + "$substring": { + "args": "str, start[, length]", + "desc": "Renvoie une chaîne contenant les caractères du premier paramètre `str` commençant à la position `start` (pas de décalage). Si `length` est spécifié, alors la sous-chaîne contiendra un maximum de caractères `length`. Si `start` est négatif alors il indique le nombre de caractères à partir de la fin de `str`." + }, + "$substringBefore": { + "args": "str, chars", + "desc": "Renvoie la sous-chaîne avant la première occurrence de la séquence de caractères `chars` dans `str`. Si `str` ne contient pas `chars`, alors il renvoie `str`." + }, + "$substringAfter": { + "args": "str, chars", + "desc": "Renvoie la sous-chaîne après la première occurrence de la séquence de caractères `chars` dans `str`. Si `str` ne contient pas `chars`, alors il renvoie `str`." + }, + "$uppercase": { + "args": "str", + "desc": "Renvoie une chaîne avec tous les caractères de `str` convertis en majuscules." + }, + "$lowercase": { + "args": "str", + "desc": "Renvoie une chaîne avec tous les caractères de `str` convertis en minuscules." + }, + "$trim": { + "args": "str", + "desc": "Normalise et supprime tous les caractères d'espacement dans `str` en appliquant les étapes suivantes :\n\n - Toutes les tabulations, retours à la ligne et sauts de ligne sont remplacés par des espaces.\n- Les séquences contiguës d'espaces sont réduites à un seul espace.\n- Les espaces de fin et de début sont supprimés.\n\n Si `str` n'est pas spécifié (c'est-à-dire que cette fonction est invoquée sans argument), alors la valeur de contexte est utilisée comme valeur de `str`. Une erreur est renvoyée si `str` n'est pas une chaîne." + }, + "$contains": { + "args": "str, pattern", + "desc": "Renvoie `true` si `str` correspond à `pattern`, sinon il renvoie `false`. Si `str` n'est pas spécifié (c'est-à-dire que cette fonction est invoquée avec un argument), alors la valeur de contexte est utilisée comme valeur de `str`. Le paramètre `pattern` peut être une chaîne ou une expression régulière." + }, + "$split": { + "args": "str[, separator][, limit]", + "desc": "Divise le paramètre `str` en un tableau de sous-chaînes. C'est une erreur si `str` n'est pas une chaîne. Le paramètre facultatif `separator` spécifie les caractères à l'intérieur de `str` à propos desquels il doit être divisé en chaîne ou en expression régulière. Si `separator` n'est pas spécifié, la chaîne vide est supposée et `str` sera divisé en un tableau de caractères uniques. C'est une erreur si `separator` n'est pas une chaîne. Le paramètre facultatif `limit` est un nombre qui spécifie le nombre maximum de sous-chaînes à inclure dans le tableau résultant. Toutes les sous-chaînes supplémentaires sont ignorées. Si `limit` n'est pas spécifié, alors `str` est entièrement divisé sans limite à la taille du tableau résultant. C'est une erreur si `limit` n'est pas un nombre non négatif." + }, + "$join": { + "args": "array[, separator]", + "desc": "Joint un tableau de chaînes de composants en une seule chaîne concaténée, chaque chaîne de composants étant séparée par le paramètre facultatif `separator`. C'est une erreur si l'entrée `array` contient un élément qui n'est pas une chaîne. Si `séparateur` n'est pas spécifié, il est supposé être la chaîne vide, c'est-à-dire qu'il n'y a pas de `séparateur` entre les chaînes de composants. C'est une erreur si `separator` n'est pas une chaîne." + }, + "$match": { + "args": "str, pattern [, limit]", + "desc": "Applique la chaîne `str` à l'expression régulière `pattern` et renvoie un tableau d'objets, chaque objet contenant des informations sur chaque occurrence d'une correspondance dans `str`." + }, + "$replace": { + "args": "str, pattern, replacement [, limit]", + "desc": "Trouve les occurrences de `pattern` dans `str` et les remplace par `replacement`.\n\nLe paramètre facultatif `limit` est le nombre maximum de remplacements." + }, + "$now": { + "args": "$[picture [, timezone]]", + "desc": "Génère un horodatage au format compatible ISO 8601 et le renvoie sous forme de chaîne. Si les paramètres optionnels d'image et de fuseau horaire sont fournis, alors l'horodatage actuel est formaté comme décrit par la fonction `$fromMillis()`" + }, + "$base64encode": { + "args": "string", + "desc": "Convertit une chaîne ASCII en une représentation en base 64. Chaque caractère de la chaîne est traité comme un octet de données binaires. Cela nécessite que tous les caractères de la chaîne se trouvent dans la plage 0x00 à 0xFF, qui inclut tous les caractères des chaînes encodées en URI. Les caractères Unicode en dehors de cette plage ne sont pas pris en charge." + }, + "$base64decode": { + "args": "string", + "desc": "Convertit les octets encodés en base 64 en une chaîne, à l'aide d'une page de codes Unicode UTF-8." + }, + "$number": { + "args": "arg", + "desc": "Convertit le paramètre `arg` en un nombre en utilisant les règles de conversion suivantes :\n\n - Les nombres sont inchangés\n - Les chaînes qui contiennent une séquence de caractères représentant un nombre JSON légal sont converties en ce nombre\n - Toutes les autres valeurs provoquer l'envoi d'une erreur." + }, + "$abs": { + "args": "number", + "desc": "Renvoie la valeur absolue du paramètre `nombre`." + }, + "$floor": { + "args": "number", + "desc": "Renvoie la valeur de `number` arrondie à l'entier le plus proche inférieur ou égal à `number`." + }, + "$ceil": { + "args": "number", + "desc": "Renvoie la valeur de `number` arrondie à l'entier le plus proche supérieur ou égal à `number`." + }, + "$round": { + "args": "number [, precision]", + "desc": "Renvoie la valeur du paramètre `number` arrondie au nombre de décimales spécifié par le paramètre facultatif `precision`." + }, + "$power": { + "args": "base, exponent", + "desc": "Renvoie la valeur de `base` élevée à la puissance de `exponent`." + }, + "$sqrt": { + "args": "number", + "desc": "Renvoie la racine carrée de la valeur du paramètre `number`." + }, + "$random": { + "args": "", + "desc": "Renvoie un nombre pseudo-aléatoire supérieur ou égal à zéro et inférieur à un." + }, + "$millis": { + "args": "", + "desc": "Renvoie le nombre de millisecondes depuis l'époque Unix (1er janvier 1970 UTC) sous forme de nombre. Tous les appels de `$millis()` dans une évaluation d'une expression renverront toutes la même valeur." + }, + "$sum": { + "args": "array", + "desc": "Renvoie la somme arithmétique d'un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre." + }, + "$max": { + "args": "array", + "desc": "Renvoie le nombre maximal dans un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre." + }, + "$min": { + "args": "array", + "desc": "Renvoie le nombre minimum dans un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre." + }, + "$average": { + "args": "array", + "desc": "Renvoie la valeur moyenne d'un `tableau` de nombres. C'est une erreur si l'entrée `array` contient un élément qui n'est pas un nombre." + }, + "$boolean": { + "args": "arg", + "desc": "Transforme l'argument en booléen en utilisant les règles suivantes :\n\n - `Boolean` : inchangé\n - `string` : vide : `false`\n - `string` : non vide : `true`\n - `number` : `0` : `false`\n - `number` : non nul : `true`\n - `null` : `false`\n - `array` : vide : `false`\n - `array` : contient un membre qui convertit en `true` : `true`\n - `array` : tous les membres sont transformés en `false` : `false`\n - `object` : vide : `false`\n - `object` : non vide : `true`\n - `function` : `false`" + }, + "$not": { + "args": "arg", + "desc": "Renvoie un booléen résultat de la négation logique de l'argument" + }, + "$exists": { + "args": "arg", + "desc": "Renvoie la valeur booléenne `true` si l'expression `arg` est évaluée à une valeur, ou `false` si l'expression ne correspond à rien (par exemple, un chemin vers une référence de champ inexistante)." + }, + "$count": { + "args": "array", + "desc": "Renvoie le nombre d'éléments du tableau" + }, + "$append": { + "args": "array, array", + "desc": "Combine deux tableaux" + }, + "$sort": { + "args": "array [, function]", + "desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais triées dans l'ordre.\n\nSi un comparateur `function` est fourni, alors il doit s'agir d'une fonction qui prend deux paramètres :\n\n`function(left , droite)`\n\nCette fonction est invoquée par l'algorithme de tri pour comparer deux valeurs à gauche et à droite. Si la valeur de left doit être placée après la valeur de right dans l'ordre de tri souhaité, la fonction doit renvoyer un booléen `true` pour indiquer un échange. Sinon, il doit renvoyer `false`." + }, + "$reverse": { + "args": "array", + "desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais dans l'ordre inverse." + }, + "$shuffle": { + "args": "array", + "desc": "Renvoie un tableau contenant toutes les valeurs du paramètre `array`, mais mélangées dans un ordre aléatoire." + }, + "$zip": { + "args": "array, ...", + "desc": "Renvoie un tableau convolué (zippé) contenant des tableaux groupés de valeurs des arguments `array1`...`arrayN` d'index 0, 1, 2...." + }, + "$keys": { + "args": "object", + "desc": "Renvoie un tableau contenant les clés de l'objet. Si l'argument est un tableau d'objets, le tableau renvoyé contient une liste dédupliquée de toutes les clés de tous les objets." + }, + "$lookup": { + "args": "object, key", + "desc": "Renvoie la valeur associée à la clé dans l'objet. Si le premier argument est un tableau d'objets, tous les objets du tableau sont recherchés et les valeurs associées à toutes les occurrences de key sont renvoyées." + }, + "$spread": { + "args": "object", + "desc": "Divise un objet contenant des paires clé/valeur en un tableau d'objets, chacun ayant une seule paire clé/valeur de l'objet d'entrée. Si le paramètre est un tableau d'objets, alors le tableau résultant contient un objet pour chaque paire clé/valeur dans chaque objet du tableau fourni." + }, + "$merge": { + "args": "array<object>", + "desc": "Fusionne un tableau d'`objets` en un seul `objet` contenant toutes les paires clé/valeur de chacun des objets du tableau d'entrée. Si l'un des objets d'entrée contient la même clé, alors l'`objet` renvoyé contiendra la valeur du dernier dans le tableau. C'est une erreur si le tableau d'entrée contient un élément qui n'est pas un objet." + }, + "$sift": { + "args": "object, function", + "desc": "Renvoie un objet qui contient uniquement les paires clé/valeur du paramètre `object` qui satisfont le prédicat `function` transmis comme second paramètre.\n\nLa `function` qui est fournie comme second paramètre doit avoir la signature suivante :\n\n`fonction(valeur [, clé [, objet]])`" + }, + "$each": { + "args": "object, function", + "desc": "Renvoie un tableau contenant les valeurs renvoyées par la `fonction` lorsqu'elle est appliquée à chaque paire clé/valeur dans l'`objet`." + }, + "$map": { + "args": "array, function", + "desc": "Renvoie un tableau contenant les résultats de l'application du paramètre `function` à chaque valeur du paramètre `array`.\n\nLa `function` fournie comme second paramètre doit avoir la signature suivante :\n\n`function( valeur [, indice [, tableau]])`" + }, + "$filter": { + "args": "array, function", + "desc": "Renvoie un tableau contenant uniquement les valeurs du paramètre `array` qui satisfont le prédicat `function`.\n\nLa `function` fournie comme second paramètre doit avoir la signature suivante :\n\n`function(value [ , indice [, tableau]])`" + }, + "$reduce": { + "args": "array, function [, init]", + "desc": "Renvoie une valeur agrégée dérivée de l'application successive du paramètre `function` à chaque valeur de `array` en combinaison avec le résultat de l'application précédente de la fonction.\n\nLa fonction doit accepter deux arguments et se comporte comme un opérateur infixe entre chaque valeur dans le `tableau`. La signature de `function` doit être de la forme : `myfunc($accumulator, $value[, $index[, $array]])`\n\nLe paramètre facultatif `init` est utilisé comme valeur initiale dans l'agrégation ." + }, + "$flowContext": { + "args": "string[, string]", + "desc": "Récupère une propriété de contexte de flux.\n\nCeci est une fonction définie par Node-RED." + }, + "$globalContext": { + "args": "string[, string]", + "desc": "Récupère une propriété de contexte globale.\n\nCeci est une fonction définie par Node-RED." + }, + "$pad": { + "args": "string, width [, char]", + "desc": "Renvoie une copie de la `chaîne` avec un rembourrage supplémentaire, si nécessaire, de sorte que son nombre total de caractères corresponde au moins à la valeur absolue du paramètre `width`.\n\nSi `width` est un nombre positif, alors la chaîne est rembourré à droite; s'il est négatif, il est rempli vers la gauche.\n\nL'argument optionnel `char` spécifie le(s) caractère(s) de remplissage à utiliser. S'il n'est pas spécifié, la valeur par défaut est le caractère espace." + }, + "$fromMillis": { + "args": "number, [, picture [, timezone]]", + "desc": "Convertisser le « nombre » représentant les millisecondes depuis l'époque Unix (1er janvier 1970 UTC) en une représentation sous forme de chaîne formatée de l'horodatage tel que spécifié par la chaîne d'image.\n\nSi le paramètre facultatif « image » est omis, l'horodatage est formaté au format ISO 8601.\n\nSi la chaîne facultative `image` est fournie, l'horodatage est formaté selon la représentation spécifiée dans cette chaîne. Le comportement de cette fonction est cohérent avec la version à deux arguments de la fonction XPath/XQuery `format-dateTime` telle que définie dans la spécification XPath F&O 3.1. Le paramètre de chaîne d'image définit la façon dont l'horodatage est formaté et a la même syntaxe que `format-dateTime`.\n\nSi la chaîne facultative `timezone` est fournie, alors l'horodatage formaté sera dans ce fuseau horaire. La chaîne `timezone` doit être au format '±HHMM', où ± est le signe plus ou moins et HHMM est le décalage en heures et minutes par rapport à UTC. Décalage positif pour les fuseaux horaires à l'est de UTC, décalage négatif pour les fuseaux horaires à l'ouest de UTC." + }, + "$formatNumber": { + "args": "number, picture [, options]", + "desc": "Convertit le `number` en une chaîne et le formate en une représentation décimale comme spécifié par la chaîne `picture`.\n\n Le comportement de cette fonction est cohérent avec la fonction XPath/XQuery fn:format-number telle que définie dans le Spécification XPath F&O 3.1. Le paramètre de chaîne d'image définit la façon dont le nombre est formaté et a la même syntaxe que fn:format-number.\n\nLe troisième argument facultatif `options` est utilisé pour remplacer les caractères de formatage spécifiques aux paramètres régionaux par défaut, tels que le séparateur décimal. S'il est fourni, cet argument doit être un objet contenant des paires nom/valeur spécifiées dans la section de format décimal de la spécification XPath F&O 3.1." + }, + "$formatBase": { + "args": "number [, radix]", + "desc": "Convertit le `number` en une chaîne et le formate en un entier représenté dans la base numérique spécifiée par l'argument `radix`. Si `radix` n'est pas spécifié, la valeur par défaut est la base 10. `radix` peut être compris entre 2 et 36, sinon une erreur est renvoyée." + }, + "$toMillis": { + "args": "timestamp", + "desc": "Convertit une chaîne `timestamp` au format ISO 8601 en nombre de millisecondes depuis l'époque Unix (1er janvier 1970 UTC) sous forme de nombre. Une erreur est renvoyée si la chaîne n'est pas au format correct." + }, + "$env": { + "args": "arg", + "desc": "Renvoie la valeur d'une variable d'environnement.\n\nCeci est une fonction définie par Node-RED." + }, + "$eval": { + "args": "expr [, context]", + "desc": "Analyse et évalue la chaîne `expr` qui contient un JSON littéral ou une expression JSONata en utilisant le contexte actuel comme contexte d'évaluation." + }, + "$formatInteger": { + "args": "number, picture", + "desc": "Transforme le `nombre` en une chaîne et le formate en une représentation entière comme spécifié par la chaîne `image`. Le paramètre de chaîne d'image définit la façon dont le nombre est formaté et a la même syntaxe que `fn:format-integer` de la spécification XPath F&O 3.1." + }, + "$parseInteger": { + "args": "string, picture", + "desc": "Analyse le contenu du paramètre `string` en un entier (comme un nombre JSON) en utilisant le format spécifié par la chaîne `picture`. Le paramètre de chaîne `picture` a le même format que `$formatInteger`." + }, + "$error": { + "args": "[str]", + "desc": "Génère une erreur avec un message. Le `str` facultatif remplacera le message par défaut de la fonction `$error() évaluée`" + }, + "$assert": { + "args": "arg, str", + "desc": "Si `arg` est vrai, la fonction renvoie undefined. Si `arg` est faux, une exception est lancée avec `str` comme message de l'exception." + }, + "$single": { + "args": "array, function", + "desc": "Renvoie la seule et unique valeur du paramètre `array` qui satisfait le prédicat `function` (c'est-à-dire que la `function` renvoie la valeur booléenne `true` lorsqu'elle est transmise à la valeur). Lève une exception si le nombre de valeurs correspondantes n'est pas exactement un.\n\nLa fonction doit être fournie dans la signature suivante : `function(value [, index [, array]])` où value est chaque entrée du tableau, index est la position de cette valeur et le tableau entier est passé comme troisième argument" + }, + "$encodeUrlComponent": { + "args": "str", + "desc": "Encode un composant URL (Uniform Resource Locator) en remplaçant chaque instance de certains caractères par une, deux, trois ou quatre séquences d'échappement représentant l'encodage UTF-8 du caractère.\n\nExemple : `$encodeUrlComponent(\"?x =test\")` => `\"%3Fx%3Dtest\"`" + }, + "$encodeUrl": { + "args": "str", + "desc": "Encode une URL (Uniform Resource Locator) en remplaçant chaque instance de certains caractères par une, deux, trois ou quatre séquences d'échappement représentant l'encodage UTF-8 du caractère. \n\nExemple : `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0% B5%D0%BB%D0%BB%D1%8B\"`" + }, + "$decodeUrlComponent": { + "args": "str", + "desc": "Décode un composant URL (Uniform Resource Locator) précédemment créé par encodeUrlComponent. \n\nExemple : `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" + }, + "$decodeUrl": { + "args": "str", + "desc": "Décode une URL (Uniform Resource Locator) précédemment créée par encodeUrl. \n\nExemple : `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`" + }, + "$distinct": { + "args": "array", + "desc": "Renvoie un tableau avec les valeurs en double supprimées de `array`" + }, + "$type": { + "args": "value", + "desc": "Renvoie le type de `value` sous forme de chaîne. Si `value` n'est pas défini, cela renverra `undefined`" + }, + "$moment": { + "args": "[str]", + "desc": "Obtient un objet de date à l'aide de la bibliothèque Moment." + } +} diff --git a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json index 6022b5e81..1d08e9dd8 100644 --- a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json @@ -23,7 +23,11 @@ "position": "配置", "enable": "有効", "disable": "無効", - "upload": "アップロード" + "upload": "アップロード", + "lock": "固定", + "unlock": "固定を解除", + "locked": "固定済み", + "unlocked": "固定なし" }, "type": { "string": "文字列", @@ -53,8 +57,10 @@ "confirmDelete": "削除の確認", "delete": "本当に '__label__' を削除しますか?", "dropFlowHere": "ここにフローをドロップしてください", + "dropImageHere": "ここに画像ファイルをドロップしてください", "addFlow": "フローの追加", "addFlowToRight": "右側にフローを追加", + "closeFlow": "フローを閉じる", "hideFlow": "フローを非表示", "hideOtherFlows": "他のフローを非表示", "showAllFlows": "全てのフローを表示", @@ -68,7 +74,13 @@ "enabled": "有効", "disabled": "無効", "info": "詳細", - "selectNodes": "ノードをクリックして選択" + "selectNodes": "ノードをクリックして選択", + "enableFlow": "フローを有効化", + "disableFlow": "フローを無効化", + "lockFlow": "フローを固定", + "unlockFlow": "フローの固定を解除", + "moveToStart": "フローを先頭へ移動", + "moveToEnd": "フローを最後へ移動" }, "menu": { "label": { @@ -101,6 +113,7 @@ "displayStatus": "ノードのステータスを表示", "displayConfig": "設定ノード", "import": "読み込み", + "importExample": "フロー例を読み込み", "export": "書き出し", "search": "ノードを検索", "searchInput": "ノードを検索", @@ -498,6 +511,7 @@ "addRemoveNode": "ノードの選択、選択解除", "editSelected": "選択したノードを編集", "deleteSelected": "選択したノードや接続を削除", + "deleteReconnect": "削除と再接続", "importNode": "フローの読み込み", "exportNode": "フローの書き出し", "nudgeNode": "選択したノードを移動(移動量小)", @@ -684,9 +698,11 @@ "empty": "空", "globalConfig": "グローバル設定ノード", "triggerAction": "アクションを実行", + "find": "ワークスペース内を検索", + "copyItemUrl": "要素のURLをコピー", + "copyURL2Clipboard": "URLをクリップボードにコピーしました", "showFlow": "表示", - "hideFlow": "非表示", - "find": "ワークスペース内を検索" + "hideFlow": "非表示" }, "help": { "name": "ヘルプ", @@ -987,7 +1003,10 @@ "quote": "引用", "link": "リンク", "horizontal-rule": "区切り線", - "toggle-preview": "プレビュー表示切替え" + "toggle-preview": "プレビュー表示切替え", + "mermaid": { + "summary": "Mermaid図" + } }, "bufferEditor": { "title": "バッファエディタ", @@ -1182,8 +1201,10 @@ "languages": { "de": "ドイツ語", "en-US": "英語", + "fr": "フランス語", "ja": "日本語", "ko": "韓国語", + "pt-BR": "ポルトガル語", "ru": "ロシア語", "zh-CN": "中国語(簡体)", "zh-TW": "中国語(繁体)" @@ -1210,6 +1231,11 @@ "junction": "分岐点", "linkNodes": "Linkノード" }, + "env-var": { + "environment": "環境変数", + "header": "大域環境変数", + "revert": "破棄" + }, "action-list": { "toggle-show-tips": "ヒント表示切替", "show-about": "Node-REDの説明を表示", @@ -1294,6 +1320,7 @@ "distribute-selection-vertically": "選択を上下に整列", "wire-series-of-nodes": "ノードを一続きに接続", "wire-node-to-multiple": "ノードを複数に接続", + "wire-multiple-to-node": "複数からノードへ接続", "split-wire-with-link-nodes": "ワイヤーをlinkノードで分割", "generate-node-names": "ノード名を生成", "show-user-settings": "ユーザ設定を表示", @@ -1353,6 +1380,14 @@ "show-project-settings": "プロジェクト設定を表示", "show-version-control-tab": "バージョンコントロールタブを表示", "start-flows": "フローを開始", - "stop-flows": "フローを停止" + "stop-flows": "フローを停止", + "copy-item-url": "要素のURLをコピー", + "copy-item-edit-url": "要素の編集URLをコピー", + "move-flow-to-start": "フローを先頭に移動", + "move-flow-to-end": "フローを末尾に移動", + "show-global-env": "大域環境変数を表示", + "lock-flow": "フローを固定", + "unlock-flow": "フローの固定を解除", + "show-node-help": "ノードのヘルプを表示" } } diff --git a/packages/node_modules/@node-red/editor-client/locales/ko/editor.json b/packages/node_modules/@node-red/editor-client/locales/ko/editor.json index 9890dda9a..3c3160086 100644 --- a/packages/node_modules/@node-red/editor-client/locales/ko/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/ko/editor.json @@ -24,16 +24,29 @@ "delete": "정말로 '__label__' 을(를) 삭제하시겠습니까?", "dropFlowHere": "플로우를 이곳에 가져오세요", "addFlow": "플로우 추가", + "addFlowToRight": "오른쪽에 플로우 추가", + "hideFlow": "플로우 숨기기", + "hideOtherFlows": "다른 플로우 숨기기", + "showAllFlows": "모든 플로우 보기", + "hideAllFlows": "모든 플로우 숨기기", + "hiddenFlows": "__count__개의 숨겨진 플로우 보기", + "hiddenFlows_plural": "__count__개의 숨겨진 플로우 보기", + "showLastHiddenFlow": "마지막으로 숨겨진 플로우 보기", + "listFlows": "플로우 리스트", + "listSubflows": "서브 플로우 리스트", "status": "상태", "enabled": "사용가능", "disabled": "사용불가능", - "info": "상세내역" + "info": "상세내역", + "selectNodes": "선택할 노드 클릭" }, "menu": { "label": { "view": { "view": "창", "grid": "눈금선", + "storeZoom": "불러오기 시 확대/축소 복원", + "storePosition": "불러오기 시 스크롤 위치 복원", "showGrid": "눈금선 보이기", "snapGrid": "노드 배치 보조 켜기", "gridSize": "눈금선 크기", @@ -41,7 +54,9 @@ "defaultDir": "기본", "ltr": "왼쪽 -> 오른쪽", "rtl": "오른쪽 -> 왼쪽", - "auto": "자동배분" + "auto": "자동배분", + "language": "언어", + "browserDefault": "브라우저 기본값" }, "sidebar": { "show": "우측사이드바 보이기" @@ -49,18 +64,19 @@ "palette": { "show": "팔렛트 보이기" }, + "edit": "수정", "settings": "설정", "userSettings": "사용자 설정", "nodes": "노드설정", - "displayStatus": "노드상태 보이기", - "displayConfig": "설정노드 보기", + "displayStatus": "노드 상태 보이기", + "displayConfig": "설정 노드 보기", "import": "가져오기", "export": "내보내기", "search": "플로우 검색", "searchInput": "플로우 검색", - "subflows": "보조 플로우", - "createSubflow": "보조 플로우 생성", - "selectionToSubflow": "보조 플로우 선택", + "subflows": "서브 플로우", + "createSubflow": "서브 플로우 생성", + "selectionToSubflow": "서브 플로우 선택", "flows": "플로우", "add": "추가", "rename": "이름변경", @@ -71,19 +87,43 @@ "editPalette": "팔렛트 관리", "other": "기타", "showTips": "Tip 보기", + "showWelcomeTours": "새 버전에 대한 가이드 보기 표시", "help": "Node-RED 웹사이트", "projects": "프로젝트", "projects-new": "신규", "projects-open": "열기", "projects-settings": "프로젝트 설정", - "showNodeLabelDefault": "새로 추가된 노드의 라벨 보이기" + "showNodeLabelDefault": "새로 추가된 노드의 라벨 보이기", + "codeEditor": "Code Editor", + "groups": "그룹", + "groupSelection": "그룹 선택", + "ungroupSelection": "그룹 선택 해제", + "groupMergeSelection": "선택 항목 병합", + "groupRemoveSelection": "선택 그룹 제거", + "arrange": "배치", + "alignLeft": "왼쪽으로 정렬", + "alignCenter": "가운데 정렬", + "alignRight": "오른쪽으로 정렬", + "alignTop": "맨 위에 정렬", + "alignMiddle": "맨 위에 정렬", + "alignBottom": "맨 아래 정렬", + "distributeHorizontally": "수평으로 배치", + "distributeVertically": "수직으로 배치", + "moveToBack": "맨 뒤로 이동", + "moveToFront": "맨 앞으로 이동", + "moveBackwards": "뒤로 이동", + "moveForwards": "앞으로 이동" } }, "actions": { "toggle-navigator": "네비게이터 표시/비표시", "zoom-out": "축소하기", "zoom-reset": "확대/축소 초기화", - "zoom-in": "확대하기" + "zoom-in": "확대하기", + "search-flows": "플로우 찾기", + "search-prev": "이전", + "search-next": "다음", + "search-counter": "\"__term__\" __result__ of __count__" }, "user": { "loggedInAs": "__name__ 에 로그인됨", @@ -99,12 +139,17 @@ } }, "notification": { + "state": { + "flowsStopped": "플로우 중지됨", + "flowsStarted": "플로우 시작됨" + }, "warning": "경고: __message__", "warnings": { "undeployedChanges": "변경사항 배포가 취소되었습니다", "nodeActionDisabled": "노드 실행이 비활성화 되었습니다", "nodeActionDisabledSubflow": "보조 플로우에서 노드 실행이 비활성화 되었습니다", "missing-types": "

타입이 없는 노드로인해 플로우가 중지되었습니다

", + "missing-modules": "

누락된 모듈로 인해 플로우가 중지되었습니다.

", "safe-mode": "

[안전모드] 플로우가 정지되었습니다.

플로우의 수정과 배포가 가능합니다. 다시 배포버튼을 누르세요.

", "restartRequired": "업그레이드한 모듈을 유효화하기 위해 Node-RED를 재시작 합니다 ", "credentials_load_failed": "

인증정보 복호화에 실패하여 플로우가 멈췄습니다.

인증정보는 암호화 되어있습니다. 프로젝트의 암호화 키가 깨졌거나 정상적이지 않습니다.

", @@ -132,7 +177,12 @@ "updated": "'__project__'가 변경 되었습니다", "pull": "'__project__'를 다시 가져왔습니다", "revert": "'__project__'를 취소했습니다", - "merge-complete": "Git 병합이 완료되었습니다" + "merge-complete": "Git 병합이 완료되었습니다", + "setupCredentials": "자격 증명 설정", + "setupProjectFiles": "프로젝트 파일 설정", + "no": "취소", + "createDefault": "기본 프로젝트 파일 만들기", + "mergeConflict": "병합 충돌 표시" }, "label": { "manage-project-dep": "프로젝트 의존성 관리", @@ -152,10 +202,14 @@ "node_plural": "__count__ 개의 노드", "configNode": "__count__ 개의 설정 노드", "configNode_plural": "__count__ 개의 설정 노드", + "group": "__count__ 개의 그룹", + "group_plural": "__count__ 개의 그룹", "flow": "__count__ 개의 플로우", "flow_plural": "__count__ 개의 플로우", "subflow": "__count__ 개의 서브 플로우", "subflow_plural": "__count__ 개의 서브 플로우", + "replacedNodes": "__count__ 개의 교체된 노드", + "replacedNodes_plural": "__count__ 개의 교체된 노드", "pasteNodes": "여기에 노드를 붙여넣기 하세요", "selectFile": "불러올 파일을 선택하세요", "importNodes": "노드 불러오기", @@ -163,28 +217,46 @@ "download": "다운로드", "importUnrecognised": "알 수 없는 형식 :", "importUnrecognised_plural": "알 수 없는 형식 :", + "importDuplicate": "가져온 중복 노드:", + "importDuplicate_plural": "가져온 중복 노드:", "nodesExported": "클립보드에 노드 내보내기", "nodesImported": "불러오기 : ", - "nodeCopied": "__count__개의 노드가 복사 되었습니다", - "nodeCopied_plural": "__count__개의 노드가 복사 되었습니다", + "nodeCopied": "__count__개의 노드가 복사되었습니다", + "nodeCopied_plural": "__count__개의 노드가 복사되었습니다", + "groupCopied": "__count__ 개의 그룹이 복사되었습니다", + "groupCopied_plural": "__count__ 개의 그룹이 복사되었습니다", + "groupStyleCopied": "그룹 스타일이 복사되었습니다", "invalidFlow": "정상적지 않은 플로우 : __message__", + "recoveredNodes": "복구된 노드", + "recoveredNodesInfo": "이 플로우의 노드를 가져올 때 유효한 플로우 ID가 누락되었습니다. 해당 플로우에 추가되었으므로 복원하거나 삭제할 수 있습니다.", + "recoveredNodesNotification": "

유효하지 않은 플로우 ID를 가진 노드입니다.

'__flowName__' 라는 플로우에 추가되었습니다.

", "export": { "selected": "선택된 노드", "current": "현재 플로우", "all": "모든 플로우", "compact": "압축형식", "formatted": "서식유지", - "copy": "클립보드로 내보내기" + "copy": "클립보드로 내보내기", + "export": "라이브러리로 내보내기", + "exportAs": "내보내기", + "overwrite": "확인", + "exists": "

\"__file__\" 이미 존재합니다.

교체하시겠습니까?

" }, "import": { "import": "가져올 위치 : ", + "importSelected": "선택 항목 가져오기", + "importCopy": "사본 가져오기", + "viewNodes": "노드 보기...", "newFlow": "새로운 플로우", + "replace": "교체", "errors": { "notArray": "입력이 JSON 배열이 아닙니다", "itemNotObject": "입력이 올바른 플로우가 아닙니다 - __index__는 노드 오브젝트가 아닙니다", "missingId": "입력이 올바른 플로우가 아닙니다 - __index__의 'id' 속성이 없습니다", "missingType": "입력이 올바른 플로우가 아닙니다 - __index__의 'type' 속성이 없습니다" - } + }, + "conflictNotification1": "가져오는 노드 중 일부가 이미 작업 공간에 있습니다..", + "conflictNotification2": "가져올 노드와 기존 노드를 바꿀지 아니면 복사본을 가져올지 선택합니다." }, "copyMessagePath": "Path가 복사 되었습니다", "copyMessageValue": "Value가 복사 되었습니다", @@ -198,6 +270,10 @@ "modifiedFlowsDesc": "변경사항이 있는 플로우만 배포합니다", "modifiedNodes": "변경된 노드", "modifiedNodesDesc": "변경사항이 있는 노드만 배포합니다", + "startFlows": "시작", + "startFlowsDesc": "플로우를 시작합니다", + "stopFlows": "중지", + "stopFlowsDesc": "플로우를 중지합니다", "restartFlows": "플로우 재시작", "restartFlowsDesc": "현재 배포된 플로우를 재시작합니다", "successfulDeploy": "배포가 성공했습니다", @@ -266,6 +342,7 @@ "newVersionError": "New Version의 JSON 형식이 올바르지 않습니다 :" }, "subflow": { + "editSubflowInstance": "서브 플로우 인스턴스 수정: __name__", "editSubflow": "플로우 템플릿 수정 : __name__", "edit": "플로우 템플릿 수정", "subflowInstances": "서브 플로우 템플릿에 __count__개의 인스턴스가 있습니다", @@ -273,14 +350,39 @@ "editSubflowProperties": "속성 수정", "input": "입력:", "output": "출력:", + "status": "상태 노드", "deleteSubflow": "서브 플로우 삭제", + "confirmDelete": "서브 플로우를 삭제하시겠습니까?", "info": "상세내역", "category": "카테고리", + "module": "모듈", + "license": "라이선스", + "licenseNone": "없음", + "licenseOther": "Other", + "type": "노드", + "version": "버전", + "versionPlaceholder": "x.y.z", + "keys": "키워드", + "keysPlaceholder": "키워드(쉼표로 구분)를 입력해주세요", + "author": "이름", + "authorPlaceholder": "이름 또는 이메일을 입력해주세요", + "desc": "설명", + "env": { + "restore": "서브 플로우 기본값으로 복원", + "remove": "환경 변수 제거" + }, "errors": { "noNodesSelected": "서브 플로우를 생성할 수 없습니다 : 노드가 선택되지 않았습니다", "multipleInputsToSelection": "서브 플로우를 생성할 수 없습니다 : 복수의 입력이 선택되었습니다" } }, + "group": { + "editGroup": "그룹 수정: __name__", + "errors": { + "cannotCreateDiffGroups": "다른 그룹의 노드를 사용하여 그룹을 생성할 수 없습니다", + "cannotAddSubflowPorts": "그룹에 서브 플로우 포트를 추가할 수 없습니다" + } + }, "editor": { "configEdit": "수정", "configAdd": "추가", @@ -294,19 +396,20 @@ "addNewType": "__type__의 노드타입 추가 ...", "nodeProperties": "노드 속성", "label": "명칭", + "color": "Color", "portLabels": "포트 설정", "labelInputs": "입력", "labelOutputs": "출력", "settingIcon": "아이콘", + "default": "default", "noDefaultLabel": "없음", "defaultLabel": "기본 명칭", "searchIcons": "아이콘 조회", "useDefault": "기본설정 사용", "description": "상세 내역", - "show": "보이기", - "hide": "숨기기", "errors": { - "scopeChange": "범위를 변경하게 되면 다른 플로우의 노드가 사용이 불가능해 집니다." + "scopeChange": "범위를 변경하게 되면 다른 플로우의 노드가 사용이 불가능해 집니다.", + "invalidProperties": "유효하지 않은 속성:" } }, "keyboard": { @@ -319,10 +422,11 @@ "global": "글로벌", "workspace": "작업공간", "selectAll": "모든 노드 선택", - "selectAllConnected": "모든 연결된 노드 선택", + "selectNone": "노드 선택 취소", + "selectAllConnected": "연결된 모든 노드 선택", "addRemoveNode": "노드 추가/삭제", "editSelected": "선택된 노드 수정", - "deleteSelected": "선택된 노드나 링크를 삭제", + "deleteSelected": "선택된 노드 또는 링크 삭제", "importNode": "노드 불러오기", "exportNode": "노드 내보내기", "nudgeNode": "선택된 노드 이동 (1px)", @@ -332,9 +436,14 @@ "copyNode": "선택된 노드 복사", "cutNode": "선택된 노드 잘라내기", "pasteNode": "노드 붙여넣기", + "copyGroupStyle": "그룹 스타일 복사하기", + "pasteGroupStyle": "그룹 스타일 붙여넣기", "undoChange": "마지막 변경 되돌리기", + "redoChange": "다시 실행하기", "searchBox": "검색창 열기", - "managePalette": "팔렛트 관리" + "managePalette": "팔렛트 관리", + "actionList": "액션 목록", + "splitWireWithLinks": "링크 노드로 선택 항목 분할" }, "library": { "library": "라이브러리", @@ -342,13 +451,16 @@ "saveToLibrary": "라이브러리로 저장...", "typeLibrary": "__type__ 라이브러리", "unnamedType": "이름없는 __type__", + "exportedToLibrary": "노드를 라이브러리로 내보냈습니다.", "dialogSaveOverwrite": "__libraryType__이 __libraryName__으로 이미 등록되어있습니다. 덮어쓸까요?", "invalidFilename": "파일명이 올바르지 않습니다", "savedNodes": "저장된 노드", "savedType": "저장된 __type__", "saveFailed": "저장 실패 : __message__", + "newFolder": "새로운 폴더", "types": { - "examples": "예시" + "local": "로컬", + "examples": "예시" } }, "palette": { @@ -358,9 +470,13 @@ "addCategory": "추가 ...", "label": { "subflows": "서브 플로우", + "network": "네트워크", + "common": "일반", "input": "입력", "output": "출력", "function": "기능", + "sequence": "sequence", + "parser": "parser", "social": "소셜", "storage": "저장", "analysis": "분석", @@ -379,7 +495,8 @@ "nodeEnabled_plural": "노드가 활성화 되었습니다:", "nodeDisabled": "노드가 비활성화 되었습니다:", "nodeDisabled_plural": "노드가 비활성화 되었습니다:", - "nodeUpgraded": "__module__ 노드모듈이 __version__으로 업그레이드 되었습니다" + "nodeUpgraded": "__module__ 노드모듈이 __version__으로 업그레이드 되었습니다", + "unknownNodeRegistered": "Error loading node: " }, "editor": { "title": "팔렛트 관리", @@ -426,6 +543,8 @@ "sortAZ": "a-z", "sortRecent": "최근", "more": "+ __count__ 개 더 보기", + "upload": "Upload module tgz file", + "refresh": "모듈 목록 새로 고침", "errors": { "catalogLoadFailed": "

노드 카탈로그를 설치하지 못했습니다.

브라우저 콘솔로그를 참고하세요.

", "installFailed": "

설치 실패 : __module__

__message__

브라우저 콘솔로그를 참고하세요.

", @@ -466,6 +585,7 @@ "label": "정보", "node": "노드", "type": "타입", + "group": "Group", "module": "모듈", "id": "ID", "status": "상태", @@ -488,7 +608,23 @@ "nodeHelp": "노드 도움말", "none": "없음", "arrayItems": "__count__ 개의 항목", - "showTips": "설정에서 도움말을 열 수 있습니다. " + "showTips": "설정에서 도움말을 열 수 있습니다. ", + "outline": "개요", + "empty": "비우기", + "globalConfig": "전역 설정 노드", + "triggerAction": "트리거 작업", + "find": "작업 공간에서 찾기" + }, + "help": { + "name": "도움말", + "label": "도움말", + "search": "도움말 검색", + "nodeHelp": "노드 도움말 보기", + "showHelp": "도움말 보기", + "showInOutline": "요약 보기", + "showTopics": "토픽 보기", + "noHelp": "선택한 도움말 항목이 없습니다", + "changeLog": "릴리즈 정보" }, "config": { "name": "노드 설정", @@ -498,7 +634,9 @@ "subflows": "보조 플로우", "flows": "플로우", "filterAll": "전체", + "showAllConfigNodes": "모든 설정 노드 보기", "filterUnused": "미사용", + "showAllUnusedConfigNodes": "사용하지 않는 모든 설정 노드 보기", "filtered": "__count__ 개 숨김" }, "context": { @@ -509,8 +647,11 @@ "empty": "공백", "node": "노드", "flow": "플로우", - "global": "Global", - "deleteConfirm": "정말로 이 아이템을 지우시겠습니까?" + "global": "글로벌", + "deleteConfirm": "정말로 이 아이템을 지우시겠습니까?", + "autoRefresh": "선택 변경 시 새로 고침", + "refrsh": "새로고침", + "delete": "삭제" }, "palette": { "name": "팔레트 관리", @@ -525,6 +666,7 @@ "noSummaryAvailable": "요약 없음", "editDescription": "프로젝트 상세내역 수정", "editDependencies": "프로젝트 의존성 수정", + "noDescriptionAvailable": "설명 없음", "editReadme": "README.md 수정", "showProjectSettings": "프로젝트 설정 보이기", "projectSettings": { @@ -537,6 +679,10 @@ "files": "파일", "flow": "플로우", "credentials": "인증정보", + "package": "Package", + "packageCreate": "변경 내용이 저장될 때 파일이 생성됩니다", + "fileNotExist": "파일이 존재하지 않습니다", + "selectFile": "파일 선택", "invalidEncryptionKey": "잘못된 암호화 키", "encryptionEnabled": "암호화 활성화", "encryptionDisabled": "암호화 비활성화", @@ -674,15 +820,29 @@ "bin": "buffer", "date": "timestamp", "jsonata": "expression", - "env": "env variable" + "env": "env variable", + "cred": "credential" } }, "editableList": { - "add": "추가" + "add": "추가", + "addTitle": "add an item" }, "search": { + "history": "Search history", + "clear": "clear all", "empty": "결과 없음", - "addNode": "노드 추가 ..." + "addNode": "노드 추가 ...", + "options": { + "configNodes": "설정 노드", + "unusedConfigNodes": "사용되지 않는 설정 노드", + "invalidNodes": "잘못된 노드", + "uknownNodes": "알 수 없는 노드", + "unusedSubflows": "사용되지 않는 서브 플로우", + "hiddenFlows": "숨겨진 플로우", + "modifiedNodes": "수정된 노드 및 플로우", + "thisFlow": "현재 플로우" + } }, "expressionEditor": { "functions": "기능", @@ -703,15 +863,36 @@ "eval": "형식 오류 :\n __message__" } }, + "monaco": { + "setTheme": "테마 설정" + }, "jsEditor": { "title": "자바스크립트 에디터" }, + "textEditor": { + "title": "텍스트 에디터" + }, "jsonEditor": { "title": "JSON 에디터", - "format": "JSON 형식" + "format": "JSON 형식", + "rawMode": "JSON 수정", + "uiMode": "비주얼 편집기", + "rawMode-readonly": "JSON", + "uiMode-readonly": "비주얼", + "insertAbove": "위로 삽입", + "insertBelow": "아래로 삽입", + "addItem": "속성 추가", + "copyPath": "속성의 키값 복사", + "expandItems": "속성 펼치기", + "collapseItems": "속성 접기", + "duplicate": "복사", + "error": { + "invalidJSON": "비유효한 JSON: " + } }, "markdownEditor": { "title": "Markdown 에디터", + "expand": "Expand", "format": "Markdown 형식", "heading1": "제목 레벨1", "heading2": "제목 레벨2", @@ -741,6 +922,7 @@ "desc2": "이 기능을 건너뛰어도 상관없습니다. 언제든지 프로젝트 메뉴에서 첫번째 프로젝트를 만들 수 있습니다.", "create": "프로젝트 생성", "clone": "프로젝트 복제", + "openExistingProject": "기존 프로젝트 열기", "not-right-now": "나중에" }, "git-config": { @@ -858,7 +1040,8 @@ "not-git": "git 저장소가 아닙니다", "no-resource": "저장소아 없습니다", "cant-get-ssh-key-path": "에러! 선택한 SSH키 경로를 가져올 수 없습니다.", - "unexpected_error": "예기치 않은 에러" + "unexpected_error": "예기치 않은 에러", + "clearContext": "프로젝트 전환 시 context 삭제" }, "delete": { "confirm": "프로젝트를 정말 지우시겠습니까?" @@ -897,7 +1080,26 @@ }, "editor-tab": { "properties": "속성", + "envProperties": "환경 변수", + "module": "모듈 속성", "description": "상세 내역", - "appearance": "모양" + "appearance": "모양", + "preview": "UI 프리뷰", + "defaultValue": "기본값" + }, + "tourGuide": { + "takeATour": "둘러보기", + "start": "시작", + "next": "다음", + "welcomeTours": "버전 별 릴리즈 정보" + }, + "diagnostics": { + "title": "시스템 정보" + }, + "contextMenu": { + "insert": "삽입", + "node": "노드", + "junction": "접합", + "linkNodes": "링크 노드" } } diff --git a/packages/node_modules/@node-red/editor-client/locales/pt-BR/editor.json b/packages/node_modules/@node-red/editor-client/locales/pt-BR/editor.json new file mode 100644 index 000000000..6e20bc32d --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/pt-BR/editor.json @@ -0,0 +1,1208 @@ +{ + "common": { + "label": { + "name": "Nome", + "ok": "O.K.", + "done": "Feito", + "cancel": "Cancelar", + "delete": "Deletar", + "close": "Fechar", + "load": "Carregar", + "save": "Salvar", + "import": "Importar", + "export": "Exportar", + "back": "Voltar", + "next": "Próximo", + "clone": "Clonar", + "cont": "Continuar", + "style": "Estilo", + "line": "Contorno", + "fill": "Preenchido", + "label": "Etiqueta", + "color": "Cor", + "position": "Posição", + "enable": "Habilitado", + "disable": "Desabilitado", + "upload": "Subir" + }, + "type": { + "string": "cadeia de caracteres", + "number": "numero", + "boolean": "booliano", + "array": "matriz", + "buffer": "armazenamento temporário", + "object": "objeto", + "jsonString": "cadeia de caracteres JSON", + "undefined": "indefinido", + "null": "nulo" + } + }, + "event": { + "loadPlugins": "Carregando programas adicionais", + "loadPalette": "Carregando Paleta", + "loadNodeCatalogs": "Carregando Catálogo de Nós", + "loadNodes": "Carregando Nós __count__", + "loadFlows": "Carregando Fluxos", + "importFlows": "Adicionar Fluxos ao espaço de trabalho", + "importError": "

Erro ao adicionar fluxos

__message__

", + "loadingProject": "Carregando projeto" + }, + "workspace": { + "defaultName": "Fluxo __number__", + "editFlow": "Editar Fluxo: __name__", + "confirmDelete": "Confirmar exclusão", + "delete": "Tem certeza de que deseja excluir '__label__'?", + "dropFlowHere": "Solte o fluxo aqui", + "addFlow": "Adicionar fluxo", + "addFlowToRight": "Adicionar fluxo à direita", + "hideFlow": "Esconder fluxo", + "hideOtherFlows": "Esconder outros fluxos", + "showAllFlows": "Mostrar todos os fluxos", + "hideAllFlows": "Esconder todos os fluxos", + "hiddenFlows": "Listar __count__ fluxo escondido", + "hiddenFlows_plural": "Listar __count__ fluxos escondidos", + "showLastHiddenFlow": "Mostrar último fluxo escondido", + "listFlows": "Listar Fluxos", + "listSubflows": "Listar subfluxos", + "status": "Estado", + "enabled": "Habilitar", + "disabled": "Desabilitar", + "info": "Descrição", + "selectNodes": "Clique em nós para selecionar" + }, + "menu": { + "label": { + "view": { + "view": "Visão", + "grid": "Grade", + "storeZoom": "Restaura nível do zoom ao carregar", + "storePosition": "Restaura posição de rolamento ao carregar", + "showGrid": "Mostre as grades", + "snapGrid": "Ajustar à grade", + "gridSize": "Tamanho da grade", + "textDir": "Direção do texto", + "defaultDir": "Padrão", + "ltr": "Esquerta-para-direita", + "rtl": "Direita-para-esquerda", + "auto": "Contextual", + "language": "Linguagem", + "browserDefault": "Padrão do navegador" + }, + "sidebar": { + "show": "Mostrar barra lateral" + }, + "palette": { + "show": "Mostrar paleta" + }, + "edit": "Editar", + "settings": "Configurações", + "userSettings": "Configurações do usuário", + "nodes": "Nós", + "displayStatus": "Mostrar estados do nó", + "displayConfig": "Configuração dos nós", + "import": "Importar", + "export": "Exportar", + "search": "Procurar fluxos", + "searchInput": "procure seus fluxos", + "subflows": "subfluxos", + "createSubflow": "Criar Subfluxo", + "selectionToSubflow": "Seleção para subfluxo", + "flows": "Fluxos", + "add": "Adicionar", + "rename": "Renomear", + "delete": "Apagar", + "keyboardShortcuts": "Atalhos do teclado", + "login": "Ingressar", + "logout": "Sair", + "editPalette": "Gerenciar paleta", + "other": "Outro", + "showTips": "Mostre as dicas", + "showWelcomeTours": "Mostrar excursão guiada para novas versões", + "help": "sítio do Node-RED", + "projects": "Projetos", + "projects-new": "Novo", + "projects-open": "Abrir", + "projects-settings": "Configurações do projeto", + "showNodeLabelDefault": "Mostrar rótulo de nós recém-adicionados", + "codeEditor": "Editor de código", + "groups": "Grupos", + "groupSelection": "Agrupar seleção", + "ungroupSelection": "Desagrupar seleção", + "groupMergeSelection": "Mesclar seleção", + "groupRemoveSelection": "Remover do grupo", + "arrange": "Organizar", + "alignLeft": "Alinhar à esquerda", + "alignCenter": "Alinhar ao centro", + "alignRight": "Alinhar à direita", + "alignTop": "Alinhar ao início", + "alignMiddle": "Alinhar ao meio", + "alignBottom": "Alinhar ao final ", + "distributeHorizontally": "Distribuir horizontalmente", + "distributeVertically": "Distribuir verticalmente", + "moveToBack": "Mover para detrás", + "moveToFront": "Mover para a frente", + "moveBackwards": "Volta", + "moveForwards": "Avança" + } + }, + "actions": { + "toggle-navigator": "Alternar navegador", + "zoom-out": "Diminuir zoom ", + "zoom-reset": "Reiniciar zoom", + "zoom-in": "Aumentar zoom", + "search-flows": "Procura fluxos", + "search-prev": "Anterior", + "search-next": "Próximo", + "search-counter": "\"__term__\" __result__ of __count__" + }, + "user": { + "loggedInAs": "Acessado como __name__", + "username": "Nome do Usuário", + "password": "Senha", + "login": "Ingressar", + "loginFailed": "Falha ao ingressar", + "notAuthorized": "Não autorizado", + "errors": { + "settings": "Você deve ingressar para acessar as configurações", + "deploy": "Você deve ingressar para implementar mudanças", + "notAuthorized": "Você precisa ter ingressado para realizar esta ação" + } + }, + "notification": { + "state": { + "flowsStopped": "Fluxos parados", + "flowsStarted": "Fluxos iniciados" + }, + "warning": "Aviso: __message__", + "warnings": { + "undeployedChanges": "o nó tem mudanças não implementadas", + "nodeActionDisabled": "ações do nó desabilitadas", + "nodeActionDisabledSubflow": "ações do nó desabilitadas dentro do subfluxo", + "missing-types": "

Fluxos parados devido a tipos de nós ausentes.

", + "missing-modules": "

Os fluxos pararam devido à falta de módulos.

", + "safe-mode": "

Fluxos parados no modo de segurança.

Você pode modificar seus fluxos e implementar as mudanças para reiniciar.

", + "restartRequired": "O Node-RED deve ser reiniciado para habilitar os módulos atualizados", + "credentials_load_failed": "

Os fluxos pararam porque as credenciais não puderam ser descriptografadas.

O arquivo de credencial de fluxo está criptografado, mas a chave de criptografia do projeto está ausente ou é inválida.

", + "credentials_load_failed_reset": "

As credenciais não puderam ser descriptografadas

O arquivo de credencial do fluxo está criptografado, mas a chave de criptografia do projeto está ausente ou é inválida.

O arquivo de credencial de fluxo será redefinido na próxima implantação. Todas as credenciais de fluxo existentes serão apagadas.

", + "missing_flow_file": "

Arquivo de fluxo de projeto não encontrado.

O projeto não está configurado com um arquivo de fluxo.

", + "missing_package_file": "

Arquivo de pacote de projeto não encontrado.

O projeto está sem um arquivo package.json.

", + "project_empty": "

O projeto está vazio.

Você deseja criar um conjunto padrão de arquivos de projeto?
Caso contrário, você terá que adicionar arquivos manualmente ao projeto fora do editor.

", + "project_not_found": "

Projeto '__project__' não encontrado.

", + "git_merge_conflict": "

A mesclagem automática de alterações falhou.

Corrija os conflitos não mesclados e confirme os resultados.

" + }, + "error": "Erro: __message__", + "errors": { + "lostConnection": "Conexão perdida com o servidor, reconectando...", + "lostConnectionReconnect": "Conexão perdida com o servidor, reconectando em __time__s.", + "lostConnectionTry": "Tentar novamente", + "cannotAddSubflowToItself": "Não é possível adicionar subfluxo a si mesmo", + "cannotAddCircularReference": "Não é possível adicionar subfluxo - referência circular detectada", + "unsupportedVersion": "

Usando uma versão não suportada do Node.js

Você deve atualizar para a versão mais recente do Node.js LTS

", + "failedToAppendNode": "

Falha ao carregar '__module__'

__error__

" + }, + "project": { + "change-branch": "Mudar para ramo local'__project__'", + "merge-abort": "Mesclagem Git abortada", + "loaded": "Projeto '__project__' carregado", + "updated": "Projeto '__project__' atualizado", + "pull": "Projeto '__project__' recarregado", + "revert": "Projeto '__project__' revertido", + "merge-complete": "Mesclagem Git completa", + "setupCredentials": "Configurar credenciais", + "setupProjectFiles": "Configurar arquivos de projeto", + "no": "Não obrigado", + "createDefault": "Criar arquivos de projeto padrão", + "mergeConflict": "Mostrar conflitos de mesclagem" + }, + "label": { + "manage-project-dep": "Gerenciar dependências do projeto", + "setup-cred": "Configurar credenciais", + "setup-project": "Arquivos de projeto de instalação", + "create-default-package": "Criar arquivo de pacote padrão", + "no-thanks": "Não obrigado", + "create-default-project": "Crie arquivos de projeto padrão", + "show-merge-conflicts": "Mostrar conflitos de mesclagem", + "unknownNodesButton": "Procura por nós desconhecidos" + } + }, + "clipboard": { + "clipboard": "Área de transferência", + "nodes": "Nós", + "node": "__count__ nó", + "node_plural": "__count__ nós", + "configNode": "__count__ nó de configuração", + "configNode_plural": "__count__ nós de configuração", + "group": "__count__ grupo", + "group_plural": "__count__ grupos", + "flow": "__count__ fluxo", + "flow_plural": "__count__ fluxos", + "subflow": "__count__ subfluxo", + "subflow_plural": "__count__ subfluxos", + "replacedNodes": "__count__ nó substituído", + "replacedNodes_plural": "__count__ nós substituídos", + "pasteNodes": "Colar fluxo JSON ou", + "selectFile": "selecione um arquivo para importar", + "importNodes": "Importar nós", + "exportNodes": "Exportar nós", + "download": "Baixar", + "importUnrecognised": "Tipo não reconhecido importado:", + "importUnrecognised_plural": "Tipos não reconhecidos importados:", + "importDuplicate": "Nó duplicado importado:", + "importDuplicate_plural": "Nós duplicados importados:", + "nodesExported": "Nós exportados para a área de transferência", + "nodesImported": "Importado:", + "nodeCopied": "__count__ nó copiado", + "nodeCopied_plural": "__count__ nós copiados", + "groupCopied": "__count__ grupo copiado", + "groupCopied_plural": "__count__ grupos copiados", + "groupStyleCopied": "Estilo de grupo copiado", + "invalidFlow": "Fluxo inválido: __message__", + "recoveredNodes": "Nós recuperados", + "recoveredNodesInfo": "Os nós neste fluxo não tinham um ID de fluxo válido quando foram importados. Eles foram adicionados a este fluxo para que você possa restaurá-los ou excluí-los.", + "recoveredNodesNotification": "

Nós importados sem um ID de fluxo válido

Eles foram adicionados a um novo fluxo chamado '__flowName__'.

", + "export": { + "selected": "nós selecionados", + "current": "fluxo corrente", + "all": "todos os fluxos", + "compact": "compactar", + "formatted": "formatado", + "copy": "Copiar para área de transferência", + "export": "Exportar biblioteca", + "exportAs": "Exportar como", + "overwrite": "Substituir", + "exists": "

\"__file__\" já existe.

Deseja substituir?

" + }, + "import": { + "import": "Importar para", + "importSelected": "Importar selecionado", + "importCopy": "Importar cópia", + "viewNodes": "Ver nós...", + "newFlow": "novo fluxo", + "replace": "substituir", + "errors": { + "notArray": "A entrada não é uma matriz JSON", + "itemNotObject": "A entrada não é um fluxo válido - o item __index__ não é um objeto de nó", + "missingId": "A entrada não é um fluxo válido - item __index__ faltando propriedade 'id'", + "missingType": "A entrada não é um fluxo válido - item __index__ faltando propriedade 'type'" + }, + "conflictNotification1": "Alguns dos nós que você está importando já existem em sua área de trabalho.", + "conflictNotification2": "Selecione quais nós importar e se deseja substituir os nós existentes ou importar uma cópia deles." + }, + "copyMessagePath": "Caminho copiado", + "copyMessageValue": "Valor copiado", + "copyMessageValue_truncated": "Valor truncado copiado" + }, + "deploy": { + "deploy": "implementar", + "full": "Cheio", + "fullDesc": "Implementar tudo no espaço de trabalho", + "modifiedFlows": "Fluxos Modificados", + "modifiedFlowsDesc": "Implantar apenas fluxos que contêm nós alterados", + "modifiedNodes": "Nós Modificados", + "modifiedNodesDesc": "Implantar apenas nós que mudaram", + "startFlows": "Iniciar", + "startFlowsDesc": "Iniciar Fluxos", + "stopFlows": "Parar", + "stopFlowsDesc": "Parar Fluxos", + "restartFlows": "Reiniciar Fluxos", + "restartFlowsDesc": "Reinicia os fluxos atuais implantados", + "successfulDeploy": "Implementado com sucesso", + "successfulRestart": "Fluxos reiniciados com sucesso", + "deployFailed": "Implementação falhou: __message__", + "unusedConfigNodes": "Você tem alguns nós de configuração não utilizados.", + "unusedConfigNodesButton": "Procurar por nós de configuração não utilizados", + "unknownNodesButton": "Procurar por nós desconhecidos", + "invalidNodesButton": "Procurar por nós inválidos", + "errors": { + "noResponse": "sem resposta do servidor" + }, + "confirm": { + "button": { + "ignore": "Ignorar", + "confirm": "Confirmar implantação", + "review": "Rever alterações", + "cancel": "Cancelar", + "merge": "Mesclar", + "overwrite": "Ignorar e implantar" + }, + "undeployedChanges": "Você tem alterações não implementadas. \n\n Se sair desta página, essas alterações serão perdidas.", + "improperlyConfigured": "O espaço de trabalho contém alguns nós que não estão configurados corretamente:", + "unknown": "O espaço de trabalho contém alguns tipos de nós desconhecidos:", + "confirm": "Tem certeza que deseja implantar?", + "doNotWarn": "não avisar sobre isso de novo ", + "conflict": "O servidor está executando um conjunto de fluxos mais recente.", + "backgroundUpdate": "Os fluxos no servidor foram atualizados.", + "conflictChecking": "Verificando se as alterações podem ser mescladas automaticamente", + "conflictAutoMerge": "As alterações não incluem conflitos e podem ser mescladas automaticamente.", + "conflictManualMerge": "As mudanças incluem conflitos que devem ser resolvidos antes de serem implantados.", + "plusNMore": "+ __count__ mais" + } + }, + "eventLog": { + "title": "Registro de Eventos", + "view": "Registro de visão" + }, + "diff": { + "unresolvedCount": "__count__ conflito não resolvido ", + "unresolvedCount_plural": "__count__ conflitos não resolvidos ", + "globalNodes": "Nós globais ", + "flowProperties": "Propriedades de fluxo ", + "type": { + "added": "adicionado", + "changed": "alterado", + "unchanged": "inalterado ", + "deleted": "Excluído", + "flowDeleted": "fluxo excluído ", + "flowAdded": "fluxo adicionado ", + "movedTo": "movido para __id__ ", + "movedFrom": "movido de __id__" + }, + "nodeCount": "__count__ nó", + "nodeCount_plural": "__count__ nós", + "local": "Mudanças locais ", + "remote": "Mudanças remotas ", + "reviewChanges": "Rever alterações ", + "noBinaryFileShowed": "Não é possível mostrar o conteúdo do arquivo binário ", + "viewCommitDiff": "Ver alterações de confirmação ", + "compareChanges": "Compare as alterações ", + "saveConflict": "Salvar resolução de conflito ", + "conflictHeader": "__resolved__ of __unresolved__ conflitos resolvidos", + "commonVersionError": "A versão comum não contém JSON válido: ", + "oldVersionError": "A versão antiga não contém JSON válido: ", + "newVersionError": "A nova versão não contém JSON válido: " + }, + "subflow": { + "editSubflowInstance": "Editar instância de subfluxo: __name__", + "editSubflow": "Editar modelo de subfluxo: __name__", + "edit": "Editar modelo de subfluxo", + "subflowInstances": "Existe uma instância __count__ deste modelo de subfluxo", + "subflowInstances_plural": "Existem __count__ instâncias deste modelo de subfluxo", + "editSubflowProperties": "editar propriedades", + "input": "entradas:", + "output": "saídas:", + "status": "estados do nó", + "deleteSubflow": "excluir subfluxo", + "confirmDelete": "Tem certeza de que deseja excluir este subfluxo?", + "info": "Descrição", + "category": "Categoria", + "module": "Módulo", + "license": "Licença", + "licenseNone": "Nenhum", + "licenseOther": "Outro", + "type": "Tipo de nó", + "version": "Versão", + "versionPlaceholder": "x.y.z", + "keys": "Palavras-chave", + "keysPlaceholder": "Palavras-chave separadas por vírgulas", + "author": "Autor", + "authorPlaceholder": "Seu nome ", + "desc": "Descrição", + "env": { + "restore": "Restaurar para o subfluxo padrão", + "remove": "Remover variável de ambiente" + }, + "errors": { + "noNodesSelected": "Não é possível criar subfluxo : nenhum nó selecionado", + "multipleInputsToSelection": "Não é possível criar subfluxo : várias entradas para seleção" + } + }, + "group": { + "editGroup": "Editar grupo: __name__", + "errors": { + "cannotCreateDiffGroups": "Não é possível criar grupo usando nós de grupos diferentes", + "cannotAddSubflowPorts": "Não é possível adicionar portas de subfluxo a um grupo" + } + }, + "editor": { + "configEdit": "Editar", + "configAdd": "Adicionar", + "configUpdate": "Atualizar", + "configDelete": "Excluir", + "nodesUse": "__count__ o nó usa esta configuração", + "nodesUse_plural": "__count__ os nós usam esta configuração", + "addNewConfig": "Adicionar novo __type__ configuração de nó", + "editNode": "Editar __type__ nó", + "editConfig": "Editar __type__ configuração de nó", + "addNewType": "Adicionar novo __type__...", + "nodeProperties": "propriedades do nó", + "label": "Etiqueta", + "color": "Cor", + "portLabels": "Rótulo da porta", + "labelInputs": "Entradas", + "labelOutputs": "Saídas", + "settingIcon": "Ícone", + "default": "padrão", + "noDefaultLabel": "nenhum", + "defaultLabel": "usar etiqueta padrão", + "searchIcons": "Procurar ícones", + "useDefault": "usar padrão", + "description": "Descrição", + "show": "Mostrar", + "hide": "Esconder", + "locale": "Selecione o idioma da interface", + "icon": "Ícone", + "inputType": "Tipo de entrada", + "selectType": "selecione os tipos...", + "loadCredentials": "Carregando credenciais de nó", + "inputs": { + "input": "entrada", + "select": "seleção", + "checkbox": "caixa de seleção", + "spinner": "caixa de mostruário giratório", + "none": "nenhum", + "hidden": "ocultar propriedade" + }, + "types": { + "str": "cadeia de caracteres", + "num": "numero", + "bool": "booliano", + "json": "JSON", + "bin": "armazenamento temporário", + "env": "variável de ambiente", + "cred": "credencial" + }, + "menu": { + "input": "entrada", + "select": "seleção", + "checkbox": "caixa de seleção", + "spinner": "roleta", + "hidden": "Somente etiqueta" + }, + "select": { + "label": "Etiqueta", + "value": "Valor" + }, + "spinner": { + "min": "Mínimo", + "max": "Máximo" + }, + "errors": { + "scopeChange": "Alterar o escopo o tornará indisponível para nós em outros fluxos que o utilizam", + "invalidProperties": "Propriedades inválidas:", + "credentialLoadFailed": "Falha ao carregar credenciais de nó" + } + }, + "keyboard": { + "title": "Atalhos do teclado", + "keyboard": "Teclado", + "filterActions": "ações de filtro", + "shortcut": "atalho", + "scope": "escopo", + "unassigned": "Não atribuído", + "global": "global", + "workspace": "área de trabalho", + "selectAll": "Selecionar todos", + "selectNone": "Selecionar nenhum", + "selectAllConnected": "Selecione todos os nós conectados", + "addRemoveNode": "Adicionar / remover nó da seleção", + "editSelected": "Editar nó selecionado", + "deleteSelected": "Excluir nós selecionados ou link", + "importNode": "Importar nós", + "exportNode": "Exportar nós", + "nudgeNode": "Mover nós selecionados (1px)", + "moveNode": "Mover nós selecionados (20px)", + "toggleSidebar": "Alternar barra lateral", + "togglePalette": "Alternar paleta", + "copyNode": "Copiar nós selecionados", + "cutNode": "Cortar nós selecionados", + "pasteNode": "Colar nós", + "copyGroupStyle": "Copiar estilo de grupo", + "pasteGroupStyle": "Colar estilo de grupo", + "undoChange": "Desfazer", + "redoChange": "Refazer", + "searchBox": "Abrir caixa de pesquisa", + "managePalette": "Gerenciar paleta", + "actionList": "Lista de Ação", + "splitWireWithLinks": "Separa a seleção com os nós de ligação" + }, + "library": { + "library": "Biblioteca", + "openLibrary": "Biblioteca aberta ...", + "saveToLibrary": "Salvar na biblioteca ...", + "typeLibrary": "__type__ biblioteca", + "unnamedType": "Sem nome __tipo__", + "exportedToLibrary": "Nós exportados para a biblioteca", + "dialogSaveOverwrite": "Já existe um __libraryType__ chamado __libraryName__. Substituir?", + "invalidFilename": "Nome de arquivo inválido", + "savedNodes": "Nós salvos", + "savedType": "Salvo __tipo__", + "saveFailed": "Falha ao salvar: __message__", + "newFolder": "Nova pasta", + "types": { + "local": "Local", + "examples": "Exemplos" + } + }, + "palette": { + "noInfo": "sem informação disponível", + "filter": "filtrar nós", + "search": "procurar módulos", + "addCategory": "Adicionar novo...", + "label": { + "subflows": "subfluxos", + "network": "rede", + "common": "comum", + "input": "entrada", + "output": "saída", + "function": "função", + "sequence": "sequencia", + "parser": "analisador sintático", + "social": "social", + "storage": "armazenar", + "analysis": "análise", + "advanced": "avançado" + }, + "actions": { + "collapse-all": "Recolher todas as categorias", + "expand-all": "Expandir todas as categorias" + }, + "event": { + "nodeAdded": "Nó adicionado à paleta:", + "nodeAdded_plural": "Nós adicionados à paleta:", + "nodeRemoved": "Nó removido da paleta:", + "nodeRemoved_plural": "Nós removidos da paleta:", + "nodeEnabled": "Nó habilitado:", + "nodeEnabled_plural": "Nós habilitados:", + "nodeDisabled": "Nó desativado:", + "nodeDisabled_plural": "Nós desativados:", + "nodeUpgraded": "Módulo de nó __module__ atualizado para a versão __version__", + "unknownNodeRegistered": "Erro carregando o nó: " + }, + "editor": { + "title": "Gerenciar paleta", + "palette": "Paleta", + "times": { + "seconds": "segundos atrás", + "minutes": "minutos atrás", + "minutesV": "__count__ minutos atrás", + "hoursV": "__count__ hora atrás", + "hoursV_plural": "__count__ horas atrás", + "daysV": "__count__ dia atrás", + "daysV_plural": "__count__ dias atrás", + "weeksV": "__count__ semana atrás", + "weeksV_plural": "__count__ semanas atrás", + "monthsV": "__count__ mês atrás", + "monthsV_plural": "__count__ meses atrás", + "yearsV": "__count__ ano atrás", + "yearsV_plural": "__count__ anos atrás", + "yearMonthsV": "__y__ ano, __count__ mês atrás", + "yearMonthsV_plural": "__y__ ano, __count__ meses atrás", + "yearsMonthsV": "__y__ anos, __count__ mês atrás", + "yearsMonthsV_plural": "__y__ anos, __count__ meses atrás" + }, + "nodeCount": "__label__ node", + "nodeCount_plural": "__label__ nodes", + "moduleCount": "módulo __count__ disponível", + "moduleCount_plural": "__count__ módulos disponíveis", + "inuse": "em uso", + "enableall": "habilitar todos", + "disableall": "desabilitar todos", + "enable": "habilitar", + "disable": "desabilitar", + "remove": "remover", + "update": "atualizar para __version__", + "updated": "atualizado", + "install": "instalar", + "installed": "instalado", + "conflict": "conflito", + "conflictTip": "

Este módulo não pode ser instalado porque inclui um
tipo de nó que já foi instalado

Conflitos com __module__

" , + "loading": "Carregando catálogos ...", + "tab-nodes": "Nós", + "tab-install": "Instalar", + "sort": "ordenar:", + "sortAZ": "a-z", + "sortRecent": "recente", + "more": "+ __count__ mais", + "upload": "Carregar arquivo tgz do módulo", + "refresh": "Atualizar lista de módulos", + "errors": { + "catalogLoadFailed": "

Falha ao carregar o catálogo de nós.

Verifique o console do navegador para obter mais informações

", + "installFailed": "

Falha ao instalar: __module__

__message__

Verifique o log para obter mais informações

", + "removeFailed": "

Falha ao remover: __module__

__message__

Verifique o log para obter mais informações

", + "updateFailed": "

Falha ao atualizar: __module__

__message__

Verifique o log para obter mais informações

", + "enableFailed": "

Falha ao ativar: __module__

__message__

Verifique o log para obter mais informações

", + "disableFailed": "

Falha ao desativar: __module__

__message__

Verifique o log para obter mais informações

" + }, + "confirm": { + "install": { + "body": "

Instalando '__module__'

Antes de instalar, leia a documentação do nó. Alguns nós têm dependências que não podem ser resolvidas automaticamente e podem exigir a reinicialização do Node-RED.

", + "title": "Instalar nós" + }, + "remove": { + "body": "

Remover '__module__'

Remover o nó irá desinstalá-lo do Node-RED. O nó pode continuar a usar recursos até que o Node-RED seja reiniciado.

", + "title": "Remover nós" + }, + "update": { + "body": "

Atualizar '__module__'

Atualizar o nó exigirá a reinicialização do Node-RED para concluir a atualização. Isso deve ser feito manualmente.

", + "title": "Atualizar nós" + }, + "cannotUpdate": { + "body": "Uma atualização para este nó está disponível, mas não está instalada em um local que o gerenciador de paletas possa atualizar.

Consulte a documentação para saber como atualizar este nó." + }, + "button": { + "review": "Abrir informação do nó", + "install": "Instalar", + "remove": "Remover", + "update": "Atualizar" + } + } + } + }, + "sidebar": { + "info": { + "name": "Informação", + "tabName": "Nome", + "label": "informações", + "node": "Nó", + "type": "Tipo", + "group": "Grupo", + "module": "Módulo", + "id": "ID", + "status": "Estado", + "enabled": "Habilitado", + "disabled": "Desabilitado", + "subflow": "Subfluxo", + "instances": "Instâncias", + "properties": "Propriedades", + "info": "Informação", + "desc": "Descrição", + "blank": "branco", + "null": "nulo", + "showMore": "mostrar mais", + "showLess": "mostrar menos", + "flow": "Fluxo", + "selection": "Seleção", + "nodes": "__count__ nós", + "flowDesc": "Descrição do Fluxo", + "subflowDesc": "Descrição do Subfluxo", + "nodeHelp": "Ajuda do Nó", + "none": "Nenhum", + "arrayItems": "__count__ items", + "showTips": "Você pode abrir as dicas a partir do painel de configurações", + "outline": "Contorno", + "empty": "vazio", + "globalConfig": "Nós de configuração global", + "triggerAction": "Ação de gatilho", + "find": "Encontre no espaço de trabalho" + }, + "help": { + "name": "Ajuda", + "label": "ajuda", + "search": "Ajuda sobre a procura", + "nodeHelp": "Ajuda sobre o nó", + "showHelp": "Mostrar ajuda", + "showInOutline": "Mostrar no contorno", + "showTopics": "Mostrar tópicos", + "noHelp": "Nenhum tópico de ajuda selecionado", + "changeLog": "Log de alteração" + }, + "config": { + "name": "Configuração dos nós", + "label": "configuração", + "global": "Em todos os fluxos", + "none": "nenhum", + "subflows": "subfluxos", + "flows": "fluxos", + "filterAll": "todos", + "showAllConfigNodes": "Ver todas as configurações dos nós", + "filterUnused": "não utilizados", + "showAllUnusedConfigNodes": "Mostrar todas os nós de configuração não usados", + "filtered": "__count__ hidden" + }, + "context": { + "name": "Contexto dos Dados", + "label": "contexto", + "none": "nenhum selecionado", + "refresh": "atualize para carregar", + "empty": "vazio", + "node": "Nó", + "flow": "Fluxo", + "global": "Global", + "deleteConfirm": "Você tem certeza que deseja remover este item?", + "autoRefresh": "Atualizar na mudança de seleção", + "refrsh": "Atualizar", + "delete": "Remover" + }, + "palette": { + "name": "Gerenciamento de paleta", + "label": "paleta" + }, + "project": { + "label": "projeto", + "name": "Projeto", + "description": "Descrição", + "dependencies": "Dependências", + "settings": "Configurações", + "noSummaryAvailable": "Nenhum resumo disponível", + "editDescription": "Editar a descrição do projeto", + "editDependencies": "Editar dependências do projeto", + "noDescriptionAvailable": "Descrição não disponível", + "editReadme": "Editar README.md", + "showProjectSettings": "Mostrar configurações do projeto", + "projectSettings": { + "title": "Configurações do Projeto", + "edit": "editar", + "none": "Nenhum", + "install": "instalar", + "removeFromProject": "remover do projeto", + "addToProject": "adicionar ao projeto", + "files": "Arquivos", + "flow": "Fluxos", + "credentials": "Credenciais", + "package": "Pacote", + "packageCreate": "O arquivo será criado quando as alterações forem salvas", + "fileNotExist": "Arquivo não existe", + "selectFile": "Selecione o arquivo", + "invalidEncryptionKey": "Chave de criptografia inválida", + "encryptionEnabled": "Criptografia habilitada", + "encryptionDisabled": "Criptografia desabilitada", + "setTheEncryptionKey": "Defina a chave de criptografia", + "resetTheEncryptionKey": "Redefina a chave de criptografia", + "changeTheEncryptionKey": "Troque a chave de criptografia", + "currentKey": "Chave atual", + "newKey": "Nova chave", + "credentialsAlert": "Isso excluirá todas as credenciais existentes", + "versionControl": "Controle de versão", + "branches": "Ramos", + "noBranches": "Sem ramos", + "deleteConfirm": "Tem certeza de que deseja excluir o ramo local '__name__'? Isto não pode ser desfeito.", + "unmergedConfirm": "O ramo local '__name__' tem alterações não mescladas que serão perdidas. Tem certeza que deseja excluir?", + "deleteUnmergedBranch": "Excluir ramo não mesclado", + "gitRemotes": "Git remoto", + "addRemote": "adicionar remoto", + "addRemote2": "Adicionar remoto", + "remoteName": "Nome do remoto", + "nameRule": "Deve conter apenas A-Z 0-9 _ -", + "url": "URL", + "urlRule": "https://, ssh:// ou file://", + "urlRule2": "Não inclua o nome de usuário / senha na URL", + "noRemotes": "Sem remotos", + "deleteRemoteConfrim": "Tem certeza de que deseja excluir o remoto '__name__'?", + "deleteRemote": "Excluir remoto" + }, + "userSettings": { + "committerDetail": "Detalhes do Cometedor", + "committerTip": "Deixe em branco para usar o padrão do sistema", + "userName": "Nome de usuário", + "email": "Email", + "workflow": "Fluxo de trabalho", + "workfowTip": "Escolha seu fluxo de trabalho git preferido", + "workflowManual": "Manual", + "workflowManualTip": "Todas as alterações devem ser confirmadas manualmente na barra lateral 'histórico'", + "workflowAuto": "Automático", + "workflowAutoTip": "As alterações são confirmadas automaticamente a cada implantação", + "sshKeys": "Chaves SSH", + "sshKeysTip": "Permite que você crie conexões seguras para repositórios git remotos.", + "add": "adicionar chave", + "addSshKey": "Adicionar chave SSH", + "addSshKeyTip": "Gerar um novo par de chaves públicas / privadas", + "name": "Nome", + "nameRule": "Deve conter apenas A-Z 0-9 _ -", + "passphrase": "Frase de passe", + "passphraseShort": "Frase de passe muito curta", + "optional": "Opcional", + "cancel": "Cancelar", + "generate": "Gerar chave", + "noSshKeys": "Sem chaves SSH", + "copyPublicKey": "Copiar chave pública para a área de transferência", + "delete": "Excluir chave key", + "gitConfig": "Configuração do Git", + "deleteConfirm": "Tem certeza de que deseja excluir a chave SSH __name__? Isso não pode ser desfeito." + }, + "versionControl": { + "unstagedChanges": "Alterações não realizadas", + "stagedChanges": "Alterações realizadas", + "unstageChange": "Desfazer alteração", + "stageChange": "Realizar alteração", + "unstageAllChange": "Desfazer todas as alterações", + "stageAllChange": "Realizar todas as alterações", + "commitChanges": "Cometer alterações", + "resolveConflicts": "Resolver conflitos", + "head": "CABEÇA", + "staged": "Alterado", + "unstaged": "Desfeita Alteração", + "local": "Local", + "remote": "Remoto", + "revert": "Tem certeza de que deseja reverter as alterações para '__file__'? Essa ação não poderá ser desfeita.", + "revertChanges": "Reverter alterações", + "localChanges": "Mudanças locais", + "none": "Nenhum", + "conflictResolve": "Todos os conflitos resolvidos. Cometa as alterações para concluir a mesclagem.", + "localFiles": "Arquivos locais", + "all": "todos", + "unmergedChanges": "Alterações não mescladas", + "abortMerge": "interromper mesclagem", + "commit": "cometer", + "changeToCommit": "Alterações para cometer", + "commitPlaceholder": "Digite sua mensagem de cometimento", + "cancelCapital": "Cancelar", + "commitCapital": "Cometer", + "commitHistory": "Histórico do cometimento", + "branch": "Ramo:", + "moreCommits": "mais cometimentos", + "changeLocalBranch": "Alterar ramo local", + "createBranchPlaceholder": "Encontrar ou criar um ramo", + "upstream": "subir do cliente ao servidor", + "localOverwrite": "Você tem alterações locais que seriam sobrescritas alterando o ramo. Você deve cometer ou desfazer essas alterações primeiro.", + "manageRemoteBranch": "Gerenciar ramo remoto", + "unableToAccess": "Incapaz de acessar o repositório remoto", + "retry": "Tentar novamente", + "setUpstreamBranch": "Definir como ramo de subida do cliente para o servidor", + "createRemoteBranchPlaceholder": "Encontrar ou criar um ramo remoto", + "trackedUpstreamBranch": "O ramo criado será definido como o ramo de subida do cliente para o servidor rastreado.", + "selectUpstreamBranch": "O ramo será criado. Selecione abaixo para defini-lo como o ramo de subida do cliente para o servidor rastreado.", + "pushFailed": "falha ao empurrar porque o remoto tem cometimentos mais recentes. Puxe e mescle primeiro, depois empurre novamente.", + "push": "empurrar", + "pull": "puxar", + "unablePull": "

Incapaz de puxar as alterações remotas; suas alterações locais não realizadas seriam sobrescritas.

Cometa suas alterações e tente novamente.

", + "showUnstagedChanges": "Mostrar alterações não realizadas", + "connectionFailed": "Não foi possível conectar ao repositório remoto:", + "pullUnrelatedHistory": "

O remoto tem um histórico não relacionado de cometimentos.

Tem certeza que deseja puxar as mudanças para o seu repositório local?

", + "pullChanges": "Puxar modificações", + "history": "histórico", + "projectHistory": "Histórico do Projeto", + "daysAgo": "__count__ dia atrás", + "daysAgo_plural": "__count__ dias atrás", + "hoursAgo": "__count__ hora atrás", + "hoursAgo_plural": "__count__ horas atrás", + "minsAgo": "__count__ min ago", + "minsAgo_plural": "__count__ minutos atrás", + "secondsAgo": "Segundos atrás", + "notTracking": "Seu ramo local não está atualmente rastreando um ramo remoto.", + "statusUnmergedChanged": "Seu repositório tem alterações não mescladas. Você precisa corrigir os conflitos e enviar o resultado.", + "repositoryUpToDate": "Seu repositório está atualizado.", + "commitsAhead": "Seu repositório está __count__ cometimento à frente do remoto. Você pode empurrar este cometimento agora.", + "commitsAhead_plural": "Seu repositório está __count__ cometimentos à frente do remoto. Você pode empurrar estes cometimentos agora.", + "commitsBehind": "Seu repositório está __count__ cometimento atrás do remoto. Você pode puxar este cometimento agora.", + "commitsBehind_plural": "Seu repositório está __count__ cometimentos atrás do remoto. Você pode puxar esses cometimentos agora.", + "commitsAheadAndBehind1": "Seu repositório está __count__ cometimento atrás e", + "commitsAheadAndBehind1_plural": "Seu repositório está __count__ cometimentos atrás e", + "commitsAheadAndBehind2": "__count__ cometimento à frente do remoto.", + "commitsAheadAndBehind2_plural": "__count__ cometimentos à frente do remoto.", + "commitsAheadAndBehind3": "Você deve baixar o cometimento remoto antes de empurrar.", + "commitsAheadAndBehind3_plural": "Você deve baixar os cometimentos remotos antes de empurrar.", + "refreshCommitHistory": "Atualizar histórico de cometimentos", + "refreshChanges": "Atualizar alterações" + } + } + }, + "typedInput": { + "type": { + "str": "cadeia de caracteres", + "num": "número", + "re": "expressão regular", + "bool": "booliano", + "json": "JSON", + "bin": "armazenamento temporário", + "date": "registro de tempo", + "jsonata": "expressão", + "env": "variável de ambiente", + "cred": "credencial" + } + }, + "editableList": { + "add": "adicionar", + "addTitle": "adicionar um item" + }, + "search": { + "history": "Histórico da procura", + "clear": "limpar tudo", + "empty": "Nenhuma equivalência encontrada", + "addNode": "adicionar um nó...", + "options": { + "configNodes": "Configuração de nós", + "unusedConfigNodes": "Configuração de nós não utilizadas", + "invalidNodes": "Nós inválidos", + "uknownNodes": "Nós desconhecidos", + "unusedSubflows": "Subfluxos não utilizados", + "hiddenFlows": "Flux escondidos", + "modifiedNodes": "Nós e Fluxos Modificados", + "thisFlow": "Fluxo atual" + } + }, + "expressionEditor": { + "functions": "Funções", + "functionReference": "Referência de função", + "insert": "Inserir", + "title": "Editor de Expressões JSONata", + "test": "Teste", + "data": "Mensagem de exemplo", + "result": "Resultado", + "format": "expressão de formato", + "compatMode": "Modo de compatibilidade habilitado", + "compatModeDesc": "

Modo de compatibilidade JSONata

A expressão atual parece ainda fazer referência a msg , então será avaliada no modo de compatibilidade. Atualize a expressão para não usar msg , pois este modo será removido no futuro.

Quando o suporte JSONata foi adicionado pela primeira vez ao Node-RED, era necessária a expressão para fazer referência ao objeto msg . Por exemplo, msg.payload seria usado para acessar a carga útil.

Isso não é mais necessário, pois a expressão será avaliada em relação à mensagem diretamente. Para acessar a carga útil, a expressão deve ser apenas payload.

", + "noMatch": "Nenhum resultado correspondente", + "errors": { + "invalid-expr": "Expressão JSONata inválida:\n __message__", + "invalid-msg": "Exemplo de mensagem JSON inválida:\n __message__", + "context-unsupported": "Não é possível testar funções de contexto\n $flowContext or $globalContext", + "eval": "Erro ao avaliar a expressão:\n __message__" + } + }, + "monaco": { + "setTheme": "Definir tema" + }, + "jsEditor": { + "title": "Editor JavaScript" + }, + "textEditor": { + "title": "Editor de texto" + }, + "jsonEditor": { + "title": "editor JSON", + "format": "formatar JSON", + "rawMode": "Editar JSON", + "uiMode": "Editor visual", + "rawMode-readonly": "JSON", + "uiMode-readonly": "Visual", + "insertAbove": "Inserir acima", + "insertBelow": "Inserir abaixo", + "addItem": "Adicionar item", + "copyPath": "Copiar caminho para o item", + "expandItems": "Expandir itens", + "collapseItems": "Recolher itens", + "duplicate": "Duplicar", + "error": { + "invalidJSON": "JSON inválido: " + } + }, + "markdownEditor": { + "title": "Editor de Remarcação", + "expand": "Expandir", + "format": "Formatado com Remarcação", + "heading1": "Cabeçalho 1", + "heading2": "Cabeçalho 2", + "heading3": "Cabeçalho 3", + "bold": "Negrito", + "italic": "Itálico", + "code": "Código", + "ordered-list": "Lista ordenada", + "unordered-list": "Lista não-ordenada", + "quote": "Citar", + "link": "criar atalho", + "horizontal-rule": "Régua Horizontal", + "toggle-preview": "Alternar visualização" + }, + "bufferEditor": { + "title": "Editor de armazenamento temporário", + "modeString": "Tratar como cadeia de caracteres UTF-8", + "modeArray": "Manipular como matriz JSON", + "modeDesc": "

Editor de armazenamento temporário

O tipo de armazenamento temporário é armazenado como uma matriz JSON de valores de bytes. O editor tentará analisar o valor inserido como uma matriz JSON. Se não for um JSON válido, será tratada como uma cadeia de caracteres UTF-8 e convertida em uma matriz de pontos de código de caractere individual.

Por exemplo, um valor de Hello World será convertido na matriz JSON:

 [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100] 

" + }, + "projects": { + "config-git": "Configurar cliente Git", + "welcome": { + "hello": "Olá! Introduzimos 'projetos' no Node-RED.", + "desc0": "Esta é uma nova maneira de gerenciar seus arquivos de fluxo e incluir controle de versão de seus fluxos.", + "desc1": "Para começar, você pode criar seu primeiro projeto ou clonar um projeto existente de um repositório git.", + "desc2": "Se você não tiver certeza, pode pular isso por enquanto. Você ainda poderá criar seu primeiro projeto a partir do menu 'Projetos' a qualquer momento.", + "create": "Criar Projeto", + "clone": "Repositório de clones", + "openExistingProject": "Abrir projeto existente", + "not-right-now": "Não nesse exato momento" + }, + "git-config": { + "setup": "Configure seu cliente de controle de versão", + "desc0": "O Node-RED usa a ferramenta de código aberto Git para controle de versão. Ele rastreia as alterações em seus arquivos de projeto e permite enviá-los para repositórios remotos.", + "desc1": "Quando você confirma um conjunto de alterações, o Git registra quem fez as alterações com um nome de usuário e endereço de e-mail. O nome de usuário pode ser o que você quiser - não precisa ser seu nome real.", + "desc2": "Seu cliente Git já está configurado com os detalhes abaixo.", + "desc3": "Você pode alterar essas configurações mais tarde na guia 'Git config' da caixa de diálogo de configurações.", + "username": "Nome do usuário", + "email": "E-mail" + }, + "project-details": { + "create": "Crie seu projeto", + "desc0": "Um projeto é mantido como um repositório Git. Isso torna muito mais fácil compartilhar seus fluxos com outras pessoas e colaborar neles.", + "desc1": "Você pode criar vários projetos e alternar rapidamente entre eles no editor.", + "desc2": "Para começar, seu projeto precisa de um nome e uma descrição opcional.", + "already-exists": "Projeto já existe", + "must-contain": "Deve conter apenas A-Z 0-9 _ -", + "project-name": "Nome do Projeto", + "desc": "Descrição", + "opt": "Opcional" + }, + "clone-project": { + "clone": "Clonar um projeto", + "desc0": "Se você já tem um repositório git contendo um projeto, pode cloná-lo para começar.", + "already-exists": "Projeto já existe", + "must-contain": "Deve conter apenas A-Z 0-9 _ -", + "project-name": "Nome do projeto", + "no-info-in-url": "Não inclua o nome de usuário / senha no url", + "git-url": "Git repository URL", + "protocols": "https: //, ssh: // ou file://", + "auth-failed": "Autenticação falhou", + "username": "Nome de usuário", + "passwd": "Senha", + "ssh-key": "Chave SSH", + "passphrase": "Frase de Passe", + "ssh-key-desc": "Antes de clonar um repositório usando ssh, você deve adicionar uma chave SSH para acessá-lo.", + "ssh-key-add": "Adicionar uma chave ssh", + "credential-key": "Chave de criptografia de credenciais", + "cant-get-ssh-key": "Erro! Não é possível obter o caminho da chave SSH selecionada.", + "already-exists2": "já existe", + "git-error": "git error", + "connection-failed": "Conexão falhou", + "not-git-repo": "Não é um repositório git", + "repo-not-found": "Repositório não encontrado" + }, + "default-files": { + "create": "Crie seus arquivos de projeto", + "desc0": "Um projeto contém seus arquivos de fluxo, um arquivo README e um arquivo package.json.", + "desc1": "Pode conter quaisquer outros arquivos que você deseja manter no repositório Git.", + "desc2": "Seus arquivos de fluxo e credenciais existentes serão copiados para o projeto.", + "flow-file": "Arquivo de fluxo", + "credentials-file": "Arquivo de credenciais" + }, + "encryption-config": { + "setup": "Configure a criptografia do seu arquivo de credenciais", + "desc0": "Seu arquivo de credenciais de fluxo pode ser criptografado para manter seu conteúdo seguro.", + "desc1": "Se você deseja armazenar essas credenciais em um repositório Git público, deve criptografá-las fornecendo uma frase-chave secreta.", + "desc2": "Seu arquivo de credenciais de fluxo não está criptografado no momento.", + "desc3": "Isso significa que seu conteúdo, como senhas e fichas de acesso, pode ser lido por qualquer pessoa com acesso ao arquivo.", + "desc4": "Se você deseja armazenar essas credenciais em um repositório Git público, deve criptografá-las fornecendo uma frase-chave secreta.", + "desc5": "Seu arquivo de credenciais de fluxo está atualmente criptografado usando a propriedade credentialSecret de seu arquivo de configurações como a chave.", + "desc6": "Seu arquivo de credenciais de fluxo está criptografado usando uma chave gerada pelo sistema. Você deve fornecer uma nova chave secreta para este projeto.", + "desc7": "A chave será armazenada separadamente dos arquivos do seu projeto. Você precisará fornecer a chave para usar este projeto em outra instância do Node-RED.", + "credentials": "Credenciais", + "enable": "Habilitar criptografia", + "disable": "Desabilitar criptografia", + "disabled": "desabilitado", + "copy": "Copiar sobre a chave existente", + "use-custom": "Usar chave personalizada", + "desc8": "O arquivo de credenciais não será criptografado e seu conteúdo será lido facilmente", + "create-project-files": "Criar arquivos de projeto", + "create-project": "Criar projeto", + "already-exists": "já existe", + "git-error": "erro no git", + "git-auth-error": "git erro de autenticação" + }, + "create-success": { + "success": "Você criou com sucesso o seu primeiro projeto!", + "desc0": "Agora você pode continuar usando o Node-RED como sempre fez.", + "desc1": "A guia 'informações' na barra lateral mostra qual é o seu projeto ativo atual. O botão ao lado do nome pode ser usado para acessar a visualização das configurações do projeto.", + "desc2": "A guia 'histórico' na barra lateral pode ser usada para ver os arquivos que foram alterados no seu projeto e para submetê-los. Ela mostra um histórico completo de seus cometimentos e permite que você envie suas alterações para um repositório remoto . " + }, + "create": { + "projects": "Projetos", + "already-exists": "Projeto já existe", + "must-contain": "Deve conter apenas A-Z 0-9 _ -", + "no-info-in-url": "Não inclua o nome de usuário/senha no url", + "open": "Abrir projeto", + "create": "Criar Projeto", + "clone": "Clone Repositório", + "project-name": "Nome do projeto", + "desc": "Descrição", + "opt": "Opcional", + "flow-file": "Arquivo de fluxo", + "credentials": "Credenciais", + "enable-encryption": "Habilitar criptografia", + "disable-encryption": "Desabilitar criptografia", + "encryption-key": "Chave de criptografia", + "desc0": "Uma frase para proteger suas credenciais com", + "desc1": "O arquivo de credenciais não será criptografado e seu conteúdo poderá ser lido facilmente", + "git-url": "URL do repositório Git", + "protocols": "https://, ssh:// or file://", + "auth-failed": "Falha na autenticação", + "username": "Nome do usuário", + "password": "Senha", + "ssh-key": "Chave SSH", + "passphrase": "Frase de Passe", + "desc2": "Antes de clonar um repositório usando ssh, você deve adicionar uma chave SSH para acessá-lo.", + "add-ssh-key": "Adicionar uma chave ssh", + "credentials-encryption-key": "Chave de criptografia de credenciais", + "already-exists-2": "já existe", + "git-error": "erro de git", + "con-failed": "Conexão falhou", + "not-git": "Não é um repositório git", + "no-resource": "Repositório não encontrado", + "cant-get-ssh-key-path": "Erro! Não é possível obter o caminho da chave SSH selecionado.", + "unexpected_error": "erro_inesperado", + "clearContext": "Limpar contexto quando ocorrer troca de projetos" + }, + "delete": { + "confirm": "Tem certeza de que deseja excluir este projeto?" + }, + "create-project-list": { + "search": "procure seus projetos", + "current": "atual" + }, + "require-clean": { + "confirm": "

Você tem alterações não implantadas que serão perdidas.

Deseja continuar?

" + }, + "send-req": { + "auth-req": "Autenticação necessária para repositório", + "username": "Nome do usuário", + "password": "Senha", + "passphrase": "Frase de Passe", + "retry": "Tentar novamente", + "update-failed": "Falha ao atualizar autenticação", + "unhandled": "Resposta de erro não tratada", + "host-key-verify-failed": "

Falha na verificação da chave do servidor anfitrião.

A chave do servidor anfitrião do repositório não pôde ser verificada. Atualize seu arquivo known_hosts e tente novamente.

" + }, + "create-branch-list": { + "invalid": "Ramo inválido", + "create": "Criar ramo", + "current": "atual" + }, + "create-default-file-set": { + "no-active": "Não é possível criar um conjunto de arquivos padrão sem um projeto ativo", + "no-empty": "Não é possível criar um arquivo padrão definido em um projeto não vazio", + "git-error": "erro no git" + }, + "errors": { + "no-username-email": "Seu cliente Git não está configurado com um nome de usuário / e-mail.", + "unexpected": "Um erro inesperado ocorreu", + "code": "código" + } + }, + "editor-tab": { + "properties": "Propriedades", + "envProperties": "Variáveis de Ambiente", + "module": "Propriedades do Módulo", + "description": "Descrição", + "appearance": "Aparência", + "preview": "Visualização da IU", + "defaultValue": "Valor padrão" + }, + "tourGuide": { + "takeATour": "Faça um tour", + "start": "Inicio", + "next": "Próximo", + "welcomeTours": "Tour de Boas-vindas" + }, + "diagnostics": { + "title": "informações do Sistema" + }, + "languages": { + "de": "Alemão", + "en-US": "Inglês", + "ja": "Japonês", + "ko": "Coreano", + "pt-BR": "Português(Brasil)", + "ru": "Russo", + "zh-CN": "Chinês(Simplificado)", + "zh-TW": "Chinês(Tradicional)" + }, + "validator": { + "errors": { + "invalid-json": "Dados JSON inválidos: __error__", + "invalid-json-prop": "__prop__: dados JSON inválidos: __error__", + "invalid-prop": "Expressão de propriedade inválida", + "invalid-prop-prop": "__prop__: expressão de propriedade inválida", + "invalid-num": "Número inválido", + "invalid-num-prop": "__prop__: número inválido", + "invalid-regexp": "Padrão de entrada inválido", + "invalid-regex-prop": "__prop__: Padrão de entrada inválido", + "missing-required-prop": "__prop__: valor de propriedade ausente", + "invalid-config": "__prop__: nó de configuração inválido", + "missing-config": "__prop__: nó de Configuração ausente", + "validation-error": "__prop__: erro de validação: __node__, __id__: __error__" + } + }, + "contextMenu": { + "insert": "Inserir", + "node": "Nó", + "junction": "Junção", + "linkNodes": "Nós de Ligação" + } +} diff --git a/packages/node_modules/@node-red/editor-client/locales/pt-BR/infotips.json b/packages/node_modules/@node-red/editor-client/locales/pt-BR/infotips.json new file mode 100755 index 000000000..7ac7502c1 --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/pt-BR/infotips.json @@ -0,0 +1,23 @@ +{ + "info": { + "tip0": "Você pode remover os nós ou links selecionados com {{core:delete-selection}}", + "tip1": "Procure por nós usando {{core:search}}", + "tip2": "{{core:toggle-sidebar}} irá alternar a visualização desta barra lateral", + "tip3": "Você pode gerenciar sua paleta de nós com {{core:manage-palette}}", + "tip4": "Seus nós de configuração de fluxo são listados no painel da barra lateral. Pode ser acessado a partir do menu ou com{{core:show-config-tab}}", + "tip5": "Habilite ou desabilite essas dicas na opção nas configurações", + "tip6": "Mova os nós selecionados usando o [left] [up] [down] e [right] chaves. Segure [shift] para empurrá-los ainda mais", + "tip7": "Arrastar um nó para um fio o unirá no link", + "tip8": "Exporte os nós selecionados ou a guia atual com {{core:show-export-dialog}}", + "tip9": "Importe um fluxo arrastando seu JSON para o editor ou com {{core:show-import-dialog}}", + "tip10": "[shift] [click] e arraste em uma porta de nó para mover todos os fios conectados ou apenas o selecionado", + "tip11": "Mostre a guia Informações com {{core:show-info-tab}} ou a guia Depurar com {{core:show-debug-tab}}", + "tip12": "[ctrl] [click] na área de trabalho para abrir a caixa de diálogo de adição rápida", + "tip13": "Mantenha pressionado [ctrl] enquanto você [click] em uma porta de nó para habilitar a ligação rápida", + "tip14": "Mantenha pressionado [shift] enquanto você [click] em um nó para também selecionar todos os seus nós conectados", + "tip15": "Mantenha pressionado [ctrl] enquanto você [click] em um nó para adicioná-lo ou removê-lo da seleção atual", + "tip16": "Alternar guias de fluxo com {{core:show-previous-tab}} e {{core:show-next-tab}}", + "tip17": "Você pode confirmar suas alterações na bandeja de edição do nó com {{core:confirm-edit-tray}} ou cancele-os com {{core:cancel-edit-tray}}", + "tip18": "Pressionando {{core:edit-selected-node}} irá editar o primeiro nó na seleção atual" + } +} diff --git a/packages/node_modules/@node-red/editor-client/locales/pt-BR/jsonata.json b/packages/node_modules/@node-red/editor-client/locales/pt-BR/jsonata.json new file mode 100755 index 000000000..18d0e78c1 --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/locales/pt-BR/jsonata.json @@ -0,0 +1,274 @@ +{ + "$string": { + "args": "arg[, prettify]", + "desc": "Converte o tipo do parâmetro `arg` em uma cadeia de caracteres usando as seguintes regras de conversão de tipo:\n\n - Cadeia de caracteres não são alteradas\n - As funções são convertidas para uma cadeia de caracteres vazia\n - os tipos numérico infinito e NaN geram um erro porque não podem ser representados como um número JSON\n - Todos os outros valores são convertidos para uma cadeia de caracteres JSON usando a função `JSON.stringify`. Se `prettify` for verdadeira, então o JSON \"prettified\" é produzido. Isto é, uma linha por campo e as linhas serão indentadas com base na profundidade do campo." + }, + "$length": { + "args": "str", + "desc": "Retorna o número de caracteres na cadeia de caracteres `str`. Um erro é gerado se `str` não for uma cadeia de caracteres." + }, + "$substring": { + "args": "str, start[, length]", + "desc": "Retorna uma cadeia de caracteres contendo os caracteres no primeiro parâmetro `str` começando na posição `start` (deslocamento zero). Se` length` for especificado, então a sub cadeia de caracteres conterá o máximo `length` de caracteres. Se` start` for negativo isso indica o número de caracteres a partir do fim de `str`." + }, + "$substringBefore": { + "args": "str, chars", + "desc": "Retorna a sub cadeia de caracteres antes da primeira ocorrência da sequência de caracteres `chars` em `string`. Se` string` não contiver `chars`, então retorna `str`. " + }, + "$substringAfter": { + "args": "str, chars", + "desc": "Retorna a sub cadeia de caracteres após a primeira ocorrência da sequência de caracteres `chars` em `string`. Se `string` não contiver `chars`, então retorna `str`. " + }, + "$uppercase": { + "args": "str", + "desc": "Retorna uma cadeia de caracteres com todos os caracteres de `string` convertidos em maiúsculas. " + }, + "$lowercase": { + "args": "str", + "desc": "Retorna uma cadeia de caracteres com todos os caracteres de `string` convertidos em minúsculas. " + }, + "$trim": { + "args": "str", + "desc": "Normaliza e retira todos os caracteres de espaço em branco em `str` aplicando as seguintes etapas:\n\n - Todas as tabulações, retornos de carro e avanços de linha são substituídos por espaços.\n- Sequências contíguas de espaços são reduzidas a um único espaço.\n- Espaços à direita e à esquerda são removidos.\n\n Se `str` não for especificado (isto é, esta função é chamada sem argumentos), então o valor do contexto é usado como o valor de `str`. Um erro é gerado se `str` não for uma cadeia de caracteres." + }, + "$contains": { + "args": "str, pattern", + "desc": "Retorna `true` se `str` tiver correspondente em `pattern`, caso contrário, retorna `false`. Se `str` não for especificado (isto é, esta função é chamada com um argumento), então o valor do contexto é usado como o valor de `str`. O parâmetro `pattern` pode ser uma cadeia de caracteres ou uma expressão regular. " + }, + "$split": { + "args": "str[, separator][, limit]", + "desc": "Divide o parâmetro `str` em uma matriz de sub cadeia de caracteres. É um erro se `str` não for uma cadeia de caracteres. O parâmetro opcional `separator` especifica os caracteres dentro de `str` sobre os quais devem ser divididos como uma cadeia de caracteres ou expressão regular. Se `separator` não for especificado, a cadeia de caracteres vazia será assumida e `str` será dividido em uma matriz de caracteres únicos. É um erro se `separador` não for uma cadeia de caracteres. O parâmetro opcional `limit` é um número que especifica o número máximo de sub cadeia de caracteres a serem incluídas na matriz resultante. Quaisquer sub cadeia de caracteres adicionais são descartadas. Se `limit` não for especificado, então `str` será totalmente dividido sem limite para o tamanho da matriz resultante . É um erro se `limit` não for um número não negativo." + }, + "$join": { + "args": "array[, separator]", + "desc": "Une uma matriz de cadeias de caracteres de componentes em uma única cadeia de caracteres concatenada com cada cadeia de caracteres de componente separada pelo parâmetro opcional `separator`. É um erro se a `matriz` de entrada contiver um item que não seja uma cadeia de caracteres. Se `separator` for não especificado, assume-se que é uma cadeia de caracteres vazia, ou seja, nenhum `separator` entre as cadeias de caracteres do componente. É um erro se `separator` não for uma cadeia de caracteres. " + }, + "$match": { + "args": "str, pattern [, limit]", + "desc": "Aplica a cadeia de caracteres `str` à expressão regular `pattern` e retorna uma matriz de objetos, com cada objeto contendo informações sobre cada ocorrência de uma correspondência dentro de `str`. " + }, + "$replace": { + "args": "str, pattern, replacement [, limit]", + "desc": "Encontra ocorrências de `pattern` dentro de `str` e as substitui por `replacement`.\n\nO parâmetro opcional `limit` é o número máximo de substituições." + }, + "$now": { + "args":"$[picture [, timezone]]", + "desc":"Gera um carimbo de data/hora em formato compatível com ISO 8601 e o retorna como uma cadeia de caracteres. Se os parâmetros opcionais de imagem e fuso horário forem fornecidos, o carimbo de data/hora atual é formatado conforme descrito pela função `$ fromMillis ()`" + }, + "$base64encode": { + "args":"string", + "desc":"Converte uma cadeia de caracteres ASCII em uma representação de base 64. Cada caractere na cadeia de caracteres é tratado como um byte de dados binários. Isso requer que todos os caracteres na cadeia de caracteres estejam no intervalo de 0x00 a 0xFF, o que inclui todos os caracteres em cadeias de caracteres codificadas em URI. Caracteres Unicode fora desse intervalo não são suportados." + }, + "$base64decode": { + "args":"string", + "desc":"Converte bytes codificados de base 64 em uma cadeia de caracteres, usando uma página de código UTF-8 Unicode." + }, + "$number": { + "args": "arg", + "desc": "Converte o parâmetro `arg` em um número usando as seguintes regras de conversão:\n\n - Os números permanecem inalterados\n - Cadeias de caracteres que contêm uma sequência de caracteres que representam um número JSON válido são convertidos para esse número\n - Todos os outros valores causam a geração de um erro." + }, + "$abs": { + "args":"number", + "desc":"Retorna o valor absoluto do parâmetro `number`." + }, + "$floor": { + "args":"number", + "desc":"Retorna o valor de `number` arredondado para baixo para o inteiro mais próximo que seja menor ou igual a `number`." + }, + "$ceil": { + "args":"number", + "desc":"Retorna o valor de `number` arredondado para o número inteiro mais próximo que é maior ou igual a `number`." + }, + "$round": { + "args":"number [, precision]", + "desc":"Retorna o valor do parâmetro `number` arredondado para o número de casas decimais especificado pelo parâmetro opcional `precision`." + }, + "$power": { + "args":"base, exponent", + "desc":"Retorna o valor de `base` elevado à potência de `exponent`." + }, + "$sqrt": { + "args":"number", + "desc":"Retorna a raiz quadrada do valor do parâmetro `number`." + }, + "$random": { + "args":"", + "desc":"Retorna um número pseudoaleatório maior ou igual a zero e menor que um." + }, + "$millis": { + "args":"", + "desc":"Retorna o número de milissegundos desde o Unix Epoch (1º de janeiro de 1970 UTC) como um número. Todas as invocações de `$ millis ()` dentro de uma avaliação de uma expressão retornarão todas o mesmo valor." + }, + "$sum": { + "args": "array", + "desc": "Retorna a soma aritmética de uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número." + }, + "$max": { + "args": "array", + "desc": "Retorna o número máximo em uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número." + }, + "$min": { + "args": "array", + "desc": "Retorna o número mínimo em uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número." + }, + "$average": { + "args": "array", + "desc": "Retorna o valor médio de uma `array` de números. É um erro se o `array` de entrada contiver um item que não seja um número." + }, + "$boolean": { + "args": "arg", + "desc": "Converte o argumento em um booliano usando as seguintes regras:\n\n - `Boolean` : inalterado\n - `string`: vazio : `false`\n - `string`: não-vazio : `true`\n - `number`: `0` : `false`\n - `number`: não-zero : `true`\n - `null` : `false`\n - `array`: vazio : `false`\n - `array`: contém um membro que converte de tipo para `true` : `true`\n - `array`: todos os membros convertidos de tipo para `false` : `false`\n - `object`: vazio : `false`\n - `object`: não-vazio : `true`\n - `function` : `false`" + }, + "$not": { + "args": "arg", + "desc": "Retorna booliano NOT no argumento. `Arg` é convertido de tipo primeiro para um booliano " + }, + "$exists": { + "args": "arg", + "desc": "Retorna booliano `true` se a expressão `arg` for avaliada como um valor, ou `false` se a expressão não corresponder a nada (por exemplo, um caminho para uma referência de campo inexistente)." + }, + "$count": { + "args": "array", + "desc": "Retorna o número de itens na matriz" + }, + "$append": { + "args": "array, array", + "desc": "Anexa duas matrizes" + }, + "$sort": { + "args":"array [, function]", + "desc":"Retorna uma matriz contendo todos os valores no parâmetro `array`, mas classificados em ordem.\n\nSe um comparador `function` for fornecido, então deve ser uma função que leva dois parâmetros:\n\n`function(left, right)`\n\nEsta função é invocada pelo algoritmo de classificação para comparar dois valores à esquerda e à direita. Se o valor de esquerda deve ser colocado após o valor de direita na ordem de classificação desejada, a função deve retornar o booliano `true` para indicar uma troca. Caso contrário, deve retornar `false`." + }, + "$reverse": { + "args":"array", + "desc":"Retorna uma matriz contendo todos os valores do parâmetro `array`, mas na ordem reversa. " + }, + "$shuffle": { + "args":"array", + "desc":"Retorna uma matriz contendo todos os valores do parâmetro `array`, mas misturados em ordem aleatória. " + }, + "$zip": { + "args":"array, ...", + "desc":"Retorna uma matriz convolucional (compactada) contendo matrizes agrupadas de valores dos argumentos `array1`… `arrayN` do índice 0, 1, 2 ...." + }, + "$keys": { + "args": "object", + "desc": "Retorna uma matriz contendo as chaves do objeto. Se o argumento for uma matriz de objetos, então a matriz retornada contém uma lista não duplicada de todas as chaves em todos os objetos." + }, + "$lookup": { + "args": "object, key", + "desc": "Retorna o valor associado à chave no objeto. Se o primeiro argumento for uma matriz de objetos, todos os objetos na matriz são pesquisados e os valores associados a todas as ocorrências da chave são retornados." + }, + "$spread": { + "args": "object", + "desc": "Divide um objeto que contém pares de chave/valor em uma matriz de objetos, cada um com um único par de chave/valor do objeto de entrada. Se o parâmetro for uma matriz de objetos, a matriz resultante conterá um objeto para cada par de chave/valor em todo objeto na matriz fornecida. " + }, + "$merge": { + "args": "array<object>", + "desc": "Mescla uma matriz de `objects` em um único `object` contendo todos os pares de chave/valor de cada um dos objetos na matriz de entrada. Se qualquer um dos objetos de entrada contiver a mesma chave, então o `object` retornado conterá o valor do último na matriz. É um erro se a matriz de entrada contiver um item que não seja um objeto." + }, + "$sift": { + "args":"object, function", + "desc": "Retorna um objeto que contém apenas os pares de chave/valor do parâmetro `object` que satisfazem o predicado `function` passado como o segundo parâmetro.\n\nA `function` que é fornecida como o segundo parâmetro deve ter o seguinte assinatura:\n\n`function(value [, key [, object]])`" + }, + "$each": { + "args":"object, function", + "desc":"Retorna uma matriz contendo os valores retornados por `function` quando aplicado a cada par chave/valor no `object`." + }, + "$map": { + "args":"array, function", + "desc":"Retorna uma matriz contendo os resultados da aplicação do parâmetro `function` a cada valor no parâmetro `array`.\n\nA `function` que é fornecido como o segundo parâmetro deve ter a seguinte assinatura:\n\n`function(value [, index [, array]])`" + }, + "$filter": { + "args":"array, function", + "desc":"Retorna uma matriz contendo apenas os valores no parâmetro `array` que satisfazem o predicado `function`.\n\nThe `function` que é fornecido como o segundo parâmetro deve ter a seguinte assinatura:\n\n`function(value [, index [, array]])`" + }, + "$reduce": { + "args":"array, function [, init]", + "desc":"Retorna um valor agregado derivado da aplicação do parâmetro `function` sucessivamente a cada valor em `array` em combinação com o resultado da aplicação anterior da função.\n\nA função deve aceitar dois argumentos e se comportar como um operador inserido entre cada valor dentro de `array`. A assinatura da `function` deve estar no formato: `myfunc($accumulator, $value[, $index[, $array]])`\n\nO parâmetro opcional `init` é usado como o valor inicial na agregação." + }, + "$flowContext": { + "args": "string[, string]", + "desc": "Recupera uma propriedade de contexto de fluxo.\n\nEsta é uma função definida pelo Node-RED. " + }, + "$globalContext": { + "args": "string[, string]", + "desc": "Recupera uma propriedade de contexto global.\n\nEsta é uma função definida pelo Node-RED. " + }, + "$pad": { + "args": "string, width [, char]", + "desc": "Retorna uma cópia da `string` com preenchimento extra, se necessário, de forma que seu número total de caracteres seja pelo menos o valor absoluto do parâmetro `width`.\n\nSe `width` for um número positivo, a cadeia de caracteres será preenchida à direita; se negativo, é preenchida à esquerda.\n\nO argumento opcional `char` especifica os caracteres de preenchimento a serem usados. Se não for especificado, o padrão é o caractere de espaço. " + }, + "$fromMillis": { + "args": "number, [, picture [, timezone]]", + "desc": "Converta o `number` que representa os milissegundos desde a época do Unix (1 January, 1970 UTC) em uma representação de cadeia de caracteres formatada do carimbo de data/hora conforme especificado pela cadeia de caracteres de imagem.\n\nSe o parâmetro opcional `image` for omitido, o carimbo de data/hora será formatado no formato ISO 8601.\n\nSe a cadeia de caracteresopcional `picture` for fornecida, o carimbo de data/hora é formatado de acordo com a representação especificada nessa cadeia de caracteres. O comportamento desta função é consistente com a versão de dois argumentos da função XPath/XQuery `format-dateTime` conforme definido na especificação XPath F&O 3.1. O parâmetro de cadeia de caracteres de imagem define como o carimbo de data/hora é formatado e tem a mesma sintaxe de `format-dateTime`.\n\nSe a cadeia de caracteres opcional `timezone` for fornecida, o carimbo de data/hora formatado estará nesse fuso horário. A cadeia de caracteres `timezone` deve estar no formato '± HHMM', onde ± é o sinal de mais ou menos e HHMM é o deslocamento em horas e minutos do UTC. Deslocamento positivo para fusos horários a leste do UTC, deslocamento negativo para fusos horários a oeste do UTC. " + }, + "$formatNumber": { + "args": "number, picture [, options]", + "desc": "Converte o tipo de `number` em uma cadeia de caracteres e o formata em uma representação decimal conforme especificado pela cadeia de caracteres `picture`.\n\n O comportamento desta função é consistente com a função XPath/XQuery fn: format-number conforme definido na especificação XPath F&O 3.1. O parâmetro de cadeia de caracteres de imagem define como o número é formatado e tem a mesma sintaxe de fn: format-number.\n\nO terceiro argumento opcional `options` é usado para substituir os caracteres de formatação específicos da localidade padrão, como o separador decimal. Se fornecido, este argumento deve ser um objeto contendo pares de nome/valor especificados na seção de formato decimal da especificação XPath F&O 3.1." + }, + "$formatBase": { + "args": "number [, radix]", + "desc": "Converte o `number` em uma cadeia de caracteres e o formata em um inteiro representado na base do número especificada pelo argumento `radix`. Se `radix` não for especificado, o padrão é a base 10. `radix` pode estar entre 2 e 36, caso contrário, um erro será gerado. " + }, + "$toMillis": { + "args": "timestamp", + "desc": "Converta o tipo de uma cadeia de caracteres `timestamp` no formato ISO 8601 para o número de milissegundos desde a época do Unix (1 January, 1970 UTC) como um número. Um erro é gerado se a cadeia de caracteres não estiver no formato correto. " + }, + "$env": { + "args": "arg", + "desc": "Retorna o valor de uma variável de ambiente.\n\nEsta é uma função definida pelo Node-RED." + }, + "$eval": { + "args": "expr [, context]", + "desc": "Analisa e avalia a cadeia de caracteres `expr` que contém um JSON literal ou uma expressão JSONata usando o contexto atual como o contexto para avaliação. " + }, + "$formatInteger": { + "args": "number, picture", + "desc": "Converte o tipo de `number` em uma cadeia de caracteres e o formata em uma representação inteira conforme especificado pela cadeia de caracteres `picture`. O parâmetro da cadeia de caracteres de imagem define como o número é formatado e tem a mesma sintaxe de `fn: format-integer` do Especificação XPath F&O 3.1. " + }, + "$parseInteger": { + "args": "string, picture", + "desc": "Examina e troca o conteúdo do parâmetro `string` para um inteiro (como um número JSON) usando o formato especificado pela cadeia de caracteres `picture`. O parâmetro da cadeia de caracteres `picture` tem o mesmo formato que `$ formatInteger`." + }, + "$error": { + "args": "[str]", + "desc": "Gera um erro com uma mensagem. O (parâmetro) opcional `str` substituirá a mensagem padrão de `$error() function evaluated`" + }, + "$assert": { + "args": "arg, str", + "desc": "Se `arg` for verdadeiro, a função retorna indefinido. Se `arg` for falso, uma exceção é gerada com `str` como a mensagem da exceção. " + }, + "$single": { + "args": "array, function", + "desc": "Retorna o único valor no parâmetro `array` que satisfaz o predicado `function` (isto é, O (parâmetro) `function` retorna o booliano `true` quando passado o valor). Gera uma exceção se o número de valores correspondentes não for exatamente um .\n\nA função deve ser fornecida na seguinte assinatura: `function(value [, index [, array]])` onde 'value' é cada entrada da matriz, 'index' é a posição desse valor e toda a matriz é passada como o terceiro argumento" + }, + "$encodeUrlComponent": { + "args": "str", + "desc": "Codifica um componente Localizador Uniforme de Recursos (URL) substituindo cada instância de certos caracteres por uma, duas, três ou quatro sequências de escape que representam a codificação UTF-8 do caractere.\n\nExemplo: `$encodeUrlComponent(\"?x=test\")` => `\"%3Fx%3Dtest\"`" + }, + "$encodeUrl": { + "args": "str", + "desc": "Codifica um Localizador Uniforme de Recursos (URL) substituindo cada instância de certos caracteres por uma, duas, três ou quatro sequências de escape que representam a codificação UTF-8 do caractere. \n\nExemplo: `$encodeUrl(\"https://mozilla.org/?x=шеллы\")` => `\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\"`" + }, + "$decodeUrlComponent": { + "args": "str", + "desc": "Decodifica um componente Localizador Uniforme de Recursos (URL) criado anteriormente por encodeUrlComponent. \n\nExemplo: `$decodeUrlComponent(\"%3Fx%3Dtest\")` => `\"?x=test\"`" + }, + "$decodeUrl": { + "args": "str", + "desc": "Decodifica um Localizador Uniforme de Recursos (URL) criado anteriormente por encodeUrl. \n\nExemplo: `$decodeUrl(\"https://mozilla.org/?x=%D1%88%D0%B5%D0%BB%D0%BB%D1%8B\")` => `\"https://mozilla.org/?x=шеллы\"`" + }, + "$distinct": { + "args": "array", + "desc": "Retorna uma matriz com valores duplicados removidos da `array` " + }, + "$type": { + "args": "value", + "desc": "Retorna o tipo de `value` como uma cadeia de caracteres. Se `value` for indefinido, retornará `undefined` " + }, + "$moment": { + "args": "[str]", + "desc": "Obtém um objeto de dados usando a biblioteca 'Moment'." + } +} diff --git a/packages/node_modules/@node-red/editor-client/locales/ru/editor.json b/packages/node_modules/@node-red/editor-client/locales/ru/editor.json index d669b3f09..8cfea1bde 100644 --- a/packages/node_modules/@node-red/editor-client/locales/ru/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/ru/editor.json @@ -1133,8 +1133,10 @@ "languages" : { "de": "Немецкий", "en-US": "Английский", + "fr": "Французский", "ja": "Японский", "ko": "Корейский", + "pt-BR":"португальский", "ru": "Русский", "zh-CN": "Китайский (упрощенный)", "zh-TW": "Китайский (традиционный)" diff --git a/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json b/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json index eca5878ae..e55240cc5 100644 --- a/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json @@ -1,1095 +1,1221 @@ { - "common": { - "label": { - "name": "姓名", - "ok": "确认", - "done": "完成", - "cancel": "取消", - "delete": "删除", - "close": "关闭", - "load": "读取", - "save": "保存", - "import": "导入", - "export": "导出", - "back": "后退", - "next": "下一个", - "clone": "克隆项目", - "cont": "继续", - "style": "风格", - "line": "大纲", - "fill": "填充", - "label": "标签", - "color": "颜色", - "position": "位置", - "enable": "启用", - "disable": "禁用", - "upload": "上传" - }, - "type": { - "string": "字符串", - "number": "数字", - "boolean": "布尔值", - "array": "数组", - "buffer": "buffer", - "object": "对象", - "jsonString": "JSON字符串", - "undefined": "未定义", - "null": "空" - } + "common": { + "label": { + "name": "名称", + "ok": "确认", + "done": "完成", + "cancel": "取消", + "delete": "删除", + "close": "关闭", + "load": "读取", + "save": "保存", + "import": "导入", + "export": "导出", + "back": "后退", + "next": "下一个", + "clone": "克隆项目", + "cont": "继续", + "style": "样式", + "line": "大纲", + "fill": "填充", + "label": "标签", + "color": "颜色", + "position": "位置", + "enable": "启用", + "disable": "禁用", + "upload": "上传" }, - "event": { - "loadPalette": "加载控制板", - "loadNodeCatalogs": "加载节点目录", - "loadNodes": "加载 __count__ 个节点", - "loadFlows": "加载流程", - "importFlows": "往工作区中加载流程" + "type": { + "string": "字符串", + "number": "数字", + "boolean": "布尔值", + "array": "数组", + "buffer": "buffer", + "object": "对象", + "jsonString": "JSON字符串", + "undefined": "未定义", + "null": "空" + } + }, + "event": { + "loadPlugins": "加载插件", + "loadPalette": "加载控制板", + "loadNodeCatalogs": "加载节点目录", + "loadNodes": "加载 __count__ 个节点", + "loadFlows": "加载流程", + "importFlows": "往工作区中加载流程", + "importError": "

加载流程错误

__message__

", + "loadingProject": "加载项目" + }, + "workspace": { + "defaultName": "流程 __number__", + "editFlow": "编辑流程: __name__", + "confirmDelete": "确认删除", + "delete": "你确定要删除 __label__ ?", + "dropFlowHere": "把流程放到这里", + "addFlow": "添加流程", + "addFlowToRight": "在右侧新增流程", + "hideFlow": "隐藏流程", + "hideOtherFlows": "隐藏其它流程", + "showAllFlows": "显示所有流程", + "hideAllFlows": "隐藏所有流程", + "hiddenFlows": "列出 __count__ 个隐藏流程", + "hiddenFlows_plural": "列出 __count__ 个隐藏流程", + "showLastHiddenFlow": "显示最后一个隐藏流程", + "listFlows": "流程一览", + "listSubflows": "列出子流程", + "status": "状态", + "enabled": "有效", + "disabled": "无效", + "info": "详细描述", + "selectNodes": "点击节点来选择" + }, + "menu": { + "label": { + "view": { + "view": "显示", + "grid": "网格", + "storeZoom": "加载时还原缩放尺寸", + "storePosition": "加载时还原滚动位置", + "showGrid": "显示网格", + "snapGrid": "对齐网格", + "gridSize": "网格尺寸", + "textDir": "文本方向", + "defaultDir": "默认方向", + "ltr": "从左到右", + "rtl": "从右到左", + "auto": "上下文", + "language": "语言", + "browserDefault": "浏览器默认" + }, + "sidebar": { + "show": "显示侧边栏" + }, + "palette": { + "show": "显示控制板" + }, + "edit": "编辑", + "settings": "设置", + "userSettings": "用户设置", + "nodes": "节点", + "displayStatus": "显示节点状态", + "displayConfig": "修改节点配置", + "import": "导入", + "export": "导出", + "search": "查找流程", + "searchInput": "查找流程", + "subflows": "子流程", + "createSubflow": "新建子流程", + "selectionToSubflow": "将选择部分更改为子流程", + "flows": "流程", + "add": "增加", + "rename": "重命名", + "delete": "删除", + "keyboardShortcuts": "键盘快捷方式", + "login": "登录", + "logout": "退出", + "editPalette": "节点管理", + "other": "其他", + "showTips": "显示小提示", + "showWelcomeTours": "显示新版本向导", + "help": "Node-RED 文档主页", + "projects": "项目", + "projects-new": "新建", + "projects-open": "打开", + "projects-settings": "项目设定", + "showNodeLabelDefault": "显示新添加的节点的标签", + "codeEditor": "代码编辑器", + "groups": "组", + "groupSelection": "选择组", + "ungroupSelection": "取消选择组", + "groupMergeSelection": "合并选择", + "groupRemoveSelection": "从组中移除", + "arrange": "布局", + "alignLeft": "左对齐", + "alignCenter": "居中对齐", + "alignRight": "右对齐", + "alignTop": "顶部对齐", + "alignMiddle": "垂直居中对齐", + "alignBottom": "底部对齐", + "distributeHorizontally": "横向分布", + "distributeVertically": "垂直分布", + "moveToBack": "置于底层", + "moveToFront": "置于顶层", + "moveBackwards": "向后移动", + "moveForwards": "向前移动" + } + }, + "actions": { + "toggle-navigator": "切换导航器", + "zoom-out": "缩小", + "zoom-reset": "重设缩放", + "zoom-in": "放大", + "search-flows": "搜索流程", + "search-prev": "上一个", + "search-next": "下一个", + "search-counter": "\"__term__\" __result__ of __count__" + }, + "user": { + "loggedInAs": "作为 __name__ 登录", + "username": "账号", + "password": "密码", + "login": "登录", + "loginFailed": "登录失败", + "notAuthorized": "未授权", + "errors": { + "settings": "设置信息需要登录后才能访问", + "deploy": "改动需要登录后才能部署", + "notAuthorized": "此操作需要登录后才能执行" + } + }, + "notification": { + "state": { + "flowsStopped": "流程已停止", + "flowsStarted": "流程已启动" }, - "workspace": { - "defaultName": "流程 __number__", - "editFlow": "编辑流程: __name__", - "confirmDelete": "确认删除", - "delete": "你确定要删除 __label__ ?", - "dropFlowHere": "把流程放到这里", - "addFlow": "添加流程", - "listFlows": "流程一览", - "status": "状态", - "enabled": "有效", - "disabled": "无效", - "info": "详细描述", - "selectNodes": "点击节点来选择" + "warning": "警告: __message__", + "warnings": { + "undeployedChanges": "节点中存在未部署的更改", + "nodeActionDisabled": "节点操作已禁用", + "nodeActionDisabledSubflow": "节点动作在子流程中被禁用", + "missing-types": "流程由于缺少节点类型而停止。请检查日志的详细信息", + "missing-modules": "

流程因缺少模块而停止。

", + "safe-mode": "

流程以安全模式停止。

您可以修改流程并部署更改以重新启动。

", + "restartRequired": "Node-RED必须重新启动,以启用升级的模块", + "credentials_load_failed": "

由于无法解密凭据,因此流程停止。

流程凭据文件已加密,但是项目的加密密钥丢失或无效。

", + "credentials_load_failed_reset": "

凭据无法解密

流凭据文件已加密,但是项目的加密密钥丢失或无效。

流凭据文件将在下一次部署时重置。任何现有的流凭证将被清除。

", + "missing_flow_file": "

找不到项目流程文件。

该项目未配置流程文件。

", + "missing_package_file": "

找不到项目包文件。

项目缺少package.json文件。

", + "project_empty": "

该项目为空。

是否要创建一组默认的项目文件?
否则,您将必须在编辑器外部手动将文件添加到项目中。

", + "project_not_found": "

未找到项目 __project__ 。

", + "git_merge_conflict": "

自动合并更改失败。

修复未合并的冲突,然后提交结果。

" + }, + "error": "错误: __message__", + "errors": { + "lostConnection": "丢失与服务器的连接,重新连接...", + "lostConnectionReconnect": "丢失与服务器的连接, __time__ 秒后重新连接", + "lostConnectionTry": "现在尝试", + "cannotAddSubflowToItself": "无法向其自身添加子流程", + "cannotAddCircularReference": "无法添加子流程 - 循环引用", + "unsupportedVersion": "您正在使用不受支持的Node.js版本
请升级到最新版本的Node.js LTS", + "failedToAppendNode": "

'__module__'加载失败

__error__

" + }, + "project": { + "change-branch": "转到本地分支'__project__'", + "merge-abort": "Git合并中止", + "loaded": "项目'__project__'已加载", + "updated": "项目'__project__'已更新", + "pull": "项目'__project__'已重新加载", + "revert": "项目 '__project__'已还原", + "merge-complete": "Git合并完成", + "setupCredentials": "设定证书", + "setupProjectFiles": "设置项目文件", + "no": "不了,谢谢", + "createDefault": "创建默认项目文件", + "mergeConflict": "显示合并冲突" + }, + "label": { + "manage-project-dep": "管理项目依赖性", + "setup-cred": "设定证书", + "setup-project": "设置项目文件", + "create-default-package": "创建默认的包文件", + "no-thanks": "不了,谢谢", + "create-default-project": "创建默认项目文件", + "show-merge-conflicts": "显示合并冲突", + "unknownNodesButton": "搜索未知节点" + } + }, + "clipboard": { + "clipboard": "剪贴板", + "nodes": "节点", + "node": "__count__ 个节点", + "node_plural": "__count__ 个节点", + "configNode": "__count__ 个配置节点", + "configNode_plural": "__count__ 个配置节点", + "group": "__count__ 个组", + "group_plural": "__count__ 个组", + "flow": "__count__ 个流程", + "flow_plural": "__count__ 个流程", + "subflow": "__count__ 个子流程", + "subflow_plural": "__count__ 子流程", + "replacedNodes": "__count__ 个节点被置换", + "replacedNodes_plural": "__count__ 个节点被置换", + "pasteNodes": "在下方粘贴节点 ", + "selectFile": "导入节点文件", + "importNodes": "导入节点", + "exportNodes": "导出节点至剪贴板", + "download": "下载", + "importUnrecognised": "导入了无法识别的类型:", + "importUnrecognised_plural": "导入了无法识别的类型:", + "importDuplicate": "导入了重复节点:", + "importDuplicate_plural": "导入了重复节点:", + "nodesExported": "节点导出到了剪贴板", + "nodesImported": "导入:", + "nodeCopied": "已复制 __count__ 个节点", + "nodeCopied_plural": "已复制 __count__ 个节点", + "groupCopied": "复制 __count__ 个组", + "groupCopied_plural": "已复制 __count__ 个groups", + "groupStyleCopied": "已复制组风格", + "invalidFlow": "无效的流程: __message__", + "recoveredNodes": "复原的节点", + "recoveredNodesInfo": "导入节点时,此流上的节点缺少有效的流ID。 它们已被添加到此流中,您可以复原或删除它们。", + "recoveredNodesNotification": "

导入的节点缺少有效的流ID

已将它们添加到名为 '__flowName__'的新流中。

", + "export": { + "selected": "已选择的节点", + "current": "当前节点", + "all": "所有流程", + "compact": "紧凑", + "formatted": "已格式化", + "copy": "导出到剪贴板", + "export": "导出到库", + "exportAs": "导出为", + "overwrite": "替换", + "exists": "

\"__file__\"已存在

是否要替换它?

" + }, + "import": { + "import": "导入到", + "importSelected": "导入所选项", + "importCopy": "导入副本", + "viewNodes": "查看节点", + "newFlow": "新流程", + "replace": "置换", + "errors": { + "notArray": "输入的不是JSON数组", + "itemNotObject": "输入的流无效 - 项目 __index__ 不是节点对象", + "missingId": "输入的流无效-项 __index__ 缺少'id'属性", + "missingType": "输入的流程无效-项 __index__ 缺少'类型'属性" + }, + "conflictNotification1": "您要导入的某些节点已经存在于工作空间中。", + "conflictNotification2": "选择要导入的节点,并确认要替换现有的节点还是导入它们的副本" + }, + "copyMessagePath": "已复制路径", + "copyMessageValue": "已复制数值", + "copyMessageValue_truncated": "已复制舍弃的数值" + }, + "deploy": { + "deploy": "部署", + "full": "全部", + "fullDesc": "在工作区中部署所有内容", + "modifiedFlows": "已修改的流程", + "modifiedFlowsDesc": "只部署包含已更改节点的流", + "modifiedNodes": "已更改的节点", + "modifiedNodesDesc": "只部署已经更改的节点", + "startFlows": "启动", + "startFlowsDesc": "启动流程", + "stopFlows": "停止", + "stopFlowsDesc": "停止流程", + "restartFlows": "重启流程", + "restartFlowsDesc": "重新启动当前部署的流程", + "successfulDeploy": "部署成功", + "successfulRestart": "成功重启流程", + "deployFailed": "部署失败: __message__", + "unusedConfigNodes": "您有一些未使用的配置节点", + "unusedConfigNodesButton": "搜索未使用的配置节点", + "unknownNodesButton": "查找未知节点", + "invalidNodesButton": "查找无效节点", + "errors": { + "noResponse": "服务器没有响应" + }, + "confirm": { + "button": { + "ignore": "忽略", + "confirm": "确认部署", + "review": "查看更改", + "cancel": "取消", + "merge": "合并", + "overwrite": "忽略 & 部署" + }, + "undeployedChanges": "您有未部署的更改。\n\n离开此页面将丢失这些更改。", + "improperlyConfigured": "工作区包含一些未正确配置的节点:", + "unknown": "工作区包含一些未知的节点类型:", + "confirm": "你确定要部署吗?", + "doNotWarn": "不要再对此发出警告", + "conflict": "服务器正在运行较新的一组流程。", + "backgroundUpdate": "服务器上的流程已更新。", + "conflictChecking": "检查是否可以自动合并更改", + "conflictAutoMerge": "此更改不包括冲突,可以自动合并", + "conflictManualMerge": "这些更改包括了在部署之前必须解决的冲突。", + "plusNMore": "+ __count__ 更多" + } + }, + "eventLog": { + "title": "事件记录日志", + "view": "查看日志" + }, + "diff": { + "unresolvedCount": "__count__个未解决的冲突", + "unresolvedCount_plural": "__count__个未解决的冲突", + "globalNodes": "全局节点", + "flowProperties": "流程属性", + "type": { + "added": "已添加", + "changed": "已更改", + "unchanged": "未更改", + "deleted": "已删除", + "flowDeleted": "已删除流程", + "flowAdded": "已添加流程", + "movedTo": "移动至__id__", + "movedFrom": "从__id__移动" + }, + "nodeCount": "__count__个节点", + "nodeCount_plural": "__count__个节点", + "local": "本地", + "remote": "远程", + "reviewChanges": "查看变更", + "noBinaryFileShowed": "无法显示二进制文件内容", + "viewCommitDiff": "查看提交更改", + "compareChanges": "比较变更", + "saveConflict": "保存冲突解决", + "conflictHeader": "已解决__unresolved__中的__resolved__个冲突", + "commonVersionError": "通用版本不包含有效的JSON:", + "oldVersionError": "旧版本不包含有效的JSON:", + "newVersionError": "新版本不包含有效的JSON:" + }, + "subflow": { + "editSubflowInstance": "编辑子流实例: __name__", + "editSubflow": "编辑流程模板: __name__", + "edit": "编辑流程模板", + "subflowInstances": "这个子流程模板有 __count__ 个实例", + "subflowInstances_plural": "这个子流程模板有 __count__ 个实例", + "editSubflowProperties": "编辑属性", + "input": "输入:", + "output": "输出:", + "status": "状态节点", + "deleteSubflow": "删除子流程", + "confirmDelete": "您确定要删除此子流程?", + "info": "详细描述", + "category": "类别", + "module": "模块", + "license": "许可", + "licenseNone": "无", + "licenseOther": "其它", + "type": "节点类型", + "version": "版本", + "versionPlaceholder": "x.y.z", + "keys": "关键字", + "keysPlaceholder": "使用英文逗号分隔关键字", + "author": "作者", + "authorPlaceholder": "名字 ", + "desc": "描述", + "env": { + "restore": "恢复为默认子流", + "remove": "删除环境变量" + }, + "errors": { + "noNodesSelected": "无法创建子流程: 未选择节点", + "multipleInputsToSelection": "无法创建子流程: 多个输入到了选择" + } + }, + "group": { + "editGroup": "编辑组: __name__", + "errors": { + "cannotCreateDiffGroups": "无法使用来自不同组的节点创建组", + "cannotAddSubflowPorts": "无法将子流程的端口添加到组" + } + }, + "editor": { + "configEdit": "编辑", + "configAdd": "添加", + "configUpdate": "更新", + "configDelete": "删除", + "nodesUse": "__count__ 个节点使用此配置", + "nodesUse_plural": "__count__ 个节点使用此配置", + "addNewConfig": "添加新的 __type__ 配置", + "editNode": "编辑 __type__ 节点", + "editConfig": "编辑 __type__ 配置", + "addNewType": "添加新的 __type__ 节点", + "nodeProperties": "节点属性", + "label": "标签", + "color": "颜色", + "portLabels": "端口标签", + "labelInputs": "输入", + "labelOutputs": "输出", + "settingIcon": "图标", + "default": "默认", + "noDefaultLabel": "无", + "defaultLabel": "使用默认标签", + "searchIcons": "搜索图标", + "useDefault": "使用默认", + "description": "描述", + "show": "显示", + "hide": "隐藏", + "locale": "选择界面语言", + "icon": "图标", + "inputType": "输入类型", + "selectType": "选择类型...", + "loadCredentials": "加载节点凭证", + "inputs": { + "input": "输入", + "select": "选择", + "checkbox": "复选框", + "spinner": "微调器", + "none": "空", + "hidden": "隐藏属性" + }, + "types": { + "str": "字符串", + "num": "数字", + "bool": "布尔", + "json": "JSON", + "bin": "buffer", + "env": "环境变量", + "cred": "证书" }, "menu": { - "label": { - "view": { - "view": "显示", - "grid": "网格", - "showGrid": "显示网格", - "snapGrid": "对齐网格", - "gridSize": "网格尺寸", - "textDir": "文本方向", - "defaultDir": "默认方向", - "ltr": "从左到右", - "rtl": "从右到左", - "auto": "上下文", - "language": "语言", - "browserDefault": "浏览器默认" - }, - "sidebar": { - "show": "显示侧边栏" - }, - "palette": { - "show": "显示控制板" - }, - "settings": "设置", - "userSettings": "用户设置", - "nodes": "节点", - "displayStatus": "显示节点状态", - "displayConfig": "修改节点配置", - "import": "导入", - "export": "导出", - "search": "查找流程", - "searchInput": "查找流程", - "subflows": "子流程", - "createSubflow": "新建子流程", - "selectionToSubflow": "将选择部分更改为子流程", - "flows": "流程", - "add": "增加", - "rename": "重命名", - "delete": "删除", - "keyboardShortcuts": "键盘快捷方式", - "login": "登录", - "logout": "退出", - "editPalette": "节点管理", - "other": "其他", - "showTips": "显示小提示", - "help": "Node-RED网页", - "projects": "项目", - "projects-new": "新建", - "projects-open": "打开", - "projects-settings": "项目设定", - "showNodeLabelDefault": "显示新添加的节点的标签", - "groups": "组", - "groupSelection": "选择组", - "ungroupSelection": "取消选择组", - "groupMergeSelection": "合并选择", - "groupRemoveSelection": "从组中移除" - } + "input": "输入", + "select": "选择", + "checkbox": "复选框", + "spinner": "微调器", + "hidden": "仅标签" + }, + "select": { + "label": "标签", + "value": "值" + }, + "spinner": { + "min": "最小值", + "max": "最大值" + }, + "errors": { + "scopeChange": "更改范围将使其他流中的节点无法使用", + "invalidProperties": "无效的属性:", + "credentialLoadFailed": "无法加载节点凭据" + } + }, + "keyboard": { + "title": "键盘快捷键", + "keyboard": "键盘", + "filterActions": "筛选动作", + "shortcut": "快捷键", + "scope": "范围", + "unassigned": "未分配", + "global": "全局", + "workspace": "工作区", + "selectAll": "选择所有节点", + "selectNone": "取消所有选择", + "selectAllConnected": "选择所有连接的节点", + "addRemoveNode": "从选择中添加/删除节点", + "editSelected": "编辑选定节点", + "deleteSelected": "删除选定节点或链接", + "importNode": "导入节点", + "exportNode": "导出节点", + "nudgeNode": "移动所选节点(1px)", + "moveNode": "移动所选节点(20px)", + "toggleSidebar": "切换侧边栏", + "togglePalette": "切换控制板", + "copyNode": "复制所选节点", + "cutNode": "剪切所选节点", + "pasteNode": "粘贴节点", + "copyGroupStyle": "复制组样式", + "pasteGroupStyle": "粘贴组样式", + "undoChange": "撤消", + "redoChange": "重做", + "searchBox": "打开搜索框", + "managePalette": "管理面板", + "actionList": "动作列表", + "splitWireWithLinks": "使用Link节点拆分已选项" + }, + "library": { + "library": "库", + "openLibrary": "打开库...", + "saveToLibrary": "保存到库...", + "typeLibrary": "__type__类型库", + "unnamedType": "无名__type__", + "exportedToLibrary": "节点导出到库", + "dialogSaveOverwrite": "一个叫做__libraryName__的__libraryType__已经存在,您需要覆盖么?", + "invalidFilename": "无效的文件名", + "savedNodes": "保存的节点", + "savedType": "已保存__type__", + "saveFailed": "保存失败: __message__", + "newFolder": "新文件夹", + "types": { + "local": "本地存储", + "examples": "示例" + } + }, + "palette": { + "noInfo": "无可用信息", + "filter": "过滤已安装模块", + "search": "搜索模块", + "addCategory": "添加新的...", + "label": { + "subflows": "子流程", + "network": "网络", + "common": "通用", + "input": "输入", + "output": "输出", + "function": "功能", + "sequence": "序列化", + "parser": "解析", + "social": "社交", + "storage": "存储", + "analysis": "分析", + "advanced": "高级" }, "actions": { - "toggle-navigator": "切换导航器", - "zoom-out": "缩小", - "zoom-reset": "重设缩放", - "zoom-in": "放大" + "collapse-all": "收起所有类别", + "expand-all": "展开所有类别" }, - "user": { - "loggedInAs": "作为 __name__ 登录", - "username": "账号", - "password": "密码", - "login": "登录", - "loginFailed": "登录失败", - "notAuthorized": "未授权", - "errors": { - "settings": "设置信息需要登录后才能访问", - "deploy": "改动需要登录后才能部署", - "notAuthorized": "此操作需要登录后才能执行" - } - }, - "notification": { - "warning": "警告: __message__", - "warnings": { - "undeployedChanges": "节点中存在未部署的更改", - "nodeActionDisabled": "节点操作已禁用", - "nodeActionDisabledSubflow": "节点动作在子流程中被禁用", - "missing-types": "流程由于缺少节点类型而停止。请检查日志的详细信息", - "safe-mode": "

流程以安全模式停止。

您可以修改流程并部署更改以重新启动。

", - "restartRequired": "Node-RED必须重新启动,以启用升级的模块", - "credentials_load_failed": "

由于无法解密凭据,因此流程停止。

流程凭据文件已加密,但是项目的加密密钥丢失或无效。

", - "credentials_load_failed_reset": "

凭据无法解密

流凭据文件已加密,但是项目的加密密钥丢失或无效。

流凭据文件将在下一次部署时重置。任何现有的流凭证将被清除。

", - "missing_flow_file": "

找不到项目流程文件。

该项目未配置流程文件。

", - "missing_package_file": "

找不到项目包文件。

项目缺少package.json文件。

", - "project_empty": "

该项目为空。

是否要创建一组默认的项目文件?
否则,您将必须在编辑器外部手动将文件添加到项目中。

", - "project_not_found": "

未找到项目 __project__ 。

", - "git_merge_conflict": "

自动合并更改失败。

修复未合并的冲突,然后提交结果。

" - }, - "error": "错误: __message__", - "errors": { - "lostConnection": "丢失与服务器的连接,重新连接...", - "lostConnectionReconnect": "丢失与服务器的连接, __time__ 秒后重新连接", - "lostConnectionTry": "现在尝试", - "cannotAddSubflowToItself": "无法向其自身添加子流程", - "cannotAddCircularReference": "无法添加子流程 - 循环引用", - "unsupportedVersion": "您正在使用不受支持的Node.js版本
请升级到最新版本的Node.js LTS", - "failedToAppendNode": "

'__module__'加载失败

__error__

" - }, - "project": { - "change-branch": "转到本地分支'__project__'", - "merge-abort": "Git合并中止", - "loaded": "项目'__project__'已加载", - "updated": "项目'__project__'已更新", - "pull": "项目'__project__'已重新加载", - "revert": "项目 '__project__'已还原", - "merge-complete": "Git合并完成", - "setupCredentials": "设定证书", - "setupProjectFiles": "设置项目文件", - "no": "不了,谢谢", - "createDefault": "创建默认项目文件", - "mergeConflict": "显示合并冲突" - }, - "label": { - "manage-project-dep": "管理项目依赖性", - "setup-cred": "设定证书", - "setup-project": "设置项目文件", - "create-default-package": "创建默认的包文件", - "no-thanks": "不了,谢谢", - "create-default-project": "创建默认项目文件", - "show-merge-conflicts": "显示合并冲突", - "unknownNodesButton": "搜索未知节点" - } - }, - "clipboard": { - "clipboard": "剪贴板", - "nodes": "节点", - "node": "__count__ 个节点", - "node_plural": "__count__ 个节点", - "configNode": "__count__ 个配置节点", - "configNode_plural": "__count__ 个配置节点", - "group": "__count__ 个组", - "group_plural": "__count__ 个组", - "flow": "__count__ 个流程", - "flow_plural": "__count__ 个流程", - "subflow": "__count__ 个子流程", - "subflow_plural": "__count__ 子流程", - "replacedNodes": "__count__ 个节点被置换", - "replacedNodes_plural": "__count__ 个节点被置换", - "pasteNodes": "在这里粘贴节点", - "selectFile": "选择要导入的文件", - "importNodes": "导入节点", - "exportNodes": "导出节点至剪贴板", - "download": "下载", - "importUnrecognised": "导入了无法识别的类型:", - "importUnrecognised_plural": "导入了无法识别的类型:", - "nodesExported": "节点导出到了剪贴板", - "nodesImported": "导入:", - "nodeCopied": "已复制 __count__ 个节点", - "nodeCopied_plural": "已复制 __count__ 个节点", - "groupCopied": "复制 __count__ 个组", - "groupCopied_plural": "已复制 __count__ 个groups", - "groupStyleCopied": "已复制组风格", - "invalidFlow": "无效的流程: __message__", - "recoveredNodes": "复原的节点", - "recoveredNodesInfo": "导入节点时,此流上的节点缺少有效的流ID。 它们已被添加到此流中,您可以复原或删除它们。", - "recoveredNodesNotification": "

导入的节点缺少有效的流ID

已将它们添加到名为 '__flowName__'的新流中。

", - "export": { - "selected": "已选择的节点", - "current": "现在的节点", - "all": "所有流程", - "compact": "紧凑", - "formatted": "已格式化", - "copy": "导出到剪贴板", - "export": "导出到库", - "exportAs": "导出为", - "overwrite": "替换", - "exists": "

\"__file__\"已存在

是否要替换它?

" - }, - "import": { - "import": "导入到", - "importSelected": "导入所选项", - "importCopy": "导入副本", - "viewNodes": "查看节点", - "newFlow": "新流程", - "replace": "置换", - "errors": { - "notArray": "输入的不是JSON数组", - "itemNotObject": "输入的流无效 - 项目 __index__ 不是节点对象", - "missingId": "输入的流无效-项 __index__ 缺少'id'属性", - "missingType": "输入的流程无效-项 __index__ 缺少'类型'属性" - }, - "conflictNotification1": "您要导入的某些节点已经存在于工作空间中。", - "conflictNotification2": "选择要导入的节点,并确认要替换现有的节点还是导入它们的副本" - }, - "copyMessagePath": "已复制路径", - "copyMessageValue": "已复制数值", - "copyMessageValue_truncated": "已复制舍弃的数值" - }, - "deploy": { - "deploy": "部署", - "full": "全面", - "fullDesc": "在工作区中部署所有内容", - "modifiedFlows": "已修改的流程", - "modifiedFlowsDesc": "只部署包含已更改节点的流", - "modifiedNodes": "已更改的节点", - "modifiedNodesDesc": "只部署已经更改的节点", - "restartFlows": "重启流程", - "restartFlowsDesc": "重新启动当前部署的流程", - "successfulDeploy": "部署成功", - "successfulRestart": "成功重启流程", - "deployFailed": "部署失败: __message__", - "unusedConfigNodes": "您有一些未使用的配置节点", - "unusedConfigNodesButton":"搜索未使用的配置节点", - "unknownNodesButton":"搜索未知节点", - "invalidNodesButton":"搜索无效节点", - "errors": { - "noResponse": "服务器没有响应" - }, - "confirm": { - "button": { - "ignore": "忽略", - "confirm": "确认部署", - "review": "查看更改", - "cancel": "取消", - "merge": "合并", - "overwrite": "忽略 & 部署" - }, - "undeployedChanges": "您有未部署的更改。\n\n离开此页面将丢失这些更改。", - "improperlyConfigured": "工作区包含一些未正确配置的节点:", - "unknown": "工作区包含一些未知的节点类型:", - "confirm": "你确定要部署吗?", - "doNotWarn": "不要再对此发出警告", - "conflict": "服务器正在运行较新的一组流程。", - "backgroundUpdate": "服务器上的流程已更新。", - "conflictChecking": "检查是否可以自动合并更改", - "conflictAutoMerge": "此更改不包括冲突,可以自动合并", - "conflictManualMerge": "这些更改包括了在部署之前必须解决的冲突。", - "plusNMore": "+ __count__ 更多" - } - }, - "eventLog": { - "title": "事件记录日志", - "view": "查看日志" - }, - "diff": { - "unresolvedCount": "__count__个未解决的冲突", - "unresolvedCount_plural": "__count__个未解决的冲突", - "globalNodes": "全局节点", - "flowProperties": "流程属性", - "type": { - "added": "已添加", - "changed": "已更改", - "unchanged": "未更改", - "deleted": "已删除", - "flowDeleted": "已删除流程", - "flowAdded": "已添加流程", - "movedTo": "移动至__id__", - "movedFrom": "从__id__移动" - }, - "nodeCount": "__count__个节点", - "nodeCount_plural": "__count__个节点", - "local": "本地", - "remote": "远程", - "reviewChanges": "查看变更", - "noBinaryFileShowed": "无法显示二进制文件内容", - "viewCommitDiff": "查看提交更改", - "compareChanges": "比较变更", - "saveConflict": "保存冲突解决", - "conflictHeader": "已解决__unresolved__中的__resolved__个冲突", - "commonVersionError": "通用版本不包含有效的JSON:", - "oldVersionError": "旧版本不包含有效的JSON:", - "newVersionError": "新版本不包含有效的JSON:" - }, - "subflow": { - "editSubflowInstance": "编辑子流实例: __name__", - "editSubflow": "编辑流程模板: __name__", - "edit": "编辑流程模板", - "subflowInstances": "这个子流程模板有 __count__ 个实例", - "subflowInstances_plural": "这个子流程模板有 __count__ 个实例", - "editSubflowProperties": "编辑属性", - "input": "输入:", - "output": "输出:", - "status": "状态节点", - "deleteSubflow": "删除子流程", - "info": "详细描述", - "category": "类别", - "env": { - "restore": "恢复为默认子流", - "remove": "删除环境变量" - }, - "errors": { - "noNodesSelected": "无法创建子流程: 未选择节点", - "multipleInputsToSelection": "无法创建子流程: 多个输入到了选择" - } - }, - "group": { - "editGroup": "编辑组: __name__", - "errors": { - "cannotCreateDiffGroups": "无法使用来自不同组的节点创建组", - "cannotAddSubflowPorts": "无法将子流程的端口添加到组" - } + "event": { + "nodeAdded": "添加到面板中的节点:", + "nodeAdded_plural": "添加到面板中的多个节点", + "nodeRemoved": "从面板中删除的节点:", + "nodeRemoved_plural": "从面板中删除的多个节点:", + "nodeEnabled": "启用节点:", + "nodeEnabled_plural": "启用多个节点:", + "nodeDisabled": "禁用节点:", + "nodeDisabled_plural": "禁用多个节点:", + "nodeUpgraded": "节点模块__module__升级到__version__版本", + "unknownNodeRegistered": "加载节点错误:
  • __type__
    __error__
" }, "editor": { - "configEdit": "编辑", - "configAdd": "添加", - "configUpdate": "更新", - "configDelete": "删除", - "nodesUse": "__count__ 个节点使用此配置", - "nodesUse_plural": "__count__ 个节点使用此配置", - "addNewConfig": "添加新的 __type__ 配置", - "editNode": "编辑 __type__ 节点", - "editConfig": "编辑 __type__ 配置", - "addNewType": "添加新的 __type__ 节点", - "nodeProperties": "节点属性", - "label": "标签", - "color": "颜色", - "portLabels": "端口标签", - "labelInputs": "输入", - "labelOutputs": "输出", - "settingIcon": "图标", - "default": "默认", - "noDefaultLabel": "无", - "defaultLabel": "使用默认标签", - "searchIcons": "搜索图标", - "useDefault": "使用默认", - "description": "描述", - "show": "显示", - "hide": "隐藏", - "locale": "选择界面语言", - "icon": "图标", - "inputType": "输入类型", - "selectType": "选择类型...", - "inputs": { - "input": "输入", - "select": "选择", - "checkbox": "复选框", - "spinner": "微调器", - "none": "空", - "hidden": "隐藏属性" + "title": "面板管理", + "palette": "控制板", + "times": { + "seconds": "秒前", + "minutes": "分前", + "minutesV": "__count__ 分前", + "hoursV": "__count__ 小时前", + "hoursV_plural": "__count__ 小时前", + "daysV": "__count__ 天前", + "daysV_plural": "__count__ 天前", + "weeksV": "__count__ 周前", + "weeksV_plural": "__count__ 周前", + "monthsV": "__count__ 月前", + "monthsV_plural": "__count__ 月前", + "yearsV": "__count__ 年前", + "yearsV_plural": "__count__ 年前", + "yearMonthsV": "__y__ 年, __count__ 月前", + "yearMonthsV_plural": "__y__ 年, __count__ 月前", + "yearsMonthsV": "__y__ 年, __count__ 月前", + "yearsMonthsV_plural": "__y__ 年, __count__ 月前" + }, + "nodeCount": "__label__ 个节点", + "nodeCount_plural": "__label__ 个节点", + "moduleCount": "__count__ 个可用模块", + "moduleCount_plural": "__count__ 个可用模块", + "inuse": "使用中", + "enableall": "全部启用", + "disableall": "全部禁用", + "enable": "启用", + "disable": "禁用", + "remove": "移除", + "update": "更新至 __version__ 版本", + "updated": "已更新", + "install": "安装", + "installed": "已安装", + "conflict": "冲突", + "conflictTip": "

无法安装此模块,因为它包含已安装的
节点类型

__module__冲突

", + "loading": "加载目录...", + "tab-nodes": "节点", + "tab-install": "安装", + "sort": "排序:", + "sortAZ": "a-z顺序", + "sortRecent": "日期顺序", + "more": "增加 __count__ 个", + "upload": "上传模块tgz文件", + "refresh": "更新模块列表", + "errors": { + "catalogLoadFailed": "无法加载节点目录。
查看浏览器控制台了解更多信息", + "installFailed": "无法安装: __module__
__message__
查看日志了解更多信息", + "removeFailed": "无法删除: __module__
__message__
查看日志了解更多信息", + "updateFailed": "无法更新: __module__
__message__
查看日志了解更多信息", + "enableFailed": "无法启用: __module__
__message__
查看日志了解更多信息", + "disableFailed": "无法禁用: __module__
__message__
查看日志了解更多信息" + }, + "confirm": { + "install": { + "body": "在安装之前,请阅读节点的文档,某些节点的依赖关系不能自动解决,可能需要重新启动Node-RED。", + "title": "安装节点" }, - "types": { - "str": "字符串", - "num": "数字", - "bool": "布尔", - "json": "JSON", - "bin": "buffer", - "env": "环境变量", - "cred": "证书" + "remove": { + "body": "删除节点将从Node-RED卸载它。节点可能会继续使用资源,直到重新启动Node-RED。", + "title": "删除节点" }, - "menu": { - "input": "输入", - "select": "选择", - "checkbox": "复选框", - "spinner": "微调器", - "hidden": "仅标签" + "update": { + "body": "更新节点将需要重新启动Node-RED来完成更新,该过程必须由手动完成。", + "title": "更新节点" }, - "select": { - "label": "标签", - "value": "值" + "cannotUpdate": { + "body": "此节点的更新可用,但不会安装在面板管理器可以更新的位置。

请参阅有关如何更新此节点的文档。" }, - "spinner": { - "min": "最小值", - "max": "最大值" - }, - "errors": { - "scopeChange": "更改范围将使其他流中的节点无法使用", - "invalidProperties": "无效的属性:" + "button": { + "review": "打开节点信息", + "install": "安装", + "remove": "删除", + "update": "更新" } + } + } + }, + "sidebar": { + "info": { + "name": "节点信息", + "tabName": "名称", + "label": "信息", + "node": "节点", + "type": "类型", + "group": "组", + "module": "模组", + "id": "ID", + "status": "状态", + "enabled": "启用", + "disabled": "禁用", + "subflow": "子流程", + "instances": "实例", + "properties": "属性", + "info": "信息", + "desc": "描述", + "blank": "空白", + "null": "空", + "showMore": "展开", + "showLess": "收起", + "flow": "流程", + "selection": "选择", + "nodes": "__count__ 个节点", + "flowDesc": "流程描述", + "subflowDesc": "子流程描述", + "nodeHelp": "节点帮助", + "none": "无", + "arrayItems": "__count__ 个项目", + "showTips": "您可以从设置面板启用提示信息", + "outline": "大纲", + "empty": "空的", + "globalConfig": "全局配置节点", + "triggerAction": "触发动作", + "find": "在工作区中查找" }, - "keyboard": { - "title": "键盘快捷键", - "keyboard": "键盘", - "filterActions": "筛选动作", - "shortcut": "快捷键", - "scope": "范围", - "unassigned": "未分配", - "global": "全局", - "workspace": "工作区", - "selectAll": "选择所有节点", - "selectAllConnected": "选择所有连接的节点", - "addRemoveNode": "从选择中添加/删除节点", - "editSelected": "编辑选定节点", - "deleteSelected": "删除选定节点或链接", - "importNode": "导入节点", - "exportNode": "导出节点", - "nudgeNode": "移动所选节点(1px)", - "moveNode": "移动所选节点(20px)", - "toggleSidebar": "切换侧边栏", - "togglePalette": "切换控制板", - "copyNode": "复制所选节点", - "cutNode": "剪切所选节点", - "pasteNode": "粘贴节点", - "undoChange": "撤消上次执行的更改", - "searchBox": "打开搜索框", - "managePalette": "管理面板", - "actionList": "动作列表" + "help": { + "name": "帮助", + "label": "帮助", + "search": "搜索帮助", + "nodeHelp": "节点帮助", + "showHelp": "显示帮助", + "showInOutline": "在大纲中显示", + "showTopics": "显示主题", + "noHelp": "未选择帮助主题", + "changeLog": "更新日志" }, - "library": { - "library": "库", - "openLibrary": "打开库...", - "saveToLibrary": "保存到库...", - "typeLibrary": "__type__类型库", - "unnamedType": "无名__type__", - "exportedToLibrary": "节点导出到库", - "dialogSaveOverwrite": "一个叫做__libraryName__的__libraryType__已经存在,您需要覆盖么?", - "invalidFilename": "无效的文件名", - "savedNodes": "保存的节点", - "savedType": "已保存__type__", - "saveFailed": "保存失败: __message__", - "newFolder": "新文件夹", - "types": { - "local": "本地的", - "examples": "例子" - }, - "exportToLibrary": "将节点导出到库" + "config": { + "name": "配置节点", + "label": "配置", + "global": "所有流程", + "none": "无", + "subflows": "子流程", + "flows": "流程", + "filterAll": "所有", + "showAllConfigNodes": "显示所有配置节点", + "filterUnused": "未使用", + "showAllUnusedConfigNodes": "显示所有未使用的配置节点", + "filtered": "__count__ 个隐藏" + }, + "context": { + "name": "上下文数据", + "label": "上下文", + "none": "未选择", + "refresh": "刷新以加载", + "empty": "空", + "node": "节点", + "flow": "流程", + "global": "全局", + "deleteConfirm": "确定要删除这个项目吗?", + "autoRefresh": "刷新选择更改", + "refrsh": "刷新", + "delete": "删除" }, "palette": { - "noInfo": "无可用信息", - "filter": "过滤节点", - "search": "搜索模块", - "addCategory": "添加新的...", - "label": { - "subflows": "子流程", - "network": "网络", - "common": "共通", - "input": "输入", - "output": "输出", - "function": "功能", - "sequence": "序列", - "parser": "解析", - "social": "社交", - "storage": "存储", - "analysis": "分析", - "advanced": "高级" - }, - "actions": { - "collapse-all": "收起所有类别", - "expand-all": "展开所有类别" - }, - "event": { - "nodeAdded": "添加到面板中的节点:", - "nodeAdded_plural": "添加到面板中的多个节点", - "nodeRemoved": "从面板中删除的节点:", - "nodeRemoved_plural": "从面板中删除的多个节点:", - "nodeEnabled": "启用节点:", - "nodeEnabled_plural": "启用多个节点:", - "nodeDisabled": "禁用节点:", - "nodeDisabled_plural": "禁用多个节点:", - "nodeUpgraded": "节点模块__module__升级到__version__版本" - }, - "editor": { - "title": "面板管理", - "palette": "控制板", - "times": { - "seconds": "秒前", - "minutes": "分前", - "minutesV": "__count__ 分前", - "hoursV": "__count__ 小时前", - "hoursV_plural": "__count__ 小时前", - "daysV": "__count__ 天前", - "daysV_plural": "__count__ 天前", - "weeksV": "__count__ 周前", - "weeksV_plural": "__count__ 周前", - "monthsV": "__count__ 月前", - "monthsV_plural": "__count__ 月前", - "yearsV": "__count__ 年前", - "yearsV_plural": "__count__ 年前", - "yearMonthsV": "__y__ 年, __count__ 月前", - "yearMonthsV_plural": "__y__ 年, __count__ 月前", - "yearsMonthsV": "__y__ 年, __count__ 月前", - "yearsMonthsV_plural": "__y__ 年, __count__ 月前" - }, - "nodeCount": "__label__ 个节点", - "nodeCount_plural": "__label__ 个节点", - "moduleCount": "__count__ 个可用模块", - "moduleCount_plural": "__count__ 个可用模块", - "inuse": "使用中", - "enableall": "全部启用", - "disableall": "全部禁用", - "enable": "启用", - "disable": "禁用", - "remove": "移除", - "update": "更新至 __version__ 版本", - "updated": "已更新", - "install": "安装", - "installed": "已安装", - "conflict": "冲突", - "conflictTip": "

无法安装此模块,因为它包含已安装的
节点类型

__module__冲突

", - "loading": "加载目录...", - "tab-nodes": "节点", - "tab-install": "安装", - "sort": "排序:", - "sortAZ": "a-z顺序", - "sortRecent": "日期顺序", - "more": "增加 __count__ 个", - "upload": "上传模块tgz文件", - "errors": { - "catalogLoadFailed": "无法加载节点目录。
查看浏览器控制台了解更多信息", - "installFailed": "无法安装: __module__
__message__
查看日志了解更多信息", - "removeFailed": "无法删除: __module__
__message__
查看日志了解更多信息", - "updateFailed": "无法更新: __module__
__message__
查看日志了解更多信息", - "enableFailed": "无法启用: __module__
__message__
查看日志了解更多信息", - "disableFailed": "无法禁用: __module__
__message__
查看日志了解更多信息" - }, - "confirm": { - "install": { - "body": "在安装之前,请阅读节点的文档,某些节点的依赖关系不能自动解决,可能需要重新启动Node-RED。", - "title": "安装节点" - }, - "remove": { - "body": "删除节点将从Node-RED卸载它。节点可能会继续使用资源,直到重新启动Node-RED。", - "title": "删除节点" - }, - "update": { - "body": "更新节点将需要重新启动Node-RED来完成更新,该过程必须由手动完成。", - "title": "更新节点" - }, - "cannotUpdate": { - "body": "此节点的更新可用,但不会安装在面板管理器可以更新的位置。

请参阅有关如何更新此节点的文档。" - }, - "button": { - "review": "打开节点信息", - "install": "安装", - "remove": "删除", - "update": "更新" - } - } - } + "name": "模块管理", + "label": "模块" }, - "sidebar": { - "info": { - "name": "节点信息", - "tabName": "名称", - "label": "信息", - "node": "节点", - "type": "类型", - "group": "组", - "module": "模组", - "id": "ID", - "status": "状态", - "enabled": "启用", - "disabled": "禁用", - "subflow": "子流程", - "instances": "实例", - "properties": "属性", - "info": "信息", - "desc": "描述", - "blank": "空白", - "null": "空", - "showMore": "展开", - "showLess": "收起", - "flow": "流程", - "selection": "选择", - "nodes": "__count__ 个节点", - "flowDesc": "流程描述", - "subflowDesc": "子流程描述", - "nodeHelp": "节点帮助", - "none": "无", - "arrayItems": "__count__ 个项目", - "showTips": "您可以从设置面板启用提示信息", - "outline": "大纲", - "empty": "空的", - "globalConfig": "全局配置节点", - "triggerAction": "触发动作", - "find": "在工作区中查找" - }, - "help": { - "name": "帮助", - "label": "帮助", - "search": "搜索帮助", - "nodeHelp": "节点帮助", - "showHelp": "显示帮助", - "showInOutline": "在大纲中显示", - "showTopics": "显示主题", - "noHelp": "未选择帮助主题" - }, - "config": { - "name": "配置节点", - "label": "配置", - "global": "所有流程", - "none": "无", - "subflows": "子流程", - "flows": "流程", - "filterAll": "所有", - "showAllConfigNodes": "显示所有配置节点", - "filterUnused": "未使用", - "showAllUnusedConfigNodes": "显示所有未使用的配置节点", - "filtered": "__count__ 个隐藏" - }, - "context": { - "name": "上下文数据", - "label": "上下文", - "none": "未选择", - "refresh": "刷新以加载", - "empty": "空", - "node": "节点", - "flow": "流程", - "global": "全局", - "deleteConfirm": "你确定要删除这个项目吗?", - "autoRefresh": "刷新选择更改", - "refrsh": "刷新", - "delete": "删除" - }, - "palette": { - "name": "节点管理", - "label": "节点" - }, - "project": { - "label": "项目", - "name": "项目", - "description": "描述", - "dependencies": "依赖", - "settings": "设置", - "noSummaryAvailable": "无可用摘要", - "editDescription": "编辑项目描述", - "editDependencies": "编辑项目依赖", - "noDescriptionAvailable": "没有可用的描述", - "editReadme": "编辑README.md", - "showProjectSettings": "显示项目设置", - "projectSettings": { - "title": "项目设置", - "edit": "编辑", - "none": "空", - "install": "安装", - "removeFromProject": "从项目中删除", - "addToProject": "添加到项目", - "files": "文件", - "flow": "流程", - "credentials": "证书", - "package": "包", - "packageCreate": "保存更改后将创建文件", - "fileNotExist": "文件不存在", - "selectFile": "选择文件", - "invalidEncryptionKey": "无效的加密密钥", - "encryptionEnabled": "启用加密", - "encryptionDisabled": "加密已禁用", - "setTheEncryptionKey": "设置加密密钥", - "resetTheEncryptionKey": "重置加密密钥", - "changeTheEncryptionKey": "更改加密密钥", - "currentKey": "当前密钥", - "newKey": "新密钥", - "credentialsAlert": "这将删除所有现有证书", - "versionControl": "版本控制", - "branches": "分支", - "noBranches": "没有分支", - "deleteConfirm": "您确定要删除本地分支'__name__'吗? 这不能被撤消。", - "unmergedConfirm": "本地分支'__name__'具有未合并的更改,这些更改将丢失。你确定要删除吗?", - "deleteUnmergedBranch": "删除未合并的分支", - "gitRemotes": "Git远程仓库", - "addRemote": "添加远程仓库", - "addRemote2": "添加远程仓库", - "remoteName": "远程仓库名", - "nameRule": "只能包含A-Z 0-9 _ -", - "url": "URL", - "urlRule": "https://, ssh:// or file://", - "urlRule2": "网址中不能包含用户名/密码", - "noRemotes": "没有远程仓库", - "deleteRemoteConfrim": "您确定要删除远程仓库'__name__'吗?", - "deleteRemote": "删除远程仓库" - }, - "userSettings": { - "committerDetail": "提交者详细信息", - "committerTip": "保留空白以使用系统默认值", - "userName": "用户名", - "email": "电子邮件", - "workflow": "工作流", - "workfowTip": "选择您偏好的工作流", - "workflowManual": "手动", - "workflowManualTip": "所有更改都必须在“历史记录”侧边栏中手动提交", - "workflowAuto": "自动", - "workflowAutoTip": "每次部署后都会自动提交更改", - "sshKeys": "SSH密钥", - "sshKeysTip": "允许您创建到远程git存储库的安全连接。", - "add": "添加密钥", - "addSshKey": "添加SSH密钥", - "addSshKeyTip": "生成新的公钥/私钥对", - "name": "名字", - "nameRule": "只能包含A-Z 0-9 _ -", - "passphrase": "密码短语", - "passphraseShort": "密码短语过短", - "optional": "可选的", - "cancel": "取消", - "generate": "生成密钥", - "noSshKeys": "没有SSH密钥", - "copyPublicKey": "将公钥复制到剪贴板", - "delete": "删除密钥", - "gitConfig": "Git配置", - "deleteConfirm": "您确定要删除SSH密钥 __name__ 吗?这不能被撤消。" - }, - "versionControl": { - "unstagedChanges": "未暂存的变更", - "stagedChanges": "暂存的变更", - "unstageChange": "取消变更的暂存", - "stageChange": "暂存变更", - "unstageAllChange": "取消所有变更的暂存", - "stageAllChange": "暂存所有变更", - "commitChanges": "提交变更", - "resolveConflicts": "解决冲突", - "head": "HEAD", - "staged": "暂存的", - "unstaged": "未暂存的", - "local": "本地的", - "remote": "远程的", - "revert": "您确定要将更改恢复为'__file__'吗?这不能被撤消。", - "revertChanges": "还原变更", - "localChanges": "本地变更", - "none": "None", - "conflictResolve": "解决所有冲突。提交更改以完成合并。", - "localFiles": "本地文件", - "all": "所有的", - "unmergedChanges": "未合并的更改", - "abortMerge": "中止合并", - "commit": "提交", - "changeToCommit": "提交变更", - "commitPlaceholder": "输入您的提交信息", - "cancelCapital": "取消", - "commitCapital": "提交", - "commitHistory": "提交历史", - "branch": "分支:", - "moreCommits": "更多提交", - "changeLocalBranch": "变更本地分支", - "createBranchPlaceholder": "查找或创建分支", - "upstream": "上游", - "localOverwrite": "切换分支会覆盖您现有的本地更改。您必须先提交或撤消那些更改。", - "manageRemoteBranch": "管理远程分支", - "unableToAccess": "无法访问远程存储库", - "retry": "重试", - "setUpstreamBranch": "设置为上游分支", - "createRemoteBranchPlaceholder": "查找或创建远程分支", - "trackedUpstreamBranch": "创建的分支将被设置为跟踪的上游分支。", - "selectUpstreamBranch": "分支将被创建。 在下面选择以将其设置为被跟踪的上游分支。", - "pushFailed": "推送失败,因为远程具有更多的最新提交。请先拉取并合并,然后再尝试推送。", - "push": "推送", - "pull": "拉取", - "unablePull": "

无法提取远程更改;您未暂存的本地更改将被覆盖。

请先提交更改,然后重试。

", - "showUnstagedChanges": "显示未暂存的更改", - "connectionFailed": "无法连接到远程存储库:", - "pullUnrelatedHistory": "

远程有无关的提交历史

您确定要将这些更改拉入本地仓库吗?

", - "pullChanges": "拉取更改", - "history": "历史", - "projectHistory": "项目历史", - "daysAgo": "__count__ 天前", - "daysAgo_plural": "__count__ 天前", - "hoursAgo": "__count__ 小时前", - "hoursAgo_plural": "__count__ 小时前", - "minsAgo": "__count__ 分钟前", - "minsAgo_plural": "__count__ 分钟前", - "secondsAgo": "秒前", - "notTracking": "您的本地分支当前未跟踪一个远程分支。", - "statusUnmergedChanged": "您的仓库中有未合并的更改。您需要解决冲突并提交结果。", - "repositoryUpToDate": "您的仓库是最新的。", - "commitsAhead": "您的存储库领先远程仓库 __count__ 次提交。您现在可以推送这些提交。", - "commitsAhead_plural": "您的存储库领先远程仓库 __count__ 次提交。您现在可以推送这些提交。", - "commitsBehind": "您的存储库落后远程仓库 __count__ 次提交。您现在可以拉取这些提交。", - "commitsBehind_plural": "您的存储库落后远程仓库 __count__ 次提交。您现在可以拉取这些提交。", - "commitsAheadAndBehind1": "您的存储库落后远程仓库 __count__ 次提交", - "commitsAheadAndBehind1_plural": "您的存储库落后远程仓库 __count__ 次提交", - "commitsAheadAndBehind2": "领先远程仓库 __count__ 次提交。", - "commitsAheadAndBehind2_plural": "领先远程仓库 __count__ 次提交。", - "commitsAheadAndBehind3": "您必须先拉取远程提交,然后才能进行推送。", - "commitsAheadAndBehind3_plural": "您必须先拉取远程提交,然后才能进行推送。", - "refreshCommitHistory": "刷新提交历史", - "refreshChanges": "刷新更改" - } - } + "project": { + "label": "项目", + "name": "项目", + "description": "描述", + "dependencies": "依赖", + "settings": "设置", + "noSummaryAvailable": "无可用摘要", + "editDescription": "编辑项目描述", + "editDependencies": "编辑项目依赖", + "noDescriptionAvailable": "没有可用的描述", + "editReadme": "编辑README.md", + "showProjectSettings": "显示项目设置", + "projectSettings": { + "title": "项目设置", + "edit": "编辑", + "none": "空", + "install": "安装", + "removeFromProject": "从项目中删除", + "addToProject": "添加到项目", + "files": "文件", + "flow": "流程", + "credentials": "证书", + "package": "包", + "packageCreate": "保存更改后将创建文件", + "fileNotExist": "文件不存在", + "selectFile": "选择文件", + "invalidEncryptionKey": "无效的加密密钥", + "encryptionEnabled": "启用加密", + "encryptionDisabled": "加密已禁用", + "setTheEncryptionKey": "设置加密密钥", + "resetTheEncryptionKey": "重置加密密钥", + "changeTheEncryptionKey": "更改加密密钥", + "currentKey": "当前密钥", + "newKey": "新密钥", + "credentialsAlert": "将删除所有现有证书", + "versionControl": "版本控制", + "branches": "分支", + "noBranches": "没有分支", + "deleteConfirm": "您确定要删除本地分支'__name__'吗? 这不能被撤消。", + "unmergedConfirm": "本地分支'__name__'具有未合并的更改,这些更改将丢失。你确定要删除吗?", + "deleteUnmergedBranch": "删除未合并的分支", + "gitRemotes": "Git远程仓库", + "addRemote": "添加远程仓库", + "addRemote2": "添加远程仓库", + "remoteName": "远程仓库名", + "nameRule": "只能包含A-Z 0-9 _ -", + "url": "URL", + "urlRule": "https://, ssh:// 或 file://", + "urlRule2": "网址中不能包含用户名/密码", + "noRemotes": "没有远程仓库", + "deleteRemoteConfrim": "您确定要删除远程仓库'__name__'吗?", + "deleteRemote": "删除远程仓库" + }, + "userSettings": { + "committerDetail": "提交者详细信息", + "committerTip": "保留空白以使用系统默认值", + "userName": "用户名", + "email": "电子邮件", + "workflow": "工作流", + "workfowTip": "选择您偏好的工作流", + "workflowManual": "手动", + "workflowManualTip": "所有更改都必须在“历史记录”侧边栏中手动提交", + "workflowAuto": "自动", + "workflowAutoTip": "每次部署后都会自动提交更改", + "sshKeys": "SSH密钥", + "sshKeysTip": "允许您创建到远程git存储库的安全连接。", + "add": "添加密钥", + "addSshKey": "添加SSH密钥", + "addSshKeyTip": "生成新的公钥/私钥对", + "name": "名字", + "nameRule": "只能包含A-Z 0-9 _ -", + "passphrase": "密码短语", + "passphraseShort": "密码短语过短", + "optional": "可选的", + "cancel": "取消", + "generate": "生成密钥", + "noSshKeys": "没有SSH密钥", + "copyPublicKey": "将公钥复制到剪贴板", + "delete": "删除密钥", + "gitConfig": "Git配置", + "deleteConfirm": "您确定要删除SSH密钥 __name__ 吗?这不能被撤消。" + }, + "versionControl": { + "unstagedChanges": "未暂存的变更", + "stagedChanges": "暂存的变更", + "unstageChange": "取消变更的暂存", + "stageChange": "暂存变更", + "unstageAllChange": "取消所有变更的暂存", + "stageAllChange": "暂存所有变更", + "commitChanges": "提交变更", + "resolveConflicts": "解决冲突", + "head": "HEAD", + "staged": "暂存的", + "unstaged": "未暂存的", + "local": "本地的", + "remote": "远程的", + "revert": "您确定要将更改恢复为'__file__'吗?这不能被撤消。", + "revertChanges": "还原变更", + "localChanges": "本地变更", + "none": "None", + "conflictResolve": "解决所有冲突。提交更改以完成合并。", + "localFiles": "本地文件", + "all": "所有的", + "unmergedChanges": "未合并的更改", + "abortMerge": "中止合并", + "commit": "提交", + "changeToCommit": "提交变更", + "commitPlaceholder": "输入您的提交信息", + "cancelCapital": "取消", + "commitCapital": "提交", + "commitHistory": "提交历史", + "branch": "分支:", + "moreCommits": "更多提交", + "changeLocalBranch": "变更本地分支", + "createBranchPlaceholder": "查找或创建分支", + "upstream": "上游", + "localOverwrite": "切换分支会覆盖您现有的本地更改。您必须先提交或撤消那些更改。", + "manageRemoteBranch": "管理远程分支", + "unableToAccess": "无法访问远程存储库", + "retry": "重试", + "setUpstreamBranch": "设置为上游分支", + "createRemoteBranchPlaceholder": "查找或创建远程分支", + "trackedUpstreamBranch": "创建的分支将被设置为跟踪的上游分支。", + "selectUpstreamBranch": "分支将被创建。 在下面选择以将其设置为被跟踪的上游分支。", + "pushFailed": "推送失败,因为远程具有更多的最新提交。请先拉取并合并,然后再尝试推送。", + "push": "推送", + "pull": "拉取", + "unablePull": "

无法提取远程更改;您未暂存的本地更改将被覆盖。

请先提交更改,然后重试。

", + "showUnstagedChanges": "显示未暂存的更改", + "connectionFailed": "无法连接到远程存储库:", + "pullUnrelatedHistory": "

远程有无关的提交历史

您确定要将这些更改拉入本地仓库吗?

", + "pullChanges": "拉取更改", + "history": "历史", + "projectHistory": "项目历史", + "daysAgo": "__count__ 天前", + "daysAgo_plural": "__count__ 天前", + "hoursAgo": "__count__ 小时前", + "hoursAgo_plural": "__count__ 小时前", + "minsAgo": "__count__ 分钟前", + "minsAgo_plural": "__count__ 分钟前", + "secondsAgo": "秒前", + "notTracking": "您的本地分支当前未跟踪一个远程分支。", + "statusUnmergedChanged": "您的仓库中有未合并的更改。您需要解决冲突并提交结果。", + "repositoryUpToDate": "您的仓库是最新的。", + "commitsAhead": "您的存储库领先远程仓库 __count__ 次提交。您现在可以推送这些提交。", + "commitsAhead_plural": "您的存储库领先远程仓库 __count__ 次提交。您现在可以推送这些提交。", + "commitsBehind": "您的存储库落后远程仓库 __count__ 次提交。您现在可以拉取这些提交。", + "commitsBehind_plural": "您的存储库落后远程仓库 __count__ 次提交。您现在可以拉取这些提交。", + "commitsAheadAndBehind1": "您的存储库落后远程仓库 __count__ 次提交", + "commitsAheadAndBehind1_plural": "您的存储库落后远程仓库 __count__ 次提交", + "commitsAheadAndBehind2": "领先远程仓库 __count__ 次提交。", + "commitsAheadAndBehind2_plural": "领先远程仓库 __count__ 次提交。", + "commitsAheadAndBehind3": "您必须先拉取远程提交,然后才能进行推送。", + "commitsAheadAndBehind3_plural": "您必须先拉取远程提交,然后才能进行推送。", + "refreshCommitHistory": "刷新提交历史", + "refreshChanges": "刷新更改" + } + } + }, + "typedInput": { + "type": { + "str": "文本", + "num": "数字", + "re": "正则表达式", + "bool": "布尔值", + "json": "JSON", + "bin": "二进制流", + "date": "时间戳", + "jsonata": "表达式", + "env": "环境变量", + "cred": "证书" + } + }, + "editableList": { + "add": "添加", + "addTitle": "添加项" + }, + "search": { + "history": "搜索历史", + "clear": "清除所有", + "empty": "找不到匹配项", + "addNode": "添加节点...", + "options": { + "configNodes": "配置节点", + "unusedConfigNodes": "未使用的配置节点", + "invalidNodes": "无效的节点", + "uknownNodes": "未知的节点", + "unusedSubflows": "未使用的子流程", + "hiddenFlows": "隐藏的流程", + "modifiedNodes": "已修改的节点或流程", + "thisFlow": "当前流程" + } + }, + "expressionEditor": { + "functions": "函数", + "functionReference": "函数引用", + "insert": "插入", + "title": "JSONata 表达式编辑器", + "test": "测试", + "data": "示例消息", + "result": "结果", + "format": "格式表达式", + "compatMode": "兼容模式启用", + "compatModeDesc": "

JSONata的兼容模式

目前的表达式仍然参考msg,所以将以兼容性模式进行评估。请更新表达式,使其不使用msg,因为此模式将在将来删除。

当JSONata支持首次添加到Node-RED时,它需要表达式引用msg对象。例如msg.payload将用于访问有效负载。

这样便不再需要表达式直接针对消息进行评估。要访问有效负载,表达式应该只是payload.

", + "noMatch": "无匹配结果", + "errors": { + "invalid-expr": "无效的JSONata表达式:\n __message__", + "invalid-msg": "无效的示例JSON消息:\n __message__", + "context-unsupported": "无法测试上下文函数\n $flowContext 或 $globalContext", + "env-unsupported": "无法测试 $env 函数", + "moment-unsupported": "无法测试 $moment 函数", + "clone-unsupported": "无法测试 $clone 函数", + "eval": "计算表达式错误:\n __message__" + } + }, + "monaco": { + "setTheme": "设置主题" + }, + "jsEditor": { + "title": "JavaScript 编辑器" + }, + "textEditor": { + "title": "文本编辑器" + }, + "jsonEditor": { + "title": "JSON 编辑器", + "format": "格式化JSON", + "rawMode": "编辑 JSON", + "uiMode": "可视化编辑器", + "rawMode-readonly": "原始JSON", + "uiMode-readonly": "可视化", + "insertAbove": "在上方插入", + "insertBelow": "在下方插入", + "addItem": "添加项目", + "copyPath": "复制路径到项目", + "expandItems": "展开项目", + "collapseItems": "折叠项目", + "duplicate": "重复", + "error": { + "invalidJSON": "无效的JSON: " + } + }, + "markdownEditor": { + "title": "Markdown 编辑器", + "expand": "展开", + "format": "格式化为markdown", + "heading1": "标题 1", + "heading2": "标题 2", + "heading3": "标题 3", + "bold": "粗体", + "italic": "斜体", + "code": "代码", + "ordered-list": "排序的列表", + "unordered-list": "非排序的列表", + "quote": "引用", + "link": "链接", + "horizontal-rule": "水平线", + "toggle-preview": "切换预览" + }, + "bufferEditor": { + "title": "Buffer 编辑器", + "modeString": "作为UTF-8字符串处理", + "modeArray": "作为JSON数组处理", + "modeDesc": "

Buffer 编辑器

Buffer类型被存储为字节值的JSON数组。编辑器将尝试将输入的数值解析为JSON数组。如果它不是有效的JSON,它将被视为UTF-8字符串,并被转换为单个字符代码点的数组。

例如,Hello World的值会被转换为JSON数组:

[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]

" + }, + "projects": { + "config-git": "配置Git客户端", + "welcome": { + "hello": "你好! 我们已经将“项目”引入了Node-RED。", + "desc0": "这是一种用于管理流程文件的新方法,并且包括对流程的版本控制。", + "desc1": "首先,您可以创建您的第一个项目或从git存储库克隆现有项目。", + "desc2": "如果不确定,可以暂时跳过此步骤。您仍然可以随时通过“项目”菜单创建第一个项目。", + "create": "建立专案", + "clone": "克隆仓库", + "openExistingProject": "打开现有项目", + "not-right-now": "稍后" }, - "typedInput": { - "type": { - "str": "文字列", - "num": "数字", - "re": "正则表达式", - "bool": "布尔值", - "json": "JSON", - "bin": "二进制流", - "date": "时间戳", - "jsonata": "表达式", - "env": "环境变量", - "cred": "证书" - } + "git-config": { + "setup": "设置您的版本控制客户端", + "desc0": "Node-RED使用开源工具Git进行版本控制。它跟踪对项目文件的更改,并允许您将其推送到远程存储库。", + "desc1": "提交一组更改时,Git会使用用户名和电子邮件地址记录谁进行了更改。用户名可以是您想要的任何名称-不必是您的真实姓名。", + "desc2": "您的Git客户端已经配置了以下详细信息。", + "desc3": "您可以稍后在设置对话框的'Git config'标签下更改这些设置。", + "username": "用户名", + "email": "电子邮件" }, - "editableList": { - "add": "添加" + "project-details": { + "create": "创建你的项目", + "desc0": "项目被维护为Git仓库。与他人一起共享您的流程", + "desc1": "您可以创建多个项目,并通过编辑器在它们之间快速切换。", + "desc2": "首先,您的项目需要一个名称和一个可选的描述。", + "already-exists": "项目已存在", + "must-contain": "只能包含A-Z 0-9 _ -", + "project-name": "项目名", + "desc": "描述", + "opt": "可选的" }, - "search": { - "empty": "找不到匹配", - "addNode": "添加一个节点...", - "options": { - "configNodes": "配置节点", - "unusedConfigNodes": "未使用的配置节点", - "invalidNodes": "无效的节点", - "uknownNodes": "未知的节点", - "unusedSubflows": "未使用的子流程" - } + "clone-project": { + "clone": "克隆一个项目", + "desc0": "如果您已经有一个包含项目的git仓库,则可以对其进行克隆以开始使用。", + "already-exists": "项目已存在", + "must-contain": "只能包含A-Z 0-9 _ -", + "project-name": "项目名", + "no-info-in-url": "网址中不要包含用户名/密码", + "git-url": "Git仓库的url", + "protocols": "https://, ssh:// or file://", + "auth-failed": "认证失败", + "username": "用户名", + "passwd": "秘密啊", + "ssh-key": "SSH密钥", + "passphrase": "密码短语", + "ssh-key-desc": "在通过ssh克隆仓库之前,必须添加SSH密钥才能访问它。", + "ssh-key-add": "添加一个ssh密钥", + "credential-key": "证书加密密钥", + "cant-get-ssh-key": "错误! 无法获取所选的SSH密钥路径。", + "already-exists2": "已存在", + "git-error": "git错误", + "connection-failed": "连接失败", + "not-git-repo": "不是一个git仓库", + "repo-not-found": "未发现仓库" }, - "expressionEditor": { - "functions": "功能", - "functionReference": "功能reference", - "insert": "插入", - "title": "JSONata表达式编辑器", - "test": "测试", - "data": "示例消息", - "result": "结果", - "format": "格式表达方法", - "compatMode": "兼容模式启用", - "compatModeDesc": "

JSONata的兼容模式

目前的表达式仍然参考msg,所以将以兼容性模式进行评估。请更新表达式,使其不使用msg,因为此模式将在将来删除。

当JSONata支持首次添加到Node-RED时,它需要表达式引用msg对象。例如msg.payload将用于访问有效负载。

这样便不再需要表达式直接针对消息进行评估。要访问有效负载,表达式应该只是payload.

", - "noMatch": "无匹配结果", - "errors": { - "invalid-expr": "无效的JSONata表达式:\n __message__", - "invalid-msg": "无效的示例JSON消息:\n __message__", - "context-unsupported": "无法测试上下文函数\n $flowContext 或 $globalContext", - "eval": "评估表达式错误:\n __message__" - } + "default-files": { + "create": "创建您的项目文件", + "desc0": "一个包含您的流程文件,Readme文件和package.json文件的项目。", + "desc1": "它可以包含您要在Git仓库中维护的任何其他文件。", + "desc2": "您现有的流程和凭证文件将被复制到项目中。", + "flow-file": "流程文件", + "credentials-file": "证书文件" }, - "jsEditor": { - "title": "JavaScript编辑器" + "encryption-config": { + "setup": "设置证书文件的加密", + "desc0": "您的流程证书文件可以被加密以确保其内容安全。", + "desc1": "如果要将这些证书存储在公共Git存储库中,则必须通过提供密钥短语来对它们进行加密。", + "desc2": "您的流程证书文件当前未加密。", + "desc3": "这意味着任何有权访问该文件的人都可以读取其内容,例如密码和访问令牌。", + "desc4": "如果要将这些证书存储在公共Git仓库中,则必须通过提供密钥短语来对它们进行加密。", + "desc5": "当前,使用设置文件中的credentialSecret属性作为密钥来加密流程证书文件。", + "desc6": "您的流程证书文件当前使用系统生成的密钥加密。您应该为此项目提供一个新的密钥。", + "desc7": "密钥将与项目文件分开存储。您将需要提供在另一个Node-RED实例中使用该项目的密钥。", + "credentials": "证书", + "enable": "启用加密", + "disable": "禁用加密", + "disabled": "禁用的", + "copy": "复制现有密钥", + "use-custom": "使用自定义密钥", + "desc8": "证书文件不会被加密,其内容很容易阅读", + "create-project-files": "创建项目文件", + "create-project": "创建项目", + "already-exists": "已存在", + "git-error": "git错误", + "git-auth-error": "git认证错误" }, - "textEditor": { - "title": "文本编辑器" + "create-success": { + "success": "您已经成功创建了第一个项目!", + "desc0": "现在,您可以像往常一样继续使用Node-RED。", + "desc1": "侧栏中的“信息”标签显示了您当前的活动项目。名称旁边的按钮可用于访问项目设置视图。", + "desc2": "侧栏中的“历史记录”标签可用于查看项目中已更改的文件并提交。它向您显示了提交的完整历史记录,并允许您将更改推送到远程存储库。" }, - "jsonEditor": { - "title": "JSON编辑器", - "format": "格式化JSON", - "rawMode": "编辑 JSON", - "uiMode": "Visual编辑器", - "insertAbove": "在上方插入", - "insertBelow": "在下方插入", - "addItem": "添加项目", - "copyPath": "复制路径到项目", - "expandItems": "展开项目", - "collapseItems": "收合项目", - "duplicate": "重复", - "error": { - "invalidJSON": "无效的JSON: " - } + "create": { + "projects": "项目", + "already-exists": "项目已存在", + "must-contain": "只能包含A-Z 0-9 _ -", + "no-info-in-url": "网址中不要包含用户名/密码", + "open": "打开项目", + "create": "创建项目", + "clone": "克隆仓库", + "project-name": "项目名", + "desc": "描述", + "opt": "可选的", + "flow-file": "流程文件", + "credentials": "证书", + "enable-encryption": "启用加密", + "disable-encryption": "禁用加密", + "encryption-key": "加密密钥", + "desc0": "用来保护您的凭证的短语", + "desc1": "凭证文件不会被加密,其内容很容易阅读", + "git-url": "Git存储库URL", + "protocols": "https://, ssh:// 或 file://", + "auth-failed": "验证失败", + "username": "用户名", + "password": "密码", + "ssh-key": "SSH密钥", + "passphrase": "密码短语", + "desc2": "在通过ssh克隆存储库之前,必须添加SSH密钥才能访问它。", + "add-ssh-key": "添加一个ssh密钥", + "credentials-encryption-key": "证书加密密钥", + "already-exists-2": "已存在", + "git-error": "git错误", + "con-failed": "连接失败", + "not-git": "不是git仓库", + "no-resource": "找不到存储库", + "cant-get-ssh-key-path": "错误!无法获取所选的SSH密钥路径。", + "unexpected_error": "意外的错误", + "clearContext": "更改项目时清除上下文" }, - "markdownEditor": { - "title": "Markdown编辑器", - "expand": "展开", - "format": "格式化为markdown", - "heading1": "标题 1", - "heading2": "标题 2", - "heading3": "标题 3", - "bold": "粗体", - "italic": "斜体", - "code": "代码", - "ordered-list": "排序的列表", - "unordered-list": "非排序的列表", - "quote": "引用", - "link": "链接", - "horizontal-rule": "水平线", - "toggle-preview": "切换预览" + "delete": { + "confirm": "您确定要删除此项目吗?" }, - "bufferEditor": { - "title": "缓冲区编辑器", - "modeString": "作为UTF-8字符串处理", - "modeArray": "作为JSON数组处理", - "modeDesc": "

缓冲区编辑器

缓冲区类型被存储为字节值的JSON数组。编辑器将尝试将输入的数值解析为JSON数组。如果它不是有效的JSON,它将被视为UTF-8字符串,并被转换为单个字符代码点的数组。

例如,Hello World的值会被转换为JSON数组:

[72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]

" + "create-project-list": { + "search": "搜索您的项目", + "current": "当前的" }, - "projects": { - "config-git": "配置Git客户端", - "welcome": { - "hello": "你好! 我们已经将“项目”引入了Node-RED。", - "desc0": "这是一种用于管理流程文件的新方法,并且包括对流程的版本控制。", - "desc1": "首先,您可以创建您的第一个项目或从git存储库克隆现有项目。", - "desc2": "如果不确定,可以暂时跳过此步骤。您仍然可以随时通过“项目”菜单创建第一个项目。", - "create": "建立专案", - "clone": "克隆仓库", - "openExistingProject": "打开现有项目", - "not-right-now": "不是现在" - }, - "git-config": { - "setup": "设置您的版本控制客户端", - "desc0": "Node-RED使用开源工具Git进行版本控制。它跟踪对项目文件的更改,并允许您将其推送到远程存储库。", - "desc1": "提交一组更改时,Git会使用用户名和电子邮件地址记录谁进行了更改。用户名可以是您想要的任何名称-不必是您的真实姓名。", - "desc2": "您的Git客户端已经配置了以下详细信息。", - "desc3": "您可以稍后在设置对话框的'Git config'标签下更改这些设置。", - "username": "用户名", - "email": "电子邮件" - }, - "project-details": { - "create": "创建你的项目", - "desc0": "项目被维护为Git仓库。与他人一起共享您的流程", - "desc1": "您可以创建多个项目,并通过编辑器在它们之间快速切换。", - "desc2": "首先,您的项目需要一个名称和一个可选的描述。", - "already-exists": "项目已存在", - "must-contain": "只能包含A-Z 0-9 _ -", - "project-name": "项目名", - "desc": "描述", - "opt": "可选的" - }, - "clone-project": { - "clone": "克隆一个项目", - "desc0": "如果您已经有一个包含项目的git仓库,则可以对其进行克隆以开始使用。", - "already-exists": "项目已存在", - "must-contain": "只能包含A-Z 0-9 _ -", - "project-name": "项目名", - "no-info-in-url": "网址中不要包含用户名/密码", - "git-url": "Git仓库的url", - "protocols": "https://, ssh:// or file://", - "auth-failed": "认证失败", - "username": "用户名", - "passwd": "秘密啊", - "ssh-key": "SSH密钥", - "passphrase": "密码短语", - "ssh-key-desc": "在通过ssh克隆仓库之前,必须添加SSH密钥才能访问它。", - "ssh-key-add": "添加一个ssh密钥", - "credential-key": "证书加密密钥", - "cant-get-ssh-key": "错误! 无法获取所选的SSH密钥路径。", - "already-exists2": "已存在", - "git-error": "git错误", - "connection-failed": "连接失败", - "not-git-repo": "不是一个git仓库", - "repo-not-found": "未发现仓库" - }, - "default-files": { - "create": "创建您的项目文件", - "desc0": "一个包含您的流程文件,Readme文件和package.json文件的项目。", - "desc1": "它可以包含您要在Git仓库中维护的任何其他文件。", - "desc2": "您现有的流程和凭证文件将被复制到项目中。", - "flow-file": "流程文件", - "credentials-file": "证书文件" - }, - "encryption-config": { - "setup": "设置证书文件的加密", - "desc0": "您的流程证书文件可以被加密以确保其内容安全。", - "desc1": "如果要将这些证书存储在公共Git存储库中,则必须通过提供密钥短语来对它们进行加密。", - "desc2": "您的流程证书文件当前未加密。", - "desc3": "这意味着任何有权访问该文件的人都可以读取其内容,例如密码和访问令牌。", - "desc4": "如果要将这些证书存储在公共Git仓库中,则必须通过提供密钥短语来对它们进行加密。", - "desc5": "当前,使用设置文件中的credentialSecret属性作为密钥来加密流程证书文件。", - "desc6": "您的流程证书文件当前使用系统生成的密钥加密。您应该为此项目提供一个新的密钥。", - "desc7": "密钥将与项目文件分开存储。您将需要提供在另一个Node-RED实例中使用该项目的密钥。", - "credentials": "证书", - "enable": "启用加密", - "disable": "禁用加密", - "disabled": "禁用的", - "copy": "复制现有密钥", - "use-custom": "使用自定义密钥", - "desc8": "证书文件不会被加密,其内容很容易阅读", - "create-project-files": "创建项目文件", - "create-project": "创建项目", - "already-exists": "已存在", - "git-error": "git错误", - "git-auth-error": "git认证错误" - }, - "create-success": { - "success": "您已经成功创建了第一个项目!", - "desc0": "现在,您可以像往常一样继续使用Node-RED。", - "desc1": "侧栏中的“信息”标签显示了您当前的活动项目。名称旁边的按钮可用于访问项目设置视图。", - "desc2": "侧栏中的“历史记录”标签可用于查看项目中已更改的文件并提交。它向您显示了提交的完整历史记录,并允许您将更改推送到远程存储库。" - }, - "create": { - "projects": "项目", - "already-exists": "项目已存在", - "must-contain": "只能包含A-Z 0-9 _ -", - "no-info-in-url": "网址中不要包含用户名/密码", - "open": "打开项目", - "create": "创建项目", - "clone": "克隆仓库", - "project-name": "项目名", - "desc": "描述", - "opt": "可选的", - "flow-file": "流程文件", - "credentials": "证书", - "enable-encryption": "启用加密", - "disable-encryption": "禁用加密", - "encryption-key": "加密密钥", - "desc0": "用来保护您的凭证的短语", - "desc1": "凭证文件不会被加密,其内容很容易阅读", - "git-url": "Git存储库URL", - "protocols": "https://, ssh:// or file://", - "auth-failed": "验证失败", - "username": "用户名", - "password": "密码", - "ssh-key": "SSH密钥", - "passphrase": "密码短语", - "desc2": "在通过ssh克隆存储库之前,必须添加SSH密钥才能访问它。", - "add-ssh-key": "添加一个ssh密钥", - "credentials-encryption-key": "证书加密密钥", - "already-exists-2": "已存在", - "git-error": "git错误", - "con-failed": "连接失败", - "not-git": "不是git仓库", - "no-resource": "找不到存储库", - "cant-get-ssh-key-path": "错误!无法获取所选的SSH密钥路径。", - "unexpected_error": "意外的错误" - }, - "delete": { - "confirm": "您确定要删除此项目吗?" - }, - "create-project-list": { - "search": "搜索您的项目", - "current": "当前的" - }, - "require-clean": { - "confirm": "

您有未部署的更改,这些更改将丢失。

您要继续吗?

" - }, - "send-req": { - "auth-req": "存储库需要认证", - "username": "用户名", - "password": "秘密", - "passphrase": "密码短语", - "retry": "重试", - "update-failed": "无法更新身份验证", - "unhandled": "未处理的错误响应", - "host-key-verify-failed": "

主机密钥验证失败。

无法验证存储库主机密钥。请更新您的known_hosts文件,然后重试。

" - }, - "create-branch-list": { - "invalid": "无效的分支", - "create": "创建分支", - "current": "当前的" - }, - "create-default-file-set": { - "no-active": "没有活动项目就无法创建默认文件集", - "no-empty": "无法在非空项目上创建默认文件集", - "git-error": "git错误" - }, - "errors": { - "no-username-email": "您的Git客户端未配置用户名/电子邮件。", - "unexpected": "发生了一个意料之外的问题", - "code": "代码" - } + "require-clean": { + "confirm": "

您有未部署的更改,这些更改将丢失。

您要继续吗?

" }, - "editor-tab": { - "properties": "属性", - "envProperties": "环境变量", - "description": "描述", - "appearance": "外观", - "preview": "UI预览", - "defaultValue": "默认值" + "send-req": { + "auth-req": "存储库需要认证", + "username": "用户名", + "password": "秘密", + "passphrase": "密码短语", + "retry": "重试", + "update-failed": "无法更新身份验证", + "unhandled": "未处理的错误响应", + "host-key-verify-failed": "

主机密钥验证失败。

无法验证存储库主机密钥。请更新您的known_hosts文件,然后重试。

" + }, + "create-branch-list": { + "invalid": "无效的分支", + "create": "创建分支", + "current": "当前的" }, "languages": { "de": "德语", "en-US": "英文", + "fr": "法语", "ja": "日语", "ko": "韩文", + "pt-BR":"葡萄牙语", + "ru":"俄語", "zh-CN": "简体中文", "zh-TW": "繁体中文" + }, + "create-default-file-set": { + "no-active": "没有活动项目就无法创建默认文件集", + "no-empty": "无法在非空项目上创建默认文件集", + "git-error": "git错误" + }, + "errors": { + "no-username-email": "您的Git客户端未配置用户名/电子邮件。", + "unexpected": "发生了一个意料之外的问题", + "code": "代码" } + }, + "editor-tab": { + "properties": "属性", + "envProperties": "环境变量", + "module": "模块属性", + "description": "描述", + "appearance": "外观", + "preview": "UI预览", + "defaultValue": "默认值" + }, + "tourGuide": { + "takeATour": "查看更新内容", + "start": "开始", + "next": "下一个", + "welcomeTours": "欢迎使用 Node-RED" + }, + "diagnostics": { + "title": "系统信息" + }, + "languages": { + "de": "德语-Deutsch", + "en-US": "英文-English", + "ja": "日语-日本", + "ko": "韩文-한국인", + "ru": "俄语-Русский", + "zh-CN": "简体中文", + "zh-TW": "繁體中文" + }, + "validator": { + "errors": { + "invalid-json": "无效的 JSON 数据: __error__", + "invalid-json-prop": "__prop__: 无效的 JSON 数据: __error__", + "invalid-prop": "无效的属性表达式", + "invalid-prop-prop": "__prop__: 无效的属性表达式", + "invalid-num": "无效的数字", + "invalid-num-prop": "__prop__: 无效的数字", + "invalid-regexp": "输入格式无效", + "invalid-regex-prop": "__prop__: 输入格式无效", + "missing-required-prop": "__prop__: 缺少属性值", + "invalid-config": "__prop__: 无效的配置节点", + "missing-config": "__prop__: 缺少配置节点", + "validation-error": "__prop__: 验证错误: __node__, __id__: __error__" + } + }, + "contextMenu": { + "insert": "插入", + "node": "节点", + "junction": "连接点", + "linkNodes": "链接节点" + } } diff --git a/packages/node_modules/@node-red/editor-client/locales/zh-TW/editor.json b/packages/node_modules/@node-red/editor-client/locales/zh-TW/editor.json index 42316176f..3646f0c9e 100644 --- a/packages/node_modules/@node-red/editor-client/locales/zh-TW/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/zh-TW/editor.json @@ -1088,8 +1088,11 @@ "languages": { "de": "德語", "en-US": "英語", + "fr": "法語", "ja": "日語", "ko": "韓語", + "pt-BR":"葡萄牙语", + "ru":"俄語", "zh-CN": "簡體中文", "zh-TW": "繁體中文" } diff --git a/packages/node_modules/@node-red/editor-client/package.json b/packages/node_modules/@node-red/editor-client/package.json index 0ef939fb3..c81d2dfc3 100644 --- a/packages/node_modules/@node-red/editor-client/package.json +++ b/packages/node_modules/@node-red/editor-client/package.json @@ -1,6 +1,6 @@ { "name": "@node-red/editor-client", - "version": "3.0.2", + "version": "3.1.0-beta.2", "license": "Apache-2.0", "repository": { "type": "git", diff --git a/packages/node_modules/@node-red/editor-client/src/js/history.js b/packages/node_modules/@node-red/editor-client/src/js/history.js index b23071239..c3a966890 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/history.js +++ b/packages/node_modules/@node-red/editor-client/src/js/history.js @@ -14,7 +14,7 @@ * limitations under the License. **/ -/** +/** * An API for undo / redo history buffer * @namespace RED.history */ @@ -378,7 +378,8 @@ RED.history = (function() { if (ev.addToGroup) { RED.group.removeFromGroup(ev.addToGroup,ev.nodes.map(function(n) { return n.n }),false); inverseEv.removeFromGroup = ev.addToGroup; - } else if (ev.removeFromGroup) { + } + if (ev.removeFromGroup) { RED.group.addToGroup(ev.removeFromGroup,ev.nodes.map(function(n) { return n.n })); inverseEv.addToGroup = ev.removeFromGroup; } @@ -421,6 +422,9 @@ RED.history = (function() { ev.node[i] = ev.changes[i]; } } + ev.node.dirty = true; + ev.node.changed = ev.changed; + var eventType; switch(ev.node.type) { case 'tab': eventType = "flows"; break; @@ -434,7 +438,9 @@ RED.history = (function() { if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('disabled')) { $("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!ev.node.disabled); - $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!ev.node.disabled); + } + if (ev.node.type === 'tab' && ev.changes.hasOwnProperty('locked')) { + $("#red-ui-tab-"+(ev.node.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!ev.node.locked); } if (ev.subflow) { inverseEv.subflow = {}; @@ -509,8 +515,6 @@ RED.history = (function() { inverseEv.links.push(ev.createdLinks[i]); } } - ev.node.dirty = true; - ev.node.changed = ev.changed; } else if (ev.t == "createSubflow") { inverseEv = { t: "deleteSubflow", @@ -646,6 +650,12 @@ RED.history = (function() { ev.groups[i].nodes = []; RED.nodes.addGroup(ev.groups[i]); RED.group.addToGroup(ev.groups[i],nodes); + if (ev.groups[i].g) { + const parentGroup = RED.nodes.group(ev.groups[i].g) + if (parentGroup) { + RED.group.addToGroup(parentGroup, ev.groups[i]) + } + } } } } else if (ev.t == "addToGroup") { diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js index 94bdbfcf7..2a14a0244 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js +++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js @@ -19,7 +19,6 @@ * @namespace RED.nodes */ RED.nodes = (function() { - var PORT_TYPE_INPUT = 1; var PORT_TYPE_OUTPUT = 0; @@ -47,6 +46,9 @@ RED.nodes = (function() { function setDirty(d) { dirty = d; + if (!d) { + allNodes.clearState() + } RED.events.emit("workspace:dirty",{dirty:dirty}); } @@ -63,12 +65,12 @@ RED.nodes = (function() { defaults: { label: {value:""}, disabled: {value: false}, + locked: {value: false}, info: {value: ""}, env: {value: []} } }; - var exports = { setModulePendingUpdated: function(module,version) { moduleList[module].pending_version = version; @@ -238,22 +240,72 @@ RED.nodes = (function() { // allNodes holds information about the Flow nodes. var allNodes = (function() { + // Map node.id -> node var nodes = {}; + // Map tab.id -> Array of nodes on that tab var tabMap = {}; + // Map tab.id -> Set of dirty object ids on that tab + var tabDirtyMap = {}; + // Map tab.id -> Set of object ids of things deleted from the tab that weren't otherwise dirty + var tabDeletedNodesMap = {}; + // Set of object ids of things added to a tab after initial import + var addedDirtyObjects = new Set() + + function changeCollectionDepth(tabNodes, toMove, direction, singleStep) { + const result = [] + const moved = new Set(); + const startIndex = direction ? tabNodes.length - 1 : 0 + const endIndex = direction ? -1 : tabNodes.length + const step = direction ? -1 : 1 + let target = startIndex // Only used for all-the-way moves + for (let i = startIndex; i != endIndex; i += step) { + if (toMove.size === 0) { + break; + } + const n = tabNodes[i] + if (toMove.has(n)) { + if (singleStep) { + if (i !== startIndex && !moved.has(tabNodes[i - step])) { + tabNodes.splice(i, 1) + tabNodes.splice(i - step, 0, n) + n._reordered = true + result.push(n) + } + } else { + if (i !== target) { + tabNodes.splice(i, 1) + tabNodes.splice(target, 0, n) + n._reordered = true + result.push(n) + } + target += step + } + toMove.delete(n); + moved.add(n); + } + } + return result + } + var api = { addTab: function(id) { tabMap[id] = []; + tabDirtyMap[id] = new Set(); + tabDeletedNodesMap[id] = new Set(); }, hasTab: function(z) { return tabMap.hasOwnProperty(z) }, removeTab: function(id) { delete tabMap[id]; + delete tabDirtyMap[id]; + delete tabDeletedNodesMap[id]; }, addNode: function(n) { nodes[n.id] = n; if (tabMap.hasOwnProperty(n.z)) { tabMap[n.z].push(n); + api.addObjectToWorkspace(n.z, n.id, n.changed || n.moved) } else { console.warn("Node added to unknown tab/subflow:",n); tabMap["_"] = tabMap["_"] || []; @@ -267,8 +319,37 @@ RED.nodes = (function() { if (i > -1) { tabMap[n.z].splice(i,1); } + api.removeObjectFromWorkspace(n.z, n.id) } }, + /** + * Add an object to our dirty/clean tracking state + * @param {String} z + * @param {String} id + * @param {Boolean} isDirty + */ + addObjectToWorkspace: function (z, id, isDirty) { + if (isDirty) { + addedDirtyObjects.add(id) + } + if (tabDeletedNodesMap[z].has(id)) { + tabDeletedNodesMap[z].delete(id) + } + api.markNodeDirty(z, id, isDirty) + }, + /** + * Remove an object from our dirty/clean tracking state + * @param {String} z + * @param {String} id + */ + removeObjectFromWorkspace: function (z, id) { + if (!addedDirtyObjects.has(id)) { + tabDeletedNodesMap[z].add(id) + } else { + addedDirtyObjects.delete(id) + } + api.markNodeDirty(z, id, false) + }, hasNode: function(id) { return nodes.hasOwnProperty(id); }, @@ -280,152 +361,54 @@ RED.nodes = (function() { n.z = newZ; api.addNode(n) }, - moveNodesForwards: function(nodes) { - var result = []; + /** + * @param {array} nodes + * @param {boolean} direction true:forwards false:back + * @param {boolean} singleStep true:single-step false:all-the-way + */ + changeDepth: function(nodes, direction, singleStep) { if (!Array.isArray(nodes)) { nodes = [nodes] } - // Can only do this for nodes on the same tab. - // Use nodes[0] to get the z - var tabNodes = tabMap[nodes[0].z]; - var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" })); - var moved = new Set(); - for (var i = tabNodes.length-1; i >= 0; i--) { - if (toMove.size === 0) { - break; - } - var n = tabNodes[i]; - if (toMove.has(n)) { - // This is a node to move. - if (i < tabNodes.length-1 && !moved.has(tabNodes[i+1])) { - // Remove from current position - tabNodes.splice(i,1); - // Add it back one position higher - tabNodes.splice(i+1,0,n); - n._reordered = true; - result.push(n); - } - toMove.delete(n); - moved.add(n); + let result = [] + const tabNodes = tabMap[nodes[0].z]; + const toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" })); + if (toMove.size > 0) { + result = result.concat(changeCollectionDepth(tabNodes, toMove, direction, singleStep)) + if (result.length > 0) { + RED.events.emit('nodes:reorder',{ + z: nodes[0].z, + nodes: result + }); } } - if (result.length > 0) { - RED.events.emit('nodes:reorder',{ - z: nodes[0].z, - nodes: result - }); + + const groupNodes = groupsByZ[nodes[0].z] || [] + const groupsToMove = new Set(nodes.filter(function(n) { return n.type === 'group'})) + if (groupsToMove.size > 0) { + const groupResult = changeCollectionDepth(groupNodes, groupsToMove, direction, singleStep) + if (groupResult.length > 0) { + result = result.concat(groupResult) + RED.events.emit('groups:reorder',{ + z: nodes[0].z, + nodes: groupResult + }); + } } - return result; + RED.view.redraw(true) + return result + }, + moveNodesForwards: function(nodes) { + return api.changeDepth(nodes, true, true) }, moveNodesBackwards: function(nodes) { - var result = []; - if (!Array.isArray(nodes)) { - nodes = [nodes] - } - // Can only do this for nodes on the same tab. - // Use nodes[0] to get the z - var tabNodes = tabMap[nodes[0].z]; - var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" })); - var moved = new Set(); - for (var i = 0; i < tabNodes.length; i++) { - if (toMove.size === 0) { - break; - } - var n = tabNodes[i]; - if (toMove.has(n)) { - // This is a node to move. - if (i > 0 && !moved.has(tabNodes[i-1])) { - // Remove from current position - tabNodes.splice(i,1); - // Add it back one position lower - tabNodes.splice(i-1,0,n); - n._reordered = true; - result.push(n); - } - toMove.delete(n); - moved.add(n); - } - } - if (result.length > 0) { - RED.events.emit('nodes:reorder',{ - z: nodes[0].z, - nodes: result - }); - } - return result; + return api.changeDepth(nodes, false, true) }, moveNodesToFront: function(nodes) { - var result = []; - if (!Array.isArray(nodes)) { - nodes = [nodes] - } - // Can only do this for nodes on the same tab. - // Use nodes[0] to get the z - var tabNodes = tabMap[nodes[0].z]; - var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" })); - var target = tabNodes.length-1; - for (var i = tabNodes.length-1; i >= 0; i--) { - if (toMove.size === 0) { - break; - } - var n = tabNodes[i]; - if (toMove.has(n)) { - // This is a node to move. - if (i < target) { - // Remove from current position - tabNodes.splice(i,1); - tabNodes.splice(target,0,n); - n._reordered = true; - result.push(n); - } - target--; - toMove.delete(n); - } - } - if (result.length > 0) { - RED.events.emit('nodes:reorder',{ - z: nodes[0].z, - nodes: result - }); - } - return result; + return api.changeDepth(nodes, true, false) }, moveNodesToBack: function(nodes) { - var result = []; - if (!Array.isArray(nodes)) { - nodes = [nodes] - } - // Can only do this for nodes on the same tab. - // Use nodes[0] to get the z - var tabNodes = tabMap[nodes[0].z]; - var toMove = new Set(nodes.filter(function(n) { return n.type !== "group" && n.type !== "subflow" })); - var target = 0; - for (var i = 0; i < tabNodes.length; i++) { - if (toMove.size === 0) { - break; - } - var n = tabNodes[i]; - if (toMove.has(n)) { - // This is a node to move. - if (i > target) { - // Remove from current position - tabNodes.splice(i,1); - // Add it back one position lower - tabNodes.splice(target,0,n); - n._reordered = true; - result.push(n); - } - target++; - toMove.delete(n); - } - } - if (result.length > 0) { - RED.events.emit('nodes:reorder',{ - z: nodes[0].z, - nodes: result - }); - } - return result; + return api.changeDepth(nodes, false, false) }, getNodes: function(z) { return tabMap[z]; @@ -433,6 +416,33 @@ RED.nodes = (function() { clear: function() { nodes = {}; tabMap = {}; + tabDirtyMap = {}; + tabDeletedNodesMap = {}; + addedDirtyObjects = new Set(); + }, + /** + * Clear all internal state on what is dirty. + */ + clearState: function () { + // Called when a deploy happens, we can forget about added/remove + // items as they have now been deployed. + addedDirtyObjects = new Set() + const flowsToCheck = new Set() + for (const [z, set] of Object.entries(tabDeletedNodesMap)) { + if (set.size > 0) { + set.clear() + flowsToCheck.add(z) + } + } + for (const [z, set] of Object.entries(tabDirtyMap)) { + if (set.size > 0) { + set.clear() + flowsToCheck.add(z) + } + } + for (const z of flowsToCheck) { + api.checkTabState(z) + } }, eachNode: function(cb) { var nodeList,i,j; @@ -498,7 +508,7 @@ RED.nodes = (function() { return result; }, getNodeOrder: function(z) { - return tabMap[z].map(function(n) { return n.id }) + return (groupsByZ[z] || []).concat(tabMap[z]).map(n => n.id) }, setNodeOrder: function(z, order) { var orderMap = {}; @@ -510,6 +520,41 @@ RED.nodes = (function() { B._reordered = true; return orderMap[A.id] - orderMap[B.id]; }) + if (groupsByZ[z]) { + groupsByZ[z].sort(function(A,B) { + return orderMap[A.id] - orderMap[B.id]; + }) + } + }, + /** + * Update our records if an object is dirty or not + * @param {String} z tab id + * @param {String} id object id + * @param {Boolean} dirty whether the object is dirty or not + */ + markNodeDirty: function(z, id, dirty) { + if (tabDirtyMap[z]) { + if (dirty) { + tabDirtyMap[z].add(id) + } else { + tabDirtyMap[z].delete(id) + } + api.checkTabState(z) + } + }, + /** + * Check if a tab should update its contentsChange flag + * @param {String} z tab id + */ + checkTabState: function (z) { + const ws = workspaces[z] + if (ws) { + const contentsChanged = tabDirtyMap[z].size > 0 || tabDeletedNodesMap[z].size > 0 + if (Boolean(ws.contentsChanged) !== contentsChanged) { + ws.contentsChanged = contentsChanged + RED.events.emit("flows:change", ws); + } + } } } return api; @@ -575,15 +620,53 @@ RED.nodes = (function() { } } + const nodeProxyHandler = { + get(node, prop) { + if (prop === '__isProxy__') { + return true + } else if (prop == '__node__') { + return node + } + return node[prop] + }, + set(node, prop, value) { + if (node.z && (RED.nodes.workspace(node.z)?.locked || RED.nodes.subflow(node.z)?.locked)) { + if ( + node._def.defaults[prop] || + prop === 'z' || + prop === 'l' || + prop === 'd' || + (prop === 'changed' && (!!node.changed) !== (!!value)) || // jshint ignore:line + ((prop === 'x' || prop === 'y') && !node.resize && node.type !== 'group') + ) { + throw new Error(`Cannot modified property '${prop}' of locked object '${node.type}:${node.id}'`) + } + } + if (node.z && (prop === 'changed' || prop === 'moved')) { + setTimeout(() => { + allNodes.markNodeDirty(node.z, node.id, node.changed || node.moved) + }, 0) + } + node[prop] = value; + return true + } + } function addNode(n) { + let newNode + if (!n.__isProxy__) { + newNode = new Proxy(n, nodeProxyHandler) + } else { + newNode = n + } + if (n.type.indexOf("subflow") !== 0) { n["_"] = n._def._; } else { var subflowId = n.type.substring(8); var sf = RED.nodes.subflow(subflowId); if (sf) { - sf.instances.push(sf); + sf.instances.push(newNode); } n["_"] = RED._; } @@ -600,12 +683,13 @@ RED.nodes = (function() { }); n.i = nextId+1; } - allNodes.addNode(n); + allNodes.addNode(newNode); if (!nodeLinks[n.id]) { nodeLinks[n.id] = {in:[],out:[]}; } } - RED.events.emit('nodes:add',n); + RED.events.emit('nodes:add',newNode); + return newNode } function addLink(l) { if (nodeLinks[l.source.id]) { @@ -632,10 +716,16 @@ RED.nodes = (function() { } if (l.source.z === l.target.z && linkTabMap[l.source.z]) { linkTabMap[l.source.z].push(l); + allNodes.addObjectToWorkspace(l.source.z, getLinkId(l), true) } RED.events.emit("links:add",l); } + function getLinkId(link) { + return link.source.id + ':' + link.sourcePort + ':' + link.target.id + } + + function getNode(id) { if (id in configNodes) { return configNodes[id]; @@ -830,6 +920,7 @@ RED.nodes = (function() { if (index !== -1) { linkTabMap[l.source.z].splice(index,1) } + allNodes.removeObjectFromWorkspace(l.source.z, getLinkId(l)) } } RED.events.emit("links:remove",l); @@ -999,6 +1090,11 @@ RED.nodes = (function() { return false; } + function getDownstreamNodes(node) { + const downstreamLinks = nodeLinks[node.id].out + const downstreamNodes = new Set(downstreamLinks.map(l => l.target)) + return Array.from(downstreamNodes) + } function getAllDownstreamNodes(node) { return getAllFlowNodes(node,'down').filter(function(n) { return n !== node }); } @@ -1046,6 +1142,9 @@ RED.nodes = (function() { node.type = n.type; for (var d in n._def.defaults) { if (n._def.defaults.hasOwnProperty(d)) { + if (d === 'locked' && !n.locked) { + continue + } node[d] = n[d]; } } @@ -1369,7 +1468,7 @@ RED.nodes = (function() { } } if (node.type !== "subflow") { - var convertedNode = RED.nodes.convertNode(node); + var convertedNode = RED.nodes.convertNode(node, { credentials: false }); for (var d in node._def.defaults) { if (node._def.defaults[d].type) { var nodeList = node[d]; @@ -1402,7 +1501,7 @@ RED.nodes = (function() { nns = nns.concat(createExportableNodeSet(node.nodes, exportedIds, exportedSubflows, exportedConfigNodes)); } } else { - var convertedSubflow = convertSubflow(node); + var convertedSubflow = convertSubflow(node, { credentials: false }); nns.push(convertedSubflow); } } @@ -1651,6 +1750,7 @@ RED.nodes = (function() { * Options: * - generateIds - whether to replace all node ids * - addFlow - whether to import nodes to a new tab + * - markChanged - whether to set changed=true on all newly imported objects * - reimport - if node has a .z property, dont overwrite it * Only applicible when `generateIds` is false * - importMap - how to resolve any conflicts. @@ -1659,7 +1759,7 @@ RED.nodes = (function() { * - id:replace - import over the top of existing */ function importNodes(newNodesObj,options) { // createNewIds,createMissingWorkspace) { - const defOpts = { generateIds: false, addFlow: false, reimport: false, importMap: {} } + const defOpts = { generateIds: false, addFlow: false, markChanged: false, reimport: false, importMap: {} } options = Object.assign({}, defOpts, options) options.importMap = options.importMap || {} const createNewIds = options.generateIds; @@ -1685,7 +1785,7 @@ RED.nodes = (function() { newNodes = newNodesObj; } - if (!$.isArray(newNodes)) { + if (!Array.isArray(newNodes)) { newNodes = [newNodes]; } @@ -1983,6 +2083,9 @@ RED.nodes = (function() { if (!n.z) { delete configNode.z; } + if (options.markChanged) { + configNode.changed = true + } if (n.hasOwnProperty('d')) { configNode.d = n.d; } @@ -2045,6 +2148,9 @@ RED.nodes = (function() { if (n.hasOwnProperty('g')) { node.g = n.g; } + if (options.markChanged) { + node.changed = true + } if (createNewIds || options.importMap[n.id] === "copy") { if (subflow_denylist[n.z]) { continue; @@ -2276,7 +2382,7 @@ RED.nodes = (function() { // get added if (activeSubflow && /^link /.test(n.type) && n.links) { n.links = n.links.filter(function(id) { - var otherNode = RED.nodes.node(id); + const otherNode = node_map[id] || RED.nodes.node(id); return (otherNode && otherNode.z === activeWorkspace) }); } @@ -2326,19 +2432,6 @@ RED.nodes = (function() { if (n.g && !new_group_set.has(n.g)) { delete n.g; } - n.nodes = n.nodes.map(function(id) { - return node_map[id]; - }) - // Just in case the group references a node that doesn't exist for some reason - n.nodes = n.nodes.filter(function(v) { - if (v) { - // Repair any nodes that have forgotten they are in this group - if (v.g !== n.id) { - v.g = n.id; - } - } - return !!v - }); if (!n.g) { groupDepthMap[n.id] = 0; } @@ -2361,21 +2454,22 @@ RED.nodes = (function() { return groupDepthMap[A.id] - groupDepthMap[B.id]; }); for (i=0;i { + const mappedNode = node_map[id] + if (!mappedNode) { + return null + } + if (mappedNode.__isProxy__) { + return mappedNode + } else { + return node_map[mappedNode.id] + } + } + // Update groups to reference proxy node objects + for (i=0;i g.id) + } function addJunction(junction) { + if (!junction.__isProxy__) { + junction = new Proxy(junction, nodeProxyHandler) + } junctionsByZ[junction.z] = junctionsByZ[junction.z] || [] junctionsByZ[junction.z].push(junction) junctions[junction.id] = junction; if (!nodeLinks[junction.id]) { nodeLinks[junction.id] = {in:[],out:[]}; } + allNodes.addObjectToWorkspace(junction.z, junction.id, junction.changed || junction.moved) RED.events.emit("junctions:add", junction) + return junction } function removeJunction(junction) { var i = junctionsByZ[junction.z].indexOf(junction) @@ -2576,6 +2723,7 @@ RED.nodes = (function() { } delete junctions[junction.id] delete nodeLinks[junction.id]; + allNodes.removeObjectFromWorkspace(junction.z, junction.id) RED.events.emit("junctions:remove", junction) var removedLinks = links.filter(function(l) { return (l.source === junction) || (l.target === junction); }); @@ -2813,6 +2961,9 @@ RED.nodes = (function() { RED.view.redraw(true); } }); + RED.events.on('deploy', function () { + allNodes.clearState() + }) }, registry:registry, setNodeList: registry.setNodeList, @@ -2861,7 +3012,7 @@ RED.nodes = (function() { }, addWorkspace: addWorkspace, removeWorkspace: removeWorkspace, - getWorkspaceOrder: function() { return workspacesOrder }, + getWorkspaceOrder: function() { return [...workspacesOrder] }, setWorkspaceOrder: function(order) { workspacesOrder = order; }, workspace: getWorkspace, @@ -2915,6 +3066,20 @@ RED.nodes = (function() { } } }, + eachGroup: function(cb) { + for (var group of Object.values(groups)) { + if (cb(group) === false) { + break + } + } + }, + eachJunction: function(cb) { + for (var junction of Object.values(junctions)) { + if (cb(junction) === false) { + break + } + } + }, node: getNode, @@ -2937,6 +3102,7 @@ RED.nodes = (function() { getAllFlowNodes: getAllFlowNodes, getAllUpstreamNodes: getAllUpstreamNodes, getAllDownstreamNodes: getAllDownstreamNodes, + getDownstreamNodes: getDownstreamNodes, getNodeIslands: getNodeIslands, createExportableNodeSet: createExportableNodeSet, createCompleteNodeSet: createCompleteNodeSet, diff --git a/packages/node_modules/@node-red/editor-client/src/js/red.js b/packages/node_modules/@node-red/editor-client/src/js/red.js index 497a93c45..89464bd6c 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/red.js +++ b/packages/node_modules/@node-red/editor-client/src/js/red.js @@ -249,8 +249,37 @@ var RED = (function() { RED.nodes.import(nodes.flows); RED.nodes.dirty(false); RED.view.redraw(true); - if (/^#flow\/.+$/.test(currentHash)) { - RED.workspaces.show(currentHash.substring(6),true); + if (/^#(flow|node|group)\/.+$/.test(currentHash)) { + const hashParts = currentHash.split('/') + const showEditDialog = hashParts.length > 2 && hashParts[2] === 'edit' + if (hashParts[0] === '#flow') { + RED.workspaces.show(hashParts[1], true); + if (showEditDialog) { + RED.workspaces.edit() + } + } else if (hashParts[0] === '#node') { + const nodeToShow = RED.nodes.node(hashParts[1]) + if (nodeToShow) { + setTimeout(() => { + RED.view.reveal(nodeToShow.id) + window.location.hash = currentHash + RED.view.select(nodeToShow.id) + if (showEditDialog) { + RED.editor.edit(nodeToShow) + } + }, 50) + } + } else if (hashParts[0] === '#group') { + const nodeToShow = RED.nodes.group(hashParts[1]) + if (nodeToShow) { + RED.view.reveal(nodeToShow.id) + window.location.hash = currentHash + RED.view.select(nodeToShow.id) + if (showEditDialog) { + RED.editor.editGroup(nodeToShow) + } + } + } } if (RED.workspaces.count() > 0) { const hiddenTabs = JSON.parse(RED.settings.getLocal("hiddenTabs")||"{}"); @@ -643,11 +672,6 @@ var RED = (function() { ]}); menuOptions.push({id:"menu-item-arrange-menu", label:RED._("menu.label.arrange"), options: [ - {id: "menu-item-view-tools-move-to-back", label:RED._("menu.label.moveToBack"), disabled: true, onselect: "core:move-selection-to-back"}, - {id: "menu-item-view-tools-move-to-front", label:RED._("menu.label.moveToFront"), disabled: true, onselect: "core:move-selection-to-front"}, - {id: "menu-item-view-tools-move-backwards", label:RED._("menu.label.moveBackwards"), disabled: true, onselect: "core:move-selection-backwards"}, - {id: "menu-item-view-tools-move-forwards", label:RED._("menu.label.moveForwards"), disabled: true, onselect: "core:move-selection-forwards"}, - null, {id: "menu-item-view-tools-align-left", label:RED._("menu.label.alignLeft"), disabled: true, onselect: "core:align-selection-to-left"}, {id: "menu-item-view-tools-align-center", label:RED._("menu.label.alignCenter"), disabled: true, onselect: "core:align-selection-to-center"}, {id: "menu-item-view-tools-align-right", label:RED._("menu.label.alignRight"), disabled: true, onselect: "core:align-selection-to-right"}, @@ -657,7 +681,12 @@ var RED = (function() { {id: "menu-item-view-tools-align-bottom", label:RED._("menu.label.alignBottom"), disabled: true, onselect: "core:align-selection-to-bottom"}, null, {id: "menu-item-view-tools-distribute-horizontally", label:RED._("menu.label.distributeHorizontally"), disabled: true, onselect: "core:distribute-selection-horizontally"}, - {id: "menu-item-view-tools-distribute-veritcally", label:RED._("menu.label.distributeVertically"), disabled: true, onselect: "core:distribute-selection-vertically"} + {id: "menu-item-view-tools-distribute-veritcally", label:RED._("menu.label.distributeVertically"), disabled: true, onselect: "core:distribute-selection-vertically"}, + null, + {id: "menu-item-view-tools-move-to-back", label:RED._("menu.label.moveToBack"), disabled: true, onselect: "core:move-selection-to-back"}, + {id: "menu-item-view-tools-move-to-front", label:RED._("menu.label.moveToFront"), disabled: true, onselect: "core:move-selection-to-front"}, + {id: "menu-item-view-tools-move-backwards", label:RED._("menu.label.moveBackwards"), disabled: true, onselect: "core:move-selection-backwards"}, + {id: "menu-item-view-tools-move-forwards", label:RED._("menu.label.moveForwards"), disabled: true, onselect: "core:move-selection-forwards"} ]}); menuOptions.push(null); @@ -750,6 +779,7 @@ var RED = (function() { RED.deploy.init(RED.settings.theme("deployButton",null)); RED.keyboard.init(buildMainMenu); + RED.envVar.init(); RED.nodes.init(); RED.runtime.init() diff --git a/packages/node_modules/@node-red/editor-client/src/js/settings.js b/packages/node_modules/@node-red/editor-client/src/js/settings.js index c9a24d636..85c930bfb 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/settings.js +++ b/packages/node_modules/@node-red/editor-client/src/js/settings.js @@ -33,8 +33,8 @@ RED.settings = (function () { if (!hasLocalStorage()) { return; } - if (key === "auth-tokens") { - localStorage.setItem(key, JSON.stringify(value)); + if (key.startsWith("auth-tokens")) { + localStorage.setItem(key+this.authTokensSuffix, JSON.stringify(value)); } else { RED.utils.setMessageProperty(userSettings,key,value); saveUserSettings(); @@ -52,8 +52,8 @@ RED.settings = (function () { if (!hasLocalStorage()) { return undefined; } - if (key === "auth-tokens") { - return JSON.parse(localStorage.getItem(key)); + if (key.startsWith("auth-tokens")) { + return JSON.parse(localStorage.getItem(key+this.authTokensSuffix)); } else { var v; try { v = RED.utils.getMessageProperty(userSettings,key); } catch(err) {} @@ -71,8 +71,8 @@ RED.settings = (function () { if (!hasLocalStorage()) { return; } - if (key === "auth-tokens") { - localStorage.removeItem(key); + if (key.startsWith("auth-tokens")) { + localStorage.removeItem(key+this.authTokensSuffix); } else { delete userSettings[key]; saveUserSettings(); @@ -99,6 +99,8 @@ RED.settings = (function () { var init = function (options, done) { var accessTokenMatch = /[?&]access_token=(.*?)(?:$|&)/.exec(window.location.search); + var path=window.location.pathname.slice(0,-1); + RED.settings.authTokensSuffix=path.replace(/\//g, '-'); if (accessTokenMatch) { var accessToken = accessTokenMatch[1]; RED.settings.set("auth-tokens",{access_token: accessToken}); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js b/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js index af82f1b14..01a993a75 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js @@ -423,11 +423,10 @@ RED.clipboard = (function() { } } - function showImportNodes(mode) { + function showImportNodes(library = 'clipboard') { if (disabled) { return; } - mode = mode || "clipboard"; dialogContainer.empty(); dialogContainer.append($(importNodesDialog)); @@ -504,7 +503,7 @@ RED.clipboard = (function() { $("#red-ui-clipboard-dialog-import-text").on("keyup", validateImport); $("#red-ui-clipboard-dialog-import-text").on('paste',function() { setTimeout(validateImport,10)}); - if (RED.workspaces.active() === 0) { + if (RED.workspaces.active() === 0 || RED.workspaces.isLocked()) { $("#red-ui-clipboard-dialog-import-opt-current").addClass('disabled').removeClass("selected"); $("#red-ui-clipboard-dialog-import-opt-new").addClass("selected"); } else { @@ -533,8 +532,8 @@ RED.clipboard = (function() { $("#red-ui-clipboard-dialog-import-file-upload").trigger("click"); }) - tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+mode); - if (mode === 'clipboard') { + tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+library); + if (library === 'clipboard') { setTimeout(function() { $("#red-ui-clipboard-dialog-import-text").trigger("focus"); },100) @@ -558,13 +557,16 @@ RED.clipboard = (function() { }); } - function showExportNodes(mode) { + /** + * Show the export dialog + * @params library which export destination to show + * @params mode whether to default to 'auto' (default) or 'flow' + **/ + function showExportNodes(library = 'clipboard', mode = 'auto' ) { if (disabled) { return; } - mode = mode || "clipboard"; - dialogContainer.empty(); dialogContainer.append($(exportNodesDialog)); @@ -654,7 +656,12 @@ RED.clipboard = (function() { $("#red-ui-clipboard-dialog-tab-library-name").val("flows.json").select(); dialogContainer.i18n(); + var format = RED.settings.flowFilePretty ? "red-ui-clipboard-dialog-export-fmt-full" : "red-ui-clipboard-dialog-export-fmt-mini"; + const userFormat = RED.settings.get("editor.dialog.export.pretty") + if (userFormat === false || userFormat === true) { + format = userFormat ? "red-ui-clipboard-dialog-export-fmt-full" : "red-ui-clipboard-dialog-export-fmt-mini"; + } $("#red-ui-clipboard-dialog-export-fmt-group > a").on("click", function(evt) { evt.preventDefault(); @@ -670,7 +677,8 @@ RED.clipboard = (function() { var nodes = JSON.parse(flow); format = $(this).attr('id'); - if (format === 'red-ui-clipboard-dialog-export-fmt-full') { + const pretty = format === "red-ui-clipboard-dialog-export-fmt-full"; + if (pretty) { flow = JSON.stringify(nodes,null,4); } else { flow = JSON.stringify(nodes); @@ -679,6 +687,7 @@ RED.clipboard = (function() { setTimeout(function() { $("#red-ui-clipboard-dialog-export-text").scrollTop(0); },50); $("#red-ui-clipboard-dialog-export-text").trigger("focus"); + RED.settings.set("editor.dialog.export.pretty", pretty) } }); @@ -722,7 +731,7 @@ RED.clipboard = (function() { nodes.unshift(parentNode); nodes = RED.nodes.createExportableNodeSet(nodes); } else if (type === 'full') { - nodes = RED.nodes.createCompleteNodeSet(false); + nodes = RED.nodes.createCompleteNodeSet({ credentials: false }); } if (nodes !== null) { if (format === "red-ui-clipboard-dialog-export-fmt-full") { @@ -766,12 +775,15 @@ RED.clipboard = (function() { } } } + if (mode === 'flow' && !$("#red-ui-clipboard-dialog-export-rng-flow").hasClass('disabled')) { + $("#red-ui-clipboard-dialog-export-rng-flow").trigger("click"); + } if (format === "red-ui-clipboard-dialog-export-fmt-full") { $("#red-ui-clipboard-dialog-export-fmt-full").trigger("click"); } else { $("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click"); } - tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode); + tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+library); var dialogHeight = 400; var winHeight = $(window).height(); @@ -1266,15 +1278,17 @@ RED.clipboard = (function() { RED.keyboard.add("#red-ui-drop-target", "escape" ,hideDropTarget); $('#red-ui-workspace-chart').on("dragenter",function(event) { - if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || - $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { + if (!RED.workspaces.isLocked() && ( + $.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || + $.inArray("Files",event.originalEvent.dataTransfer.types) != -1)) { $("#red-ui-drop-target").css({display:'table'}).focus(); } }); $('#red-ui-drop-target').on("dragover",function(event) { if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || - $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { + $.inArray("Files",event.originalEvent.dataTransfer.types) != -1 || + RED.workspaces.isLocked()) { event.preventDefault(); } }) @@ -1282,27 +1296,29 @@ RED.clipboard = (function() { hideDropTarget(); }) .on("drop",function(event) { - try { - if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) { - var data = event.originalEvent.dataTransfer.getData("text/plain"); - data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1); - importNodes(data); - } else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { - var files = event.originalEvent.dataTransfer.files; - if (files.length === 1) { - var file = files[0]; - var reader = new FileReader(); - reader.onload = (function(theFile) { - return function(e) { - importNodes(e.target.result); - }; - })(file); - reader.readAsText(file); + if (!RED.workspaces.isLocked()) { + try { + if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) { + var data = event.originalEvent.dataTransfer.getData("text/plain"); + data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1); + importNodes(data); + } else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { + var files = event.originalEvent.dataTransfer.files; + if (files.length === 1) { + var file = files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + importNodes(e.target.result); + }; + })(file); + reader.readAsText(file); + } } + } catch(err) { + // Ensure any errors throw above doesn't stop the drop target from + // being hidden. } - } catch(err) { - // Ensure any errors throw above doesn't stop the drop target from - // being hidden. } hideDropTarget(); event.preventDefault(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js index f308614d7..8ee1f0e29 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js @@ -417,6 +417,9 @@ } else { return null; } + }, + cancel: function() { + this.element.sortable("cancel"); } }); })(jQuery); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js index 2d95f894a..8d0f1dbd3 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js @@ -94,8 +94,8 @@ RED.menu = (function() { var link = $(linkContent).appendTo(item); opt.link = link; - if (typeof opt.onselect === 'string') { - var shortcut = RED.keyboard.getShortcut(opt.onselect); + if (typeof opt.onselect === 'string' || opt.shortcut) { + var shortcut = opt.shortcut || RED.keyboard.getShortcut(opt.onselect); if (shortcut && shortcut.key) { opt.shortcutSpan = $(''+RED.keyboard.formatKey(shortcut.key, true)+'').appendTo(link.find(".red-ui-menu-label")); } diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js index 8901cf11f..abb76e622 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js @@ -141,7 +141,29 @@ RED.tabs = (function() { }) } - + if (options.contextmenu) { + wrapper.on('contextmenu', function(evt) { + let clickedTab + let target = evt.target + while(target.nodeName !== 'A' && target.nodeName !== 'UL' && target.nodeName !== 'BODY') { + target = target.parentNode + } + if (target.nodeName === 'A') { + const href = target.getAttribute('href') + if (href) { + clickedTab = tabs[href.slice(1)] + } + } + evt.preventDefault() + evt.stopPropagation() + RED.contextMenu.show({ + x:evt.clientX-5, + y:evt.clientY-5, + options: options.contextmenu(clickedTab) + }) + return false + }) + } var scrollLeft; var scrollRight; @@ -161,7 +183,7 @@ RED.tabs = (function() { // Assume this is wheel event which might not trigger // the scroll event, so do things manually var sl = scrollContainer.scrollLeft(); - sl -= evt.originalEvent.deltaY; + sl += evt.originalEvent.deltaY; scrollContainer.scrollLeft(sl); } }) @@ -807,23 +829,22 @@ RED.tabs = (function() { event.preventDefault(); removeTab(tab.id); }); - RED.popover.tooltip(closeLink,RED._("workspace.hideFlow")); - } - if (tab.hideable) { - li.addClass("red-ui-tabs-closeable") - var closeLink = $("",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li); - closeLink.append(''); - closeLink.append(''); - closeLink.on("click",function(event) { - event.preventDefault(); - hideTab(tab.id); - }); - RED.popover.tooltip(closeLink,RED._("workspace.hideFlow")); + RED.popover.tooltip(closeLink,RED._("workspace.closeFlow")); } + // if (tab.hideable) { + // li.addClass("red-ui-tabs-closeable") + // var closeLink = $("",{href:"#",class:"red-ui-tab-close red-ui-tab-hide"}).appendTo(li); + // closeLink.append(''); + // closeLink.append(''); + // closeLink.on("click",function(event) { + // event.preventDefault(); + // hideTab(tab.id); + // }); + // RED.popover.tooltip(closeLink,RED._("workspace.hideFlow")); + // } var badges = $('').appendTo(li); if (options.onselect) { - $('').appendTo(badges); $('').appendTo(badges); } @@ -938,6 +959,9 @@ RED.tabs = (function() { activeIndex: function() { return ul.find("li.active").index() }, + getTabIndex: function (id) { + return ul.find("a[href='#"+id+"']").parent().index() + }, contains: function(id) { return ul.find("a[href='#"+id+"']").length > 0; }, diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js index a1fdb402a..b63cdc1a2 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/contextMenu.js @@ -1,21 +1,6 @@ RED.contextMenu = (function () { let menu; - function createMenu() { - // menu = RED.popover.menu({ - // options: [ - // { - // label: 'delete selection', - // onselect: function() { - // RED.actions.invoke('core:delete-selection') - // RED.view.focus() - // } - // }, - // { label: 'world' } - // ], - // width: 200, - // }) - } function disposeMenu() { $(document).off("mousedown.red-ui-workspace-context-menu"); @@ -28,114 +13,172 @@ RED.contextMenu = (function () { if (menu) { menu.remove() } + let menuItems = [] + if (options.options) { + menuItems = options.options + } else if (options.type === 'workspace') { + const selection = RED.view.selection() + const noSelection = !selection || Object.keys(selection).length === 0 + const hasSelection = (selection.nodes && selection.nodes.length > 0); + const hasMultipleSelection = hasSelection && selection.nodes.length > 1; + const virtulLinks = (selection.links && selection.links.filter(e => !!e.link)) || []; + const wireLinks = (selection.links && selection.links.filter(e => !e.link)) || []; + const hasLinks = wireLinks.length > 0; + const isSingleLink = !hasSelection && hasLinks && wireLinks.length === 1 + const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1 + const canDelete = hasSelection || hasLinks + const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group' + const canEdit = !RED.workspaces.isLocked() + const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g + const isAllGroups = hasSelection && selection.nodes.filter(n => n.type !== 'group').length === 0 + const hasGroup = hasSelection && selection.nodes.filter(n => n.type === 'group' ).length > 0 + const offset = $("#red-ui-workspace-chart").offset() - const selection = RED.view.selection() - const noSelection = !selection || Object.keys(selection).length === 0 - const hasSelection = (selection.nodes && selection.nodes.length > 0); - const hasMultipleSelection = hasSelection && selection.nodes.length > 1; - const virtulLinks = (selection.links && selection.links.filter(e => !!e.link)) || []; - const wireLinks = (selection.links && selection.links.filter(e => !e.link)) || []; - const hasLinks = wireLinks.length > 0; - const isSingleLink = !hasSelection && hasLinks && wireLinks.length === 1 - const isMultipleLinks = !hasSelection && hasLinks && wireLinks.length > 1 - const canDelete = hasSelection || hasLinks - const isGroup = hasSelection && selection.nodes.length === 1 && selection.nodes[0].type === 'group' - - const canRemoveFromGroup = hasSelection && !!selection.nodes[0].g - const offset = $("#red-ui-workspace-chart").offset() - - // addX/addY must be the position in the workspace accounting for both scroll and scale - // The +5 is because we display the contextMenu -5,-5 to actual click position - let addX = (options.x + 5 - offset.left + $("#red-ui-workspace-chart").scrollLeft()) / RED.view.scale() - let addY = (options.y + 5 - offset.top + $("#red-ui-workspace-chart").scrollTop()) / RED.view.scale() - - const menuItems = [ - { onselect: 'core:show-action-list', onpostselect: function () { } }, - { - label: RED._("contextMenu.insert"), - options: [ - { - label: RED._("contextMenu.node"), - onselect: function () { - RED.view.showQuickAddDialog({ - position: [addX, addY], - touchTrigger: true, - splice: isSingleLink ? selection.links[0] : undefined, - // spliceMultiple: isMultipleLinks - }) - }, - onpostselect: function() { - // ensure quick add dialog search input has focus - $('#red-ui-type-search-input').trigger('focus') - } - }, - (hasLinks) ? { // has least 1 wire selected - label: RED._("contextMenu.junction"), - onselect: 'core:split-wires-with-junctions', - disabled: !hasLinks - } : { - label: RED._("contextMenu.junction"), - onselect: function () { - const nn = { - _def: { defaults: {} }, - type: 'junction', - z: RED.workspaces.active(), - id: RED.nodes.id(), - x: addX, - y: addY, - w: 0, h: 0, - outputs: 1, - inputs: 1, - dirty: true - } - const historyEvent = { - dirty: RED.nodes.dirty(), - t: 'add', - junctions: [nn] - } - RED.nodes.addJunction(nn); - RED.history.push(historyEvent); - RED.nodes.dirty(true); - RED.view.select({nodes: [nn] }); - RED.view.redraw(true) - } - }, - { - label: RED._("contextMenu.linkNodes"), - onselect: 'core:split-wire-with-link-nodes', - disabled: !hasLinks - } - ] - - + let addX = options.x - offset.left + $("#red-ui-workspace-chart").scrollLeft() + let addY = options.y - offset.top + $("#red-ui-workspace-chart").scrollTop() + if (RED.view.snapGrid) { + const gridSize = RED.view.gridSize() + addX = gridSize * Math.floor(addX / gridSize) + addY = gridSize * Math.floor(addY / gridSize) + } + + menuItems.push( + { onselect: 'core:show-action-list', onpostselect: function () { } } + ) + + const insertOptions = [] + menuItems.push({ label: RED._("contextMenu.insert"), options: insertOptions }) + insertOptions.push( + { + label: RED._("contextMenu.node"), + onselect: function () { + RED.view.showQuickAddDialog({ + position: [addX, addY], + touchTrigger: true, + splice: isSingleLink ? selection.links[0] : undefined, + // spliceMultiple: isMultipleLinks + }) + }, + disabled: !canEdit + }, + (hasLinks) ? { // has least 1 wire selected + label: RED._("contextMenu.junction"), + onselect: 'core:split-wires-with-junctions', + disabled: !canEdit || !hasLinks + } : { + label: RED._("contextMenu.junction"), + onselect: function () { + const nn = { + _def: { defaults: {} }, + type: 'junction', + z: RED.workspaces.active(), + id: RED.nodes.id(), + x: addX, + y: addY, + w: 0, h: 0, + outputs: 1, + inputs: 1, + dirty: true, + moved: true + } + const junction = RED.nodes.addJunction(nn); + const historyEvent = { + dirty: RED.nodes.dirty(), + t: 'add', + junctions: [junction] + } + RED.history.push(historyEvent); + RED.nodes.dirty(true); + RED.view.select({nodes: [junction] }); + RED.view.redraw(true) + }, + disabled: !canEdit + }, + { + label: RED._("contextMenu.linkNodes"), + onselect: 'core:split-wire-with-link-nodes', + disabled: !canEdit || !hasLinks + }, + null, + { onselect: 'core:show-import-dialog', label: RED._('common.label.import')}, + { onselect: 'core:show-examples-import-dialog', label: RED._('menu.label.importExample') } + ) + if (hasSelection && canEdit) { + const nodeOptions = [] + if (!hasMultipleSelection && !isGroup) { + nodeOptions.push( + { onselect: 'core:show-node-help' }, + null + ) + } + nodeOptions.push( + { onselect: 'core:enable-selected-nodes' }, + { onselect: 'core:disable-selected-nodes' }, + null, + { onselect: 'core:show-selected-node-labels' }, + { onselect: 'core:hide-selected-node-labels' } + ) + menuItems.push({ + label: RED._('sidebar.info.node'), + options: nodeOptions + }) + menuItems.push({ + label: RED._('sidebar.info.group'), + options: [ + { onselect: 'core:group-selection' }, + { onselect: 'core:ungroup-selection', disabled: !hasGroup }, + ] + }) + if (hasGroup) { + menuItems[menuItems.length - 1].options.push( + { onselect: 'core:merge-selection-to-group', label: RED._("menu.label.groupMergeSelection") } + ) + + } + if (canRemoveFromGroup) { + menuItems[menuItems.length - 1].options.push( + { onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") } + ) + } + menuItems[menuItems.length - 1].options.push( + null, + { onselect: 'core:copy-group-style', disabled: !hasGroup }, + { onselect: 'core:paste-group-style', disabled: !hasGroup} + ) + } + if (canEdit && hasMultipleSelection) { + menuItems.push({ + label: RED._('menu.label.arrange'), + options: [ + { label:RED._("menu.label.alignLeft"), onselect: "core:align-selection-to-left"}, + { label:RED._("menu.label.alignCenter"), onselect: "core:align-selection-to-center"}, + { label:RED._("menu.label.alignRight"), onselect: "core:align-selection-to-right"}, + null, + { label:RED._("menu.label.alignTop"), onselect: "core:align-selection-to-top"}, + { label:RED._("menu.label.alignMiddle"), onselect: "core:align-selection-to-middle"}, + { label:RED._("menu.label.alignBottom"), onselect: "core:align-selection-to-bottom"}, + null, + { label:RED._("menu.label.distributeHorizontally"), onselect: "core:distribute-selection-horizontally"}, + { label:RED._("menu.label.distributeVertically"), onselect: "core:distribute-selection-vertically"} + ] + }) } - ] - menuItems.push( - null, - { onselect: 'core:undo', disabled: RED.history.list().length === 0 }, - { onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 }, - null, - { onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !hasSelection }, - { onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection }, - { onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !RED.view.clipboard() }, - { onselect: 'core:delete-selection', disabled: !canDelete }, - { onselect: 'core:show-export-dialog', label: RED._("menu.label.export") }, - { onselect: 'core:select-all-nodes' } - ) - if (hasSelection) { menuItems.push( null, - isGroup ? - { onselect: 'core:ungroup-selection', disabled: !isGroup } - : { onselect: 'core:group-selection', disabled: !hasSelection } + { onselect: 'core:undo', disabled: RED.history.list().length === 0 }, + { onselect: 'core:redo', disabled: RED.history.listRedo().length === 0 }, + null, + { onselect: 'core:cut-selection-to-internal-clipboard', label: RED._("keyboard.cutNode"), disabled: !canEdit || !hasSelection }, + { onselect: 'core:copy-selection-to-internal-clipboard', label: RED._("keyboard.copyNode"), disabled: !hasSelection }, + { onselect: 'core:paste-from-internal-clipboard', label: RED._("keyboard.pasteNode"), disabled: !canEdit || !RED.view.clipboard() }, + { onselect: 'core:delete-selection', disabled: !canEdit || !canDelete }, + { onselect: 'core:delete-selection-and-reconnect', label: RED._('keyboard.deleteReconnect'), disabled: !canEdit || !canDelete }, + { onselect: 'core:show-export-dialog', label: RED._("menu.label.export") }, + { onselect: 'core:select-all-nodes' }, ) - if (canRemoveFromGroup) { - menuItems.push({ onselect: 'core:remove-selection-from-group', label: RED._("menu.label.groupRemoveSelection") }) - } - } var direction = "right"; diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js index 8a8df6837..a09fdeb01 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js @@ -557,7 +557,17 @@ RED.deploy = (function() { } else { RED.notify('

' + RED._("deploy.successfulDeploy") + '

', "success"); } + const flowsToLock = new Set() + function ensureUnlocked(id) { + const flow = id && (RED.nodes.workspace(id) || RED.nodes.subflow(id) || null); + const isLocked = flow ? flow.locked : false; + if (flow && isLocked) { + flow.locked = false; + flowsToLock.add(flow) + } + } RED.nodes.eachNode(function (node) { + ensureUnlocked(node.z) if (node.changed) { node.dirty = true; node.changed = false; @@ -570,7 +580,32 @@ RED.deploy = (function() { delete node.credentials; } }); + RED.nodes.eachGroup(function (node) { + ensureUnlocked(node.z) + if (node.changed) { + node.dirty = true; + node.changed = false; + } + if (node.moved) { + node.dirty = true; + node.moved = false; + } + }) + RED.nodes.eachJunction(function (node) { + ensureUnlocked(node.z) + if (node.changed) { + node.dirty = true; + node.changed = false; + } + if (node.moved) { + node.dirty = true; + node.moved = false; + } + }) RED.nodes.eachConfig(function (confNode) { + if (confNode.z) { + ensureUnlocked(confNode.z) + } confNode.changed = false; if (confNode.credentials) { delete confNode.credentials; @@ -580,8 +615,16 @@ RED.deploy = (function() { subflow.changed = false; }); RED.nodes.eachWorkspace(function (ws) { - ws.changed = false; + if (ws.changed || ws.added) { + ensureUnlocked(ws.z) + ws.changed = false; + delete ws.added + RED.events.emit("flows:change", ws) + } }); + flowsToLock.forEach(flow => { + flow.locked = true + }) // Once deployed, cannot undo back to a clean state RED.history.markAllDirty(); RED.view.redraw(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js index 188819734..3c994491c 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js @@ -862,6 +862,7 @@ RED.editor = (function() { function showEditDialog(node, defaultTab) { if (buildingEditDialog) { return } buildingEditDialog = true; + if (node.z && RED.workspaces.isLocked(node.z)) { return } var editing_node = node; var removeInfoEditorOnClose = false; var skipInfoRefreshOnClose = false; @@ -1047,6 +1048,13 @@ RED.editor = (function() { var trayFooterLeft = $('').appendTo(trayFooter) + var helpButton = $('').on("click", function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + RED.sidebar.help.show(editing_node.type); + }).appendTo(trayFooterLeft); + RED.popover.tooltip(helpButton, RED._("sidebar.help.showHelp")); + $('').prop("checked",!!node.d).appendTo(trayFooterLeft).toggleButton({ enabledIcon: "fa-circle-thin", disabledIcon: "fa-ban", @@ -1150,6 +1158,8 @@ RED.editor = (function() { var editing_config_node = RED.nodes.node(id); var activeEditPanes = []; + if (editing_config_node && editing_config_node.z && RED.workspaces.isLocked(editing_config_node.z)) { return } + var configNodeScope = ""; // default to global var activeSubflow = RED.nodes.subflow(RED.workspaces.active()); if (activeSubflow) { @@ -1192,6 +1202,13 @@ RED.editor = (function() { var trayFooterLeft = $('').appendTo(trayFooter) + var helpButton = $('').on("click", function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + RED.sidebar.help.show(editing_config_node.type); + }).appendTo(trayFooterLeft); + RED.popover.tooltip(helpButton, RED._("sidebar.help.showHelp")); + $('').prop("checked",!!editing_config_node.d).appendTo(trayFooterLeft).toggleButton({ enabledIcon: "fa-circle-thin", disabledIcon: "fa-ban", @@ -1696,6 +1713,7 @@ RED.editor = (function() { function showEditGroupDialog(group, defaultTab) { if (buildingEditDialog) { return } buildingEditDialog = true; + if (group.z && RED.workspaces.isLocked(group.z)) { return } var editing_node = group; editStack.push(group); RED.view.state(RED.state.EDITING); @@ -1855,11 +1873,15 @@ RED.editor = (function() { workspace.disabled = disabled; $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-disabled',!!workspace.disabled); - if (workspace.id === RED.workspaces.active()) { - $("#red-ui-workspace").toggleClass("red-ui-workspace-disabled",!!workspace.disabled); - } } + var locked = $("#node-input-locked").prop("checked"); + if (workspace.locked !== locked) { + editState.changes.locked = workspace.locked; + editState.changed = true; + workspace.locked = locked; + $("#red-ui-tab-"+(workspace.id.replace(".","-"))).toggleClass('red-ui-workspace-locked',!!workspace.locked); + } if (editState.changed) { var historyEvent = { t: "edit", @@ -1900,6 +1922,7 @@ RED.editor = (function() { var trayBody = tray.find('.red-ui-tray-body'); trayBody.parent().css('overflow','hidden'); var trayFooterLeft = $('').appendTo(trayFooter) + var trayFooterRight = $('').appendTo(trayFooter) var nodeEditPanes = [ 'editor-tab-flow-properties', @@ -1914,6 +1937,18 @@ RED.editor = (function() { disabledIcon: "fa-ban", invertState: true }) + + if (!workspace.hasOwnProperty("locked")) { + workspace.locked = false; + } + $('').prop("checked",workspace.locked).appendTo(trayFooterRight).toggleButton({ + enabledLabel: RED._("common.label.unlocked"), + enabledIcon: "fa-unlock-alt", + disabledLabel: RED._("common.label.locked"), + disabledIcon: "fa-lock", + invertState: true + }) + prepareEditDialog(trayBody, nodeEditPanes, workspace, {}, "node-input", defaultTab, function(_activeEditPanes) { activeEditPanes = _activeEditPanes; trayBody.i18n(); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js index 7cee2026b..b92881764 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editors/code-editor.js @@ -45,6 +45,9 @@ selectedCodeEditor = RED.editor.codeEditor[defaultEditor]; initialised = selectedCodeEditor.init(); } + + $('

').appendTo('#red-ui-editor'); + $("#red-ui-image-drop-target").hide(); } function create(options) { @@ -64,6 +67,7 @@ options = {}; } + var editor = null; if (this.editor.type === MONACO) { // compatibility (see above note) if (!options.element && !options.id) { @@ -74,10 +78,14 @@ console.warn("createEditor() options.element or options.id is not valid", options); $("#dialog-form").append('