commit 734726fc1230dc272abd818b018d011dd87d0038 Author: Manan006 Date: Wed Jan 31 17:57:16 2024 +0530 Initial Commit diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..d381628 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +**/xtscancodes.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..a53bb40 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,50 @@ +{ + "env": { + "browser": true, + "es6": true + }, + "parserOptions": { + "sourceType": "module" + }, + "extends": "eslint:recommended", + "rules": { + // Unsafe or confusing stuff that we forbid + + "no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }], + "no-constant-condition": ["error", { "checkLoops": false }], + "no-var": "error", + "no-useless-constructor": "error", + "object-shorthand": ["error", "methods", { "avoidQuotes": true }], + "prefer-arrow-callback": "error", + "arrow-body-style": ["error", "as-needed", { "requireReturnForObjectLiteral": false } ], + "arrow-parens": ["error", "as-needed", { "requireForBlockBody": true }], + "arrow-spacing": ["error"], + "no-confusing-arrow": ["error", { "allowParens": true }], + + // Enforced coding style + + "brace-style": ["error", "1tbs", { "allowSingleLine": true }], + "indent": ["error", 4, { "SwitchCase": 1, + "FunctionDeclaration": { "parameters": "first" }, + "CallExpression": { "arguments": "first" }, + "ArrayExpression": "first", + "ObjectExpression": "first", + "ignoreComments": true }], + "comma-spacing": ["error"], + "comma-style": ["error"], + "curly": ["error", "multi-line"], + "func-call-spacing": ["error"], + "func-names": ["error"], + "func-style": ["error", "declaration", { "allowArrowFunctions": true }], + "key-spacing": ["error"], + "keyword-spacing": ["error"], + "no-trailing-spaces": ["error"], + "semi": ["error"], + "space-before-blocks": ["error"], + "space-before-function-paren": ["error", { "anonymous": "always", + "named": "never", + "asyncArrow": "always" }], + "switch-colon-spacing": ["error"], + "camelcase": ["error", { allow: ["^XK_", "^XF86XK_"] }], + } +} diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..94ac6f8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,34 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Client (please complete the following information):** + - OS: [e.g. iOS] + - Browser: [e.g. chrome, safari] + - Browser version: [e.g. 22] + +**Server (please complete the following information):** + - noVNC version: [e.g. 1.0.0 or git commit id] + - VNC server: [e.g. QEMU, TigerVNC] + - WebSocket proxy: [e.g. websockify] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..cbd35aa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Question or discussion + url: https://groups.google.com/forum/?fromgroups#!forum/novnc + about: Ask a question or start a discussion diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..066b2d9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..6b0ac96 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,56 @@ +name: Publish + +on: + push: + pull_request: + release: + types: [published] + +jobs: + npm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + # Needs to be explicitly specified for auth to work + registry-url: 'https://registry.npmjs.org' + - run: npm install + - uses: actions/upload-artifact@v2 + with: + name: npm + path: lib + - run: npm publish --access public + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + if: ${{ github.event_name == 'release' && !github.event.release.prerelease }} + - run: npm publish --access public --tag beta + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + if: ${{ github.event_name == 'release' && github.event.release.prerelease }} + snap: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: | + VERSION=$(grep '"version"' package.json | cut -d '"' -f 4) + echo $VERSION + sed -i "s/@VERSION@/$VERSION/g" snap/snapcraft.yaml + - uses: snapcore/action-build@v1 + id: snapcraft + - uses: actions/upload-artifact@v2 + with: + name: snap + path: ${{ steps.snapcraft.outputs.snap }} + - uses: snapcore/action-publish@v1 + with: + store_login: ${{ secrets.SNAPCRAFT_LOGIN }} + snap: ${{ steps.build.outputs.snap }} + release: stable + if: ${{ github.event_name == 'release' && !github.event.release.prerelease }} + - uses: snapcore/action-publish@v1 + with: + store_login: ${{ secrets.SNAPCRAFT_LOGIN }} + snap: ${{ steps.build.outputs.snap }} + release: beta + if: ${{ github.event_name == 'release' && github.event.release.prerelease }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..aaa3673 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,19 @@ +name: Lint + +on: [push, pull_request] + +jobs: + eslint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + - run: npm install + - run: npm run lint + html: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + - run: npm install + - run: git ls-tree --name-only -r HEAD | grep -E "[.](html|css)$" | xargs ./utils/validate diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..a0bcb36 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,28 @@ +name: Test + +on: [push, pull_request] + +jobs: + test: + strategy: + matrix: + os: + - ubuntu-latest + - windows-latest + browser: + - ChromeHeadless + - FirefoxHeadless + include: + - os: macos-latest + browser: Safari + - os: windows-latest + browser: EdgeHeadless + fail-fast: false + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + - run: npm install + - run: npm run test + env: + TEST_BROWSER_NAME: ${{ matrix.browser }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c178dba --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*.pyc +*.o +tests/data_*.js +utils/rebind.so +utils/websockify +/node_modules +/build +/lib +recordings +*.swp +*~ +noVNC-*.tgz diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..dec0e89 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,13 @@ +maintainers: +- Joel Martin (@kanaka) +- Solly Ross (@directxman12) +- Samuel Mannehed for Cendio AB (@samhed) +- Pierre Ossman for Cendio AB (@CendioOssman) +maintainersEmeritus: +- @astrand +contributors: +# There are a bunch of people that should be here. +# If you want to be on this list, feel free send a PR +# to add yourself. +- jalf +- NTT corp. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..ee81d20 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,62 @@ +noVNC is Copyright (C) 2019 The noVNC Authors +(./AUTHORS) + +The noVNC core library files are licensed under the MPL 2.0 (Mozilla +Public License 2.0). The noVNC core library is composed of the +Javascript code necessary for full noVNC operation. This includes (but +is not limited to): + + core/**/*.js + app/*.js + test/playback.js + +The HTML, CSS, font and images files that included with the noVNC +source distibution (or repository) are not considered part of the +noVNC core library and are licensed under more permissive licenses. +The intent is to allow easy integration of noVNC into existing web +sites and web applications. + +The HTML, CSS, font and image files are licensed as follows: + + *.html : 2-Clause BSD license + + app/styles/*.css : 2-Clause BSD license + + app/styles/Orbitron* : SIL Open Font License 1.1 + (Copyright 2009 Matt McInerney) + + app/images/ : Creative Commons Attribution-ShareAlike + http://creativecommons.org/licenses/by-sa/3.0/ + +Some portions of noVNC are copyright to their individual authors. +Please refer to the individual source files and/or to the noVNC commit +history: https://github.com/novnc/noVNC/commits/master + +The are several files and projects that have been incorporated into +the noVNC core library. Here is a list of those files and the original +licenses (all MPL 2.0 compatible): + + core/base64.js : MPL 2.0 + + core/des.js : Various BSD style licenses + + vendor/pako/ : MIT + +Any other files not mentioned above are typically marked with +a copyright/license header at the top of the file. The default noVNC +license is MPL-2.0. + +The following license texts are included: + + docs/LICENSE.MPL-2.0 + docs/LICENSE.OFL-1.1 + docs/LICENSE.BSD-3-Clause (New BSD) + docs/LICENSE.BSD-2-Clause (Simplified BSD / FreeBSD) + vendor/pako/LICENSE (MIT) + +Or alternatively the license texts may be found here: + + http://www.mozilla.org/MPL/2.0/ + http://scripts.sil.org/OFL + http://en.wikipedia.org/wiki/BSD_licenses + https://opensource.org/licenses/MIT diff --git a/README.md b/README.md new file mode 100644 index 0000000..d77cb51 --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +## KasmVNC Web Front-End + + + +KasmVNC provides remote web-based access to a Desktop or application. While VNC is in the name, KasmVNC differs from other VNC variants such as TigerVNC, RealVNC, and TurboVNC. KasmVNC has broken from the RFB specification which defines VNC, in order to support modern technologies and increase security. KasmVNC is accessed by users from any modern browser and does not support legacy VNC viewer applications. KasmVNC uses a modern YAML based configuration at the server and user level, allowing for ease of management. + +[Kasm Technologies](https://www.kasmweb.com) developed Kasm Workspaces, the Containerized Streaming Platform. Kasm has open-sourced the Workspace docker images, which include containerized [full desktops and apps](https://github.com/kasmtech/workspaces-images) and [base images](https://github.com/kasmtech/workspaces-core-images) intended for developers to create custimized streaming containers. These containers can be used standalone or within the [Kasm Workspaces Platform](https://www.kasmweb.com) which provides a full Enterprise feature set. + +## News/Help/Contact + +For support with KasmVNC, post on the [KasmVNC Project](https://github.com/kasmtech/KasmVNC). + +## Documentation + +**Do not use the README from the master branch**, unless you are compiling KasmVNC yourself from the tip of master. Use the documentation for your specific release. + + - [KasmVNC 1.0.0 Documentation](https://www.kasmweb.com/kasmvnc/docs/1.0.0/index.html) + + For beta releases prior to version 1.0.0, use the README in this github project on the tagged commit for that release. + +## Features + + - Webp image compression for better bandwidth usage + - Automatic mixing of webp and jpeg based on CPU availability on server + - WebRTC UDP Transit + - Lossless QOI Image format for Local LAN + - [Dynamic jpeg/webp image coompression](https://github.com/kasmtech/KasmVNC/wiki/Video-Rendering-Options#dynamic-image-quality) quality settings based on screen change rates + - Seemless clipboard support (on Chromium based browsers) + - Binary clipboard support for text, images, and formatted text (on Chromium based browsers) + - Allow client to set/change most configuration settings + - Multi-User support with permissions that can be changed via the API + - Web UI uses a webpack for faster load times. + - Network and CPU bottleneck statistics + - Relative cursor support (game pointer mode) + - Cursor lock + - IME support for languages with extended characters + - Better mobile support + +## Screenshots + + + + +## Browser Requirements + +For a full listing of features and minimum browser version required for each browser, see this [KasmVNC Wiki Article](https://github.com/kasmtech/KasmVNC/wiki/Browser-Support). + + +## Server Requirements + +KasmVNC is an absolute requirement. This fork of noVNC is explicitly modified to work with KasmVNC and breaks the RFB specification. It will not work with legacy VNC servers. + +## Running noVNC + +KasmVNC has a built in web server and the web code is baked into KasmVNC. There are no instructions to provide, just install KasmVNC follow the instructions to configure and run it. + +## Development + +The noVNC code is webpacked for performance reasons. The CI pipeline in the KasmVNC project is responsible for building the web code and packaging it with KasmVNC. diff --git a/app/error-handler.js b/app/error-handler.js new file mode 100644 index 0000000..cf966f4 --- /dev/null +++ b/app/error-handler.js @@ -0,0 +1,72 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +// NB: this should *not* be included as a module until we have +// native support in the browsers, so that our error handler +// can catch script-loading errors. + +// No ES6 can be used in this file since it's used for the translation +/* eslint-disable prefer-arrow-callback */ + +(function _scope() { + "use strict"; + + // Fallback for all uncaught errors + function handleError(event, err) { + try { + const msg = document.getElementById('noVNC_fallback_errormsg'); + + // Only show the initial error + if (msg.hasChildNodes()) { + return false; + } + + // Skip allowed errors + let allowedErrors = [ "The user has exited the lock before this request was completed." ]; + if (event.message && allowedErrors.includes(event.message)) { + return false; + } + + let div = document.createElement("div"); + div.classList.add('noVNC_message'); + div.appendChild(document.createTextNode(event.message)); + msg.appendChild(div); + + if (event.filename) { + div = document.createElement("div"); + div.className = 'noVNC_location'; + let text = event.filename; + if (event.lineno !== undefined) { + text += ":" + event.lineno; + if (event.colno !== undefined) { + text += ":" + event.colno; + } + } + div.appendChild(document.createTextNode(text)); + msg.appendChild(div); + } + + if (err && err.stack) { + div = document.createElement("div"); + div.className = 'noVNC_stack'; + div.appendChild(document.createTextNode(err.stack)); + msg.appendChild(div); + } + + document.getElementById('noVNC_fallback_error') + .classList.add("noVNC_open"); + } catch (exc) { + document.write("Kasm encountered an error."); + } + // Don't return true since this would prevent the error + // from being printed to the browser console. + return false; + } + window.addEventListener('error', function onerror(evt) { handleError(evt, evt.error); }); + window.addEventListener('unhandledrejection', function onreject(evt) { handleError(evt.reason, evt.reason); }); +})(); diff --git a/app/images/alt.svg b/app/images/alt.svg new file mode 100644 index 0000000..e5bb461 --- /dev/null +++ b/app/images/alt.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/app/images/clipboard.svg b/app/images/clipboard.svg new file mode 100644 index 0000000..79af275 --- /dev/null +++ b/app/images/clipboard.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/app/images/connect.svg b/app/images/connect.svg new file mode 100644 index 0000000..56cde41 --- /dev/null +++ b/app/images/connect.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/app/images/ctrl.svg b/app/images/ctrl.svg new file mode 100644 index 0000000..856e939 --- /dev/null +++ b/app/images/ctrl.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/app/images/ctrlaltdel.svg b/app/images/ctrlaltdel.svg new file mode 100644 index 0000000..d7744ea --- /dev/null +++ b/app/images/ctrlaltdel.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/app/images/disconnect.svg b/app/images/disconnect.svg new file mode 100644 index 0000000..6be7d18 --- /dev/null +++ b/app/images/disconnect.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/app/images/download.gif b/app/images/download.gif new file mode 100644 index 0000000..3a52406 Binary files /dev/null and b/app/images/download.gif differ diff --git a/app/images/drag.svg b/app/images/drag.svg new file mode 100644 index 0000000..139caf9 --- /dev/null +++ b/app/images/drag.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/app/images/error.svg b/app/images/error.svg new file mode 100644 index 0000000..8356d3f --- /dev/null +++ b/app/images/error.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/app/images/esc.svg b/app/images/esc.svg new file mode 100644 index 0000000..830152b --- /dev/null +++ b/app/images/esc.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/app/images/expander.svg b/app/images/expander.svg new file mode 100644 index 0000000..e163535 --- /dev/null +++ b/app/images/expander.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/app/images/fullscreen.svg b/app/images/fullscreen.svg new file mode 100644 index 0000000..29bd05d --- /dev/null +++ b/app/images/fullscreen.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/app/images/gamepad.png b/app/images/gamepad.png new file mode 100644 index 0000000..5ea9f1e Binary files /dev/null and b/app/images/gamepad.png differ diff --git a/app/images/handle.svg b/app/images/handle.svg new file mode 100644 index 0000000..4a7a126 --- /dev/null +++ b/app/images/handle.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/app/images/handle_bg.svg b/app/images/handle_bg.svg new file mode 100644 index 0000000..7579c42 --- /dev/null +++ b/app/images/handle_bg.svg @@ -0,0 +1,172 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/app/images/icons/368_kasm_logo_only_120x120.png b/app/images/icons/368_kasm_logo_only_120x120.png new file mode 100644 index 0000000..fe2c4a4 Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_120x120.png differ diff --git a/app/images/icons/368_kasm_logo_only_144x144.png b/app/images/icons/368_kasm_logo_only_144x144.png new file mode 100644 index 0000000..74e1926 Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_144x144.png differ diff --git a/app/images/icons/368_kasm_logo_only_152x152.png b/app/images/icons/368_kasm_logo_only_152x152.png new file mode 100644 index 0000000..766cde4 Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_152x152.png differ diff --git a/app/images/icons/368_kasm_logo_only_16x16.png b/app/images/icons/368_kasm_logo_only_16x16.png new file mode 100644 index 0000000..218d5f7 Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_16x16.png differ diff --git a/app/images/icons/368_kasm_logo_only_192x192.png b/app/images/icons/368_kasm_logo_only_192x192.png new file mode 100644 index 0000000..edf21cd Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_192x192.png differ diff --git a/app/images/icons/368_kasm_logo_only_24x24.png b/app/images/icons/368_kasm_logo_only_24x24.png new file mode 100644 index 0000000..c002335 Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_24x24.png differ diff --git a/app/images/icons/368_kasm_logo_only_32x32.png b/app/images/icons/368_kasm_logo_only_32x32.png new file mode 100644 index 0000000..f3aa408 Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_32x32.png differ diff --git a/app/images/icons/368_kasm_logo_only_48x48.png b/app/images/icons/368_kasm_logo_only_48x48.png new file mode 100644 index 0000000..dc65cc4 Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_48x48.png differ diff --git a/app/images/icons/368_kasm_logo_only_60x60.png b/app/images/icons/368_kasm_logo_only_60x60.png new file mode 100644 index 0000000..717211f Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_60x60.png differ diff --git a/app/images/icons/368_kasm_logo_only_64x64.png b/app/images/icons/368_kasm_logo_only_64x64.png new file mode 100644 index 0000000..0c34b70 Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_64x64.png differ diff --git a/app/images/icons/368_kasm_logo_only_72x72.png b/app/images/icons/368_kasm_logo_only_72x72.png new file mode 100644 index 0000000..9af2ec2 Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_72x72.png differ diff --git a/app/images/icons/368_kasm_logo_only_76x76.png b/app/images/icons/368_kasm_logo_only_76x76.png new file mode 100644 index 0000000..984d7a8 Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_76x76.png differ diff --git a/app/images/icons/368_kasm_logo_only_96x96.png b/app/images/icons/368_kasm_logo_only_96x96.png new file mode 100644 index 0000000..4fda28a Binary files /dev/null and b/app/images/icons/368_kasm_logo_only_96x96.png differ diff --git a/app/images/icons/Makefile b/app/images/icons/Makefile new file mode 100644 index 0000000..8aba655 --- /dev/null +++ b/app/images/icons/Makefile @@ -0,0 +1,42 @@ +ICONS := \ + 368_kasm_logo_only_16x16.png \ + 368_kasm_logo_only_24x24.png \ + 368_kasm_logo_only_32x32.png \ + 368_kasm_logo_only_48x48.png \ + 368_kasm_logo_only_64x64.png + +ANDROID_LAUNCHER := \ + 368_kasm_logo_only_48x48.png \ + 368_kasm_logo_only_-72x72.png \ + 368_kasm_logo_only_96x96.png \ + 368_kasm_logo_only_144x144.png \ + 368_kasm_logo_only_192x192.png + +IPHONE_LAUNCHER := \ + 368_kasm_logo_only_60x60.png \ + 368_kasm_logo_only_120x120.png + +IPAD_LAUNCHER := \ + 368_kasm_logo_only_76x76.png \ + 368_kasm_logo_only_152x152.png + +ALL_ICONS := $(ICONS) $(ANDROID_LAUNCHER) $(IPHONE_LAUNCHER) $(IPAD_LAUNCHER) + +all: $(ALL_ICONS) + +368_kasm_logo_only_16x16.png: kasm-icon-sm.svg + convert -density 90 \ + -background transparent "$<" "$@" +368_kasm_logo_only_24x24.png: kasm-icon-sm.svg + convert -density 135 \ + -background transparent "$<" "$@" +368_kasm_logo_only_32x32.png: kasm-icon-sm.svg + convert -density 180 \ + -background transparent "$<" "$@" + +368_kasm_logo_only_%.png: kasm-icon.svg + convert -density $$[`echo $* | cut -d x -f 1` * 90 / 48] \ + -background transparent "$<" "$@" + +clean: + rm -f *.png diff --git a/app/images/icons/kasm_logo.svg b/app/images/icons/kasm_logo.svg new file mode 100644 index 0000000..1de2030 --- /dev/null +++ b/app/images/icons/kasm_logo.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/images/icons/novnc-120x120.png b/app/images/icons/novnc-120x120.png new file mode 100644 index 0000000..fe2c4a4 Binary files /dev/null and b/app/images/icons/novnc-120x120.png differ diff --git a/app/images/icons/novnc-144x144.png b/app/images/icons/novnc-144x144.png new file mode 100644 index 0000000..74e1926 Binary files /dev/null and b/app/images/icons/novnc-144x144.png differ diff --git a/app/images/icons/novnc-152x152.png b/app/images/icons/novnc-152x152.png new file mode 100644 index 0000000..766cde4 Binary files /dev/null and b/app/images/icons/novnc-152x152.png differ diff --git a/app/images/icons/novnc-16x16.png b/app/images/icons/novnc-16x16.png new file mode 100644 index 0000000..218d5f7 Binary files /dev/null and b/app/images/icons/novnc-16x16.png differ diff --git a/app/images/icons/novnc-192x192.png b/app/images/icons/novnc-192x192.png new file mode 100644 index 0000000..edf21cd Binary files /dev/null and b/app/images/icons/novnc-192x192.png differ diff --git a/app/images/icons/novnc-24x24.png b/app/images/icons/novnc-24x24.png new file mode 100644 index 0000000..c002335 Binary files /dev/null and b/app/images/icons/novnc-24x24.png differ diff --git a/app/images/icons/novnc-32x32.png b/app/images/icons/novnc-32x32.png new file mode 100644 index 0000000..f3aa408 Binary files /dev/null and b/app/images/icons/novnc-32x32.png differ diff --git a/app/images/icons/novnc-48x48.png b/app/images/icons/novnc-48x48.png new file mode 100644 index 0000000..dc65cc4 Binary files /dev/null and b/app/images/icons/novnc-48x48.png differ diff --git a/app/images/icons/novnc-60x60.png b/app/images/icons/novnc-60x60.png new file mode 100644 index 0000000..717211f Binary files /dev/null and b/app/images/icons/novnc-60x60.png differ diff --git a/app/images/icons/novnc-64x64.png b/app/images/icons/novnc-64x64.png new file mode 100644 index 0000000..0c34b70 Binary files /dev/null and b/app/images/icons/novnc-64x64.png differ diff --git a/app/images/icons/novnc-72x72.png b/app/images/icons/novnc-72x72.png new file mode 100644 index 0000000..9af2ec2 Binary files /dev/null and b/app/images/icons/novnc-72x72.png differ diff --git a/app/images/icons/novnc-76x76.png b/app/images/icons/novnc-76x76.png new file mode 100644 index 0000000..984d7a8 Binary files /dev/null and b/app/images/icons/novnc-76x76.png differ diff --git a/app/images/icons/novnc-96x96.png b/app/images/icons/novnc-96x96.png new file mode 100644 index 0000000..4fda28a Binary files /dev/null and b/app/images/icons/novnc-96x96.png differ diff --git a/app/images/icons/novnc-icon-sm.svg b/app/images/icons/novnc-icon-sm.svg new file mode 100644 index 0000000..a775dd4 --- /dev/null +++ b/app/images/icons/novnc-icon-sm.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/images/icons/novnc-icon.svg b/app/images/icons/novnc-icon.svg new file mode 100644 index 0000000..a775dd4 --- /dev/null +++ b/app/images/icons/novnc-icon.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/app/images/info.svg b/app/images/info.svg new file mode 100644 index 0000000..557b772 --- /dev/null +++ b/app/images/info.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/app/images/keyboard.svg b/app/images/keyboard.svg new file mode 100644 index 0000000..137b350 --- /dev/null +++ b/app/images/keyboard.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/app/images/pointer.svg b/app/images/pointer.svg new file mode 100644 index 0000000..7cbb3c7 --- /dev/null +++ b/app/images/pointer.svg @@ -0,0 +1,78 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + \ No newline at end of file diff --git a/app/images/power.svg b/app/images/power.svg new file mode 100644 index 0000000..4925d3e --- /dev/null +++ b/app/images/power.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/app/images/refresh.gif b/app/images/refresh.gif new file mode 100644 index 0000000..cfa80ce Binary files /dev/null and b/app/images/refresh.gif differ diff --git a/app/images/settings.svg b/app/images/settings.svg new file mode 100644 index 0000000..dbb2e80 --- /dev/null +++ b/app/images/settings.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/app/images/splash.jpg b/app/images/splash.jpg new file mode 100644 index 0000000..a600b5a Binary files /dev/null and b/app/images/splash.jpg differ diff --git a/app/images/tab.svg b/app/images/tab.svg new file mode 100644 index 0000000..1ccb322 --- /dev/null +++ b/app/images/tab.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/app/images/toggleextrakeys.svg b/app/images/toggleextrakeys.svg new file mode 100644 index 0000000..b578c0d --- /dev/null +++ b/app/images/toggleextrakeys.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/app/images/warning.svg b/app/images/warning.svg new file mode 100644 index 0000000..7114f9b --- /dev/null +++ b/app/images/warning.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/app/images/windows.svg b/app/images/windows.svg new file mode 100644 index 0000000..ad5eec3 --- /dev/null +++ b/app/images/windows.svg @@ -0,0 +1,65 @@ + + + +image/svg+xml + + + \ No newline at end of file diff --git a/app/locale/README b/app/locale/README new file mode 100644 index 0000000..ca4f548 --- /dev/null +++ b/app/locale/README @@ -0,0 +1 @@ +DO NOT MODIFY THE FILES IN THIS FOLDER, THEY ARE AUTOMATICALLY GENERATED FROM THE PO-FILES. diff --git a/app/locale/af.json b/app/locale/af.json new file mode 100644 index 0000000..c50ecbc --- /dev/null +++ b/app/locale/af.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Verbind tans...", + "Disconnecting...": "Ontkoppel tans ...", + "Reconnecting...": "Herkoppel tans...", + "Internal error": "Interne fout", + "Must set host": "Moet gasheer stel", + "Connected (encrypted) to ": "Gekoppel (geïnkripteer) aan ", + "Connected (unencrypted) to ": "Gekoppel (ongenkripteer) aan ", + "Something went wrong, connection is closed": "Iets het verkeerd geloop, verbinding is gesluit", + "Failed to connect to server": "Kon nie aan bediener koppel", + "Disconnected": "Ontkoppel", + "New connection has been rejected with reason: ": "Nuwe verbinding is verwerp met rede:", + "New connection has been rejected": "Nuwe verbinding is afgekeur", + "Credentials are required": "Geloofsbriewe word vereis", + "Hide/Show the control bar": "Versteek/wys die beheerbalk", + "Drag": "Sleep", + "Move/Drag Viewport": "Skuif/sleep Viewport", + "Keyboard": "Sleutelbord", + "Show Keyboard": "Wys sleutelbord", + "Extra keys": "Ekstra sleutels", + "Show Extra Keys": "Wys ekstra sleutels", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Wissel Ctrl", + "Alt": "Alt", + "Toggle Alt": "Wissel Alt", + "Toggle Windows": "Wissel Windows", + "Windows": "Windows", + "Send Tab": "Stuur oortjie", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Stuur ontsnap", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Stuur Ctrl-Alt-Del", + "Shutdown/Reboot": "Sluit af/herlaai", + "Shutdown/Reboot...": "Sluit af/herlaai...", + "Power": "Krag", + "Shutdown": "Sluit af", + "Reboot": "Herlaai", + "Reset": "Herstel", + "Clipboard": "Klipbord", + "Clear": "Vee", + "Fullscreen": "Volskerm", + "Settings": "Instellings", + "Shared Mode": "Gedeelde modus", + "View Only": "Slegs kyk", + "Clip to Window": "Klip na venster", + "Scaling Mode:": "Skaalmodus:", + "None": "Geen", + "Local Scaling": "Plaaslike skaal", + "Remote Resizing": "Verander grootte op afstand", + "Advanced": "Gevorderd", + "Quality:": "Gehalte:", + "Compression level:": "Kompressievlak:", + "Repeater ID:": "Herhaler ID:", + "WebSocket": "WebSocket", + "Encrypt": "Enkripteer", + "Host:": "Gasheer:", + "Port:": "Port:", + "Path:": "Pad:", + "Automatic Reconnect": "Outomatiese herkoppel", + "Reconnect Delay (ms):": "Herkoppel vertraging (ms):", + "Show Dot when No Cursor": "Wys punt wanneer geen wyser is nie", + "Logging:": "Aanteken:", + "Version:": "Weergawe:", + "Disconnect": "Ontkoppel", + "Connect": "Verbind", + "Username:": "Gebruikersnaam:", + "Password:": "Wagwoord:", + "Send Credentials": "Stuur geloofsbriewe", + "Cancel": "Kanselleer", + "Keys": "Sleutels", + "Game Cursor Mode": "Spelwysermodus", + "Press Esc Key to Exit Pointer Lock Mode": "Druk Esc-sleutel om die aanwyserslotmodus te verlaat", + "Game Mode paused, click on screen to resume Game Mode.": "Spelmodus is onderbreek, klik op die skerm om Spelmodus te hervat.", + "Clipboard Up": "Klipbord op", + "CLipboard Down": "Klipbord af", + "Clipboard Seamless": "Klipbord Naatloos", + "Prefer Local Cursor": "Verkies plaaslike wyser", + "Translate keyboard shortcuts": "Vertaal sleutelbordkortpaaie", + "Enable WebRTC UDP Transit": "Aktiveer WebRTC UDP Transit", + "Enable WebP Compression": "Aktiveer WebP-kompressie", + "Enable Performance Stats": "Aktiveer prestasiestatistieke", + "Enable Pointer Lock": "Aktiveer wyserslot", + "IME Input Mode": "IME-invoermodus", + "Show Virtual Keyboard Control": "Wys virtuele sleutelbordbeheer", + "Toggle Control Panel via Keystrokes": "Wissel beheerpaneel via toetsaanslagen", + "Render Native Resolution": "Lewer oorspronklike resolusie", + "Keyboard Shortcuts": "Sleutelbord kortpaaie", + "Enable KasmVNC Keyboard Shortcuts": "Aktiveer KasmVNC-sleutelbordkortpaaie", + "1 - Toggle Control Panel": "1 - Wissel beheerpaneel", + "2 - Toggle Game Pointer Mode": "2 - Wissel spelwysermodus", + "3 - Toggle Pointer Lock": "3 - Wissel wyserslot", + "Stream Quality": "Stroomkwaliteit", + "Preset Modes:": "Vooraf ingestelde modusse:", + "Static": "Staties", + "Low": "Laag", + "Medium": "Medium", + "High": "Hoog", + "Extreme": "Ekstreem", + "Lossless": "Verliesloos", + "Custom": "Gepasmaakte", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Outomatiese dinamiese", + "Off": "Af", + "On": "Aan", + "Dynamic Quality Min:": "Dynamiese kwaliteit min:", + "Dynamic Quality Max:": "Dynamiese kwaliteit maksimum:", + "Treat Lossless:": "Behandel Lossless:", + "Frame Rate:": "Raamtempo:", + "Video JPEG Quality:": "Video JPEG Kwaliteit:", + "Video WEBP Quality:": "Video WEBP kwaliteit:", + "Video Area:": "Video-area:", + "Video Time:": "Video Tyd:", + "Video Out Time:": "Video-uittyd:", + "Video Mode Width:": "Videomoduswydte:", + "Video Mode Height:": "Videomodus Hoogte:", + "Documentation": "Dokumentasie", + "Drag Viewport": "Sleep Viewport", + "KasmVNC encountered an error:": "KasmVNC het 'n fout teëgekom:" +} \ No newline at end of file diff --git a/app/locale/af_ZA.json b/app/locale/af_ZA.json new file mode 100644 index 0000000..c50ecbc --- /dev/null +++ b/app/locale/af_ZA.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Verbind tans...", + "Disconnecting...": "Ontkoppel tans ...", + "Reconnecting...": "Herkoppel tans...", + "Internal error": "Interne fout", + "Must set host": "Moet gasheer stel", + "Connected (encrypted) to ": "Gekoppel (geïnkripteer) aan ", + "Connected (unencrypted) to ": "Gekoppel (ongenkripteer) aan ", + "Something went wrong, connection is closed": "Iets het verkeerd geloop, verbinding is gesluit", + "Failed to connect to server": "Kon nie aan bediener koppel", + "Disconnected": "Ontkoppel", + "New connection has been rejected with reason: ": "Nuwe verbinding is verwerp met rede:", + "New connection has been rejected": "Nuwe verbinding is afgekeur", + "Credentials are required": "Geloofsbriewe word vereis", + "Hide/Show the control bar": "Versteek/wys die beheerbalk", + "Drag": "Sleep", + "Move/Drag Viewport": "Skuif/sleep Viewport", + "Keyboard": "Sleutelbord", + "Show Keyboard": "Wys sleutelbord", + "Extra keys": "Ekstra sleutels", + "Show Extra Keys": "Wys ekstra sleutels", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Wissel Ctrl", + "Alt": "Alt", + "Toggle Alt": "Wissel Alt", + "Toggle Windows": "Wissel Windows", + "Windows": "Windows", + "Send Tab": "Stuur oortjie", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Stuur ontsnap", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Stuur Ctrl-Alt-Del", + "Shutdown/Reboot": "Sluit af/herlaai", + "Shutdown/Reboot...": "Sluit af/herlaai...", + "Power": "Krag", + "Shutdown": "Sluit af", + "Reboot": "Herlaai", + "Reset": "Herstel", + "Clipboard": "Klipbord", + "Clear": "Vee", + "Fullscreen": "Volskerm", + "Settings": "Instellings", + "Shared Mode": "Gedeelde modus", + "View Only": "Slegs kyk", + "Clip to Window": "Klip na venster", + "Scaling Mode:": "Skaalmodus:", + "None": "Geen", + "Local Scaling": "Plaaslike skaal", + "Remote Resizing": "Verander grootte op afstand", + "Advanced": "Gevorderd", + "Quality:": "Gehalte:", + "Compression level:": "Kompressievlak:", + "Repeater ID:": "Herhaler ID:", + "WebSocket": "WebSocket", + "Encrypt": "Enkripteer", + "Host:": "Gasheer:", + "Port:": "Port:", + "Path:": "Pad:", + "Automatic Reconnect": "Outomatiese herkoppel", + "Reconnect Delay (ms):": "Herkoppel vertraging (ms):", + "Show Dot when No Cursor": "Wys punt wanneer geen wyser is nie", + "Logging:": "Aanteken:", + "Version:": "Weergawe:", + "Disconnect": "Ontkoppel", + "Connect": "Verbind", + "Username:": "Gebruikersnaam:", + "Password:": "Wagwoord:", + "Send Credentials": "Stuur geloofsbriewe", + "Cancel": "Kanselleer", + "Keys": "Sleutels", + "Game Cursor Mode": "Spelwysermodus", + "Press Esc Key to Exit Pointer Lock Mode": "Druk Esc-sleutel om die aanwyserslotmodus te verlaat", + "Game Mode paused, click on screen to resume Game Mode.": "Spelmodus is onderbreek, klik op die skerm om Spelmodus te hervat.", + "Clipboard Up": "Klipbord op", + "CLipboard Down": "Klipbord af", + "Clipboard Seamless": "Klipbord Naatloos", + "Prefer Local Cursor": "Verkies plaaslike wyser", + "Translate keyboard shortcuts": "Vertaal sleutelbordkortpaaie", + "Enable WebRTC UDP Transit": "Aktiveer WebRTC UDP Transit", + "Enable WebP Compression": "Aktiveer WebP-kompressie", + "Enable Performance Stats": "Aktiveer prestasiestatistieke", + "Enable Pointer Lock": "Aktiveer wyserslot", + "IME Input Mode": "IME-invoermodus", + "Show Virtual Keyboard Control": "Wys virtuele sleutelbordbeheer", + "Toggle Control Panel via Keystrokes": "Wissel beheerpaneel via toetsaanslagen", + "Render Native Resolution": "Lewer oorspronklike resolusie", + "Keyboard Shortcuts": "Sleutelbord kortpaaie", + "Enable KasmVNC Keyboard Shortcuts": "Aktiveer KasmVNC-sleutelbordkortpaaie", + "1 - Toggle Control Panel": "1 - Wissel beheerpaneel", + "2 - Toggle Game Pointer Mode": "2 - Wissel spelwysermodus", + "3 - Toggle Pointer Lock": "3 - Wissel wyserslot", + "Stream Quality": "Stroomkwaliteit", + "Preset Modes:": "Vooraf ingestelde modusse:", + "Static": "Staties", + "Low": "Laag", + "Medium": "Medium", + "High": "Hoog", + "Extreme": "Ekstreem", + "Lossless": "Verliesloos", + "Custom": "Gepasmaakte", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Outomatiese dinamiese", + "Off": "Af", + "On": "Aan", + "Dynamic Quality Min:": "Dynamiese kwaliteit min:", + "Dynamic Quality Max:": "Dynamiese kwaliteit maksimum:", + "Treat Lossless:": "Behandel Lossless:", + "Frame Rate:": "Raamtempo:", + "Video JPEG Quality:": "Video JPEG Kwaliteit:", + "Video WEBP Quality:": "Video WEBP kwaliteit:", + "Video Area:": "Video-area:", + "Video Time:": "Video Tyd:", + "Video Out Time:": "Video-uittyd:", + "Video Mode Width:": "Videomoduswydte:", + "Video Mode Height:": "Videomodus Hoogte:", + "Documentation": "Dokumentasie", + "Drag Viewport": "Sleep Viewport", + "KasmVNC encountered an error:": "KasmVNC het 'n fout teëgekom:" +} \ No newline at end of file diff --git a/app/locale/am.json b/app/locale/am.json new file mode 100644 index 0000000..b949f59 --- /dev/null +++ b/app/locale/am.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "በማገናኘት ላይ...", + "Disconnecting...": "ግንኙነት ማቋረጥ...", + "Reconnecting...": "እንደገና በመገናኘት ላይ...", + "Internal error": "ውስጣዊ ስህተት", + "Must set host": "አስተናጋጅ ማዘጋጀት አለበት", + "Connected (encrypted) to ": "ተገናኝቷል (የተመሰጠረ)", + "Connected (unencrypted) to ": "ተገናኝቷል (ያልተመሰጠረ)", + "Something went wrong, connection is closed": "የሆነ ችግር ተፈጥሯል፣ ግንኙነቱ ተዘግቷል", + "Failed to connect to server": "ከአገልጋይ ጋር መገናኘት አልተሳካም", + "Disconnected": "ግንኙነት ተቋርጧል", + "New connection has been rejected with reason: ": "አዲስ ግንኙነት በምክንያት ውድቅ ተደርጓል፡", + "New connection has been rejected": "አዲስ ግንኙነት ውድቅ ተደርጓል", + "Credentials are required": "ማስረጃዎች ያስፈልጋሉ", + "Hide/Show the control bar": "የቁጥጥር አሞሌን ደብቅ/ አሳይ", + "Drag": "ጎትት", + "Move/Drag Viewport": "የእይታ ቦታን አንቀሳቅስ/ጎትት", + "Keyboard": "የቁልፍ ሰሌዳ", + "Show Keyboard": "የቁልፍ ሰሌዳ አሳይ", + "Extra keys": "ተጨማሪ ቁልፎች", + "Show Extra Keys": "ተጨማሪ ቁልፎችን አሳይ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ቀያይር", + "Alt": "Alt", + "Toggle Alt": "Alt ቀይር", + "Toggle Windows": "ዊንዶውስ ቀያይር", + "Windows": "ዊንዶውስ", + "Send Tab": "ትር ላክ", + "Tab": "ታብ", + "Esc": "Esc", + "Send Escape": "ማምለጫ ላክ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ላክ", + "Shutdown/Reboot": "ዝጋ/ዳግም አስነሳ", + "Shutdown/Reboot...": "ዝጋ/ዳግም አስነሳ...", + "Power": "ኃይል", + "Shutdown": "ዝጋው", + "Reboot": "ዳግም አስነሳ", + "Reset": "ዳግም አስጀምር", + "Clipboard": "ክሊፕቦርድ", + "Clear": "ግልጽ", + "Fullscreen": "ሙሉ ማያ", + "Settings": "ቅንብሮች", + "Shared Mode": "የተጋራ ሁነታ", + "View Only": "እይታ ብቻ", + "Clip to Window": "ወደ መስኮት ቅንጥብ", + "Scaling Mode:": "መለኪያ ሁነታ:", + "None": "ምንም", + "Local Scaling": "አካባቢያዊ ልኬት", + "Remote Resizing": "የርቀት ማስተካከያ", + "Advanced": "የላቀ", + "Quality:": "ጥራት:", + "Compression level:": "የመጨናነቅ ደረጃ", + "Repeater ID:": "ተደጋጋሚ መታወቂያ:", + "WebSocket": "WebSocket", + "Encrypt": "አመስጥር", + "Host:": "አስተናጋጅ:", + "Port:": "ወደብ:", + "Path:": "መንገድ:", + "Automatic Reconnect": "ራስ-ሰር ዳግም ማገናኘት", + "Reconnect Delay (ms):": "ዘግይቶ እንደገና ያገናኙ (ms):", + "Show Dot when No Cursor": "ጠቋሚ በማይኖርበት ጊዜ ነጥብ አሳይ", + "Logging:": "መመዝገብ:", + "Version:": "ስሪት:", + "Disconnect": "ግንኙነት አቋርጥ", + "Connect": "ተገናኝ", + "Username:": "የተጠቃሚ ስም", + "Password:": "የይለፍ ቃል:", + "Send Credentials": "ምስክርነቶችን ላክ", + "Cancel": "ሰርዝ", + "Keys": "ቁልፎች", + "Game Cursor Mode": "የጨዋታ ጠቋሚ ሁነታ", + "Press Esc Key to Exit Pointer Lock Mode": "ከጠቋሚ መቆለፊያ ሁነታ ለመውጣት Esc ቁልፍን ተጫን", + "Game Mode paused, click on screen to resume Game Mode.": "የጨዋታ ሁነታ ባለበት ቆሟል፣ የጨዋታ ሁነታን ለመቀጠል ስክሪኑ ላይ ጠቅ ያድርጉ።", + "Clipboard Up": "ክሊፕቦርድ ወደ ላይ", + "CLipboard Down": "ክሊፕቦርድ ወደታች", + "Clipboard Seamless": "ክሊፕቦርድ እንከን የለሽ", + "Prefer Local Cursor": "አካባቢያዊ ጠቋሚን ምረጥ", + "Translate keyboard shortcuts": "የቁልፍ ሰሌዳ አቋራጮችን ተርጉም", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit አንቃ", + "Enable WebP Compression": "WebP compression አንቃ", + "Enable Performance Stats": "የአፈጻጸም ስታቲስቲክስን አንቃ", + "Enable Pointer Lock": "ጠቋሚ መቆለፊያን አንቃ", + "IME Input Mode": "IME ግቤት ሁነታ", + "Show Virtual Keyboard Control": "ምናባዊ የቁልፍ ሰሌዳ ቁጥጥር አሳይ", + "Toggle Control Panel via Keystrokes": "የቁጥጥር ፓነልን በቁልፍ ጭነቶች ቀይር", + "Render Native Resolution": "ቤተኛ መፍትሄ ስጥ", + "Keyboard Shortcuts": "የቁልፍ ሰሌዳ አቋራጮች", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ቁልፍ ሰሌዳ አቋራጮችን አንቃ", + "1 - Toggle Control Panel": "1 - የቁጥጥር ፓነልን ቀይር", + "2 - Toggle Game Pointer Mode": "2 - የጨዋታ ጠቋሚ ሁነታን ቀይር", + "3 - Toggle Pointer Lock": "3 - የጠቋሚ መቆለፊያን ቀይር", + "Stream Quality": "የዥረት ጥራት", + "Preset Modes:": "ቅድመ-ሁኔታዎች", + "Static": "ስታቲክ", + "Low": "ዝቅተኛ", + "Medium": "መካከለኛ", + "High": "ከፍተኛ", + "Extreme": "እጅግ", + "Lossless": "የማይጠፋ", + "Custom": "ብጁ", + "Anti-Aliasing:": "የትብብር ተቃራኒዎች:", + "Auto Dynamic": "ራስ-ሰር ተለዋዋጭ", + "Off": "ጠፍቷል", + "On": "በርቷል", + "Dynamic Quality Min:": "ተለዋዋጭ ጥራት ደቂቃ:", + "Dynamic Quality Max:": "ተለዋዋጭ ጥራት ከፍተኛ፡", + "Treat Lossless:": "ያለ ኪሳራ ማከም:", + "Frame Rate:": "የፍሬም መጠን:", + "Video JPEG Quality:": "የቪዲዮ JPEG ጥራት:", + "Video WEBP Quality:": "የቪዲዮ WEBP ጥራት:", + "Video Area:": "የቪዲዮ አካባቢ:", + "Video Time:": "የቪዲዮ ጊዜ:", + "Video Out Time:": "የቪዲዮ ማብቂያ ጊዜ:", + "Video Mode Width:": "የቪዲዮ ሁነታ ስፋት:", + "Video Mode Height:": "የቪዲዮ ሁነታ ቁመት:", + "Documentation": "ሰነድ", + "Drag Viewport": "መመልከቻ ጎትት", + "KasmVNC encountered an error:": "KasmVNC ስህተት አጋጥሞታል::" +} \ No newline at end of file diff --git a/app/locale/am_ET.json b/app/locale/am_ET.json new file mode 100644 index 0000000..b949f59 --- /dev/null +++ b/app/locale/am_ET.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "በማገናኘት ላይ...", + "Disconnecting...": "ግንኙነት ማቋረጥ...", + "Reconnecting...": "እንደገና በመገናኘት ላይ...", + "Internal error": "ውስጣዊ ስህተት", + "Must set host": "አስተናጋጅ ማዘጋጀት አለበት", + "Connected (encrypted) to ": "ተገናኝቷል (የተመሰጠረ)", + "Connected (unencrypted) to ": "ተገናኝቷል (ያልተመሰጠረ)", + "Something went wrong, connection is closed": "የሆነ ችግር ተፈጥሯል፣ ግንኙነቱ ተዘግቷል", + "Failed to connect to server": "ከአገልጋይ ጋር መገናኘት አልተሳካም", + "Disconnected": "ግንኙነት ተቋርጧል", + "New connection has been rejected with reason: ": "አዲስ ግንኙነት በምክንያት ውድቅ ተደርጓል፡", + "New connection has been rejected": "አዲስ ግንኙነት ውድቅ ተደርጓል", + "Credentials are required": "ማስረጃዎች ያስፈልጋሉ", + "Hide/Show the control bar": "የቁጥጥር አሞሌን ደብቅ/ አሳይ", + "Drag": "ጎትት", + "Move/Drag Viewport": "የእይታ ቦታን አንቀሳቅስ/ጎትት", + "Keyboard": "የቁልፍ ሰሌዳ", + "Show Keyboard": "የቁልፍ ሰሌዳ አሳይ", + "Extra keys": "ተጨማሪ ቁልፎች", + "Show Extra Keys": "ተጨማሪ ቁልፎችን አሳይ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ቀያይር", + "Alt": "Alt", + "Toggle Alt": "Alt ቀይር", + "Toggle Windows": "ዊንዶውስ ቀያይር", + "Windows": "ዊንዶውስ", + "Send Tab": "ትር ላክ", + "Tab": "ታብ", + "Esc": "Esc", + "Send Escape": "ማምለጫ ላክ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ላክ", + "Shutdown/Reboot": "ዝጋ/ዳግም አስነሳ", + "Shutdown/Reboot...": "ዝጋ/ዳግም አስነሳ...", + "Power": "ኃይል", + "Shutdown": "ዝጋው", + "Reboot": "ዳግም አስነሳ", + "Reset": "ዳግም አስጀምር", + "Clipboard": "ክሊፕቦርድ", + "Clear": "ግልጽ", + "Fullscreen": "ሙሉ ማያ", + "Settings": "ቅንብሮች", + "Shared Mode": "የተጋራ ሁነታ", + "View Only": "እይታ ብቻ", + "Clip to Window": "ወደ መስኮት ቅንጥብ", + "Scaling Mode:": "መለኪያ ሁነታ:", + "None": "ምንም", + "Local Scaling": "አካባቢያዊ ልኬት", + "Remote Resizing": "የርቀት ማስተካከያ", + "Advanced": "የላቀ", + "Quality:": "ጥራት:", + "Compression level:": "የመጨናነቅ ደረጃ", + "Repeater ID:": "ተደጋጋሚ መታወቂያ:", + "WebSocket": "WebSocket", + "Encrypt": "አመስጥር", + "Host:": "አስተናጋጅ:", + "Port:": "ወደብ:", + "Path:": "መንገድ:", + "Automatic Reconnect": "ራስ-ሰር ዳግም ማገናኘት", + "Reconnect Delay (ms):": "ዘግይቶ እንደገና ያገናኙ (ms):", + "Show Dot when No Cursor": "ጠቋሚ በማይኖርበት ጊዜ ነጥብ አሳይ", + "Logging:": "መመዝገብ:", + "Version:": "ስሪት:", + "Disconnect": "ግንኙነት አቋርጥ", + "Connect": "ተገናኝ", + "Username:": "የተጠቃሚ ስም", + "Password:": "የይለፍ ቃል:", + "Send Credentials": "ምስክርነቶችን ላክ", + "Cancel": "ሰርዝ", + "Keys": "ቁልፎች", + "Game Cursor Mode": "የጨዋታ ጠቋሚ ሁነታ", + "Press Esc Key to Exit Pointer Lock Mode": "ከጠቋሚ መቆለፊያ ሁነታ ለመውጣት Esc ቁልፍን ተጫን", + "Game Mode paused, click on screen to resume Game Mode.": "የጨዋታ ሁነታ ባለበት ቆሟል፣ የጨዋታ ሁነታን ለመቀጠል ስክሪኑ ላይ ጠቅ ያድርጉ።", + "Clipboard Up": "ክሊፕቦርድ ወደ ላይ", + "CLipboard Down": "ክሊፕቦርድ ወደታች", + "Clipboard Seamless": "ክሊፕቦርድ እንከን የለሽ", + "Prefer Local Cursor": "አካባቢያዊ ጠቋሚን ምረጥ", + "Translate keyboard shortcuts": "የቁልፍ ሰሌዳ አቋራጮችን ተርጉም", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit አንቃ", + "Enable WebP Compression": "WebP compression አንቃ", + "Enable Performance Stats": "የአፈጻጸም ስታቲስቲክስን አንቃ", + "Enable Pointer Lock": "ጠቋሚ መቆለፊያን አንቃ", + "IME Input Mode": "IME ግቤት ሁነታ", + "Show Virtual Keyboard Control": "ምናባዊ የቁልፍ ሰሌዳ ቁጥጥር አሳይ", + "Toggle Control Panel via Keystrokes": "የቁጥጥር ፓነልን በቁልፍ ጭነቶች ቀይር", + "Render Native Resolution": "ቤተኛ መፍትሄ ስጥ", + "Keyboard Shortcuts": "የቁልፍ ሰሌዳ አቋራጮች", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ቁልፍ ሰሌዳ አቋራጮችን አንቃ", + "1 - Toggle Control Panel": "1 - የቁጥጥር ፓነልን ቀይር", + "2 - Toggle Game Pointer Mode": "2 - የጨዋታ ጠቋሚ ሁነታን ቀይር", + "3 - Toggle Pointer Lock": "3 - የጠቋሚ መቆለፊያን ቀይር", + "Stream Quality": "የዥረት ጥራት", + "Preset Modes:": "ቅድመ-ሁኔታዎች", + "Static": "ስታቲክ", + "Low": "ዝቅተኛ", + "Medium": "መካከለኛ", + "High": "ከፍተኛ", + "Extreme": "እጅግ", + "Lossless": "የማይጠፋ", + "Custom": "ብጁ", + "Anti-Aliasing:": "የትብብር ተቃራኒዎች:", + "Auto Dynamic": "ራስ-ሰር ተለዋዋጭ", + "Off": "ጠፍቷል", + "On": "በርቷል", + "Dynamic Quality Min:": "ተለዋዋጭ ጥራት ደቂቃ:", + "Dynamic Quality Max:": "ተለዋዋጭ ጥራት ከፍተኛ፡", + "Treat Lossless:": "ያለ ኪሳራ ማከም:", + "Frame Rate:": "የፍሬም መጠን:", + "Video JPEG Quality:": "የቪዲዮ JPEG ጥራት:", + "Video WEBP Quality:": "የቪዲዮ WEBP ጥራት:", + "Video Area:": "የቪዲዮ አካባቢ:", + "Video Time:": "የቪዲዮ ጊዜ:", + "Video Out Time:": "የቪዲዮ ማብቂያ ጊዜ:", + "Video Mode Width:": "የቪዲዮ ሁነታ ስፋት:", + "Video Mode Height:": "የቪዲዮ ሁነታ ቁመት:", + "Documentation": "ሰነድ", + "Drag Viewport": "መመልከቻ ጎትት", + "KasmVNC encountered an error:": "KasmVNC ስህተት አጋጥሞታል::" +} \ No newline at end of file diff --git a/app/locale/ar.json b/app/locale/ar.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_AE.json b/app/locale/ar_AE.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_AE.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_BH.json b/app/locale/ar_BH.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_BH.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_DZ.json b/app/locale/ar_DZ.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_DZ.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_EG.json b/app/locale/ar_EG.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_EG.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_IN.json b/app/locale/ar_IN.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_IQ.json b/app/locale/ar_IQ.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_IQ.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_JO.json b/app/locale/ar_JO.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_JO.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_KW.json b/app/locale/ar_KW.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_KW.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_LB.json b/app/locale/ar_LB.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_LB.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_LY.json b/app/locale/ar_LY.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_LY.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_MA.json b/app/locale/ar_MA.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_MA.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_OM.json b/app/locale/ar_OM.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_OM.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_QA.json b/app/locale/ar_QA.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_QA.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_SA.json b/app/locale/ar_SA.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_SA.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_SD.json b/app/locale/ar_SD.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_SD.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_SY.json b/app/locale/ar_SY.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_SY.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_TN.json b/app/locale/ar_TN.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_TN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/ar_YE.json b/app/locale/ar_YE.json new file mode 100644 index 0000000..d164ca2 --- /dev/null +++ b/app/locale/ar_YE.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻞﻴﺻﻮﺗ", + "Disconnecting...": " ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Reconnecting...": " ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Internal error": "ﻲﻠﺧﺍﺩ ﺄﻄﺧ", + "Must set host": "ﻒﻴﻀﻤﻟﺍ ﻦﻴﻴﻌﺗ ﺐﺠﻳ", + "Connected (encrypted) to ": "ـﺑ (ﺮﻔﺸﻣ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ـﺑ (ﺮﻔﺸﻣ ﺮﻴﻏ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﻖﻠﻐﻣ ﻝﺎﺼﺗﻻﺍ ، ﺄﻄﺧ ﺙﺪﺣ", + "Failed to connect to server": "ﻡﺩﺎﺨﻟﺎﺑ ﻝﺎﺼﺗﻻﺍ ﻞﺸﻓ", + "Disconnected": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻘﻧﺍ", + "New connection has been rejected with reason: ": "ﺐﺒﺴﺑ ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "New connection has been rejected": "ﺪﻳﺪﺠﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺾﻓﺭ ﻢﺗ", + "Credentials are required": "ﺔﺑﻮﻠﻄﻣ ﺩﺎﻤﺘﻋﻻﺍ ﻕﺍﺭﻭﺃ", + "Hide/Show the control bar": "ﻢﻜﺤﺘﻟﺍ ﻂﻳﺮﺷ ﺭﺎﻬﻇﺇ / ءﺎﻔﺧﺇ", + "Drag": "ﺮﺠﻳ", + "Move/Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳ / ﻞﻘﻧ", + "Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ", + "Show Keyboard": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺭﺎﻬﻇﺇ", + "Extra keys": "ﺔﻴﻓﺎﺿﺇ ﺢﻴﺗﺎﻔﻣ", + "Show Extra Keys": "ﺔﻴﻓﺎﺿﻹﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺭﺎﻬﻇﺇ", + "Ctrl": "ﻝﻭﺮﺘﻨﻛ", + "Toggle Ctrl": "Ctrl ﻞﻳﺪﺒﺗ", + "Alt": "ﻞﻳﺪﺑ", + "Toggle Alt": "Alt ﻞﻳﺪﺒﺗ", + "Toggle Windows": "Windows ﻞﻳﺪﺒﺗ", + "Windows": "ﻚﻴﺑﺎﺒﺷ", + "Send Tab": "ﺐﻳﻮﺒﺘﻟﺍ ﺔﻣﻼﻋ ﻝﺎﺳﺭﺇ", + "Tab": "ﺔﻋﻮﻓﺪﻣ ﺮﻴﻏ ﺓﺭﻮﺗﺎﻓ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺏﻭﺮﻬﻟﺍ ﺔﻟﺎﺳﺭ ﻝﺎﺳﺭﺇ", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺇ", + "Shutdown/Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Shutdown/Reboot...": " ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺇ / ﻞﻴﻐﺸﺘﻟﺍ ﻑﺎﻘﻳﺇ", + "Power": "ﺓﻮﻗ", + "Shutdown": "ﻖﻠﻏﺍ", + "Reboot": "ﻞﻴﻐﺸﺘﻟﺍ ﺓﺩﺎﻋﺍ", + "Reset": "ﻂﺒﺿ ﺓﺩﺎﻋﺇ", + "Clipboard": "ﺔﻈﻓﺎﺤﻟﺍ", + "Clear": "ﺢﺿﺍﻭ", + "Fullscreen": "ﺔﺷﺎﺸﻟﺍ ﺮﻴﺒﻜﺗ", + "Settings": "ﺕﺍﺩﺍﺪﻋﺇ", + "Shared Mode": "ﻙﺮﺘﺸﻤﻟﺍ ﻊﺿﻮﻟﺍ", + "View Only": "ﻂﻘﻓ ﻉﻼﻃﻼﻟ", + "Clip to Window": "ﺓﺬﻓﺎﻨﻟﺍ ﻲﻓ ﺺﻗ", + "Scaling Mode:": "ﻢﻴﺠﺤﺘﻟﺍ ﻊﺿﻭ", + "None": "ﺪﺣﺃ ﻻ", + "Local Scaling": "ﻲﻠﺤﻤﻟﺍ ﻢﻴﺠﺤﺘﻟﺍ", + "Remote Resizing": "ﺪﻌﺑ ﻦﻋ ﻢﺠﺤﻟﺍ ﺮﻴﻴﻐﺗ", + "Advanced": "ﻡﺪﻘﺘﻣ", + "Quality:": "ﺓﺩﻮﺟ", + "Compression level:": "ﻂﻐﻀﻟﺍ ﻯﻮﺘﺴﻣ", + "Repeater ID:": "ﺭﺮﻜﻤﻟﺍ ﻑﺮﻌﻣ", + "WebSocket": "WebSocket", + "Encrypt": "ﺮﻴﻔﺸﺗ", + "Host:": "ﻒﻴﻀﺘﺴﻳ", + "Port:": "ءﺎﻨﻴﻣ", + "Path:": "ﻖﻳﺮﻃ", + "Automatic Reconnect": "ﻲﺋﺎﻘﻠﺘﻟﺍ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Reconnect Delay (ms):": "(ﺔﻴﻧﺎﺛ ﻲﻠﻠﻣ) ﺮﻴﺧﺄﺗ ﻝﺎﺼﺗﻻﺍ ﺓﺩﺎﻋﺇ", + "Show Dot when No Cursor": "ﺮﺷﺆﻣ ﺩﻮﺟﻭ ﻡﺪﻋ ﺪﻨﻋ ﺔﻄﻘﻨﻟﺍ ﺭﺎﻬﻇﺇ", + "Logging:": "ﻞﻴﺠﺴﺗ", + "Version:": "ﺭﺍﺪﺻﺇ", + "Disconnect": "ﻝﺎﺼﺗﻻﺍ ﻊﻄﻗ", + "Connect": "ﻞﺼﺘﻳ", + "Username:": "ﻡﺪﺨﺘﺴﻤﻟﺍ ﻢﺳﺍ", + "Password:": "ﺭﻭﺮﻤﻟﺍ ﺔﻤﻠﻛ", + "Send Credentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻝﺎﺳﺭﺇ", + "Cancel": "ﻲﻐﻠﻳ", + "Keys": "ﺢﻴﺗﺎﻔﻣ", + "Game Cursor Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻊﺿﻭ ﻦﻣ ﺝﻭﺮﺨﻠﻟ Esc ﺡﺎﺘﻔﻣ ﻰﻠﻋ ﻂﻐﺿﺍ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻑﺎﻨﺌﺘﺳﻻ ﺔﺷﺎﺸﻟﺍ ﻰﻠﻋ ﺮﻘﻧﺍ ، ﺎﺘًﻗﺆﻣ ﺔﺒﻌﻠﻟﺍ ﻊﺿﻭ ﻒﻗﻮﺗ", + "Clipboard Up": "ﺔﻈﻓﺎﺤﻟﺍ", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "ﺲﻠﺴﻟﺍ ﺔﻈﻓﺎﺤﻟﺍ", + "Prefer Local Cursor": "ﻲﻠﺤﻤﻟﺍ ﺮﺷﺆﻤﻟﺍ ﻞﻴﻀﻔﺗ", + "Translate keyboard shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﺔﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻦﻴﻜﻤﺗ", + "Enable WebP Compression": "WebP ﻂﻐﺿ ﻦﻴﻜﻤﺗ", + "Enable Performance Stats": "ءﺍﺩﻷﺍ ﺕﺎﻴﺋﺎﺼﺣﺇ ﻦﻴﻜﻤﺗ", + "Enable Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻦﻴﻜﻤﺗ", + "IME Input Mode": "IME ﻝﺎﺧﺩﺇ ﻊﺿﻭ", + "Show Virtual Keyboard Control": "ﺔﻴﺿﺍﺮﺘﻓﻻﺍ ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﻲﻓ ﻢﻜﺤﺘﻟﺍ ﺭﺎﻬﻇﺇ", + "Toggle Control Panel via Keystrokes": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺕﺎﻄﻐﺿ ﺮﺒﻋ ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ", + "Render Native Resolution": "ﻲﻠﺻﻷﺍ ﻞﺤﻟﺍ ﺽﺮﻋ", + "Keyboard Shortcuts": "ﺢﻴﺗﺎﻔﻤﻟﺍ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺢﻴﺗﺎﻔﻣ ﺔﺣﻮﻟ ﺕﺍﺭﺎﺼﺘﺧﺍ ﻦﻴﻜﻤﺗ", + "1 - Toggle Control Panel": "ﻢﻜﺤﺘﻟﺍ ﺔﺣﻮﻟ ﻞﻳﺪﺒﺗ - 1", + "2 - Toggle Game Pointer Mode": "ﺔﺒﻌﻠﻟﺍ ﺮﺷﺆﻣ ﻊﺿﻭ ﻞﻳﺪﺒﺗ - 2", + "3 - Toggle Pointer Lock": "ﺮﺷﺆﻤﻟﺍ ﻞﻔﻗ ﻞﻳﺪﺒﺗ - 3", + "Stream Quality": "ﺚﺒﻟﺍ ﺓﺩﻮﺟ", + "Preset Modes:": "ﻖﺒﺴﻤﻟﺍ ﻂﺒﻀﻟﺍ ﻉﺎﺿﻭﺃ", + "Static": "ﺔﺘﺑﺎﺛ", + "Low": "ﻞﻴﻠﻗ", + "Medium": "ﺔﻄﺳﺍﻭ", + "High": "ﻲﻟﺎﻋ", + "Extreme": "ﻰﺼﻗﺃ", + "Lossless": "ﺕﺎﻧﺎﻴﺑ ﻥﺍﺪﻘﻓ ﻥﻭﺪﺑ", + "Custom": "ﺺﺼﺨﻣ", + "Anti-Aliasing:": "ﻞﻘﺼﻟﺍ", + "Auto Dynamic": "ﻲﺋﺎﻘﻠﺗ ﻲﻜﻴﻣﺎﻨﻳﺩ", + "Off": "ﻦﻋ", + "On": "ﻰﻠﻋ", + "Dynamic Quality Min:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺪﻟﺍ ﺓﺩﻮﺠﻠﻟ ﻰﻧﺩﻷﺍ ﺪﺤﻟﺍ", + "Dynamic Quality Max:": "ﺔﻴﻜﻴﻣﺎﻨﻳﺩ ﺓﺩﻮﺟ ﻰﺼﻗﺃ", + "Treat Lossless:": "ﺓﺭﺎﺴﺧ ﻼﺑ ﺝﻼﻋ", + "Frame Rate:": "ﺭﺎﻃﻹﺍ ﻝﺪﻌﻣ", + "Video JPEG Quality:": "JPEG ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video WEBP Quality:": "WEBP ﻮﻳﺪﻴﻔﻟﺍ ﺓﺩﻮﺟ", + "Video Area:": "ﻮﻳﺪﻴﻔﻟﺍ ﺔﻘﻄﻨﻣ", + "Video Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺖﻗﻭ", + "Video Out Time:": "ﻮﻳﺪﻴﻔﻟﺍ ﺝﻭﺮﺧ ﺖﻗﻭ", + "Video Mode Width:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﻳﺪﻴﻔﻟﺍ ﻊﺿﻭ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﻖﻴﺛﻮﺗ", + "Drag Viewport": "ﺽﺮﻌﻟﺍ ﺬﻔﻨﻣ ﺐﺤﺳﺍ", + "KasmVNC encountered an error:": "ﺄﻄﺧ KasmVNC ﻪﺟﺍﻭ" +} \ No newline at end of file diff --git a/app/locale/az.json b/app/locale/az.json new file mode 100644 index 0000000..e623b5f --- /dev/null +++ b/app/locale/az.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Qoşulur...", + "Disconnecting...": "Bağlantı kəsilir...", + "Reconnecting...": "Yenidən qoşulur...", + "Internal error": "Daxili səhv", + "Must set host": "Host təyin etməlidir", + "Connected (encrypted) to ": "Qoşuldu (şifrələnmiş)", + "Connected (unencrypted) to ": "Qoşuldu (şifrlənməmiş)", + "Something went wrong, connection is closed": "Nəsə xəta baş verdi, əlaqə bağlanıb", + "Failed to connect to server": "Serverə qoşulmaq alınmadı", + "Disconnected": "Əlaqə kəsildi", + "New connection has been rejected with reason: ": "Yeni əlaqə səbəblə rədd edildi:", + "New connection has been rejected": "Yeni əlaqə rədd edildi", + "Credentials are required": "Etibarnamə tələb olunur", + "Hide/Show the control bar": "İdarə çubuğunu gizlət/göstər", + "Drag": "Sürük", + "Move/Drag Viewport": "Görünüş portunu köçürün/çəkin", + "Keyboard": "Klaviatura", + "Show Keyboard": "Klaviaturanı göstər", + "Extra keys": "Əlavə açarlar", + "Show Extra Keys": "Əlavə açarları göstər", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl-ə keçid", + "Alt": "Alt", + "Toggle Alt": "Alt düyməsini dəyişdirin", + "Toggle Windows": "Windows-u dəyişdirin", + "Windows": "Windows", + "Send Tab": "Göndər nişanı", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Qaçış göndər", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del göndər", + "Shutdown/Reboot": "Söndürmə/Yenidən başla", + "Shutdown/Reboot...": "Söndürmə/Yenidən başla...", + "Power": "Güc", + "Shutdown": "Söndür", + "Reboot": "Yenidən başladın", + "Reset": "Sıfırla", + "Clipboard": "Bufer", + "Clear": "Aydın", + "Fullscreen": "Tam ekran", + "Settings": "Parametrlər", + "Shared Mode": "Paylaşılan rejim", + "View Only": "Yalnız Baxış", + "Clip to Window": "Pəncərəyə Klip", + "Scaling Mode:": "Ölçmə rejimi:", + "None": "Yox", + "Local Scaling": "Yerli Ölçəkləmə", + "Remote Resizing": "Uzaqdan Ölçüsü", + "Advanced": "Qabaqcıl", + "Quality:": "Keyfiyyət:", + "Compression level:": "Sıxılma səviyyəsi:", + "Repeater ID:": "Təkrarlayıcı ID:", + "WebSocket": "WebSocket", + "Encrypt": "Şifrələ", + "Host:": "Ev sahibi:", + "Port:": "Liman:", + "Path:": "Yol:", + "Automatic Reconnect": "Avtomatik yenidən qoşulma", + "Reconnect Delay (ms):": "Yenidən qoşulma gecikməsi (ms):", + "Show Dot when No Cursor": "Kursor olmayanda Nöqtə göstər", + "Logging:": "Giriş:", + "Version:": "Versiya:", + "Disconnect": "Bağlantıyı kəs", + "Connect": "Qoşun", + "Username:": "İstifadəçi adı:", + "Password:": "Parol:", + "Send Credentials": "Etibarnamələri göndər", + "Cancel": "Ləğv et", + "Keys": "Açarlar", + "Game Cursor Mode": "Oyun kursoru rejimi", + "Press Esc Key to Exit Pointer Lock Mode": "Göstərici kilidi rejimindən çıxmaq üçün Esc düyməsini basın", + "Game Mode paused, click on screen to resume Game Mode.": "Oyun rejimi dayandırıldı, Oyun rejimini davam etdirmək üçün ekrana klikləyin.", + "Clipboard Up": "Bufer Yuxarı", + "CLipboard Down": "Clipboard Aşağı", + "Clipboard Seamless": "Clipboard Sorunsuz", + "Prefer Local Cursor": "Yerli kursora üstünlük verin", + "Translate keyboard shortcuts": "Klaviatura qısa yollarını tərcümə et", + "Enable WebRTC UDP Transit": "WebRTC UDP Transitini aktivləşdirin", + "Enable WebP Compression": "WebP sıxılmasını aktivləşdir", + "Enable Performance Stats": "Performans statistikasını aktivləşdirin", + "Enable Pointer Lock": "Göstərici kilidini aktivləşdir", + "IME Input Mode": "IME Giriş rejimi", + "Show Virtual Keyboard Control": "Virtual klaviatura nəzarətini göstər", + "Toggle Control Panel via Keystrokes": "İdarəetmə panelini düymə vuruşları ilə dəyişdirin", + "Render Native Resolution": "Doğma Çözünürlük göstərin", + "Keyboard Shortcuts": "Klaviatura Qısayolları", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC Klaviatura Qısayollarını Aktivləşdirin", + "1 - Toggle Control Panel": "1 - İdarəetmə Panelini dəyişdirin", + "2 - Toggle Game Pointer Mode": "2 - Oyun Göstərici rejimini dəyişdirin", + "3 - Toggle Pointer Lock": "3 - Göstərici Kilidini dəyişdirin", + "Stream Quality": "Yayın keyfiyyəti", + "Preset Modes:": "Öncədən qurulmuş rejimlər:", + "Static": "Statik", + "Low": "Aşağı", + "Medium": "Orta", + "High": "Yüksək", + "Extreme": "Həddindən artıq", + "Lossless": "İtkisiz", + "Custom": "Xüsusi", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Avtomatik dinamik", + "Off": "Söndürülmüş", + "On": "Aktiv", + "Dynamic Quality Min:": "Dinamik Keyfiyyət Min:", + "Dynamic Quality Max:": "Maks. Dinamik Keyfiyyət:", + "Treat Lossless:": "İtkisiz Müalicə:", + "Frame Rate:": "Çərçivə Tezliyi:", + "Video JPEG Quality:": "Video JPEG Keyfiyyəti:", + "Video WEBP Quality:": "Video WEBP Keyfiyyəti:", + "Video Area:": "Video sahəsi:", + "Video Time:": "Video vaxtı:", + "Video Out Time:": "Videonun Çıxış vaxtı:", + "Video Mode Width:": "Video rejiminin eni:", + "Video Mode Height:": "Video rejimi hündürlüyü:", + "Documentation": "Sənədlər", + "Drag Viewport": "Görünüş sahəsini sürükləyin", + "KasmVNC encountered an error:": "KasmVNC xəta ilə qarşılaşdı:" +} \ No newline at end of file diff --git a/app/locale/az_AZ.json b/app/locale/az_AZ.json new file mode 100644 index 0000000..e623b5f --- /dev/null +++ b/app/locale/az_AZ.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Qoşulur...", + "Disconnecting...": "Bağlantı kəsilir...", + "Reconnecting...": "Yenidən qoşulur...", + "Internal error": "Daxili səhv", + "Must set host": "Host təyin etməlidir", + "Connected (encrypted) to ": "Qoşuldu (şifrələnmiş)", + "Connected (unencrypted) to ": "Qoşuldu (şifrlənməmiş)", + "Something went wrong, connection is closed": "Nəsə xəta baş verdi, əlaqə bağlanıb", + "Failed to connect to server": "Serverə qoşulmaq alınmadı", + "Disconnected": "Əlaqə kəsildi", + "New connection has been rejected with reason: ": "Yeni əlaqə səbəblə rədd edildi:", + "New connection has been rejected": "Yeni əlaqə rədd edildi", + "Credentials are required": "Etibarnamə tələb olunur", + "Hide/Show the control bar": "İdarə çubuğunu gizlət/göstər", + "Drag": "Sürük", + "Move/Drag Viewport": "Görünüş portunu köçürün/çəkin", + "Keyboard": "Klaviatura", + "Show Keyboard": "Klaviaturanı göstər", + "Extra keys": "Əlavə açarlar", + "Show Extra Keys": "Əlavə açarları göstər", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl-ə keçid", + "Alt": "Alt", + "Toggle Alt": "Alt düyməsini dəyişdirin", + "Toggle Windows": "Windows-u dəyişdirin", + "Windows": "Windows", + "Send Tab": "Göndər nişanı", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Qaçış göndər", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del göndər", + "Shutdown/Reboot": "Söndürmə/Yenidən başla", + "Shutdown/Reboot...": "Söndürmə/Yenidən başla...", + "Power": "Güc", + "Shutdown": "Söndür", + "Reboot": "Yenidən başladın", + "Reset": "Sıfırla", + "Clipboard": "Bufer", + "Clear": "Aydın", + "Fullscreen": "Tam ekran", + "Settings": "Parametrlər", + "Shared Mode": "Paylaşılan rejim", + "View Only": "Yalnız Baxış", + "Clip to Window": "Pəncərəyə Klip", + "Scaling Mode:": "Ölçmə rejimi:", + "None": "Yox", + "Local Scaling": "Yerli Ölçəkləmə", + "Remote Resizing": "Uzaqdan Ölçüsü", + "Advanced": "Qabaqcıl", + "Quality:": "Keyfiyyət:", + "Compression level:": "Sıxılma səviyyəsi:", + "Repeater ID:": "Təkrarlayıcı ID:", + "WebSocket": "WebSocket", + "Encrypt": "Şifrələ", + "Host:": "Ev sahibi:", + "Port:": "Liman:", + "Path:": "Yol:", + "Automatic Reconnect": "Avtomatik yenidən qoşulma", + "Reconnect Delay (ms):": "Yenidən qoşulma gecikməsi (ms):", + "Show Dot when No Cursor": "Kursor olmayanda Nöqtə göstər", + "Logging:": "Giriş:", + "Version:": "Versiya:", + "Disconnect": "Bağlantıyı kəs", + "Connect": "Qoşun", + "Username:": "İstifadəçi adı:", + "Password:": "Parol:", + "Send Credentials": "Etibarnamələri göndər", + "Cancel": "Ləğv et", + "Keys": "Açarlar", + "Game Cursor Mode": "Oyun kursoru rejimi", + "Press Esc Key to Exit Pointer Lock Mode": "Göstərici kilidi rejimindən çıxmaq üçün Esc düyməsini basın", + "Game Mode paused, click on screen to resume Game Mode.": "Oyun rejimi dayandırıldı, Oyun rejimini davam etdirmək üçün ekrana klikləyin.", + "Clipboard Up": "Bufer Yuxarı", + "CLipboard Down": "Clipboard Aşağı", + "Clipboard Seamless": "Clipboard Sorunsuz", + "Prefer Local Cursor": "Yerli kursora üstünlük verin", + "Translate keyboard shortcuts": "Klaviatura qısa yollarını tərcümə et", + "Enable WebRTC UDP Transit": "WebRTC UDP Transitini aktivləşdirin", + "Enable WebP Compression": "WebP sıxılmasını aktivləşdir", + "Enable Performance Stats": "Performans statistikasını aktivləşdirin", + "Enable Pointer Lock": "Göstərici kilidini aktivləşdir", + "IME Input Mode": "IME Giriş rejimi", + "Show Virtual Keyboard Control": "Virtual klaviatura nəzarətini göstər", + "Toggle Control Panel via Keystrokes": "İdarəetmə panelini düymə vuruşları ilə dəyişdirin", + "Render Native Resolution": "Doğma Çözünürlük göstərin", + "Keyboard Shortcuts": "Klaviatura Qısayolları", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC Klaviatura Qısayollarını Aktivləşdirin", + "1 - Toggle Control Panel": "1 - İdarəetmə Panelini dəyişdirin", + "2 - Toggle Game Pointer Mode": "2 - Oyun Göstərici rejimini dəyişdirin", + "3 - Toggle Pointer Lock": "3 - Göstərici Kilidini dəyişdirin", + "Stream Quality": "Yayın keyfiyyəti", + "Preset Modes:": "Öncədən qurulmuş rejimlər:", + "Static": "Statik", + "Low": "Aşağı", + "Medium": "Orta", + "High": "Yüksək", + "Extreme": "Həddindən artıq", + "Lossless": "İtkisiz", + "Custom": "Xüsusi", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Avtomatik dinamik", + "Off": "Söndürülmüş", + "On": "Aktiv", + "Dynamic Quality Min:": "Dinamik Keyfiyyət Min:", + "Dynamic Quality Max:": "Maks. Dinamik Keyfiyyət:", + "Treat Lossless:": "İtkisiz Müalicə:", + "Frame Rate:": "Çərçivə Tezliyi:", + "Video JPEG Quality:": "Video JPEG Keyfiyyəti:", + "Video WEBP Quality:": "Video WEBP Keyfiyyəti:", + "Video Area:": "Video sahəsi:", + "Video Time:": "Video vaxtı:", + "Video Out Time:": "Videonun Çıxış vaxtı:", + "Video Mode Width:": "Video rejiminin eni:", + "Video Mode Height:": "Video rejimi hündürlüyü:", + "Documentation": "Sənədlər", + "Drag Viewport": "Görünüş sahəsini sürükləyin", + "KasmVNC encountered an error:": "KasmVNC xəta ilə qarşılaşdı:" +} \ No newline at end of file diff --git a/app/locale/be.json b/app/locale/be.json new file mode 100644 index 0000000..369e189 --- /dev/null +++ b/app/locale/be.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Падключэнне...", + "Disconnecting...": "Адключэнне...", + "Reconnecting...": "Паўторнае падключэнне...", + "Internal error": "Унутраная памылка", + "Must set host": "Неабходна ўсталяваць хост", + "Connected (encrypted) to ": "Падключаны (зашыфраваны) да ", + "Connected (unencrypted) to ": "Падключана (не зашыфравана) да ", + "Something went wrong, connection is closed": "Нешта пайшло не так, злучэнне спынена", + "Failed to connect to server": "Не атрымалася падлучыцца да сервера", + "Disconnected": "Адключаны", + "New connection has been rejected with reason: ": "Новае злучэнне было адхілена па прычыне: ", + "New connection has been rejected": "Новае злучэнне было адхілена", + "Credentials are required": "Патрабуюцца ўліковыя даныя", + "Hide/Show the control bar": "Схаваць/паказаць панэль кіравання", + "Drag": "перацягнуць", + "Move/Drag Viewport": "Перамясціць/перацягнуць акно прагляду", + "Keyboard": "Клавіятура", + "Show Keyboard": "Паказаць клавіятуру", + "Extra keys": "Дадатковыя ключы", + "Show Extra Keys": "Паказаць дадатковыя ключы", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Пераключыць Ctrl", + "Alt": "Альт", + "Toggle Alt": "Пераключыць Alt", + "Toggle Windows": "Пераключыць Windows", + "Windows": "Windows", + "Send Tab": "Адправіць укладку", + "Tab": "Укладка", + "Esc": "Esc", + "Send Escape": "Адправіць Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Адправіць Ctrl-Alt-Del", + "Shutdown/Reboot": "Выключэнне/Перазагрузка", + "Shutdown/Reboot...": "Выключэнне/Перазагрузка...", + "Power": "Сіла", + "Shutdown": "Адключэнне", + "Reboot": "Перазагрузка", + "Reset": "Скінуць", + "Clipboard": "Буфер абмену", + "Clear": "Ясна", + "Fullscreen": "Поуны экран", + "Settings": "Настройкі", + "Shared Mode": "Агульны рэжым", + "View Only": "Толькі прагляд", + "Clip to Window": "Кліп у акно", + "Scaling Mode:": "Рэжым маштабавання:", + "None": "Ніводнага", + "Local Scaling": "Лакальнае маштабаванне", + "Remote Resizing": "Аддаленае змяненне памеру", + "Advanced": "Прасунуты", + "Quality:": "Якасць:", + "Compression level:": "Узровень сціску:", + "Repeater ID:": "Ідэнтыфікатар рэтранслятара:", + "WebSocket": "WebSocket", + "Encrypt": "Шыфраваць", + "Host:": "Вядучы:", + "Port:": "Порт:", + "Path:": "Шлях:", + "Automatic Reconnect": "Аўтаматычнае паўторнае падключэнне", + "Reconnect Delay (ms):": "Затрымка паўторнага падключэння (мс):", + "Show Dot when No Cursor": "Паказваць кропку, калі курсора няма", + "Logging:": "Запіс:", + "Version:": "Версія:", + "Disconnect": "Адключыць", + "Connect": "Падключыць", + "Username:": "Імя карыстальніка:", + "Password:": "Пароль:", + "Send Credentials": "Адправіць уліковыя дадзеныя", + "Cancel": "Адмяніць", + "Keys": "Ключы", + "Game Cursor Mode": "Рэжым гульнявога курсора", + "Press Esc Key to Exit Pointer Lock Mode": "Націсніце клавішу Esc, каб выйсці з рэжыму блакіроўкі паказальніка", + "Game Mode paused, click on screen to resume Game Mode.": "Гульнёвы рэжым прыпынены, пстрыкніце па экране, каб узнавіць гульнявы рэжым.", + "Clipboard Up": "Буфер абмену ўверх", + "CLipboard Down": "Буфер абмену ўніз", + "Clipboard Seamless": "Бясшвоўны буфер абмену", + "Prefer Local Cursor": "Аддаваць перавагу лакальнаму курсору", + "Translate keyboard shortcuts": "Перакласці спалучэнні клавіш", + "Enable WebRTC UDP Transit": "Уключыць WebRTC UDP Transit", + "Enable WebP Compression": "Уключыць сціск WebP", + "Enable Performance Stats": "Уключыць статыстыку прадукцыйнасці", + "Enable Pointer Lock": "Уключыць блакіроўку паказальніка", + "IME Input Mode": "Рэжым уводу IME", + "Show Virtual Keyboard Control": "Паказаць кіраванне віртуальнай клавіятурай", + "Toggle Control Panel via Keystrokes": "Пераключыць панэль кіравання з дапамогай клавіш", + "Render Native Resolution": "Візуалізаваць роднае разрозненне", + "Keyboard Shortcuts": "Спалучэнні клавіш", + "Enable KasmVNC Keyboard Shortcuts": "Уключыць спалучэнні клавіш KasmVNC", + "1 - Toggle Control Panel": "1 - Пераключыць панэль кіравання", + "2 - Toggle Game Pointer Mode": "2 - Пераключыць рэжым указальніка гульні", + "3 - Toggle Pointer Lock": "3 - Пераключыць блакіроўку паказальніка", + "Stream Quality": "Якасць плыні", + "Preset Modes:": "Папярэдне зададзеныя рэжымы:", + "Static": "Статычны", + "Low": "Нізкі", + "Medium": "Сярэдні", + "High": "Высокі", + "Extreme": "Экстрым", + "Lossless": "без страт", + "Custom": "На заказ", + "Anti-Aliasing:": "Згладжванне:", + "Auto Dynamic": "Аўтадынаміка", + "Off": "Выключана", + "On": "Уключана", + "Dynamic Quality Min:": "Мінімальная дынамічная якасць:", + "Dynamic Quality Max:": "Максімальная дынамічная якасць", + "Treat Lossless:": "Лечыць Lossless:", + "Frame Rate:": "Частата кадраў:", + "Video JPEG Quality:": "Якасць відэа JPEG:", + "Video WEBP Quality:": "Якасць відэа WEBP:", + "Video Area:": "Вобласць відэа:", + "Video Time:": "Час відэа:", + "Video Out Time:": "Час выхаду відэа:", + "Video Mode Width:": "Шырыня рэжыму відэа:", + "Video Mode Height:": "Вышыня рэжыму відэа:", + "Documentation": "Дакументацыя", + "Drag Viewport": "Перацягнуць акно прагляду", + "KasmVNC encountered an error:": "KasmVNC выявіў памылку:" +} \ No newline at end of file diff --git a/app/locale/be_BY.json b/app/locale/be_BY.json new file mode 100644 index 0000000..369e189 --- /dev/null +++ b/app/locale/be_BY.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Падключэнне...", + "Disconnecting...": "Адключэнне...", + "Reconnecting...": "Паўторнае падключэнне...", + "Internal error": "Унутраная памылка", + "Must set host": "Неабходна ўсталяваць хост", + "Connected (encrypted) to ": "Падключаны (зашыфраваны) да ", + "Connected (unencrypted) to ": "Падключана (не зашыфравана) да ", + "Something went wrong, connection is closed": "Нешта пайшло не так, злучэнне спынена", + "Failed to connect to server": "Не атрымалася падлучыцца да сервера", + "Disconnected": "Адключаны", + "New connection has been rejected with reason: ": "Новае злучэнне было адхілена па прычыне: ", + "New connection has been rejected": "Новае злучэнне было адхілена", + "Credentials are required": "Патрабуюцца ўліковыя даныя", + "Hide/Show the control bar": "Схаваць/паказаць панэль кіравання", + "Drag": "перацягнуць", + "Move/Drag Viewport": "Перамясціць/перацягнуць акно прагляду", + "Keyboard": "Клавіятура", + "Show Keyboard": "Паказаць клавіятуру", + "Extra keys": "Дадатковыя ключы", + "Show Extra Keys": "Паказаць дадатковыя ключы", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Пераключыць Ctrl", + "Alt": "Альт", + "Toggle Alt": "Пераключыць Alt", + "Toggle Windows": "Пераключыць Windows", + "Windows": "Windows", + "Send Tab": "Адправіць укладку", + "Tab": "Укладка", + "Esc": "Esc", + "Send Escape": "Адправіць Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Адправіць Ctrl-Alt-Del", + "Shutdown/Reboot": "Выключэнне/Перазагрузка", + "Shutdown/Reboot...": "Выключэнне/Перазагрузка...", + "Power": "Сіла", + "Shutdown": "Адключэнне", + "Reboot": "Перазагрузка", + "Reset": "Скінуць", + "Clipboard": "Буфер абмену", + "Clear": "Ясна", + "Fullscreen": "Поуны экран", + "Settings": "Настройкі", + "Shared Mode": "Агульны рэжым", + "View Only": "Толькі прагляд", + "Clip to Window": "Кліп у акно", + "Scaling Mode:": "Рэжым маштабавання:", + "None": "Ніводнага", + "Local Scaling": "Лакальнае маштабаванне", + "Remote Resizing": "Аддаленае змяненне памеру", + "Advanced": "Прасунуты", + "Quality:": "Якасць:", + "Compression level:": "Узровень сціску:", + "Repeater ID:": "Ідэнтыфікатар рэтранслятара:", + "WebSocket": "WebSocket", + "Encrypt": "Шыфраваць", + "Host:": "Вядучы:", + "Port:": "Порт:", + "Path:": "Шлях:", + "Automatic Reconnect": "Аўтаматычнае паўторнае падключэнне", + "Reconnect Delay (ms):": "Затрымка паўторнага падключэння (мс):", + "Show Dot when No Cursor": "Паказваць кропку, калі курсора няма", + "Logging:": "Запіс:", + "Version:": "Версія:", + "Disconnect": "Адключыць", + "Connect": "Падключыць", + "Username:": "Імя карыстальніка:", + "Password:": "Пароль:", + "Send Credentials": "Адправіць уліковыя дадзеныя", + "Cancel": "Адмяніць", + "Keys": "Ключы", + "Game Cursor Mode": "Рэжым гульнявога курсора", + "Press Esc Key to Exit Pointer Lock Mode": "Націсніце клавішу Esc, каб выйсці з рэжыму блакіроўкі паказальніка", + "Game Mode paused, click on screen to resume Game Mode.": "Гульнёвы рэжым прыпынены, пстрыкніце па экране, каб узнавіць гульнявы рэжым.", + "Clipboard Up": "Буфер абмену ўверх", + "CLipboard Down": "Буфер абмену ўніз", + "Clipboard Seamless": "Бясшвоўны буфер абмену", + "Prefer Local Cursor": "Аддаваць перавагу лакальнаму курсору", + "Translate keyboard shortcuts": "Перакласці спалучэнні клавіш", + "Enable WebRTC UDP Transit": "Уключыць WebRTC UDP Transit", + "Enable WebP Compression": "Уключыць сціск WebP", + "Enable Performance Stats": "Уключыць статыстыку прадукцыйнасці", + "Enable Pointer Lock": "Уключыць блакіроўку паказальніка", + "IME Input Mode": "Рэжым уводу IME", + "Show Virtual Keyboard Control": "Паказаць кіраванне віртуальнай клавіятурай", + "Toggle Control Panel via Keystrokes": "Пераключыць панэль кіравання з дапамогай клавіш", + "Render Native Resolution": "Візуалізаваць роднае разрозненне", + "Keyboard Shortcuts": "Спалучэнні клавіш", + "Enable KasmVNC Keyboard Shortcuts": "Уключыць спалучэнні клавіш KasmVNC", + "1 - Toggle Control Panel": "1 - Пераключыць панэль кіравання", + "2 - Toggle Game Pointer Mode": "2 - Пераключыць рэжым указальніка гульні", + "3 - Toggle Pointer Lock": "3 - Пераключыць блакіроўку паказальніка", + "Stream Quality": "Якасць плыні", + "Preset Modes:": "Папярэдне зададзеныя рэжымы:", + "Static": "Статычны", + "Low": "Нізкі", + "Medium": "Сярэдні", + "High": "Высокі", + "Extreme": "Экстрым", + "Lossless": "без страт", + "Custom": "На заказ", + "Anti-Aliasing:": "Згладжванне:", + "Auto Dynamic": "Аўтадынаміка", + "Off": "Выключана", + "On": "Уключана", + "Dynamic Quality Min:": "Мінімальная дынамічная якасць:", + "Dynamic Quality Max:": "Максімальная дынамічная якасць", + "Treat Lossless:": "Лечыць Lossless:", + "Frame Rate:": "Частата кадраў:", + "Video JPEG Quality:": "Якасць відэа JPEG:", + "Video WEBP Quality:": "Якасць відэа WEBP:", + "Video Area:": "Вобласць відэа:", + "Video Time:": "Час відэа:", + "Video Out Time:": "Час выхаду відэа:", + "Video Mode Width:": "Шырыня рэжыму відэа:", + "Video Mode Height:": "Вышыня рэжыму відэа:", + "Documentation": "Дакументацыя", + "Drag Viewport": "Перацягнуць акно прагляду", + "KasmVNC encountered an error:": "KasmVNC выявіў памылку:" +} \ No newline at end of file diff --git a/app/locale/bg.json b/app/locale/bg.json new file mode 100644 index 0000000..9d6219e --- /dev/null +++ b/app/locale/bg.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Свързване...", + "Disconnecting...": "Прекъсване на връзката...", + "Reconnecting...": "Повторно свързване...", + "Internal error": "Вътрешна грешка", + "Must set host": "Трябва да зададете хост", + "Connected (encrypted) to ": "Свързан (криптиран) към ", + "Connected (unencrypted) to ": "Свързан (некриптиран) с ", + "Something went wrong, connection is closed": "Нещо се обърка, връзката е затворена", + "Failed to connect to server": "Не може да се свърже със сървъра", + "Disconnected": "Прекъснат", + "New connection has been rejected with reason: ": "Нова връзка е отхвърлена с причина:", + "New connection has been rejected": "Нова връзка е отхвърлена", + "Credentials are required": "Изискват се идентификационни данни", + "Hide/Show the control bar": "Скриване/Показване на контролната лента", + "Drag": "Плъзнете", + "Move/Drag Viewport": "Преместване/плъзгане на изгледен прозорец", + "Keyboard": "Клавиатура", + "Show Keyboard": "Покажи клавиатурата", + "Extra keys": "Допълнителни ключове", + "Show Extra Keys": "Покажи допълнителни ключове", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Превключване на Ctrl", + "Alt": "Alt", + "Toggle Alt": "Превключване на Alt", + "Toggle Windows": "Превключване на Windows", + "Windows": "Windows", + "Send Tab": "Раздел Изпращане", + "Tab": "Раздел", + "Esc": "Esc", + "Send Escape": "Изпрати Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Изпращане на Ctrl-Alt-Del", + "Shutdown/Reboot": "Изключване/Рестартиране", + "Shutdown/Reboot...": "Изключване/Рестартиране...", + "Power": "мощност", + "Shutdown": "Изключвам", + "Reboot": "Рестартиране", + "Reset": "Нулиране", + "Clipboard": "Клипборд", + "Clear": "Ясно", + "Fullscreen": "Цял екран", + "Settings": "Настройки", + "Shared Mode": "Споделен режим", + "View Only": "Само преглед", + "Clip to Window": "Клип към прозорец", + "Scaling Mode:": "Режим на мащабиране:", + "None": "Нито един", + "Local Scaling": "Локално мащабиране", + "Remote Resizing": "Отдалечено преоразмеряване", + "Advanced": "Напреднали", + "Quality:": "Качество:", + "Compression level:": "Ниво на компресия:", + "Repeater ID:": "ID на ретранслатора:", + "WebSocket": "WebSocket", + "Encrypt": "Шифроване", + "Host:": "Домакин:", + "Port:": "Порт:", + "Path:": "Път:", + "Automatic Reconnect": "Автоматично повторно свързване", + "Reconnect Delay (ms):": "Забавяне при повторно свързване (ms):", + "Show Dot when No Cursor": "Показване на точка, когато няма курсор", + "Logging:": "Регистриране:", + "Version:": "Версия:", + "Disconnect": "Прекъсване", + "Connect": "Свързване", + "Username:": "Потребителско име:", + "Password:": "Парола:", + "Send Credentials": "Изпращане на идентификационни данни", + "Cancel": "Отказ", + "Keys": "Ключове", + "Game Cursor Mode": "Режим на курсора на играта", + "Press Esc Key to Exit Pointer Lock Mode": "Натиснете клавиша Esc, за да излезете от режима на заключване на показалеца", + "Game Mode paused, click on screen to resume Game Mode.": "Режимът на играта е на пауза, щракнете върху екрана, за да възобновите режима на игра.", + "Clipboard Up": "Клипборда нагоре", + "CLipboard Down": "Клипборда надолу", + "Clipboard Seamless": "Безпроблемно клипборд", + "Prefer Local Cursor": "Предпочитам локален курсор", + "Translate keyboard shortcuts": "Превод на клавишни комбинации", + "Enable WebRTC UDP Transit": "Активиране на WebRTC UDP Transit", + "Enable WebP Compression": "Активиране на WebP компресия", + "Enable Performance Stats": "Активиране на статистика за ефективността", + "Enable Pointer Lock": "Активиране на заключване на показалеца", + "IME Input Mode": "Режим на въвеждане на IME", + "Show Virtual Keyboard Control": "Показване на управлението на виртуалната клавиатура", + "Toggle Control Panel via Keystrokes": "Превключване на контролния панел чрез натискане на клавиши", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Комбинация от клавиши", + "Enable KasmVNC Keyboard Shortcuts": "Активиране на клавишните комбинации на KasmVNC", + "1 - Toggle Control Panel": "1 – Превключване на контролния панел", + "2 - Toggle Game Pointer Mode": "2 – Превключване на режима на показалеца на играта", + "3 - Toggle Pointer Lock": "3 – Превключване на заключването на показалеца", + "Stream Quality": "Качество на потока", + "Preset Modes:": "Предварително зададени режими:", + "Static": "Статичен", + "Low": "Нисък", + "Medium": "среден", + "High": "Високо", + "Extreme": "Екстремни", + "Lossless": "без загуба", + "Custom": "Персонализиран", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Авто динамичен", + "Off": "Изключено", + "On": "На", + "Dynamic Quality Min:": "Минимално динамично качество:", + "Dynamic Quality Max:": "Макс. динамично качество:", + "Treat Lossless:": "Лекувайте без загуба:", + "Frame Rate:": "Скорост на кадрите:", + "Video JPEG Quality:": "Видео JPEG качество:", + "Video WEBP Quality:": "Качество на видео WEBP:", + "Video Area:": "Видео зона:", + "Video Time:": "Време на видеото:", + "Video Out Time:": "Време за изход на видео:", + "Video Mode Width:": "Ширина на видео режим:", + "Video Mode Height:": "Височина на видео режим:", + "Documentation": "документация", + "Drag Viewport": "Изглед с плъзгане", + "KasmVNC encountered an error:": "KasmVNC откри грешка:" +} \ No newline at end of file diff --git a/app/locale/bg_BG.json b/app/locale/bg_BG.json new file mode 100644 index 0000000..9d6219e --- /dev/null +++ b/app/locale/bg_BG.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Свързване...", + "Disconnecting...": "Прекъсване на връзката...", + "Reconnecting...": "Повторно свързване...", + "Internal error": "Вътрешна грешка", + "Must set host": "Трябва да зададете хост", + "Connected (encrypted) to ": "Свързан (криптиран) към ", + "Connected (unencrypted) to ": "Свързан (некриптиран) с ", + "Something went wrong, connection is closed": "Нещо се обърка, връзката е затворена", + "Failed to connect to server": "Не може да се свърже със сървъра", + "Disconnected": "Прекъснат", + "New connection has been rejected with reason: ": "Нова връзка е отхвърлена с причина:", + "New connection has been rejected": "Нова връзка е отхвърлена", + "Credentials are required": "Изискват се идентификационни данни", + "Hide/Show the control bar": "Скриване/Показване на контролната лента", + "Drag": "Плъзнете", + "Move/Drag Viewport": "Преместване/плъзгане на изгледен прозорец", + "Keyboard": "Клавиатура", + "Show Keyboard": "Покажи клавиатурата", + "Extra keys": "Допълнителни ключове", + "Show Extra Keys": "Покажи допълнителни ключове", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Превключване на Ctrl", + "Alt": "Alt", + "Toggle Alt": "Превключване на Alt", + "Toggle Windows": "Превключване на Windows", + "Windows": "Windows", + "Send Tab": "Раздел Изпращане", + "Tab": "Раздел", + "Esc": "Esc", + "Send Escape": "Изпрати Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Изпращане на Ctrl-Alt-Del", + "Shutdown/Reboot": "Изключване/Рестартиране", + "Shutdown/Reboot...": "Изключване/Рестартиране...", + "Power": "мощност", + "Shutdown": "Изключвам", + "Reboot": "Рестартиране", + "Reset": "Нулиране", + "Clipboard": "Клипборд", + "Clear": "Ясно", + "Fullscreen": "Цял екран", + "Settings": "Настройки", + "Shared Mode": "Споделен режим", + "View Only": "Само преглед", + "Clip to Window": "Клип към прозорец", + "Scaling Mode:": "Режим на мащабиране:", + "None": "Нито един", + "Local Scaling": "Локално мащабиране", + "Remote Resizing": "Отдалечено преоразмеряване", + "Advanced": "Напреднали", + "Quality:": "Качество:", + "Compression level:": "Ниво на компресия:", + "Repeater ID:": "ID на ретранслатора:", + "WebSocket": "WebSocket", + "Encrypt": "Шифроване", + "Host:": "Домакин:", + "Port:": "Порт:", + "Path:": "Път:", + "Automatic Reconnect": "Автоматично повторно свързване", + "Reconnect Delay (ms):": "Забавяне при повторно свързване (ms):", + "Show Dot when No Cursor": "Показване на точка, когато няма курсор", + "Logging:": "Регистриране:", + "Version:": "Версия:", + "Disconnect": "Прекъсване", + "Connect": "Свързване", + "Username:": "Потребителско име:", + "Password:": "Парола:", + "Send Credentials": "Изпращане на идентификационни данни", + "Cancel": "Отказ", + "Keys": "Ключове", + "Game Cursor Mode": "Режим на курсора на играта", + "Press Esc Key to Exit Pointer Lock Mode": "Натиснете клавиша Esc, за да излезете от режима на заключване на показалеца", + "Game Mode paused, click on screen to resume Game Mode.": "Режимът на играта е на пауза, щракнете върху екрана, за да възобновите режима на игра.", + "Clipboard Up": "Клипборда нагоре", + "CLipboard Down": "Клипборда надолу", + "Clipboard Seamless": "Безпроблемно клипборд", + "Prefer Local Cursor": "Предпочитам локален курсор", + "Translate keyboard shortcuts": "Превод на клавишни комбинации", + "Enable WebRTC UDP Transit": "Активиране на WebRTC UDP Transit", + "Enable WebP Compression": "Активиране на WebP компресия", + "Enable Performance Stats": "Активиране на статистика за ефективността", + "Enable Pointer Lock": "Активиране на заключване на показалеца", + "IME Input Mode": "Режим на въвеждане на IME", + "Show Virtual Keyboard Control": "Показване на управлението на виртуалната клавиатура", + "Toggle Control Panel via Keystrokes": "Превключване на контролния панел чрез натискане на клавиши", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Комбинация от клавиши", + "Enable KasmVNC Keyboard Shortcuts": "Активиране на клавишните комбинации на KasmVNC", + "1 - Toggle Control Panel": "1 – Превключване на контролния панел", + "2 - Toggle Game Pointer Mode": "2 – Превключване на режима на показалеца на играта", + "3 - Toggle Pointer Lock": "3 – Превключване на заключването на показалеца", + "Stream Quality": "Качество на потока", + "Preset Modes:": "Предварително зададени режими:", + "Static": "Статичен", + "Low": "Нисък", + "Medium": "среден", + "High": "Високо", + "Extreme": "Екстремни", + "Lossless": "без загуба", + "Custom": "Персонализиран", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Авто динамичен", + "Off": "Изключено", + "On": "На", + "Dynamic Quality Min:": "Минимално динамично качество:", + "Dynamic Quality Max:": "Макс. динамично качество:", + "Treat Lossless:": "Лекувайте без загуба:", + "Frame Rate:": "Скорост на кадрите:", + "Video JPEG Quality:": "Видео JPEG качество:", + "Video WEBP Quality:": "Качество на видео WEBP:", + "Video Area:": "Видео зона:", + "Video Time:": "Време на видеото:", + "Video Out Time:": "Време за изход на видео:", + "Video Mode Width:": "Ширина на видео режим:", + "Video Mode Height:": "Височина на видео режим:", + "Documentation": "документация", + "Drag Viewport": "Изглед с плъзгане", + "KasmVNC encountered an error:": "KasmVNC откри грешка:" +} \ No newline at end of file diff --git a/app/locale/bn.json b/app/locale/bn.json new file mode 100644 index 0000000..4021202 --- /dev/null +++ b/app/locale/bn.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "সংযুক্ত হচ্ছে...", + "Disconnecting...": "সংযোগ বিচ্ছিন্ন হচ্ছে...", + "Reconnecting...": "পুনরায় সংযোগ করা হচ্ছে...", + "Internal error": "অভ্যন্তরীণ ত্রুটি", + "Must set host": "হোস্ট সেট করতে হবে", + "Connected (encrypted) to ": "এর সাথে সংযুক্ত (এনক্রিপ্ট করা) ", + "Connected (unencrypted) to ": "এর সাথে সংযুক্ত (এনক্রিপ্ট করা হয়নি) ", + "Something went wrong, connection is closed": "কিছু ভুল হয়েছে, সংযোগ বন্ধ আছে", + "Failed to connect to server": "সার্ভারের সাথে সংযোগ করতে ব্যর্থ", + "Disconnected": "সংযোগ বিচ্ছিন্ন", + "New connection has been rejected with reason: ": "নতুন সংযোগ কারণ সহ প্রত্যাখ্যান করা হয়েছে:", + "New connection has been rejected": "নতুন সংযোগ প্রত্যাখ্যান করা হয়েছে", + "Credentials are required": "শংসাপত্র প্রয়োজন", + "Hide/Show the control bar": "কন্ট্রোল বার লুকান/দেখান", + "Drag": "টেনে আনুন", + "Move/Drag Viewport": "ভিউপোর্ট সরান/টেনে আনুন", + "Keyboard": "কীবোর্ড", + "Show Keyboard": "কীবোর্ড দেখান", + "Extra keys": "অতিরিক্ত কী", + "Show Extra Keys": "অতিরিক্ত কী দেখান", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl টগল করুন", + "Alt": "Alt", + "Toggle Alt": "Alt টগল করুন", + "Toggle Windows": "উইন্ডোজ টগল করুন", + "Windows": "উইন্ডোজ", + "Send Tab": "ট্যাব পাঠান", + "Tab": "ট্যাব", + "Esc": "প্রস্থান", + "Send Escape": "পলায়ন পাঠান", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del পাঠান", + "Shutdown/Reboot": "শাটডাউন/রিবুট", + "Shutdown/Reboot...": "শাটডাউন/রিবুট...", + "Power": "শক্তি", + "Shutdown": "শাটডাউন", + "Reboot": "রিবুট", + "Reset": "রিসেট", + "Clipboard": "ক্লিপবোর্ড", + "Clear": "পরিষ্কার", + "Fullscreen": "পূর্ণ পর্দা", + "Settings": "সেটিংস", + "Shared Mode": "ভাগ করা মোড", + "View Only": "শুধু দেখো", + "Clip to Window": "উইন্ডোতে ক্লিপ করুন", + "Scaling Mode:": "স্কেলিং মোড:", + "None": "কিছুই না", + "Local Scaling": "স্থানীয় স্কেলিং", + "Remote Resizing": "রিমোট রিসাইজিং", + "Advanced": "উন্নত", + "Quality:": "গুণমান:", + "Compression level:": "সংকোচন স্তর:", + "Repeater ID:": "রিপিটার আইডি:", + "WebSocket": "ওয়েবসকেট", + "Encrypt": "এনক্রিপ্ট", + "Host:": "হোস্ট:", + "Port:": "বন্দর:", + "Path:": "পথ:", + "Automatic Reconnect": "স্বয়ংক্রিয় পুনঃসংযোগ", + "Reconnect Delay (ms):": "পুনঃসংযোগ বিলম্ব (ms):", + "Show Dot when No Cursor": "কারসার না থাকলে বিন্দু দেখান", + "Logging:": "লগিং:", + "Version:": "সংস্করণ:", + "Disconnect": "সংযোগ বিচ্ছিন্ন করুন", + "Connect": "সংযোগ করুন", + "Username:": "ব্যবহারকারীর নাম:", + "Password:": "পাসওয়ার্ড:", + "Send Credentials": "প্রমাণপত্র পাঠান", + "Cancel": "বাতিল করুন", + "Keys": "চাবি", + "Game Cursor Mode": "গেম কার্সার মোড", + "Press Esc Key to Exit Pointer Lock Mode": "পয়েন্টার লক মোড থেকে প্রস্থান করতে Esc কী টিপুন", + "Game Mode paused, click on screen to resume Game Mode.": "গেম মোড পজ করা হয়েছে, গেম মোড পুনরায় শুরু করতে স্ক্রিনে ক্লিক করুন।", + "Clipboard Up": "ক্লিপবোর্ড আপ", + "CLipboard Down": "ক্লিপবোর্ড নিচে", + "Clipboard Seamless": "ক্লিপবোর্ড বিরামহীন", + "Prefer Local Cursor": "স্থানীয় কার্সার পছন্দ করুন", + "Translate keyboard shortcuts": "কীবোর্ড শর্টকাট অনুবাদ করুন", + "Enable WebRTC UDP Transit": "WebRTC UDP ট্রানজিট সক্ষম করুন", + "Enable WebP Compression": "WebP কম্প্রেশন সক্ষম করুন", + "Enable Performance Stats": "কর্মক্ষমতা পরিসংখ্যান সক্ষম করুন", + "Enable Pointer Lock": "পয়েন্টার লক সক্ষম করুন", + "IME Input Mode": "আইএমই ইনপুট মোড", + "Show Virtual Keyboard Control": "ভার্চুয়াল কীবোর্ড নিয়ন্ত্রণ দেখান", + "Toggle Control Panel via Keystrokes": "কীস্ট্রোকের মাধ্যমে কন্ট্রোল প্যানেল টগল করুন", + "Render Native Resolution": "নেটিভ রেজোলিউশন রেন্ডার করুন", + "Keyboard Shortcuts": "কীবোর্ড শর্টকাট", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC কীবোর্ড শর্টকাট সক্ষম করুন", + "1 - Toggle Control Panel": "1 - কন্ট্রোল প্যানেল টগল করুন", + "2 - Toggle Game Pointer Mode": "2 - গেম পয়েন্টার মোড টগল করুন", + "3 - Toggle Pointer Lock": "3 - পয়েন্টার লক টগল করুন", + "Stream Quality": "স্ট্রিম কোয়ালিটি", + "Preset Modes:": "প্রিসেট মোড:", + "Static": "অচল", + "Low": "নিম্ন", + "Medium": "মধ্যম", + "High": "উচ্চ", + "Extreme": "চরম", + "Lossless": "ক্ষতিহীন", + "Custom": "কাস্টম", + "Anti-Aliasing:": "এন্টি-আলিয়াসিং:", + "Auto Dynamic": "অটো ডাইনামিক", + "Off": "বন্ধ", + "On": "চালু", + "Dynamic Quality Min:": "ডাইনামিক কোয়ালিটি মিন:", + "Dynamic Quality Max:": "ডাইনামিক কোয়ালিটি ম্যাক্স:", + "Treat Lossless:": "ক্ষতিহীন চিকিত্সা করুন:", + "Frame Rate:": "চক্রের হার:", + "Video JPEG Quality:": "ভিডিও JPEG কোয়ালিটি:", + "Video WEBP Quality:": "ভিডিও WEBP গুণমান:", + "Video Area:": "ভিডিও এলাকা:", + "Video Time:": "ভিডিও সময়:", + "Video Out Time:": "ভিডিও আউট টাইম:", + "Video Mode Width:": "ভিডিও মোড প্রস্থ:", + "Video Mode Height:": "ভিডিও মোড উচ্চতা:", + "Documentation": "ডকুমেন্টেশন", + "Drag Viewport": "ভিউপোর্ট টানুন", + "KasmVNC encountered an error:": "KasmVNC একটি ত্রুটির সম্মুখীন হয়েছে:" +} \ No newline at end of file diff --git a/app/locale/bn_BD.json b/app/locale/bn_BD.json new file mode 100644 index 0000000..4021202 --- /dev/null +++ b/app/locale/bn_BD.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "সংযুক্ত হচ্ছে...", + "Disconnecting...": "সংযোগ বিচ্ছিন্ন হচ্ছে...", + "Reconnecting...": "পুনরায় সংযোগ করা হচ্ছে...", + "Internal error": "অভ্যন্তরীণ ত্রুটি", + "Must set host": "হোস্ট সেট করতে হবে", + "Connected (encrypted) to ": "এর সাথে সংযুক্ত (এনক্রিপ্ট করা) ", + "Connected (unencrypted) to ": "এর সাথে সংযুক্ত (এনক্রিপ্ট করা হয়নি) ", + "Something went wrong, connection is closed": "কিছু ভুল হয়েছে, সংযোগ বন্ধ আছে", + "Failed to connect to server": "সার্ভারের সাথে সংযোগ করতে ব্যর্থ", + "Disconnected": "সংযোগ বিচ্ছিন্ন", + "New connection has been rejected with reason: ": "নতুন সংযোগ কারণ সহ প্রত্যাখ্যান করা হয়েছে:", + "New connection has been rejected": "নতুন সংযোগ প্রত্যাখ্যান করা হয়েছে", + "Credentials are required": "শংসাপত্র প্রয়োজন", + "Hide/Show the control bar": "কন্ট্রোল বার লুকান/দেখান", + "Drag": "টেনে আনুন", + "Move/Drag Viewport": "ভিউপোর্ট সরান/টেনে আনুন", + "Keyboard": "কীবোর্ড", + "Show Keyboard": "কীবোর্ড দেখান", + "Extra keys": "অতিরিক্ত কী", + "Show Extra Keys": "অতিরিক্ত কী দেখান", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl টগল করুন", + "Alt": "Alt", + "Toggle Alt": "Alt টগল করুন", + "Toggle Windows": "উইন্ডোজ টগল করুন", + "Windows": "উইন্ডোজ", + "Send Tab": "ট্যাব পাঠান", + "Tab": "ট্যাব", + "Esc": "প্রস্থান", + "Send Escape": "পলায়ন পাঠান", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del পাঠান", + "Shutdown/Reboot": "শাটডাউন/রিবুট", + "Shutdown/Reboot...": "শাটডাউন/রিবুট...", + "Power": "শক্তি", + "Shutdown": "শাটডাউন", + "Reboot": "রিবুট", + "Reset": "রিসেট", + "Clipboard": "ক্লিপবোর্ড", + "Clear": "পরিষ্কার", + "Fullscreen": "পূর্ণ পর্দা", + "Settings": "সেটিংস", + "Shared Mode": "ভাগ করা মোড", + "View Only": "শুধু দেখো", + "Clip to Window": "উইন্ডোতে ক্লিপ করুন", + "Scaling Mode:": "স্কেলিং মোড:", + "None": "কিছুই না", + "Local Scaling": "স্থানীয় স্কেলিং", + "Remote Resizing": "রিমোট রিসাইজিং", + "Advanced": "উন্নত", + "Quality:": "গুণমান:", + "Compression level:": "সংকোচন স্তর:", + "Repeater ID:": "রিপিটার আইডি:", + "WebSocket": "ওয়েবসকেট", + "Encrypt": "এনক্রিপ্ট", + "Host:": "হোস্ট:", + "Port:": "বন্দর:", + "Path:": "পথ:", + "Automatic Reconnect": "স্বয়ংক্রিয় পুনঃসংযোগ", + "Reconnect Delay (ms):": "পুনঃসংযোগ বিলম্ব (ms):", + "Show Dot when No Cursor": "কারসার না থাকলে বিন্দু দেখান", + "Logging:": "লগিং:", + "Version:": "সংস্করণ:", + "Disconnect": "সংযোগ বিচ্ছিন্ন করুন", + "Connect": "সংযোগ করুন", + "Username:": "ব্যবহারকারীর নাম:", + "Password:": "পাসওয়ার্ড:", + "Send Credentials": "প্রমাণপত্র পাঠান", + "Cancel": "বাতিল করুন", + "Keys": "চাবি", + "Game Cursor Mode": "গেম কার্সার মোড", + "Press Esc Key to Exit Pointer Lock Mode": "পয়েন্টার লক মোড থেকে প্রস্থান করতে Esc কী টিপুন", + "Game Mode paused, click on screen to resume Game Mode.": "গেম মোড পজ করা হয়েছে, গেম মোড পুনরায় শুরু করতে স্ক্রিনে ক্লিক করুন।", + "Clipboard Up": "ক্লিপবোর্ড আপ", + "CLipboard Down": "ক্লিপবোর্ড নিচে", + "Clipboard Seamless": "ক্লিপবোর্ড বিরামহীন", + "Prefer Local Cursor": "স্থানীয় কার্সার পছন্দ করুন", + "Translate keyboard shortcuts": "কীবোর্ড শর্টকাট অনুবাদ করুন", + "Enable WebRTC UDP Transit": "WebRTC UDP ট্রানজিট সক্ষম করুন", + "Enable WebP Compression": "WebP কম্প্রেশন সক্ষম করুন", + "Enable Performance Stats": "কর্মক্ষমতা পরিসংখ্যান সক্ষম করুন", + "Enable Pointer Lock": "পয়েন্টার লক সক্ষম করুন", + "IME Input Mode": "আইএমই ইনপুট মোড", + "Show Virtual Keyboard Control": "ভার্চুয়াল কীবোর্ড নিয়ন্ত্রণ দেখান", + "Toggle Control Panel via Keystrokes": "কীস্ট্রোকের মাধ্যমে কন্ট্রোল প্যানেল টগল করুন", + "Render Native Resolution": "নেটিভ রেজোলিউশন রেন্ডার করুন", + "Keyboard Shortcuts": "কীবোর্ড শর্টকাট", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC কীবোর্ড শর্টকাট সক্ষম করুন", + "1 - Toggle Control Panel": "1 - কন্ট্রোল প্যানেল টগল করুন", + "2 - Toggle Game Pointer Mode": "2 - গেম পয়েন্টার মোড টগল করুন", + "3 - Toggle Pointer Lock": "3 - পয়েন্টার লক টগল করুন", + "Stream Quality": "স্ট্রিম কোয়ালিটি", + "Preset Modes:": "প্রিসেট মোড:", + "Static": "অচল", + "Low": "নিম্ন", + "Medium": "মধ্যম", + "High": "উচ্চ", + "Extreme": "চরম", + "Lossless": "ক্ষতিহীন", + "Custom": "কাস্টম", + "Anti-Aliasing:": "এন্টি-আলিয়াসিং:", + "Auto Dynamic": "অটো ডাইনামিক", + "Off": "বন্ধ", + "On": "চালু", + "Dynamic Quality Min:": "ডাইনামিক কোয়ালিটি মিন:", + "Dynamic Quality Max:": "ডাইনামিক কোয়ালিটি ম্যাক্স:", + "Treat Lossless:": "ক্ষতিহীন চিকিত্সা করুন:", + "Frame Rate:": "চক্রের হার:", + "Video JPEG Quality:": "ভিডিও JPEG কোয়ালিটি:", + "Video WEBP Quality:": "ভিডিও WEBP গুণমান:", + "Video Area:": "ভিডিও এলাকা:", + "Video Time:": "ভিডিও সময়:", + "Video Out Time:": "ভিডিও আউট টাইম:", + "Video Mode Width:": "ভিডিও মোড প্রস্থ:", + "Video Mode Height:": "ভিডিও মোড উচ্চতা:", + "Documentation": "ডকুমেন্টেশন", + "Drag Viewport": "ভিউপোর্ট টানুন", + "KasmVNC encountered an error:": "KasmVNC একটি ত্রুটির সম্মুখীন হয়েছে:" +} \ No newline at end of file diff --git a/app/locale/bn_IN.json b/app/locale/bn_IN.json new file mode 100644 index 0000000..4021202 --- /dev/null +++ b/app/locale/bn_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "সংযুক্ত হচ্ছে...", + "Disconnecting...": "সংযোগ বিচ্ছিন্ন হচ্ছে...", + "Reconnecting...": "পুনরায় সংযোগ করা হচ্ছে...", + "Internal error": "অভ্যন্তরীণ ত্রুটি", + "Must set host": "হোস্ট সেট করতে হবে", + "Connected (encrypted) to ": "এর সাথে সংযুক্ত (এনক্রিপ্ট করা) ", + "Connected (unencrypted) to ": "এর সাথে সংযুক্ত (এনক্রিপ্ট করা হয়নি) ", + "Something went wrong, connection is closed": "কিছু ভুল হয়েছে, সংযোগ বন্ধ আছে", + "Failed to connect to server": "সার্ভারের সাথে সংযোগ করতে ব্যর্থ", + "Disconnected": "সংযোগ বিচ্ছিন্ন", + "New connection has been rejected with reason: ": "নতুন সংযোগ কারণ সহ প্রত্যাখ্যান করা হয়েছে:", + "New connection has been rejected": "নতুন সংযোগ প্রত্যাখ্যান করা হয়েছে", + "Credentials are required": "শংসাপত্র প্রয়োজন", + "Hide/Show the control bar": "কন্ট্রোল বার লুকান/দেখান", + "Drag": "টেনে আনুন", + "Move/Drag Viewport": "ভিউপোর্ট সরান/টেনে আনুন", + "Keyboard": "কীবোর্ড", + "Show Keyboard": "কীবোর্ড দেখান", + "Extra keys": "অতিরিক্ত কী", + "Show Extra Keys": "অতিরিক্ত কী দেখান", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl টগল করুন", + "Alt": "Alt", + "Toggle Alt": "Alt টগল করুন", + "Toggle Windows": "উইন্ডোজ টগল করুন", + "Windows": "উইন্ডোজ", + "Send Tab": "ট্যাব পাঠান", + "Tab": "ট্যাব", + "Esc": "প্রস্থান", + "Send Escape": "পলায়ন পাঠান", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del পাঠান", + "Shutdown/Reboot": "শাটডাউন/রিবুট", + "Shutdown/Reboot...": "শাটডাউন/রিবুট...", + "Power": "শক্তি", + "Shutdown": "শাটডাউন", + "Reboot": "রিবুট", + "Reset": "রিসেট", + "Clipboard": "ক্লিপবোর্ড", + "Clear": "পরিষ্কার", + "Fullscreen": "পূর্ণ পর্দা", + "Settings": "সেটিংস", + "Shared Mode": "ভাগ করা মোড", + "View Only": "শুধু দেখো", + "Clip to Window": "উইন্ডোতে ক্লিপ করুন", + "Scaling Mode:": "স্কেলিং মোড:", + "None": "কিছুই না", + "Local Scaling": "স্থানীয় স্কেলিং", + "Remote Resizing": "রিমোট রিসাইজিং", + "Advanced": "উন্নত", + "Quality:": "গুণমান:", + "Compression level:": "সংকোচন স্তর:", + "Repeater ID:": "রিপিটার আইডি:", + "WebSocket": "ওয়েবসকেট", + "Encrypt": "এনক্রিপ্ট", + "Host:": "হোস্ট:", + "Port:": "বন্দর:", + "Path:": "পথ:", + "Automatic Reconnect": "স্বয়ংক্রিয় পুনঃসংযোগ", + "Reconnect Delay (ms):": "পুনঃসংযোগ বিলম্ব (ms):", + "Show Dot when No Cursor": "কারসার না থাকলে বিন্দু দেখান", + "Logging:": "লগিং:", + "Version:": "সংস্করণ:", + "Disconnect": "সংযোগ বিচ্ছিন্ন করুন", + "Connect": "সংযোগ করুন", + "Username:": "ব্যবহারকারীর নাম:", + "Password:": "পাসওয়ার্ড:", + "Send Credentials": "প্রমাণপত্র পাঠান", + "Cancel": "বাতিল করুন", + "Keys": "চাবি", + "Game Cursor Mode": "গেম কার্সার মোড", + "Press Esc Key to Exit Pointer Lock Mode": "পয়েন্টার লক মোড থেকে প্রস্থান করতে Esc কী টিপুন", + "Game Mode paused, click on screen to resume Game Mode.": "গেম মোড পজ করা হয়েছে, গেম মোড পুনরায় শুরু করতে স্ক্রিনে ক্লিক করুন।", + "Clipboard Up": "ক্লিপবোর্ড আপ", + "CLipboard Down": "ক্লিপবোর্ড নিচে", + "Clipboard Seamless": "ক্লিপবোর্ড বিরামহীন", + "Prefer Local Cursor": "স্থানীয় কার্সার পছন্দ করুন", + "Translate keyboard shortcuts": "কীবোর্ড শর্টকাট অনুবাদ করুন", + "Enable WebRTC UDP Transit": "WebRTC UDP ট্রানজিট সক্ষম করুন", + "Enable WebP Compression": "WebP কম্প্রেশন সক্ষম করুন", + "Enable Performance Stats": "কর্মক্ষমতা পরিসংখ্যান সক্ষম করুন", + "Enable Pointer Lock": "পয়েন্টার লক সক্ষম করুন", + "IME Input Mode": "আইএমই ইনপুট মোড", + "Show Virtual Keyboard Control": "ভার্চুয়াল কীবোর্ড নিয়ন্ত্রণ দেখান", + "Toggle Control Panel via Keystrokes": "কীস্ট্রোকের মাধ্যমে কন্ট্রোল প্যানেল টগল করুন", + "Render Native Resolution": "নেটিভ রেজোলিউশন রেন্ডার করুন", + "Keyboard Shortcuts": "কীবোর্ড শর্টকাট", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC কীবোর্ড শর্টকাট সক্ষম করুন", + "1 - Toggle Control Panel": "1 - কন্ট্রোল প্যানেল টগল করুন", + "2 - Toggle Game Pointer Mode": "2 - গেম পয়েন্টার মোড টগল করুন", + "3 - Toggle Pointer Lock": "3 - পয়েন্টার লক টগল করুন", + "Stream Quality": "স্ট্রিম কোয়ালিটি", + "Preset Modes:": "প্রিসেট মোড:", + "Static": "অচল", + "Low": "নিম্ন", + "Medium": "মধ্যম", + "High": "উচ্চ", + "Extreme": "চরম", + "Lossless": "ক্ষতিহীন", + "Custom": "কাস্টম", + "Anti-Aliasing:": "এন্টি-আলিয়াসিং:", + "Auto Dynamic": "অটো ডাইনামিক", + "Off": "বন্ধ", + "On": "চালু", + "Dynamic Quality Min:": "ডাইনামিক কোয়ালিটি মিন:", + "Dynamic Quality Max:": "ডাইনামিক কোয়ালিটি ম্যাক্স:", + "Treat Lossless:": "ক্ষতিহীন চিকিত্সা করুন:", + "Frame Rate:": "চক্রের হার:", + "Video JPEG Quality:": "ভিডিও JPEG কোয়ালিটি:", + "Video WEBP Quality:": "ভিডিও WEBP গুণমান:", + "Video Area:": "ভিডিও এলাকা:", + "Video Time:": "ভিডিও সময়:", + "Video Out Time:": "ভিডিও আউট টাইম:", + "Video Mode Width:": "ভিডিও মোড প্রস্থ:", + "Video Mode Height:": "ভিডিও মোড উচ্চতা:", + "Documentation": "ডকুমেন্টেশন", + "Drag Viewport": "ভিউপোর্ট টানুন", + "KasmVNC encountered an error:": "KasmVNC একটি ত্রুটির সম্মুখীন হয়েছে:" +} \ No newline at end of file diff --git a/app/locale/bs.json b/app/locale/bs.json new file mode 100644 index 0000000..d3d800b --- /dev/null +++ b/app/locale/bs.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Povezivanje...", + "Disconnecting...": "Prekidanje veze...", + "Reconnecting...": "Ponovno povezivanje...", + "Internal error": "Interna greška", + "Must set host": "Mora se postaviti host", + "Connected (encrypted) to ": "Povezano (šifrirano) na ", + "Connected (unencrypted) to ": "Povezano (nešifrirano) na ", + "Something went wrong, connection is closed": "Nešto nije u redu, veza je zatvorena", + "Failed to connect to server": "Neuspjelo povezivanje na server", + "Disconnected": "isključeno", + "New connection has been rejected with reason: ": "Nova veza je odbijena s razlogom: ", + "New connection has been rejected": "Nova veza je odbijena", + "Credentials are required": "Potrebni su akreditivi", + "Hide/Show the control bar": "Sakrij/Prikaži kontrolnu traku", + "Drag": "povuci", + "Move/Drag Viewport": "Premjesti/povucite okvir za prikaz", + "Keyboard": "tastatura", + "Show Keyboard": "Prikaži tastaturu", + "Extra keys": "dodatni ključevi", + "Show Extra Keys": "Prikaži dodatne ključeve", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Prebaci Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Windows", + "Send Tab": "Pošalji karticu", + "Tab": "tab", + "Esc": "Itd", + "Send Escape": "Pošalji bijeg", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Pošalji Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "snaga", + "Shutdown": "Ugasiti", + "Reboot": "ponovno pokretanje", + "Reset": "Resetovati", + "Clipboard": "međuspremnik", + "Clear": "jasno", + "Fullscreen": "Cijeli ekran", + "Settings": "Postavke", + "Shared Mode": "Shared Mode", + "View Only": "Samo prikaz", + "Clip to Window": "Klip to prozor", + "Scaling Mode:": "Način skaliranja:", + "None": "nijedno", + "Local Scaling": "Lokalno skaliranje", + "Remote Resizing": "Daljinsko mijenjanje veličine", + "Advanced": "napredni", + "Quality:": "Kvalitet:", + "Compression level:": "Nivo kompresije:", + "Repeater ID:": "ID repetitora:", + "WebSocket": "WebSocket", + "Encrypt": "šifriranje", + "Host:": "domaćin:", + "Port:": "Luka:", + "Path:": "Put:", + "Automatic Reconnect": "Automatsko ponovno povezivanje", + "Reconnect Delay (ms):": "Kašnjenje ponovnog povezivanja (ms):", + "Show Dot when No Cursor": "Prikaži tačku kada nema kursora", + "Logging:": "Logiranje:", + "Version:": "Verzija:", + "Disconnect": "Prekini", + "Connect": "poveži se", + "Username:": "Korisničko ime:", + "Password:": "Lozinka:", + "Send Credentials": "Pošalji akreditive", + "Cancel": "Otkaži", + "Keys": "ključevi", + "Game Cursor Mode": "Način kursora igre", + "Press Esc Key to Exit Pointer Lock Mode": "Pritisnite tipku Esc da izađete iz načina zaključavanja pokazivača", + "Game Mode paused, click on screen to resume Game Mode.": "Režim igre je pauziran, kliknite na ekran da nastavite Game Mode.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Bešavni međuspremnik", + "Prefer Local Cursor": "Preferiraj lokalni kursor", + "Translate keyboard shortcuts": "Prevedi prečice na tastaturi", + "Enable WebRTC UDP Transit": "Omogući WebRTC UDP tranzit", + "Enable WebP Compression": "Omogući WebP kompresiju", + "Enable Performance Stats": "Omogući statistiku performansi", + "Enable Pointer Lock": "Omogući zaključavanje pokazivača", + "IME Input Mode": "IME način unosa", + "Show Virtual Keyboard Control": "Prikaži kontrolu virtuelne tastature", + "Toggle Control Panel via Keystrokes": "Prebacite kontrolnu tablu pritiskom na tipke", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Prečice na tastaturi", + "Enable KasmVNC Keyboard Shortcuts": "Omogući KasmVNC prečice na tastaturi", + "1 - Toggle Control Panel": "1 - Uključite kontrolnu tablu", + "2 - Toggle Game Pointer Mode": "2 - Uključite način rada pokazivača igre", + "3 - Toggle Pointer Lock": "3 - Prebaci zaključavanje pokazivača", + "Stream Quality": "Kvalitet prijenosa", + "Preset Modes:": "Unaprijed postavljeni načini rada:", + "Static": "statična", + "Low": "nisko", + "Medium": "srednji", + "High": "visoko", + "Extreme": "ekstremno", + "Lossless": "bez gubitaka", + "Custom": "prilagođeno", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Isključeno", + "On": "Uključeno", + "Dynamic Quality Min:": "Minimalni dinamički kvalitet:", + "Dynamic Quality Max:": "Maksimalni dinamički kvalitet:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Brzina kadrova:", + "Video JPEG Quality:": "Video JPEG kvalitet:", + "Video WEBP Quality:": "Video WEBP kvalitet:", + "Video Area:": "Video područje:", + "Video Time:": "Vrijeme videa:", + "Video Out Time:": "Vrijeme izlaza videa:", + "Video Mode Width:": "Širina video načina rada:", + "Video Mode Height:": "Visina video načina:", + "Documentation": "dokumentacija", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "KasmVNC je naišao na grešku:" +} \ No newline at end of file diff --git a/app/locale/bs_BA.json b/app/locale/bs_BA.json new file mode 100644 index 0000000..d3d800b --- /dev/null +++ b/app/locale/bs_BA.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Povezivanje...", + "Disconnecting...": "Prekidanje veze...", + "Reconnecting...": "Ponovno povezivanje...", + "Internal error": "Interna greška", + "Must set host": "Mora se postaviti host", + "Connected (encrypted) to ": "Povezano (šifrirano) na ", + "Connected (unencrypted) to ": "Povezano (nešifrirano) na ", + "Something went wrong, connection is closed": "Nešto nije u redu, veza je zatvorena", + "Failed to connect to server": "Neuspjelo povezivanje na server", + "Disconnected": "isključeno", + "New connection has been rejected with reason: ": "Nova veza je odbijena s razlogom: ", + "New connection has been rejected": "Nova veza je odbijena", + "Credentials are required": "Potrebni su akreditivi", + "Hide/Show the control bar": "Sakrij/Prikaži kontrolnu traku", + "Drag": "povuci", + "Move/Drag Viewport": "Premjesti/povucite okvir za prikaz", + "Keyboard": "tastatura", + "Show Keyboard": "Prikaži tastaturu", + "Extra keys": "dodatni ključevi", + "Show Extra Keys": "Prikaži dodatne ključeve", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Prebaci Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Windows", + "Send Tab": "Pošalji karticu", + "Tab": "tab", + "Esc": "Itd", + "Send Escape": "Pošalji bijeg", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Pošalji Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "snaga", + "Shutdown": "Ugasiti", + "Reboot": "ponovno pokretanje", + "Reset": "Resetovati", + "Clipboard": "međuspremnik", + "Clear": "jasno", + "Fullscreen": "Cijeli ekran", + "Settings": "Postavke", + "Shared Mode": "Shared Mode", + "View Only": "Samo prikaz", + "Clip to Window": "Klip to prozor", + "Scaling Mode:": "Način skaliranja:", + "None": "nijedno", + "Local Scaling": "Lokalno skaliranje", + "Remote Resizing": "Daljinsko mijenjanje veličine", + "Advanced": "napredni", + "Quality:": "Kvalitet:", + "Compression level:": "Nivo kompresije:", + "Repeater ID:": "ID repetitora:", + "WebSocket": "WebSocket", + "Encrypt": "šifriranje", + "Host:": "domaćin:", + "Port:": "Luka:", + "Path:": "Put:", + "Automatic Reconnect": "Automatsko ponovno povezivanje", + "Reconnect Delay (ms):": "Kašnjenje ponovnog povezivanja (ms):", + "Show Dot when No Cursor": "Prikaži tačku kada nema kursora", + "Logging:": "Logiranje:", + "Version:": "Verzija:", + "Disconnect": "Prekini", + "Connect": "poveži se", + "Username:": "Korisničko ime:", + "Password:": "Lozinka:", + "Send Credentials": "Pošalji akreditive", + "Cancel": "Otkaži", + "Keys": "ključevi", + "Game Cursor Mode": "Način kursora igre", + "Press Esc Key to Exit Pointer Lock Mode": "Pritisnite tipku Esc da izađete iz načina zaključavanja pokazivača", + "Game Mode paused, click on screen to resume Game Mode.": "Režim igre je pauziran, kliknite na ekran da nastavite Game Mode.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Bešavni međuspremnik", + "Prefer Local Cursor": "Preferiraj lokalni kursor", + "Translate keyboard shortcuts": "Prevedi prečice na tastaturi", + "Enable WebRTC UDP Transit": "Omogući WebRTC UDP tranzit", + "Enable WebP Compression": "Omogući WebP kompresiju", + "Enable Performance Stats": "Omogući statistiku performansi", + "Enable Pointer Lock": "Omogući zaključavanje pokazivača", + "IME Input Mode": "IME način unosa", + "Show Virtual Keyboard Control": "Prikaži kontrolu virtuelne tastature", + "Toggle Control Panel via Keystrokes": "Prebacite kontrolnu tablu pritiskom na tipke", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Prečice na tastaturi", + "Enable KasmVNC Keyboard Shortcuts": "Omogući KasmVNC prečice na tastaturi", + "1 - Toggle Control Panel": "1 - Uključite kontrolnu tablu", + "2 - Toggle Game Pointer Mode": "2 - Uključite način rada pokazivača igre", + "3 - Toggle Pointer Lock": "3 - Prebaci zaključavanje pokazivača", + "Stream Quality": "Kvalitet prijenosa", + "Preset Modes:": "Unaprijed postavljeni načini rada:", + "Static": "statična", + "Low": "nisko", + "Medium": "srednji", + "High": "visoko", + "Extreme": "ekstremno", + "Lossless": "bez gubitaka", + "Custom": "prilagođeno", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Isključeno", + "On": "Uključeno", + "Dynamic Quality Min:": "Minimalni dinamički kvalitet:", + "Dynamic Quality Max:": "Maksimalni dinamički kvalitet:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Brzina kadrova:", + "Video JPEG Quality:": "Video JPEG kvalitet:", + "Video WEBP Quality:": "Video WEBP kvalitet:", + "Video Area:": "Video područje:", + "Video Time:": "Vrijeme videa:", + "Video Out Time:": "Vrijeme izlaza videa:", + "Video Mode Width:": "Širina video načina rada:", + "Video Mode Height:": "Visina video načina:", + "Documentation": "dokumentacija", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "KasmVNC je naišao na grešku:" +} \ No newline at end of file diff --git a/app/locale/ca.json b/app/locale/ca.json new file mode 100644 index 0000000..4d65f9c --- /dev/null +++ b/app/locale/ca.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Connectant...", + "Disconnecting...": "Desconnectant...", + "Reconnecting...": "Reconnectant...", + "Internal error": "Error intern", + "Must set host": "Cal configurar l'amfitrió", + "Connected (encrypted) to ": "Connectat (xifrat) a", + "Connected (unencrypted) to ": "Connectat (sense xifrar) a", + "Something went wrong, connection is closed": "Alguna cosa ha anat malament, la connexió està tancada", + "Failed to connect to server": "Ha fallat la connexió amb el servidor", + "Disconnected": "Desconnectat", + "New connection has been rejected with reason: ": "S'ha rebutjat una connexió nova per un motiu:", + "New connection has been rejected": "S'ha rebutjat una connexió nova", + "Credentials are required": "Les credencials són necessàries", + "Hide/Show the control bar": "Oculta/Mostra la barra de control", + "Drag": "Arrossegar", + "Move/Drag Viewport": "Mou/Arrossegueu la finestra gràfica", + "Keyboard": "Teclat", + "Show Keyboard": "Mostra el teclat", + "Extra keys": "Claus addicionals", + "Show Extra Keys": "Mostra les claus addicionals", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Canvia Ctrl", + "Alt": "Alt", + "Toggle Alt": "Canvia Alt", + "Toggle Windows": "Canvia Windows", + "Windows": "Windows", + "Send Tab": "Envia la pestanya", + "Tab": "pestanya", + "Esc": "Esc", + "Send Escape": "Envia escapar", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Envia Ctrl-Alt-Supr", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Poder", + "Shutdown": "Tancar", + "Reboot": "Reiniciar", + "Reset": "Restablir", + "Clipboard": "Porta-retalls", + "Clear": "Netejar", + "Fullscreen": "Pantalla completa", + "Settings": "Configuració", + "Shared Mode": "Mode compartit", + "View Only": "Només vista", + "Clip to Window": "Clip a la finestra", + "Scaling Mode:": "Mode d'escala:", + "None": "Cap", + "Local Scaling": "Escala local", + "Remote Resizing": "Redimensionament remot", + "Advanced": "Avançat", + "Quality:": "Qualitat:", + "Compression level:": "Nivell de compressió:", + "Repeater ID:": "ID del repetidor:", + "WebSocket": "WebSocket", + "Encrypt": "Xifrar", + "Host:": "Amfitrió:", + "Port:": "Port:", + "Path:": "Camí:", + "Automatic Reconnect": "Reconnexió automàtica", + "Reconnect Delay (ms):": "Retard de tornada a connectar (ms):", + "Show Dot when No Cursor": "Mostra el punt quan no hi ha cursor", + "Logging:": "Registre:", + "Version:": "Versió:", + "Disconnect": "Desconnectar", + "Connect": "Connexió", + "Username:": "Nom d'usuari:", + "Password:": "Contrasenya:", + "Send Credentials": "Envia credencials", + "Cancel": "Cancel · lar", + "Keys": "Claus", + "Game Cursor Mode": "Mode de cursor de joc", + "Press Esc Key to Exit Pointer Lock Mode": "Premeu la tecla Esc per sortir del mode de bloqueig del punter", + "Game Mode paused, click on screen to resume Game Mode.": "Mode de joc en pausa, feu clic a la pantalla per reprendre el mode de joc", + "Clipboard Up": "Porta-retalls amunt", + "CLipboard Down": "Porta-retalls avall", + "Clipboard Seamless": "Porta-retalls sense costures", + "Prefer Local Cursor": "Preferir el cursor local", + "Translate keyboard shortcuts": "Tradueix les dreceres del teclat", + "Enable WebRTC UDP Transit": "Activa WebRTC UDP Transit", + "Enable WebP Compression": "Activa la compressió WebP", + "Enable Performance Stats": "Activa les estadístiques de rendiment", + "Enable Pointer Lock": "Activa el bloqueig del punter", + "IME Input Mode": "Mode d'entrada IME", + "Show Virtual Keyboard Control": "Mostra el control del teclat virtual", + "Toggle Control Panel via Keystrokes": "Canvia el tauler de control mitjançant les pulsacions de tecles", + "Render Native Resolution": "Representa la resolució nativa", + "Keyboard Shortcuts": "Dreceres de teclat", + "Enable KasmVNC Keyboard Shortcuts": "Activa les dreceres de teclat de KasmVNC", + "1 - Toggle Control Panel": "1 - Canvia el tauler de control", + "2 - Toggle Game Pointer Mode": "2 - Canvia el mode de punter de joc", + "3 - Toggle Pointer Lock": "3 - Commuta el bloqueig del punter", + "Stream Quality": "Qualitat del flux", + "Preset Modes:": "Modes preestablerts:", + "Static": "Estàtic", + "Low": "Baix", + "Medium": "mitjà", + "High": "Alt", + "Extreme": "Extrem", + "Lossless": "Sense pèrdues", + "Custom": "Personalitzat", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Dinàmica automàtica", + "Off": "Desactivat", + "On": "Activat", + "Dynamic Quality Min:": "Qualitat dinàmica mínima:", + "Dynamic Quality Max:": "Qualitat dinàmica màxima:", + "Treat Lossless:": "Traiteu sense pèrdues:", + "Frame Rate:": "Velocitat de fotogrames:", + "Video JPEG Quality:": "Qualitat del vídeo JPEG:", + "Video WEBP Quality:": "Qualitat del WEBP del vídeo:", + "Video Area:": "Àrea de vídeo:", + "Video Time:": "Hora del vídeo:", + "Video Out Time:": "Hora de sortida del vídeo:", + "Video Mode Width:": "Amplada del mode de vídeo:", + "Video Mode Height:": "Alçada del mode de vídeo:", + "Documentation": "Documentació", + "Drag Viewport": "Arrossegar la finestra gràfica", + "KasmVNC encountered an error:": "KasmVNC ha trobat un error:" +} \ No newline at end of file diff --git a/app/locale/ca_AD.json b/app/locale/ca_AD.json new file mode 100644 index 0000000..4d65f9c --- /dev/null +++ b/app/locale/ca_AD.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Connectant...", + "Disconnecting...": "Desconnectant...", + "Reconnecting...": "Reconnectant...", + "Internal error": "Error intern", + "Must set host": "Cal configurar l'amfitrió", + "Connected (encrypted) to ": "Connectat (xifrat) a", + "Connected (unencrypted) to ": "Connectat (sense xifrar) a", + "Something went wrong, connection is closed": "Alguna cosa ha anat malament, la connexió està tancada", + "Failed to connect to server": "Ha fallat la connexió amb el servidor", + "Disconnected": "Desconnectat", + "New connection has been rejected with reason: ": "S'ha rebutjat una connexió nova per un motiu:", + "New connection has been rejected": "S'ha rebutjat una connexió nova", + "Credentials are required": "Les credencials són necessàries", + "Hide/Show the control bar": "Oculta/Mostra la barra de control", + "Drag": "Arrossegar", + "Move/Drag Viewport": "Mou/Arrossegueu la finestra gràfica", + "Keyboard": "Teclat", + "Show Keyboard": "Mostra el teclat", + "Extra keys": "Claus addicionals", + "Show Extra Keys": "Mostra les claus addicionals", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Canvia Ctrl", + "Alt": "Alt", + "Toggle Alt": "Canvia Alt", + "Toggle Windows": "Canvia Windows", + "Windows": "Windows", + "Send Tab": "Envia la pestanya", + "Tab": "pestanya", + "Esc": "Esc", + "Send Escape": "Envia escapar", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Envia Ctrl-Alt-Supr", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Poder", + "Shutdown": "Tancar", + "Reboot": "Reiniciar", + "Reset": "Restablir", + "Clipboard": "Porta-retalls", + "Clear": "Netejar", + "Fullscreen": "Pantalla completa", + "Settings": "Configuració", + "Shared Mode": "Mode compartit", + "View Only": "Només vista", + "Clip to Window": "Clip a la finestra", + "Scaling Mode:": "Mode d'escala:", + "None": "Cap", + "Local Scaling": "Escala local", + "Remote Resizing": "Redimensionament remot", + "Advanced": "Avançat", + "Quality:": "Qualitat:", + "Compression level:": "Nivell de compressió:", + "Repeater ID:": "ID del repetidor:", + "WebSocket": "WebSocket", + "Encrypt": "Xifrar", + "Host:": "Amfitrió:", + "Port:": "Port:", + "Path:": "Camí:", + "Automatic Reconnect": "Reconnexió automàtica", + "Reconnect Delay (ms):": "Retard de tornada a connectar (ms):", + "Show Dot when No Cursor": "Mostra el punt quan no hi ha cursor", + "Logging:": "Registre:", + "Version:": "Versió:", + "Disconnect": "Desconnectar", + "Connect": "Connexió", + "Username:": "Nom d'usuari:", + "Password:": "Contrasenya:", + "Send Credentials": "Envia credencials", + "Cancel": "Cancel · lar", + "Keys": "Claus", + "Game Cursor Mode": "Mode de cursor de joc", + "Press Esc Key to Exit Pointer Lock Mode": "Premeu la tecla Esc per sortir del mode de bloqueig del punter", + "Game Mode paused, click on screen to resume Game Mode.": "Mode de joc en pausa, feu clic a la pantalla per reprendre el mode de joc", + "Clipboard Up": "Porta-retalls amunt", + "CLipboard Down": "Porta-retalls avall", + "Clipboard Seamless": "Porta-retalls sense costures", + "Prefer Local Cursor": "Preferir el cursor local", + "Translate keyboard shortcuts": "Tradueix les dreceres del teclat", + "Enable WebRTC UDP Transit": "Activa WebRTC UDP Transit", + "Enable WebP Compression": "Activa la compressió WebP", + "Enable Performance Stats": "Activa les estadístiques de rendiment", + "Enable Pointer Lock": "Activa el bloqueig del punter", + "IME Input Mode": "Mode d'entrada IME", + "Show Virtual Keyboard Control": "Mostra el control del teclat virtual", + "Toggle Control Panel via Keystrokes": "Canvia el tauler de control mitjançant les pulsacions de tecles", + "Render Native Resolution": "Representa la resolució nativa", + "Keyboard Shortcuts": "Dreceres de teclat", + "Enable KasmVNC Keyboard Shortcuts": "Activa les dreceres de teclat de KasmVNC", + "1 - Toggle Control Panel": "1 - Canvia el tauler de control", + "2 - Toggle Game Pointer Mode": "2 - Canvia el mode de punter de joc", + "3 - Toggle Pointer Lock": "3 - Commuta el bloqueig del punter", + "Stream Quality": "Qualitat del flux", + "Preset Modes:": "Modes preestablerts:", + "Static": "Estàtic", + "Low": "Baix", + "Medium": "mitjà", + "High": "Alt", + "Extreme": "Extrem", + "Lossless": "Sense pèrdues", + "Custom": "Personalitzat", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Dinàmica automàtica", + "Off": "Desactivat", + "On": "Activat", + "Dynamic Quality Min:": "Qualitat dinàmica mínima:", + "Dynamic Quality Max:": "Qualitat dinàmica màxima:", + "Treat Lossless:": "Traiteu sense pèrdues:", + "Frame Rate:": "Velocitat de fotogrames:", + "Video JPEG Quality:": "Qualitat del vídeo JPEG:", + "Video WEBP Quality:": "Qualitat del WEBP del vídeo:", + "Video Area:": "Àrea de vídeo:", + "Video Time:": "Hora del vídeo:", + "Video Out Time:": "Hora de sortida del vídeo:", + "Video Mode Width:": "Amplada del mode de vídeo:", + "Video Mode Height:": "Alçada del mode de vídeo:", + "Documentation": "Documentació", + "Drag Viewport": "Arrossegar la finestra gràfica", + "KasmVNC encountered an error:": "KasmVNC ha trobat un error:" +} \ No newline at end of file diff --git a/app/locale/ca_ES.json b/app/locale/ca_ES.json new file mode 100644 index 0000000..4d65f9c --- /dev/null +++ b/app/locale/ca_ES.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Connectant...", + "Disconnecting...": "Desconnectant...", + "Reconnecting...": "Reconnectant...", + "Internal error": "Error intern", + "Must set host": "Cal configurar l'amfitrió", + "Connected (encrypted) to ": "Connectat (xifrat) a", + "Connected (unencrypted) to ": "Connectat (sense xifrar) a", + "Something went wrong, connection is closed": "Alguna cosa ha anat malament, la connexió està tancada", + "Failed to connect to server": "Ha fallat la connexió amb el servidor", + "Disconnected": "Desconnectat", + "New connection has been rejected with reason: ": "S'ha rebutjat una connexió nova per un motiu:", + "New connection has been rejected": "S'ha rebutjat una connexió nova", + "Credentials are required": "Les credencials són necessàries", + "Hide/Show the control bar": "Oculta/Mostra la barra de control", + "Drag": "Arrossegar", + "Move/Drag Viewport": "Mou/Arrossegueu la finestra gràfica", + "Keyboard": "Teclat", + "Show Keyboard": "Mostra el teclat", + "Extra keys": "Claus addicionals", + "Show Extra Keys": "Mostra les claus addicionals", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Canvia Ctrl", + "Alt": "Alt", + "Toggle Alt": "Canvia Alt", + "Toggle Windows": "Canvia Windows", + "Windows": "Windows", + "Send Tab": "Envia la pestanya", + "Tab": "pestanya", + "Esc": "Esc", + "Send Escape": "Envia escapar", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Envia Ctrl-Alt-Supr", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Poder", + "Shutdown": "Tancar", + "Reboot": "Reiniciar", + "Reset": "Restablir", + "Clipboard": "Porta-retalls", + "Clear": "Netejar", + "Fullscreen": "Pantalla completa", + "Settings": "Configuració", + "Shared Mode": "Mode compartit", + "View Only": "Només vista", + "Clip to Window": "Clip a la finestra", + "Scaling Mode:": "Mode d'escala:", + "None": "Cap", + "Local Scaling": "Escala local", + "Remote Resizing": "Redimensionament remot", + "Advanced": "Avançat", + "Quality:": "Qualitat:", + "Compression level:": "Nivell de compressió:", + "Repeater ID:": "ID del repetidor:", + "WebSocket": "WebSocket", + "Encrypt": "Xifrar", + "Host:": "Amfitrió:", + "Port:": "Port:", + "Path:": "Camí:", + "Automatic Reconnect": "Reconnexió automàtica", + "Reconnect Delay (ms):": "Retard de tornada a connectar (ms):", + "Show Dot when No Cursor": "Mostra el punt quan no hi ha cursor", + "Logging:": "Registre:", + "Version:": "Versió:", + "Disconnect": "Desconnectar", + "Connect": "Connexió", + "Username:": "Nom d'usuari:", + "Password:": "Contrasenya:", + "Send Credentials": "Envia credencials", + "Cancel": "Cancel · lar", + "Keys": "Claus", + "Game Cursor Mode": "Mode de cursor de joc", + "Press Esc Key to Exit Pointer Lock Mode": "Premeu la tecla Esc per sortir del mode de bloqueig del punter", + "Game Mode paused, click on screen to resume Game Mode.": "Mode de joc en pausa, feu clic a la pantalla per reprendre el mode de joc", + "Clipboard Up": "Porta-retalls amunt", + "CLipboard Down": "Porta-retalls avall", + "Clipboard Seamless": "Porta-retalls sense costures", + "Prefer Local Cursor": "Preferir el cursor local", + "Translate keyboard shortcuts": "Tradueix les dreceres del teclat", + "Enable WebRTC UDP Transit": "Activa WebRTC UDP Transit", + "Enable WebP Compression": "Activa la compressió WebP", + "Enable Performance Stats": "Activa les estadístiques de rendiment", + "Enable Pointer Lock": "Activa el bloqueig del punter", + "IME Input Mode": "Mode d'entrada IME", + "Show Virtual Keyboard Control": "Mostra el control del teclat virtual", + "Toggle Control Panel via Keystrokes": "Canvia el tauler de control mitjançant les pulsacions de tecles", + "Render Native Resolution": "Representa la resolució nativa", + "Keyboard Shortcuts": "Dreceres de teclat", + "Enable KasmVNC Keyboard Shortcuts": "Activa les dreceres de teclat de KasmVNC", + "1 - Toggle Control Panel": "1 - Canvia el tauler de control", + "2 - Toggle Game Pointer Mode": "2 - Canvia el mode de punter de joc", + "3 - Toggle Pointer Lock": "3 - Commuta el bloqueig del punter", + "Stream Quality": "Qualitat del flux", + "Preset Modes:": "Modes preestablerts:", + "Static": "Estàtic", + "Low": "Baix", + "Medium": "mitjà", + "High": "Alt", + "Extreme": "Extrem", + "Lossless": "Sense pèrdues", + "Custom": "Personalitzat", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Dinàmica automàtica", + "Off": "Desactivat", + "On": "Activat", + "Dynamic Quality Min:": "Qualitat dinàmica mínima:", + "Dynamic Quality Max:": "Qualitat dinàmica màxima:", + "Treat Lossless:": "Traiteu sense pèrdues:", + "Frame Rate:": "Velocitat de fotogrames:", + "Video JPEG Quality:": "Qualitat del vídeo JPEG:", + "Video WEBP Quality:": "Qualitat del WEBP del vídeo:", + "Video Area:": "Àrea de vídeo:", + "Video Time:": "Hora del vídeo:", + "Video Out Time:": "Hora de sortida del vídeo:", + "Video Mode Width:": "Amplada del mode de vídeo:", + "Video Mode Height:": "Alçada del mode de vídeo:", + "Documentation": "Documentació", + "Drag Viewport": "Arrossegar la finestra gràfica", + "KasmVNC encountered an error:": "KasmVNC ha trobat un error:" +} \ No newline at end of file diff --git a/app/locale/ca_FR.json b/app/locale/ca_FR.json new file mode 100644 index 0000000..4d65f9c --- /dev/null +++ b/app/locale/ca_FR.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Connectant...", + "Disconnecting...": "Desconnectant...", + "Reconnecting...": "Reconnectant...", + "Internal error": "Error intern", + "Must set host": "Cal configurar l'amfitrió", + "Connected (encrypted) to ": "Connectat (xifrat) a", + "Connected (unencrypted) to ": "Connectat (sense xifrar) a", + "Something went wrong, connection is closed": "Alguna cosa ha anat malament, la connexió està tancada", + "Failed to connect to server": "Ha fallat la connexió amb el servidor", + "Disconnected": "Desconnectat", + "New connection has been rejected with reason: ": "S'ha rebutjat una connexió nova per un motiu:", + "New connection has been rejected": "S'ha rebutjat una connexió nova", + "Credentials are required": "Les credencials són necessàries", + "Hide/Show the control bar": "Oculta/Mostra la barra de control", + "Drag": "Arrossegar", + "Move/Drag Viewport": "Mou/Arrossegueu la finestra gràfica", + "Keyboard": "Teclat", + "Show Keyboard": "Mostra el teclat", + "Extra keys": "Claus addicionals", + "Show Extra Keys": "Mostra les claus addicionals", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Canvia Ctrl", + "Alt": "Alt", + "Toggle Alt": "Canvia Alt", + "Toggle Windows": "Canvia Windows", + "Windows": "Windows", + "Send Tab": "Envia la pestanya", + "Tab": "pestanya", + "Esc": "Esc", + "Send Escape": "Envia escapar", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Envia Ctrl-Alt-Supr", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Poder", + "Shutdown": "Tancar", + "Reboot": "Reiniciar", + "Reset": "Restablir", + "Clipboard": "Porta-retalls", + "Clear": "Netejar", + "Fullscreen": "Pantalla completa", + "Settings": "Configuració", + "Shared Mode": "Mode compartit", + "View Only": "Només vista", + "Clip to Window": "Clip a la finestra", + "Scaling Mode:": "Mode d'escala:", + "None": "Cap", + "Local Scaling": "Escala local", + "Remote Resizing": "Redimensionament remot", + "Advanced": "Avançat", + "Quality:": "Qualitat:", + "Compression level:": "Nivell de compressió:", + "Repeater ID:": "ID del repetidor:", + "WebSocket": "WebSocket", + "Encrypt": "Xifrar", + "Host:": "Amfitrió:", + "Port:": "Port:", + "Path:": "Camí:", + "Automatic Reconnect": "Reconnexió automàtica", + "Reconnect Delay (ms):": "Retard de tornada a connectar (ms):", + "Show Dot when No Cursor": "Mostra el punt quan no hi ha cursor", + "Logging:": "Registre:", + "Version:": "Versió:", + "Disconnect": "Desconnectar", + "Connect": "Connexió", + "Username:": "Nom d'usuari:", + "Password:": "Contrasenya:", + "Send Credentials": "Envia credencials", + "Cancel": "Cancel · lar", + "Keys": "Claus", + "Game Cursor Mode": "Mode de cursor de joc", + "Press Esc Key to Exit Pointer Lock Mode": "Premeu la tecla Esc per sortir del mode de bloqueig del punter", + "Game Mode paused, click on screen to resume Game Mode.": "Mode de joc en pausa, feu clic a la pantalla per reprendre el mode de joc", + "Clipboard Up": "Porta-retalls amunt", + "CLipboard Down": "Porta-retalls avall", + "Clipboard Seamless": "Porta-retalls sense costures", + "Prefer Local Cursor": "Preferir el cursor local", + "Translate keyboard shortcuts": "Tradueix les dreceres del teclat", + "Enable WebRTC UDP Transit": "Activa WebRTC UDP Transit", + "Enable WebP Compression": "Activa la compressió WebP", + "Enable Performance Stats": "Activa les estadístiques de rendiment", + "Enable Pointer Lock": "Activa el bloqueig del punter", + "IME Input Mode": "Mode d'entrada IME", + "Show Virtual Keyboard Control": "Mostra el control del teclat virtual", + "Toggle Control Panel via Keystrokes": "Canvia el tauler de control mitjançant les pulsacions de tecles", + "Render Native Resolution": "Representa la resolució nativa", + "Keyboard Shortcuts": "Dreceres de teclat", + "Enable KasmVNC Keyboard Shortcuts": "Activa les dreceres de teclat de KasmVNC", + "1 - Toggle Control Panel": "1 - Canvia el tauler de control", + "2 - Toggle Game Pointer Mode": "2 - Canvia el mode de punter de joc", + "3 - Toggle Pointer Lock": "3 - Commuta el bloqueig del punter", + "Stream Quality": "Qualitat del flux", + "Preset Modes:": "Modes preestablerts:", + "Static": "Estàtic", + "Low": "Baix", + "Medium": "mitjà", + "High": "Alt", + "Extreme": "Extrem", + "Lossless": "Sense pèrdues", + "Custom": "Personalitzat", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Dinàmica automàtica", + "Off": "Desactivat", + "On": "Activat", + "Dynamic Quality Min:": "Qualitat dinàmica mínima:", + "Dynamic Quality Max:": "Qualitat dinàmica màxima:", + "Treat Lossless:": "Traiteu sense pèrdues:", + "Frame Rate:": "Velocitat de fotogrames:", + "Video JPEG Quality:": "Qualitat del vídeo JPEG:", + "Video WEBP Quality:": "Qualitat del WEBP del vídeo:", + "Video Area:": "Àrea de vídeo:", + "Video Time:": "Hora del vídeo:", + "Video Out Time:": "Hora de sortida del vídeo:", + "Video Mode Width:": "Amplada del mode de vídeo:", + "Video Mode Height:": "Alçada del mode de vídeo:", + "Documentation": "Documentació", + "Drag Viewport": "Arrossegar la finestra gràfica", + "KasmVNC encountered an error:": "KasmVNC ha trobat un error:" +} \ No newline at end of file diff --git a/app/locale/ca_IT.json b/app/locale/ca_IT.json new file mode 100644 index 0000000..4d65f9c --- /dev/null +++ b/app/locale/ca_IT.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Connectant...", + "Disconnecting...": "Desconnectant...", + "Reconnecting...": "Reconnectant...", + "Internal error": "Error intern", + "Must set host": "Cal configurar l'amfitrió", + "Connected (encrypted) to ": "Connectat (xifrat) a", + "Connected (unencrypted) to ": "Connectat (sense xifrar) a", + "Something went wrong, connection is closed": "Alguna cosa ha anat malament, la connexió està tancada", + "Failed to connect to server": "Ha fallat la connexió amb el servidor", + "Disconnected": "Desconnectat", + "New connection has been rejected with reason: ": "S'ha rebutjat una connexió nova per un motiu:", + "New connection has been rejected": "S'ha rebutjat una connexió nova", + "Credentials are required": "Les credencials són necessàries", + "Hide/Show the control bar": "Oculta/Mostra la barra de control", + "Drag": "Arrossegar", + "Move/Drag Viewport": "Mou/Arrossegueu la finestra gràfica", + "Keyboard": "Teclat", + "Show Keyboard": "Mostra el teclat", + "Extra keys": "Claus addicionals", + "Show Extra Keys": "Mostra les claus addicionals", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Canvia Ctrl", + "Alt": "Alt", + "Toggle Alt": "Canvia Alt", + "Toggle Windows": "Canvia Windows", + "Windows": "Windows", + "Send Tab": "Envia la pestanya", + "Tab": "pestanya", + "Esc": "Esc", + "Send Escape": "Envia escapar", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Envia Ctrl-Alt-Supr", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Poder", + "Shutdown": "Tancar", + "Reboot": "Reiniciar", + "Reset": "Restablir", + "Clipboard": "Porta-retalls", + "Clear": "Netejar", + "Fullscreen": "Pantalla completa", + "Settings": "Configuració", + "Shared Mode": "Mode compartit", + "View Only": "Només vista", + "Clip to Window": "Clip a la finestra", + "Scaling Mode:": "Mode d'escala:", + "None": "Cap", + "Local Scaling": "Escala local", + "Remote Resizing": "Redimensionament remot", + "Advanced": "Avançat", + "Quality:": "Qualitat:", + "Compression level:": "Nivell de compressió:", + "Repeater ID:": "ID del repetidor:", + "WebSocket": "WebSocket", + "Encrypt": "Xifrar", + "Host:": "Amfitrió:", + "Port:": "Port:", + "Path:": "Camí:", + "Automatic Reconnect": "Reconnexió automàtica", + "Reconnect Delay (ms):": "Retard de tornada a connectar (ms):", + "Show Dot when No Cursor": "Mostra el punt quan no hi ha cursor", + "Logging:": "Registre:", + "Version:": "Versió:", + "Disconnect": "Desconnectar", + "Connect": "Connexió", + "Username:": "Nom d'usuari:", + "Password:": "Contrasenya:", + "Send Credentials": "Envia credencials", + "Cancel": "Cancel · lar", + "Keys": "Claus", + "Game Cursor Mode": "Mode de cursor de joc", + "Press Esc Key to Exit Pointer Lock Mode": "Premeu la tecla Esc per sortir del mode de bloqueig del punter", + "Game Mode paused, click on screen to resume Game Mode.": "Mode de joc en pausa, feu clic a la pantalla per reprendre el mode de joc", + "Clipboard Up": "Porta-retalls amunt", + "CLipboard Down": "Porta-retalls avall", + "Clipboard Seamless": "Porta-retalls sense costures", + "Prefer Local Cursor": "Preferir el cursor local", + "Translate keyboard shortcuts": "Tradueix les dreceres del teclat", + "Enable WebRTC UDP Transit": "Activa WebRTC UDP Transit", + "Enable WebP Compression": "Activa la compressió WebP", + "Enable Performance Stats": "Activa les estadístiques de rendiment", + "Enable Pointer Lock": "Activa el bloqueig del punter", + "IME Input Mode": "Mode d'entrada IME", + "Show Virtual Keyboard Control": "Mostra el control del teclat virtual", + "Toggle Control Panel via Keystrokes": "Canvia el tauler de control mitjançant les pulsacions de tecles", + "Render Native Resolution": "Representa la resolució nativa", + "Keyboard Shortcuts": "Dreceres de teclat", + "Enable KasmVNC Keyboard Shortcuts": "Activa les dreceres de teclat de KasmVNC", + "1 - Toggle Control Panel": "1 - Canvia el tauler de control", + "2 - Toggle Game Pointer Mode": "2 - Canvia el mode de punter de joc", + "3 - Toggle Pointer Lock": "3 - Commuta el bloqueig del punter", + "Stream Quality": "Qualitat del flux", + "Preset Modes:": "Modes preestablerts:", + "Static": "Estàtic", + "Low": "Baix", + "Medium": "mitjà", + "High": "Alt", + "Extreme": "Extrem", + "Lossless": "Sense pèrdues", + "Custom": "Personalitzat", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Dinàmica automàtica", + "Off": "Desactivat", + "On": "Activat", + "Dynamic Quality Min:": "Qualitat dinàmica mínima:", + "Dynamic Quality Max:": "Qualitat dinàmica màxima:", + "Treat Lossless:": "Traiteu sense pèrdues:", + "Frame Rate:": "Velocitat de fotogrames:", + "Video JPEG Quality:": "Qualitat del vídeo JPEG:", + "Video WEBP Quality:": "Qualitat del WEBP del vídeo:", + "Video Area:": "Àrea de vídeo:", + "Video Time:": "Hora del vídeo:", + "Video Out Time:": "Hora de sortida del vídeo:", + "Video Mode Width:": "Amplada del mode de vídeo:", + "Video Mode Height:": "Alçada del mode de vídeo:", + "Documentation": "Documentació", + "Drag Viewport": "Arrossegar la finestra gràfica", + "KasmVNC encountered an error:": "KasmVNC ha trobat un error:" +} \ No newline at end of file diff --git a/app/locale/cs.json b/app/locale/cs.json new file mode 100644 index 0000000..88df58e --- /dev/null +++ b/app/locale/cs.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Připojení...", + "Disconnecting...": "Odpojení...", + "Reconnecting...": "Obnova připojení...", + "Internal error": "Vnitřní chyba", + "Must set host": "Hostitel musí být nastavení", + "Connected (encrypted) to ": "Připojení (šifrované) k ", + "Connected (unencrypted) to ": "Připojení (nešifrované) k ", + "Something went wrong, connection is closed": "Něco se pokazilo, odpojeno", + "Failed to connect to server": "Chyba připojení k serveru", + "Disconnected": "Odpojeno", + "New connection has been rejected with reason: ": "Nové připojení bylo odmítnuto s odůvodněním: ", + "New connection has been rejected": "Nové připojení bylo odmítnuto", + "Password is required": "Je vyžadováno heslo", + "Hide/Show the control bar": "Skrýt/zobrazit ovládací panel", + "Move/Drag Viewport": "Přesunout/přetáhnout výřez", + "viewport drag": "přesun výřezu", + "Active Mouse Button": "Aktivní tlačítka myši", + "No mousebutton": "Žádné", + "Left mousebutton": "Levé tlačítko myši", + "Middle mousebutton": "Prostřední tlačítko myši", + "Right mousebutton": "Pravé tlačítko myši", + "Keyboard": "Klávesnice", + "Show Keyboard": "Zobrazit klávesnici", + "Extra keys": "Extra klávesy", + "Show Extra Keys": "Zobrazit extra klávesy", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Přepnout Ctrl", + "Alt": "Alt", + "Toggle Alt": "Přepnout Alt", + "Send Tab": "Odeslat tabulátor", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Odeslat Esc", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Poslat Ctrl-Alt-Del", + "Shutdown/Reboot": "Vypnutí/Restart", + "Shutdown/Reboot...": "Vypnutí/Restart...", + "Power": "Napájení", + "Shutdown": "Vypnout", + "Reboot": "Restart", + "Reset": "Reset", + "Clipboard": "Schránka", + "Clear": "Vymazat", + "Fullscreen": "Celá obrazovka", + "Settings": "Nastavení", + "Shared Mode": "Sdílený režim", + "View Only": "Pouze prohlížení", + "Clip to Window": "Přizpůsobit oknu", + "Scaling Mode:": "Přizpůsobení velikosti", + "None": "Žádné", + "Local Scaling": "Místní", + "Remote Resizing": "Vzdálené", + "Advanced": "Pokročilé", + "Repeater ID:": "ID opakovače", + "WebSocket": "WebSocket", + "Encrypt": "Šifrování:", + "Host:": "Hostitel:", + "Port:": "Port:", + "Path:": "Cesta", + "Automatic Reconnect": "Automatická obnova připojení", + "Reconnect Delay (ms):": "Zpoždění připojení (ms)", + "Show Dot when No Cursor": "Tečka místo chybějícího kurzoru myši", + "Logging:": "Logování:", + "Disconnect": "Odpojit", + "Connect": "Připojit", + "Password:": "Heslo", + "Send Password": "Odeslat heslo", + "Cancel": "Zrušit", + "Credentials are required": "Jsou vyžadovány přihlašovací údaje", + "Drag": "Táhnout", + "Toggle Windows": "Přepnout Windows", + "Windows": "Okna", + "Quality:": "Kvalitní:", + "Compression level:": "Úroveň komprese:", + "Version:": "Verze:", + "Username:": "Uživatelské jméno:", + "Send Credentials": "Odeslat přihlašovací údaje", + "Keys": "klíče", + "Game Cursor Mode": "Režim herního kurzoru", + "Press Esc Key to Exit Pointer Lock Mode": "Stisknutím klávesy Esc ukončíte režim uzamčení ukazatele", + "Game Mode paused, click on screen to resume Game Mode.": "Herní režim pozastaven, kliknutím na obrazovku obnovíte herní režim.", + "Clipboard Up": "Schránka nahoru", + "CLipboard Down": "Schránka dolů", + "Clipboard Seamless": "Bezproblémová schránka", + "Prefer Local Cursor": "Upřednostňovat místní kurzor", + "Translate keyboard shortcuts": "Přeložit klávesové zkratky", + "Enable WebRTC UDP Transit": "Povolit WebRTC UDP Transit", + "Enable WebP Compression": "Povolit kompresi WebP", + "Enable Performance Stats": "Povolit statistiky výkonu", + "Enable Pointer Lock": "Povolit zámek ukazatele", + "IME Input Mode": "Režim vstupu IME", + "Show Virtual Keyboard Control": "Zobrazit ovládání virtuální klávesnice", + "Toggle Control Panel via Keystrokes": "Přepnout ovládací panel pomocí kláves", + "Render Native Resolution": "Vykreslit nativní rozlišení", + "Keyboard Shortcuts": "Klávesové zkratky", + "Enable KasmVNC Keyboard Shortcuts": "Povolit klávesové zkratky KasmVNC", + "1 - Toggle Control Panel": "1 - Přepnout ovládací panel", + "2 - Toggle Game Pointer Mode": "2 - Přepnout režim ukazatele hry", + "3 - Toggle Pointer Lock": "3 - Přepnout zámek ukazatele", + "Stream Quality": "Kvalita streamu", + "Preset Modes:": "Přednastavené režimy:", + "Static": "Statický", + "Low": "Nízký", + "Medium": "Střední", + "High": "Vysoký", + "Extreme": "Extrémní", + "Lossless": "bezeztrátový", + "Custom": "Zvyk", + "Anti-Aliasing:": "Anti aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Vypnuto", + "On": "Na", + "Dynamic Quality Min:": "Minimální dynamická kvalita:", + "Dynamic Quality Max:": "Dynamická kvalita Max:", + "Treat Lossless:": "Zacházet bez ztráty:", + "Frame Rate:": "Snímková frekvence:", + "Video JPEG Quality:": "Kvalita videa JPEG:", + "Video WEBP Quality:": "Video WEBP kvalita:", + "Video Area:": "Oblast videa:", + "Video Time:": "Čas videa:", + "Video Out Time:": "Doba výstupu videa:", + "Video Mode Width:": "Šířka režimu videa:", + "Video Mode Height:": "Výška režimu videa:", + "Documentation": "Dokumentace", + "Drag Viewport": "Přetáhnout výřez", + "KasmVNC encountered an error:": "KasmVNC narazil na chybu:" +} \ No newline at end of file diff --git a/app/locale/cs_CZ.json b/app/locale/cs_CZ.json new file mode 100644 index 0000000..88df58e --- /dev/null +++ b/app/locale/cs_CZ.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Připojení...", + "Disconnecting...": "Odpojení...", + "Reconnecting...": "Obnova připojení...", + "Internal error": "Vnitřní chyba", + "Must set host": "Hostitel musí být nastavení", + "Connected (encrypted) to ": "Připojení (šifrované) k ", + "Connected (unencrypted) to ": "Připojení (nešifrované) k ", + "Something went wrong, connection is closed": "Něco se pokazilo, odpojeno", + "Failed to connect to server": "Chyba připojení k serveru", + "Disconnected": "Odpojeno", + "New connection has been rejected with reason: ": "Nové připojení bylo odmítnuto s odůvodněním: ", + "New connection has been rejected": "Nové připojení bylo odmítnuto", + "Password is required": "Je vyžadováno heslo", + "Hide/Show the control bar": "Skrýt/zobrazit ovládací panel", + "Move/Drag Viewport": "Přesunout/přetáhnout výřez", + "viewport drag": "přesun výřezu", + "Active Mouse Button": "Aktivní tlačítka myši", + "No mousebutton": "Žádné", + "Left mousebutton": "Levé tlačítko myši", + "Middle mousebutton": "Prostřední tlačítko myši", + "Right mousebutton": "Pravé tlačítko myši", + "Keyboard": "Klávesnice", + "Show Keyboard": "Zobrazit klávesnici", + "Extra keys": "Extra klávesy", + "Show Extra Keys": "Zobrazit extra klávesy", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Přepnout Ctrl", + "Alt": "Alt", + "Toggle Alt": "Přepnout Alt", + "Send Tab": "Odeslat tabulátor", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Odeslat Esc", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Poslat Ctrl-Alt-Del", + "Shutdown/Reboot": "Vypnutí/Restart", + "Shutdown/Reboot...": "Vypnutí/Restart...", + "Power": "Napájení", + "Shutdown": "Vypnout", + "Reboot": "Restart", + "Reset": "Reset", + "Clipboard": "Schránka", + "Clear": "Vymazat", + "Fullscreen": "Celá obrazovka", + "Settings": "Nastavení", + "Shared Mode": "Sdílený režim", + "View Only": "Pouze prohlížení", + "Clip to Window": "Přizpůsobit oknu", + "Scaling Mode:": "Přizpůsobení velikosti", + "None": "Žádné", + "Local Scaling": "Místní", + "Remote Resizing": "Vzdálené", + "Advanced": "Pokročilé", + "Repeater ID:": "ID opakovače", + "WebSocket": "WebSocket", + "Encrypt": "Šifrování:", + "Host:": "Hostitel:", + "Port:": "Port:", + "Path:": "Cesta", + "Automatic Reconnect": "Automatická obnova připojení", + "Reconnect Delay (ms):": "Zpoždění připojení (ms)", + "Show Dot when No Cursor": "Tečka místo chybějícího kurzoru myši", + "Logging:": "Logování:", + "Disconnect": "Odpojit", + "Connect": "Připojit", + "Password:": "Heslo", + "Send Password": "Odeslat heslo", + "Cancel": "Zrušit", + "Credentials are required": "Jsou vyžadovány přihlašovací údaje", + "Drag": "Táhnout", + "Toggle Windows": "Přepnout Windows", + "Windows": "Okna", + "Quality:": "Kvalitní:", + "Compression level:": "Úroveň komprese:", + "Version:": "Verze:", + "Username:": "Uživatelské jméno:", + "Send Credentials": "Odeslat přihlašovací údaje", + "Keys": "klíče", + "Game Cursor Mode": "Režim herního kurzoru", + "Press Esc Key to Exit Pointer Lock Mode": "Stisknutím klávesy Esc ukončíte režim uzamčení ukazatele", + "Game Mode paused, click on screen to resume Game Mode.": "Herní režim pozastaven, kliknutím na obrazovku obnovíte herní režim.", + "Clipboard Up": "Schránka nahoru", + "CLipboard Down": "Schránka dolů", + "Clipboard Seamless": "Bezproblémová schránka", + "Prefer Local Cursor": "Upřednostňovat místní kurzor", + "Translate keyboard shortcuts": "Přeložit klávesové zkratky", + "Enable WebRTC UDP Transit": "Povolit WebRTC UDP Transit", + "Enable WebP Compression": "Povolit kompresi WebP", + "Enable Performance Stats": "Povolit statistiky výkonu", + "Enable Pointer Lock": "Povolit zámek ukazatele", + "IME Input Mode": "Režim vstupu IME", + "Show Virtual Keyboard Control": "Zobrazit ovládání virtuální klávesnice", + "Toggle Control Panel via Keystrokes": "Přepnout ovládací panel pomocí kláves", + "Render Native Resolution": "Vykreslit nativní rozlišení", + "Keyboard Shortcuts": "Klávesové zkratky", + "Enable KasmVNC Keyboard Shortcuts": "Povolit klávesové zkratky KasmVNC", + "1 - Toggle Control Panel": "1 - Přepnout ovládací panel", + "2 - Toggle Game Pointer Mode": "2 - Přepnout režim ukazatele hry", + "3 - Toggle Pointer Lock": "3 - Přepnout zámek ukazatele", + "Stream Quality": "Kvalita streamu", + "Preset Modes:": "Přednastavené režimy:", + "Static": "Statický", + "Low": "Nízký", + "Medium": "Střední", + "High": "Vysoký", + "Extreme": "Extrémní", + "Lossless": "bezeztrátový", + "Custom": "Zvyk", + "Anti-Aliasing:": "Anti aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Vypnuto", + "On": "Na", + "Dynamic Quality Min:": "Minimální dynamická kvalita:", + "Dynamic Quality Max:": "Dynamická kvalita Max:", + "Treat Lossless:": "Zacházet bez ztráty:", + "Frame Rate:": "Snímková frekvence:", + "Video JPEG Quality:": "Kvalita videa JPEG:", + "Video WEBP Quality:": "Video WEBP kvalita:", + "Video Area:": "Oblast videa:", + "Video Time:": "Čas videa:", + "Video Out Time:": "Doba výstupu videa:", + "Video Mode Width:": "Šířka režimu videa:", + "Video Mode Height:": "Výška režimu videa:", + "Documentation": "Dokumentace", + "Drag Viewport": "Přetáhnout výřez", + "KasmVNC encountered an error:": "KasmVNC narazil na chybu:" +} \ No newline at end of file diff --git a/app/locale/cy.json b/app/locale/cy.json new file mode 100644 index 0000000..ff2f8aa --- /dev/null +++ b/app/locale/cy.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Cysylltu...", + "Disconnecting...": "Datgysylltu...", + "Reconnecting...": "Ailgysylltu...", + "Internal error": "Gwall mewnol", + "Must set host": "Rhaid gosod gwesteiwr", + "Connected (encrypted) to ": "Cysylltiedig (amgryptio) i ", + "Connected (unencrypted) to ": " Wedi cysylltu (heb ei amgryptio) i ", + "Something went wrong, connection is closed": "Aeth rhywbeth o'i le, mae'r cysylltiad ar gau", + "Failed to connect to server": "Methu cysylltu i'r gweinydd", + "Disconnected": "Datgysylltu", + "New connection has been rejected with reason: ": "Cysylltiad newydd wedi'i wrthod gyda rheswm:", + "New connection has been rejected": "Cysylltiad newydd wedi'i wrthod", + "Credentials are required": "Mae angen tystlythyrau", + "Hide/Show the control bar": "Cuddio/Dangos y bar rheoli", + "Drag": "Llusgo", + "Move/Drag Viewport": "Symud/Llusgwch Viewport", + "Keyboard": "Bellfwrdd", + "Show Keyboard": "Dangos bysellfwrdd", + "Extra keys": "Allweddi ychwanegol", + "Show Extra Keys": "Dangos Allweddi Ychwanegol", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Toggle Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Windows", + "Send Tab": "Anfon Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Anfon Dianc", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Anfon Ctrl-Alt-Del", + "Shutdown/Reboot": "Cau i Lawr/Ailgychwyn", + "Shutdown/Reboot...": "Cau i Lawr/Ailgychwyn...", + "Power": "Pŵer", + "Shutdown": "Cau i lawr", + "Reboot": "Ailgychwyn", + "Reset": "Ail gychwyn", + "Clipboard": "Clipfwrdd", + "Clear": "Clir", + "Fullscreen": "Sgrin llawn", + "Settings": "Gosodiadau", + "Shared Mode": "Modd a Rennir", + "View Only": "Gweld yn Unig", + "Clip to Window": "Clip i Ffenestr", + "Scaling Mode:": "Modd Graddio:", + "None": "Dim", + "Local Scaling": "Graddio lleol", + "Remote Resizing": "Newid maint o bell", + "Advanced": "Uwch", + "Quality:": "Ansawdd:", + "Compression level:": "Lefel cywasgu:", + "Repeater ID:": "ID ailadroddydd:", + "WebSocket": "WebSoced", + "Encrypt": "Amgryptio", + "Host:": "Gwesteiwr:", + "Port:": "Porthladd:", + "Path:": "Llwybr:", + "Automatic Reconnect": "Ailgysylltu Awtomatig", + "Reconnect Delay (ms):": "Ailgysylltu Oedi (ms):", + "Show Dot when No Cursor": "Dangos Dot pan nad oes Cyrchwr", + "Logging:": "Logio:", + "Version:": "Fersiwn:", + "Disconnect": "Datgysylltu", + "Connect": "Cysylltu", + "Username:": "Enw defnyddiwr:", + "Password:": "Cyfrinair:", + "Send Credentials": "Anfon Manylion", + "Cancel": "Canslo", + "Keys": "Allweddi", + "Game Cursor Mode": "Modd Cyrchwr Gêm", + "Press Esc Key to Exit Pointer Lock Mode": "Pwyswch Allwedd Esc i Gadael Modd Cloi Pwyntydd", + "Game Mode paused, click on screen to resume Game Mode.": "Modd Gêm seibio, cliciwch ar y sgrin i ailddechrau Modd Gêm.", + "Clipboard Up": "Clipfwrdd i Fyny", + "CLipboard Down": "Clipfwrdd i lawr", + "Clipboard Seamless": "Clipfwrdd Di-dor", + "Prefer Local Cursor": "Gwell cyrchwr lleol", + "Translate keyboard shortcuts": "Cyfieithu llwybrau byr bysellfwrdd", + "Enable WebRTC UDP Transit": "Galluogi WebRTC UDP Transit", + "Enable WebP Compression": "Galluogi Cywasgiad WebP", + "Enable Performance Stats": "Galluogi Ystadegau Perfformiad", + "Enable Pointer Lock": "Galluogi Lock Pointer", + "IME Input Mode": "Modd Mewnbwn IME", + "Show Virtual Keyboard Control": "Dangos Rheolaeth Bysellfwrdd Rhithwir", + "Toggle Control Panel via Keystrokes": "Toggle Control Panel trwy Keystrokes", + "Render Native Resolution": "Rendro Datrysiad Brodorol", + "Keyboard Shortcuts": "Llwybrau byr bysellfwrdd", + "Enable KasmVNC Keyboard Shortcuts": "Galluogi Llwybrau Byr Bysellfwrdd KasmVNC", + "1 - Toggle Control Panel": "1 - Toglo Panel Rheoli", + "2 - Toggle Game Pointer Mode": "2 - Toglo Modd Pwyntiwr Gêm", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Ansawdd llif", + "Preset Modes:": "Moddau Rhagosodedig:", + "Static": "Statig", + "Low": "Isel", + "Medium": "Canolig", + "High": "Uchel", + "Extreme": "Eithafol", + "Lossless": "di-golled", + "Custom": "Cwsmer", + "Anti-Aliasing:": "Gwrth-Aliasing:", + "Auto Dynamic": "Deinamig Awtomatig", + "Off": "i ffwrdd", + "On": "Ar", + "Dynamic Quality Min:": "Isafswm Ansawdd Dynamig:", + "Dynamic Quality Max:": "Uchafswm Ansawdd Dynamig:", + "Treat Lossless:": "Trin yn Ddi-golled:", + "Frame Rate:": "Cyfradd Ffram:", + "Video JPEG Quality:": "Ansawdd Fideo JPEG:", + "Video WEBP Quality:": "Ansawdd Fideo WEBP:", + "Video Area:": "Maes Fideo:", + "Video Time:": "Amser Fideo:", + "Video Out Time:": "Amser Allan Fideo:", + "Video Mode Width:": "Lled Modd Fideo:", + "Video Mode Height:": "Uchder Modd Fideo:", + "Documentation": "Dogfennaeth", + "Drag Viewport": "Llusgwch Viewport", + "KasmVNC encountered an error:": "Mae KasmVNC wedi dod ar draws gwall:" +} \ No newline at end of file diff --git a/app/locale/cy_GB.json b/app/locale/cy_GB.json new file mode 100644 index 0000000..ff2f8aa --- /dev/null +++ b/app/locale/cy_GB.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Cysylltu...", + "Disconnecting...": "Datgysylltu...", + "Reconnecting...": "Ailgysylltu...", + "Internal error": "Gwall mewnol", + "Must set host": "Rhaid gosod gwesteiwr", + "Connected (encrypted) to ": "Cysylltiedig (amgryptio) i ", + "Connected (unencrypted) to ": " Wedi cysylltu (heb ei amgryptio) i ", + "Something went wrong, connection is closed": "Aeth rhywbeth o'i le, mae'r cysylltiad ar gau", + "Failed to connect to server": "Methu cysylltu i'r gweinydd", + "Disconnected": "Datgysylltu", + "New connection has been rejected with reason: ": "Cysylltiad newydd wedi'i wrthod gyda rheswm:", + "New connection has been rejected": "Cysylltiad newydd wedi'i wrthod", + "Credentials are required": "Mae angen tystlythyrau", + "Hide/Show the control bar": "Cuddio/Dangos y bar rheoli", + "Drag": "Llusgo", + "Move/Drag Viewport": "Symud/Llusgwch Viewport", + "Keyboard": "Bellfwrdd", + "Show Keyboard": "Dangos bysellfwrdd", + "Extra keys": "Allweddi ychwanegol", + "Show Extra Keys": "Dangos Allweddi Ychwanegol", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Toggle Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Windows", + "Send Tab": "Anfon Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Anfon Dianc", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Anfon Ctrl-Alt-Del", + "Shutdown/Reboot": "Cau i Lawr/Ailgychwyn", + "Shutdown/Reboot...": "Cau i Lawr/Ailgychwyn...", + "Power": "Pŵer", + "Shutdown": "Cau i lawr", + "Reboot": "Ailgychwyn", + "Reset": "Ail gychwyn", + "Clipboard": "Clipfwrdd", + "Clear": "Clir", + "Fullscreen": "Sgrin llawn", + "Settings": "Gosodiadau", + "Shared Mode": "Modd a Rennir", + "View Only": "Gweld yn Unig", + "Clip to Window": "Clip i Ffenestr", + "Scaling Mode:": "Modd Graddio:", + "None": "Dim", + "Local Scaling": "Graddio lleol", + "Remote Resizing": "Newid maint o bell", + "Advanced": "Uwch", + "Quality:": "Ansawdd:", + "Compression level:": "Lefel cywasgu:", + "Repeater ID:": "ID ailadroddydd:", + "WebSocket": "WebSoced", + "Encrypt": "Amgryptio", + "Host:": "Gwesteiwr:", + "Port:": "Porthladd:", + "Path:": "Llwybr:", + "Automatic Reconnect": "Ailgysylltu Awtomatig", + "Reconnect Delay (ms):": "Ailgysylltu Oedi (ms):", + "Show Dot when No Cursor": "Dangos Dot pan nad oes Cyrchwr", + "Logging:": "Logio:", + "Version:": "Fersiwn:", + "Disconnect": "Datgysylltu", + "Connect": "Cysylltu", + "Username:": "Enw defnyddiwr:", + "Password:": "Cyfrinair:", + "Send Credentials": "Anfon Manylion", + "Cancel": "Canslo", + "Keys": "Allweddi", + "Game Cursor Mode": "Modd Cyrchwr Gêm", + "Press Esc Key to Exit Pointer Lock Mode": "Pwyswch Allwedd Esc i Gadael Modd Cloi Pwyntydd", + "Game Mode paused, click on screen to resume Game Mode.": "Modd Gêm seibio, cliciwch ar y sgrin i ailddechrau Modd Gêm.", + "Clipboard Up": "Clipfwrdd i Fyny", + "CLipboard Down": "Clipfwrdd i lawr", + "Clipboard Seamless": "Clipfwrdd Di-dor", + "Prefer Local Cursor": "Gwell cyrchwr lleol", + "Translate keyboard shortcuts": "Cyfieithu llwybrau byr bysellfwrdd", + "Enable WebRTC UDP Transit": "Galluogi WebRTC UDP Transit", + "Enable WebP Compression": "Galluogi Cywasgiad WebP", + "Enable Performance Stats": "Galluogi Ystadegau Perfformiad", + "Enable Pointer Lock": "Galluogi Lock Pointer", + "IME Input Mode": "Modd Mewnbwn IME", + "Show Virtual Keyboard Control": "Dangos Rheolaeth Bysellfwrdd Rhithwir", + "Toggle Control Panel via Keystrokes": "Toggle Control Panel trwy Keystrokes", + "Render Native Resolution": "Rendro Datrysiad Brodorol", + "Keyboard Shortcuts": "Llwybrau byr bysellfwrdd", + "Enable KasmVNC Keyboard Shortcuts": "Galluogi Llwybrau Byr Bysellfwrdd KasmVNC", + "1 - Toggle Control Panel": "1 - Toglo Panel Rheoli", + "2 - Toggle Game Pointer Mode": "2 - Toglo Modd Pwyntiwr Gêm", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Ansawdd llif", + "Preset Modes:": "Moddau Rhagosodedig:", + "Static": "Statig", + "Low": "Isel", + "Medium": "Canolig", + "High": "Uchel", + "Extreme": "Eithafol", + "Lossless": "di-golled", + "Custom": "Cwsmer", + "Anti-Aliasing:": "Gwrth-Aliasing:", + "Auto Dynamic": "Deinamig Awtomatig", + "Off": "i ffwrdd", + "On": "Ar", + "Dynamic Quality Min:": "Isafswm Ansawdd Dynamig:", + "Dynamic Quality Max:": "Uchafswm Ansawdd Dynamig:", + "Treat Lossless:": "Trin yn Ddi-golled:", + "Frame Rate:": "Cyfradd Ffram:", + "Video JPEG Quality:": "Ansawdd Fideo JPEG:", + "Video WEBP Quality:": "Ansawdd Fideo WEBP:", + "Video Area:": "Maes Fideo:", + "Video Time:": "Amser Fideo:", + "Video Out Time:": "Amser Allan Fideo:", + "Video Mode Width:": "Lled Modd Fideo:", + "Video Mode Height:": "Uchder Modd Fideo:", + "Documentation": "Dogfennaeth", + "Drag Viewport": "Llusgwch Viewport", + "KasmVNC encountered an error:": "Mae KasmVNC wedi dod ar draws gwall:" +} \ No newline at end of file diff --git a/app/locale/da.json b/app/locale/da.json new file mode 100644 index 0000000..cb89cb5 --- /dev/null +++ b/app/locale/da.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Tilslutning...", + "Disconnecting...": "Afbryder forbindelsen...", + "Reconnecting...": "Opretter forbindelse igen...", + "Internal error": "Intern fejl", + "Must set host": "Skal være vært", + "Connected (encrypted) to ": "Forbundet (krypteret) til", + "Connected (unencrypted) to ": "Forbundet (ukrypteret) til ", + "Something went wrong, connection is closed": "Noget gik galt, forbindelsen er lukket", + "Failed to connect to server": "Det lykkedes ikke at oprette forbindelse til serveren", + "Disconnected": "Afbrudt", + "New connection has been rejected with reason: ": "Ny forbindelse er blevet afvist med grund: ", + "New connection has been rejected": "Ny forbindelse er blevet afvist", + "Credentials are required": "Legitimationsoplysninger er påkrævet", + "Hide/Show the control bar": "Skjul/vis kontrollinjen", + "Drag": "Træk", + "Move/Drag Viewport": "Flyt/træk visningsport", + "Keyboard": "Tastatur", + "Show Keyboard": "Vis tastatur", + "Extra keys": "Ekstra nøgler", + "Show Extra Keys": "Vis ekstra nøgler", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Skift Ctrl", + "Alt": "Alt", + "Toggle Alt": "Skift alt", + "Toggle Windows": "Skift Windows", + "Windows": "Windows", + "Send Tab": "Send fane", + "Tab": "Fane", + "Esc": "Esc", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Send Ctrl-Alt-Del", + "Shutdown/Reboot": "Sluk/genstart", + "Shutdown/Reboot...": "Sluk/genstart...", + "Power": "Strøm", + "Shutdown": "Lukke ned", + "Reboot": "Genstart", + "Reset": "Nulstil", + "Clipboard": "Udklipsholder", + "Clear": "Klar", + "Fullscreen": "Fuld skærm", + "Settings": "Indstillinger", + "Shared Mode": "Delt tilstand", + "View Only": "Kun se", + "Clip to Window": "Klip til vindue", + "Scaling Mode:": "Skaleringstilstand:", + "None": "Ingen", + "Local Scaling": "Lokal skalering", + "Remote Resizing": "Remote resizing", + "Advanced": "Fremskreden", + "Quality:": "Kvalitet:", + "Compression level:": "Kompressionsniveau:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Krypter", + "Host:": "Vært:", + "Port:": "Havn:", + "Path:": "Sti:", + "Automatic Reconnect": "Automatisk genforbindelse", + "Reconnect Delay (ms):": "Genforbindelsesforsinkelse (ms):", + "Show Dot when No Cursor": "Vis prik, når ingen markør", + "Logging:": "Logger:", + "Version:": "Version:", + "Disconnect": "Koble fra", + "Connect": "Forbinde", + "Username:": "Brugernavn:", + "Password:": "Adgangskode:", + "Send Credentials": "Send legitimationsoplysninger", + "Cancel": "Afbestille", + "Keys": "Nøgler", + "Game Cursor Mode": "Spilmarkørtilstand", + "Press Esc Key to Exit Pointer Lock Mode": "Tryk på Esc-tasten for at afslutte markørlåsetilstand", + "Game Mode paused, click on screen to resume Game Mode.": "Spiltilstand sat på pause, klik på skærmen for at genoptage spiltilstand.", + "Clipboard Up": "Udklipsholder op", + "CLipboard Down": "Udklipsholder ned", + "Clipboard Seamless": "Udklipsholder sømløs", + "Prefer Local Cursor": "Foretrækker lokal markør", + "Translate keyboard shortcuts": "Oversæt tastaturgenveje", + "Enable WebRTC UDP Transit": "Aktiver WebRTC UDP Transit", + "Enable WebP Compression": "Aktiver WebP-komprimering", + "Enable Performance Stats": "Aktiver præstationsstatistikker", + "Enable Pointer Lock": "Aktiver markørlås", + "IME Input Mode": "IME Input Mode", + "Show Virtual Keyboard Control": "Vis Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "Skift kontrolpanel via tastetryk", + "Render Native Resolution": "Gengiver oprindelig opløsning", + "Keyboard Shortcuts": "Tastaturgenveje", + "Enable KasmVNC Keyboard Shortcuts": "Aktiver KasmVNC-tastaturgenveje", + "1 - Toggle Control Panel": "1 - Skift kontrolpanel", + "2 - Toggle Game Pointer Mode": "2 - Skift Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Streamkvalitet", + "Preset Modes:": "Forudindstillede tilstande:", + "Static": "Statisk", + "Low": "Lav", + "Medium": "Medium", + "High": "Høj", + "Extreme": "Ekstrem", + "Lossless": "tabsfri", + "Custom": "Brugerdefinerede", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Af", + "On": "På", + "Dynamic Quality Min:": "Dynamisk kvalitet min:", + "Dynamic Quality Max:": "Dynamisk kvalitet Max:", + "Treat Lossless:": "Behandl Lossless:", + "Frame Rate:": "Billedhastighed:", + "Video JPEG Quality:": "Video JPEG-kvalitet:", + "Video WEBP Quality:": "Video WEBP-kvalitet:", + "Video Area:": "Videoområde:", + "Video Time:": "Videotid:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Videotilstandsbredde:", + "Video Mode Height:": "Video Mode Højde:", + "Documentation": "Dokumentation", + "Drag Viewport": "Træk visningsport", + "KasmVNC encountered an error:": "KasmVNC stødte på en fejl:" +} \ No newline at end of file diff --git a/app/locale/da_DK.json b/app/locale/da_DK.json new file mode 100644 index 0000000..cb89cb5 --- /dev/null +++ b/app/locale/da_DK.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Tilslutning...", + "Disconnecting...": "Afbryder forbindelsen...", + "Reconnecting...": "Opretter forbindelse igen...", + "Internal error": "Intern fejl", + "Must set host": "Skal være vært", + "Connected (encrypted) to ": "Forbundet (krypteret) til", + "Connected (unencrypted) to ": "Forbundet (ukrypteret) til ", + "Something went wrong, connection is closed": "Noget gik galt, forbindelsen er lukket", + "Failed to connect to server": "Det lykkedes ikke at oprette forbindelse til serveren", + "Disconnected": "Afbrudt", + "New connection has been rejected with reason: ": "Ny forbindelse er blevet afvist med grund: ", + "New connection has been rejected": "Ny forbindelse er blevet afvist", + "Credentials are required": "Legitimationsoplysninger er påkrævet", + "Hide/Show the control bar": "Skjul/vis kontrollinjen", + "Drag": "Træk", + "Move/Drag Viewport": "Flyt/træk visningsport", + "Keyboard": "Tastatur", + "Show Keyboard": "Vis tastatur", + "Extra keys": "Ekstra nøgler", + "Show Extra Keys": "Vis ekstra nøgler", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Skift Ctrl", + "Alt": "Alt", + "Toggle Alt": "Skift alt", + "Toggle Windows": "Skift Windows", + "Windows": "Windows", + "Send Tab": "Send fane", + "Tab": "Fane", + "Esc": "Esc", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Send Ctrl-Alt-Del", + "Shutdown/Reboot": "Sluk/genstart", + "Shutdown/Reboot...": "Sluk/genstart...", + "Power": "Strøm", + "Shutdown": "Lukke ned", + "Reboot": "Genstart", + "Reset": "Nulstil", + "Clipboard": "Udklipsholder", + "Clear": "Klar", + "Fullscreen": "Fuld skærm", + "Settings": "Indstillinger", + "Shared Mode": "Delt tilstand", + "View Only": "Kun se", + "Clip to Window": "Klip til vindue", + "Scaling Mode:": "Skaleringstilstand:", + "None": "Ingen", + "Local Scaling": "Lokal skalering", + "Remote Resizing": "Remote resizing", + "Advanced": "Fremskreden", + "Quality:": "Kvalitet:", + "Compression level:": "Kompressionsniveau:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Krypter", + "Host:": "Vært:", + "Port:": "Havn:", + "Path:": "Sti:", + "Automatic Reconnect": "Automatisk genforbindelse", + "Reconnect Delay (ms):": "Genforbindelsesforsinkelse (ms):", + "Show Dot when No Cursor": "Vis prik, når ingen markør", + "Logging:": "Logger:", + "Version:": "Version:", + "Disconnect": "Koble fra", + "Connect": "Forbinde", + "Username:": "Brugernavn:", + "Password:": "Adgangskode:", + "Send Credentials": "Send legitimationsoplysninger", + "Cancel": "Afbestille", + "Keys": "Nøgler", + "Game Cursor Mode": "Spilmarkørtilstand", + "Press Esc Key to Exit Pointer Lock Mode": "Tryk på Esc-tasten for at afslutte markørlåsetilstand", + "Game Mode paused, click on screen to resume Game Mode.": "Spiltilstand sat på pause, klik på skærmen for at genoptage spiltilstand.", + "Clipboard Up": "Udklipsholder op", + "CLipboard Down": "Udklipsholder ned", + "Clipboard Seamless": "Udklipsholder sømløs", + "Prefer Local Cursor": "Foretrækker lokal markør", + "Translate keyboard shortcuts": "Oversæt tastaturgenveje", + "Enable WebRTC UDP Transit": "Aktiver WebRTC UDP Transit", + "Enable WebP Compression": "Aktiver WebP-komprimering", + "Enable Performance Stats": "Aktiver præstationsstatistikker", + "Enable Pointer Lock": "Aktiver markørlås", + "IME Input Mode": "IME Input Mode", + "Show Virtual Keyboard Control": "Vis Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "Skift kontrolpanel via tastetryk", + "Render Native Resolution": "Gengiver oprindelig opløsning", + "Keyboard Shortcuts": "Tastaturgenveje", + "Enable KasmVNC Keyboard Shortcuts": "Aktiver KasmVNC-tastaturgenveje", + "1 - Toggle Control Panel": "1 - Skift kontrolpanel", + "2 - Toggle Game Pointer Mode": "2 - Skift Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Streamkvalitet", + "Preset Modes:": "Forudindstillede tilstande:", + "Static": "Statisk", + "Low": "Lav", + "Medium": "Medium", + "High": "Høj", + "Extreme": "Ekstrem", + "Lossless": "tabsfri", + "Custom": "Brugerdefinerede", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Af", + "On": "På", + "Dynamic Quality Min:": "Dynamisk kvalitet min:", + "Dynamic Quality Max:": "Dynamisk kvalitet Max:", + "Treat Lossless:": "Behandl Lossless:", + "Frame Rate:": "Billedhastighed:", + "Video JPEG Quality:": "Video JPEG-kvalitet:", + "Video WEBP Quality:": "Video WEBP-kvalitet:", + "Video Area:": "Videoområde:", + "Video Time:": "Videotid:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Videotilstandsbredde:", + "Video Mode Height:": "Video Mode Højde:", + "Documentation": "Dokumentation", + "Drag Viewport": "Træk visningsport", + "KasmVNC encountered an error:": "KasmVNC stødte på en fejl:" +} \ No newline at end of file diff --git a/app/locale/de.json b/app/locale/de.json new file mode 100644 index 0000000..36f44ea --- /dev/null +++ b/app/locale/de.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Verbinden...", + "Disconnecting...": "Verbindung trennen...", + "Reconnecting...": "Verbindung wiederherstellen...", + "Internal error": "Interner Fehler", + "Must set host": "Richten Sie den Server ein", + "Connected (encrypted) to ": "Verbunden mit (verschlüsselt) ", + "Connected (unencrypted) to ": "Verbunden mit (unverschlüsselt) ", + "Something went wrong, connection is closed": "Etwas lief schief, Verbindung wurde getrennt", + "Disconnected": "Verbindung zum Server getrennt", + "New connection has been rejected with reason: ": "Verbindung wurde aus folgendem Grund abgelehnt: ", + "New connection has been rejected": "Verbindung wurde abgelehnt", + "Password is required": "Passwort ist erforderlich", + "Hide/Show the control bar": "Kontrollleiste verstecken/anzeigen", + "Move/Drag Viewport": "Ansichtsfenster verschieben/ziehen", + "viewport drag": "Ansichtsfenster ziehen", + "Active Mouse Button": "Aktive Maustaste", + "No mousebutton": "Keine Maustaste", + "Left mousebutton": "Linke Maustaste", + "Middle mousebutton": "Mittlere Maustaste", + "Right mousebutton": "Rechte Maustaste", + "Keyboard": "Tastatur", + "Show Keyboard": "Tastatur anzeigen", + "Extra keys": "Zusatztasten", + "Show Extra Keys": "Zusatztasten anzeigen", + "Ctrl": "Strg", + "Toggle Ctrl": "Strg umschalten", + "Alt": "Alt", + "Toggle Alt": "Alt umschalten", + "Send Tab": "Tab senden", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Escape senden", + "Ctrl+Alt+Del": "Strg+Alt+Entf", + "Send Ctrl-Alt-Del": "Strg+Alt+Entf senden", + "Shutdown/Reboot": "Herunterfahren/Neustarten", + "Shutdown/Reboot...": "Herunterfahren/Neustarten...", + "Power": "Energie", + "Shutdown": "Herunterfahren", + "Reboot": "Neustarten", + "Reset": "Zurücksetzen", + "Clipboard": "Zwischenablage", + "Clear": "Löschen", + "Fullscreen": "Vollbild", + "Settings": "Einstellungen", + "Shared Mode": "Geteilter Modus", + "View Only": "Nur betrachten", + "Clip to Window": "Auf Fenster begrenzen", + "Scaling Mode:": "Skalierungsmodus:", + "None": "Keiner", + "Local Scaling": "Lokales skalieren", + "Remote Resizing": "Serverseitiges skalieren", + "Advanced": "Erweitert", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Verschlüsselt", + "Host:": "Server:", + "Port:": "Port:", + "Path:": "Pfad:", + "Automatic Reconnect": "Automatisch wiederverbinden", + "Reconnect Delay (ms):": "Wiederverbindungsverzögerung (ms):", + "Logging:": "Protokollierung:", + "Disconnect": "Verbindung trennen", + "Connect": "Verbinden", + "Password:": "Passwort:", + "Cancel": "Abbrechen", + "Canvas not supported.": "Canvas nicht unterstützt.", + "Failed to connect to server": "Verbindung zum Server fehlgeschlagen", + "Credentials are required": "Anmeldeinformationen sind erforderlich", + "Drag": "Ziehen", + "Toggle Windows": "Fenster umschalten", + "Windows": "Fenster", + "Quality:": "Qualität:", + "Compression level:": "Komprimierungsstufe:", + "Show Dot when No Cursor": "Punkt anzeigen, wenn kein Cursor", + "Version:": "Ausführung:", + "Username:": "Nutzername:", + "Send Credentials": "Anmeldeinformationen senden", + "Keys": "Schlüssel", + "Game Cursor Mode": "Spiel-Cursor-Modus", + "Press Esc Key to Exit Pointer Lock Mode": "Drücken Sie die Esc-Taste, um den Zeigersperrmodus zu verlassen", + "Game Mode paused, click on screen to resume Game Mode.": "Spielmodus angehalten, klicken Sie auf den Bildschirm, um den Spielmodus fortzusetzen.", + "Clipboard Up": "Zwischenablage hoch", + "CLipboard Down": "Zwischenablage runter", + "Clipboard Seamless": "Zwischenablage nahtlos", + "Prefer Local Cursor": "Lokalen Cursor bevorzugen", + "Translate keyboard shortcuts": "Tastaturkürzel übersetzen", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit aktivieren", + "Enable WebP Compression": "WebP-Komprimierung aktivieren", + "Enable Performance Stats": "Leistungsstatistik aktivieren", + "Enable Pointer Lock": "Zeigersperre aktivieren", + "IME Input Mode": "IME-Eingabemodus", + "Show Virtual Keyboard Control": "Steuerung der virtuellen Tastatur anzeigen", + "Toggle Control Panel via Keystrokes": "Systemsteuerung per Tastendruck umschalten", + "Render Native Resolution": "Native Auflösung rendern", + "Keyboard Shortcuts": "Tastatürkürzel", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-Tastaturkürzel aktivieren", + "1 - Toggle Control Panel": "1 - Systemsteuerung umschalten", + "2 - Toggle Game Pointer Mode": "2 - Spielzeigermodus umschalten", + "3 - Toggle Pointer Lock": "3 - Zeigersperre umschalten", + "Stream Quality": "Streamqualität", + "Preset Modes:": "Voreingestellte Modi:", + "Static": "Statisch", + "Low": "Niedrig", + "Medium": "Mittel", + "High": "Hoch", + "Extreme": "Extrem", + "Lossless": "verlustfrei", + "Custom": "Brauch", + "Anti-Aliasing:": "Kantenglättung:", + "Auto Dynamic": "Auto-Dynamik", + "Off": "Aus", + "On": "An", + "Dynamic Quality Min:": "Dynamische Qualität Min.:", + "Dynamic Quality Max:": "Maximale dynamische Qualität:", + "Treat Lossless:": "Verlustlos behandeln:", + "Frame Rate:": "Bildrate:", + "Video JPEG Quality:": "Video-JPEG-Qualität:", + "Video WEBP Quality:": "Video-WEBP-Qualität:", + "Video Area:": "Videobereich:", + "Video Time:": "Videozeit:", + "Video Out Time:": "Video-Out-Zeit:", + "Video Mode Width:": "Breite des Videomodus:", + "Video Mode Height:": "Höhe im Videomodus:", + "Documentation": "Dokumentation", + "Drag Viewport": "Darstellungsfenster ziehen", + "KasmVNC encountered an error:": "KasmVNC hat einen Fehler festgestellt:" +} \ No newline at end of file diff --git a/app/locale/de_AT.json b/app/locale/de_AT.json new file mode 100644 index 0000000..36f44ea --- /dev/null +++ b/app/locale/de_AT.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Verbinden...", + "Disconnecting...": "Verbindung trennen...", + "Reconnecting...": "Verbindung wiederherstellen...", + "Internal error": "Interner Fehler", + "Must set host": "Richten Sie den Server ein", + "Connected (encrypted) to ": "Verbunden mit (verschlüsselt) ", + "Connected (unencrypted) to ": "Verbunden mit (unverschlüsselt) ", + "Something went wrong, connection is closed": "Etwas lief schief, Verbindung wurde getrennt", + "Disconnected": "Verbindung zum Server getrennt", + "New connection has been rejected with reason: ": "Verbindung wurde aus folgendem Grund abgelehnt: ", + "New connection has been rejected": "Verbindung wurde abgelehnt", + "Password is required": "Passwort ist erforderlich", + "Hide/Show the control bar": "Kontrollleiste verstecken/anzeigen", + "Move/Drag Viewport": "Ansichtsfenster verschieben/ziehen", + "viewport drag": "Ansichtsfenster ziehen", + "Active Mouse Button": "Aktive Maustaste", + "No mousebutton": "Keine Maustaste", + "Left mousebutton": "Linke Maustaste", + "Middle mousebutton": "Mittlere Maustaste", + "Right mousebutton": "Rechte Maustaste", + "Keyboard": "Tastatur", + "Show Keyboard": "Tastatur anzeigen", + "Extra keys": "Zusatztasten", + "Show Extra Keys": "Zusatztasten anzeigen", + "Ctrl": "Strg", + "Toggle Ctrl": "Strg umschalten", + "Alt": "Alt", + "Toggle Alt": "Alt umschalten", + "Send Tab": "Tab senden", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Escape senden", + "Ctrl+Alt+Del": "Strg+Alt+Entf", + "Send Ctrl-Alt-Del": "Strg+Alt+Entf senden", + "Shutdown/Reboot": "Herunterfahren/Neustarten", + "Shutdown/Reboot...": "Herunterfahren/Neustarten...", + "Power": "Energie", + "Shutdown": "Herunterfahren", + "Reboot": "Neustarten", + "Reset": "Zurücksetzen", + "Clipboard": "Zwischenablage", + "Clear": "Löschen", + "Fullscreen": "Vollbild", + "Settings": "Einstellungen", + "Shared Mode": "Geteilter Modus", + "View Only": "Nur betrachten", + "Clip to Window": "Auf Fenster begrenzen", + "Scaling Mode:": "Skalierungsmodus:", + "None": "Keiner", + "Local Scaling": "Lokales skalieren", + "Remote Resizing": "Serverseitiges skalieren", + "Advanced": "Erweitert", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Verschlüsselt", + "Host:": "Server:", + "Port:": "Port:", + "Path:": "Pfad:", + "Automatic Reconnect": "Automatisch wiederverbinden", + "Reconnect Delay (ms):": "Wiederverbindungsverzögerung (ms):", + "Logging:": "Protokollierung:", + "Disconnect": "Verbindung trennen", + "Connect": "Verbinden", + "Password:": "Passwort:", + "Cancel": "Abbrechen", + "Canvas not supported.": "Canvas nicht unterstützt.", + "Failed to connect to server": "Verbindung zum Server fehlgeschlagen", + "Credentials are required": "Anmeldeinformationen sind erforderlich", + "Drag": "Ziehen", + "Toggle Windows": "Fenster umschalten", + "Windows": "Fenster", + "Quality:": "Qualität:", + "Compression level:": "Komprimierungsstufe:", + "Show Dot when No Cursor": "Punkt anzeigen, wenn kein Cursor", + "Version:": "Ausführung:", + "Username:": "Nutzername:", + "Send Credentials": "Anmeldeinformationen senden", + "Keys": "Schlüssel", + "Game Cursor Mode": "Spiel-Cursor-Modus", + "Press Esc Key to Exit Pointer Lock Mode": "Drücken Sie die Esc-Taste, um den Zeigersperrmodus zu verlassen", + "Game Mode paused, click on screen to resume Game Mode.": "Spielmodus angehalten, klicken Sie auf den Bildschirm, um den Spielmodus fortzusetzen.", + "Clipboard Up": "Zwischenablage hoch", + "CLipboard Down": "Zwischenablage runter", + "Clipboard Seamless": "Zwischenablage nahtlos", + "Prefer Local Cursor": "Lokalen Cursor bevorzugen", + "Translate keyboard shortcuts": "Tastaturkürzel übersetzen", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit aktivieren", + "Enable WebP Compression": "WebP-Komprimierung aktivieren", + "Enable Performance Stats": "Leistungsstatistik aktivieren", + "Enable Pointer Lock": "Zeigersperre aktivieren", + "IME Input Mode": "IME-Eingabemodus", + "Show Virtual Keyboard Control": "Steuerung der virtuellen Tastatur anzeigen", + "Toggle Control Panel via Keystrokes": "Systemsteuerung per Tastendruck umschalten", + "Render Native Resolution": "Native Auflösung rendern", + "Keyboard Shortcuts": "Tastatürkürzel", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-Tastaturkürzel aktivieren", + "1 - Toggle Control Panel": "1 - Systemsteuerung umschalten", + "2 - Toggle Game Pointer Mode": "2 - Spielzeigermodus umschalten", + "3 - Toggle Pointer Lock": "3 - Zeigersperre umschalten", + "Stream Quality": "Streamqualität", + "Preset Modes:": "Voreingestellte Modi:", + "Static": "Statisch", + "Low": "Niedrig", + "Medium": "Mittel", + "High": "Hoch", + "Extreme": "Extrem", + "Lossless": "verlustfrei", + "Custom": "Brauch", + "Anti-Aliasing:": "Kantenglättung:", + "Auto Dynamic": "Auto-Dynamik", + "Off": "Aus", + "On": "An", + "Dynamic Quality Min:": "Dynamische Qualität Min.:", + "Dynamic Quality Max:": "Maximale dynamische Qualität:", + "Treat Lossless:": "Verlustlos behandeln:", + "Frame Rate:": "Bildrate:", + "Video JPEG Quality:": "Video-JPEG-Qualität:", + "Video WEBP Quality:": "Video-WEBP-Qualität:", + "Video Area:": "Videobereich:", + "Video Time:": "Videozeit:", + "Video Out Time:": "Video-Out-Zeit:", + "Video Mode Width:": "Breite des Videomodus:", + "Video Mode Height:": "Höhe im Videomodus:", + "Documentation": "Dokumentation", + "Drag Viewport": "Darstellungsfenster ziehen", + "KasmVNC encountered an error:": "KasmVNC hat einen Fehler festgestellt:" +} \ No newline at end of file diff --git a/app/locale/de_BE.json b/app/locale/de_BE.json new file mode 100644 index 0000000..36f44ea --- /dev/null +++ b/app/locale/de_BE.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Verbinden...", + "Disconnecting...": "Verbindung trennen...", + "Reconnecting...": "Verbindung wiederherstellen...", + "Internal error": "Interner Fehler", + "Must set host": "Richten Sie den Server ein", + "Connected (encrypted) to ": "Verbunden mit (verschlüsselt) ", + "Connected (unencrypted) to ": "Verbunden mit (unverschlüsselt) ", + "Something went wrong, connection is closed": "Etwas lief schief, Verbindung wurde getrennt", + "Disconnected": "Verbindung zum Server getrennt", + "New connection has been rejected with reason: ": "Verbindung wurde aus folgendem Grund abgelehnt: ", + "New connection has been rejected": "Verbindung wurde abgelehnt", + "Password is required": "Passwort ist erforderlich", + "Hide/Show the control bar": "Kontrollleiste verstecken/anzeigen", + "Move/Drag Viewport": "Ansichtsfenster verschieben/ziehen", + "viewport drag": "Ansichtsfenster ziehen", + "Active Mouse Button": "Aktive Maustaste", + "No mousebutton": "Keine Maustaste", + "Left mousebutton": "Linke Maustaste", + "Middle mousebutton": "Mittlere Maustaste", + "Right mousebutton": "Rechte Maustaste", + "Keyboard": "Tastatur", + "Show Keyboard": "Tastatur anzeigen", + "Extra keys": "Zusatztasten", + "Show Extra Keys": "Zusatztasten anzeigen", + "Ctrl": "Strg", + "Toggle Ctrl": "Strg umschalten", + "Alt": "Alt", + "Toggle Alt": "Alt umschalten", + "Send Tab": "Tab senden", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Escape senden", + "Ctrl+Alt+Del": "Strg+Alt+Entf", + "Send Ctrl-Alt-Del": "Strg+Alt+Entf senden", + "Shutdown/Reboot": "Herunterfahren/Neustarten", + "Shutdown/Reboot...": "Herunterfahren/Neustarten...", + "Power": "Energie", + "Shutdown": "Herunterfahren", + "Reboot": "Neustarten", + "Reset": "Zurücksetzen", + "Clipboard": "Zwischenablage", + "Clear": "Löschen", + "Fullscreen": "Vollbild", + "Settings": "Einstellungen", + "Shared Mode": "Geteilter Modus", + "View Only": "Nur betrachten", + "Clip to Window": "Auf Fenster begrenzen", + "Scaling Mode:": "Skalierungsmodus:", + "None": "Keiner", + "Local Scaling": "Lokales skalieren", + "Remote Resizing": "Serverseitiges skalieren", + "Advanced": "Erweitert", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Verschlüsselt", + "Host:": "Server:", + "Port:": "Port:", + "Path:": "Pfad:", + "Automatic Reconnect": "Automatisch wiederverbinden", + "Reconnect Delay (ms):": "Wiederverbindungsverzögerung (ms):", + "Logging:": "Protokollierung:", + "Disconnect": "Verbindung trennen", + "Connect": "Verbinden", + "Password:": "Passwort:", + "Cancel": "Abbrechen", + "Canvas not supported.": "Canvas nicht unterstützt.", + "Failed to connect to server": "Verbindung zum Server fehlgeschlagen", + "Credentials are required": "Anmeldeinformationen sind erforderlich", + "Drag": "Ziehen", + "Toggle Windows": "Fenster umschalten", + "Windows": "Fenster", + "Quality:": "Qualität:", + "Compression level:": "Komprimierungsstufe:", + "Show Dot when No Cursor": "Punkt anzeigen, wenn kein Cursor", + "Version:": "Ausführung:", + "Username:": "Nutzername:", + "Send Credentials": "Anmeldeinformationen senden", + "Keys": "Schlüssel", + "Game Cursor Mode": "Spiel-Cursor-Modus", + "Press Esc Key to Exit Pointer Lock Mode": "Drücken Sie die Esc-Taste, um den Zeigersperrmodus zu verlassen", + "Game Mode paused, click on screen to resume Game Mode.": "Spielmodus angehalten, klicken Sie auf den Bildschirm, um den Spielmodus fortzusetzen.", + "Clipboard Up": "Zwischenablage hoch", + "CLipboard Down": "Zwischenablage runter", + "Clipboard Seamless": "Zwischenablage nahtlos", + "Prefer Local Cursor": "Lokalen Cursor bevorzugen", + "Translate keyboard shortcuts": "Tastaturkürzel übersetzen", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit aktivieren", + "Enable WebP Compression": "WebP-Komprimierung aktivieren", + "Enable Performance Stats": "Leistungsstatistik aktivieren", + "Enable Pointer Lock": "Zeigersperre aktivieren", + "IME Input Mode": "IME-Eingabemodus", + "Show Virtual Keyboard Control": "Steuerung der virtuellen Tastatur anzeigen", + "Toggle Control Panel via Keystrokes": "Systemsteuerung per Tastendruck umschalten", + "Render Native Resolution": "Native Auflösung rendern", + "Keyboard Shortcuts": "Tastatürkürzel", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-Tastaturkürzel aktivieren", + "1 - Toggle Control Panel": "1 - Systemsteuerung umschalten", + "2 - Toggle Game Pointer Mode": "2 - Spielzeigermodus umschalten", + "3 - Toggle Pointer Lock": "3 - Zeigersperre umschalten", + "Stream Quality": "Streamqualität", + "Preset Modes:": "Voreingestellte Modi:", + "Static": "Statisch", + "Low": "Niedrig", + "Medium": "Mittel", + "High": "Hoch", + "Extreme": "Extrem", + "Lossless": "verlustfrei", + "Custom": "Brauch", + "Anti-Aliasing:": "Kantenglättung:", + "Auto Dynamic": "Auto-Dynamik", + "Off": "Aus", + "On": "An", + "Dynamic Quality Min:": "Dynamische Qualität Min.:", + "Dynamic Quality Max:": "Maximale dynamische Qualität:", + "Treat Lossless:": "Verlustlos behandeln:", + "Frame Rate:": "Bildrate:", + "Video JPEG Quality:": "Video-JPEG-Qualität:", + "Video WEBP Quality:": "Video-WEBP-Qualität:", + "Video Area:": "Videobereich:", + "Video Time:": "Videozeit:", + "Video Out Time:": "Video-Out-Zeit:", + "Video Mode Width:": "Breite des Videomodus:", + "Video Mode Height:": "Höhe im Videomodus:", + "Documentation": "Dokumentation", + "Drag Viewport": "Darstellungsfenster ziehen", + "KasmVNC encountered an error:": "KasmVNC hat einen Fehler festgestellt:" +} \ No newline at end of file diff --git a/app/locale/de_CH.json b/app/locale/de_CH.json new file mode 100644 index 0000000..36f44ea --- /dev/null +++ b/app/locale/de_CH.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Verbinden...", + "Disconnecting...": "Verbindung trennen...", + "Reconnecting...": "Verbindung wiederherstellen...", + "Internal error": "Interner Fehler", + "Must set host": "Richten Sie den Server ein", + "Connected (encrypted) to ": "Verbunden mit (verschlüsselt) ", + "Connected (unencrypted) to ": "Verbunden mit (unverschlüsselt) ", + "Something went wrong, connection is closed": "Etwas lief schief, Verbindung wurde getrennt", + "Disconnected": "Verbindung zum Server getrennt", + "New connection has been rejected with reason: ": "Verbindung wurde aus folgendem Grund abgelehnt: ", + "New connection has been rejected": "Verbindung wurde abgelehnt", + "Password is required": "Passwort ist erforderlich", + "Hide/Show the control bar": "Kontrollleiste verstecken/anzeigen", + "Move/Drag Viewport": "Ansichtsfenster verschieben/ziehen", + "viewport drag": "Ansichtsfenster ziehen", + "Active Mouse Button": "Aktive Maustaste", + "No mousebutton": "Keine Maustaste", + "Left mousebutton": "Linke Maustaste", + "Middle mousebutton": "Mittlere Maustaste", + "Right mousebutton": "Rechte Maustaste", + "Keyboard": "Tastatur", + "Show Keyboard": "Tastatur anzeigen", + "Extra keys": "Zusatztasten", + "Show Extra Keys": "Zusatztasten anzeigen", + "Ctrl": "Strg", + "Toggle Ctrl": "Strg umschalten", + "Alt": "Alt", + "Toggle Alt": "Alt umschalten", + "Send Tab": "Tab senden", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Escape senden", + "Ctrl+Alt+Del": "Strg+Alt+Entf", + "Send Ctrl-Alt-Del": "Strg+Alt+Entf senden", + "Shutdown/Reboot": "Herunterfahren/Neustarten", + "Shutdown/Reboot...": "Herunterfahren/Neustarten...", + "Power": "Energie", + "Shutdown": "Herunterfahren", + "Reboot": "Neustarten", + "Reset": "Zurücksetzen", + "Clipboard": "Zwischenablage", + "Clear": "Löschen", + "Fullscreen": "Vollbild", + "Settings": "Einstellungen", + "Shared Mode": "Geteilter Modus", + "View Only": "Nur betrachten", + "Clip to Window": "Auf Fenster begrenzen", + "Scaling Mode:": "Skalierungsmodus:", + "None": "Keiner", + "Local Scaling": "Lokales skalieren", + "Remote Resizing": "Serverseitiges skalieren", + "Advanced": "Erweitert", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Verschlüsselt", + "Host:": "Server:", + "Port:": "Port:", + "Path:": "Pfad:", + "Automatic Reconnect": "Automatisch wiederverbinden", + "Reconnect Delay (ms):": "Wiederverbindungsverzögerung (ms):", + "Logging:": "Protokollierung:", + "Disconnect": "Verbindung trennen", + "Connect": "Verbinden", + "Password:": "Passwort:", + "Cancel": "Abbrechen", + "Canvas not supported.": "Canvas nicht unterstützt.", + "Failed to connect to server": "Verbindung zum Server fehlgeschlagen", + "Credentials are required": "Anmeldeinformationen sind erforderlich", + "Drag": "Ziehen", + "Toggle Windows": "Fenster umschalten", + "Windows": "Fenster", + "Quality:": "Qualität:", + "Compression level:": "Komprimierungsstufe:", + "Show Dot when No Cursor": "Punkt anzeigen, wenn kein Cursor", + "Version:": "Ausführung:", + "Username:": "Nutzername:", + "Send Credentials": "Anmeldeinformationen senden", + "Keys": "Schlüssel", + "Game Cursor Mode": "Spiel-Cursor-Modus", + "Press Esc Key to Exit Pointer Lock Mode": "Drücken Sie die Esc-Taste, um den Zeigersperrmodus zu verlassen", + "Game Mode paused, click on screen to resume Game Mode.": "Spielmodus angehalten, klicken Sie auf den Bildschirm, um den Spielmodus fortzusetzen.", + "Clipboard Up": "Zwischenablage hoch", + "CLipboard Down": "Zwischenablage runter", + "Clipboard Seamless": "Zwischenablage nahtlos", + "Prefer Local Cursor": "Lokalen Cursor bevorzugen", + "Translate keyboard shortcuts": "Tastaturkürzel übersetzen", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit aktivieren", + "Enable WebP Compression": "WebP-Komprimierung aktivieren", + "Enable Performance Stats": "Leistungsstatistik aktivieren", + "Enable Pointer Lock": "Zeigersperre aktivieren", + "IME Input Mode": "IME-Eingabemodus", + "Show Virtual Keyboard Control": "Steuerung der virtuellen Tastatur anzeigen", + "Toggle Control Panel via Keystrokes": "Systemsteuerung per Tastendruck umschalten", + "Render Native Resolution": "Native Auflösung rendern", + "Keyboard Shortcuts": "Tastatürkürzel", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-Tastaturkürzel aktivieren", + "1 - Toggle Control Panel": "1 - Systemsteuerung umschalten", + "2 - Toggle Game Pointer Mode": "2 - Spielzeigermodus umschalten", + "3 - Toggle Pointer Lock": "3 - Zeigersperre umschalten", + "Stream Quality": "Streamqualität", + "Preset Modes:": "Voreingestellte Modi:", + "Static": "Statisch", + "Low": "Niedrig", + "Medium": "Mittel", + "High": "Hoch", + "Extreme": "Extrem", + "Lossless": "verlustfrei", + "Custom": "Brauch", + "Anti-Aliasing:": "Kantenglättung:", + "Auto Dynamic": "Auto-Dynamik", + "Off": "Aus", + "On": "An", + "Dynamic Quality Min:": "Dynamische Qualität Min.:", + "Dynamic Quality Max:": "Maximale dynamische Qualität:", + "Treat Lossless:": "Verlustlos behandeln:", + "Frame Rate:": "Bildrate:", + "Video JPEG Quality:": "Video-JPEG-Qualität:", + "Video WEBP Quality:": "Video-WEBP-Qualität:", + "Video Area:": "Videobereich:", + "Video Time:": "Videozeit:", + "Video Out Time:": "Video-Out-Zeit:", + "Video Mode Width:": "Breite des Videomodus:", + "Video Mode Height:": "Höhe im Videomodus:", + "Documentation": "Dokumentation", + "Drag Viewport": "Darstellungsfenster ziehen", + "KasmVNC encountered an error:": "KasmVNC hat einen Fehler festgestellt:" +} \ No newline at end of file diff --git a/app/locale/de_DE.json b/app/locale/de_DE.json new file mode 100644 index 0000000..8c22595 --- /dev/null +++ b/app/locale/de_DE.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Verbinden...", + "Disconnecting...": "Verbindung trennen...", + "Reconnecting...": "Wiederverbinden...", + "Internal error": "Interner Fehler", + "Must set host": "Host muss festgelegt werden", + "Connected (encrypted) to ": "Verbunden (verschlüsselt) mit", + "Connected (unencrypted) to ": "Verbunden (unverschlüsselt) mit ", + "Something went wrong, connection is closed": "Etwas ist schief gelaufen, Verbindung ist geschlossen", + "Failed to connect to server": "Verbindung zum Server fehlgeschlagen", + "Disconnected": "Getrennt", + "New connection has been rejected with reason: ": "Neue Verbindung wurde mit Begründung abgelehnt: ", + "New connection has been rejected": "Neue Verbindung wurde abgelehnt", + "Credentials are required": "Anmeldeinformationen sind erforderlich", + "Hide/Show the control bar": "Steuerleiste ausblenden/einblenden", + "Drag": "Ziehen", + "Move/Drag Viewport": "Ansichtsfenster verschieben/ziehen", + "Keyboard": "Klaviatur", + "Show Keyboard": "Tastatur anzeigen", + "Extra keys": "Zusätzliche Schlüssel", + "Show Extra Keys": "Zusätzliche Schlüssel anzeigen", + "Ctrl": "Strg", + "Toggle Ctrl": "Strg umschalten", + "Alt": "Alt", + "Toggle Alt": "Umschalten Alt", + "Toggle Windows": "Fenster umschalten", + "Windows": "Fenster", + "Send Tab": "Tab senden", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Flucht senden", + "Ctrl+Alt+Del": "Strg+Alt+Entf", + "Send Ctrl-Alt-Del": "Strg-Alt-Entf senden", + "Shutdown/Reboot": "Herunterfahren/Neustart", + "Shutdown/Reboot...": "Herunterfahren/Neustart...", + "Power": "Leistung", + "Shutdown": "Abschalten", + "Reboot": "Neustart", + "Reset": "Zurücksetzen", + "Clipboard": "Klemmbrett", + "Clear": "Klar", + "Fullscreen": "Ganzer Bildschirm", + "Settings": "Einstellungen", + "Shared Mode": "Gemeinsamer Modus", + "View Only": "Nur anschauen", + "Clip to Window": "An Fenster anheften", + "Scaling Mode:": "Skalierungsmodus:", + "None": "Keiner", + "Local Scaling": "Lokale Skalierung", + "Remote Resizing": "Remote-Größenänderung", + "Advanced": "Fortschrittlich", + "Quality:": "Qualität:", + "Compression level:": "Komprimierungsstufe:", + "Repeater ID:": "Repeater-ID:", + "WebSocket": "WebSocket", + "Encrypt": "Verschlüsseln", + "Host:": "Gastgeber:", + "Port:": "Hafen:", + "Path:": "Weg:", + "Automatic Reconnect": "Automatische Wiederverbindung", + "Reconnect Delay (ms):": "Wiederverbindungsverzögerung (ms):", + "Show Dot when No Cursor": "Punkt anzeigen, wenn kein Cursor", + "Logging:": "Protokollierung:", + "Version:": "Ausführung:", + "Disconnect": "Trennen", + "Connect": "Verbinden", + "Username:": "Nutzername:", + "Password:": "Passwort:", + "Send Credentials": "Anmeldeinformationen senden", + "Cancel": "Stornieren", + "Keys": "Schlüssel", + "Game Cursor Mode": "Spiel-Cursor-Modus", + "Press Esc Key to Exit Pointer Lock Mode": "Drücken Sie die Esc-Taste, um den Zeigersperrmodus zu verlassen", + "Game Mode paused, click on screen to resume Game Mode.": "Spielmodus angehalten, klicken Sie auf den Bildschirm, um den Spielmodus fortzusetzen.", + "Clipboard Up": "Zwischenablage hoch", + "CLipboard Down": "Zwischenablage runter", + "Clipboard Seamless": "Zwischenablage nahtlos", + "Prefer Local Cursor": "Lokalen Cursor bevorzugen", + "Translate keyboard shortcuts": "Tastaturkürzel übersetzen", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit aktivieren", + "Enable WebP Compression": "WebP-Komprimierung aktivieren", + "Enable Performance Stats": "Leistungsstatistik aktivieren", + "Enable Pointer Lock": "Zeigersperre aktivieren", + "IME Input Mode": "IME-Eingabemodus", + "Show Virtual Keyboard Control": "Steuerung der virtuellen Tastatur anzeigen", + "Toggle Control Panel via Keystrokes": "Systemsteuerung per Tastendruck umschalten", + "Render Native Resolution": "Native Auflösung rendern", + "Keyboard Shortcuts": "Tastatürkürzel", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-Tastaturkürzel aktivieren", + "1 - Toggle Control Panel": "1 - Systemsteuerung umschalten", + "2 - Toggle Game Pointer Mode": "2 - Spielzeigermodus umschalten", + "3 - Toggle Pointer Lock": "3 - Zeigersperre umschalten", + "Stream Quality": "Streamqualität", + "Preset Modes:": "Voreingestellte Modi:", + "Static": "Statisch", + "Low": "Niedrig", + "Medium": "Mittel", + "High": "Hoch", + "Extreme": "Extrem", + "Lossless": "verlustfrei", + "Custom": "Brauch", + "Anti-Aliasing:": "Kantenglättung:", + "Auto Dynamic": "Auto-Dynamik", + "Off": "Aus", + "On": "An", + "Dynamic Quality Min:": "Dynamische Qualität Min.:", + "Dynamic Quality Max:": "Maximale dynamische Qualität:", + "Treat Lossless:": "Verlustlos behandeln:", + "Frame Rate:": "Bildrate:", + "Video JPEG Quality:": "Video-JPEG-Qualität:", + "Video WEBP Quality:": "Video-WEBP-Qualität:", + "Video Area:": "Videobereich:", + "Video Time:": "Videozeit:", + "Video Out Time:": "Video-Out-Zeit:", + "Video Mode Width:": "Breite des Videomodus:", + "Video Mode Height:": "Höhe im Videomodus:", + "Documentation": "Dokumentation", + "Drag Viewport": "Darstellungsfenster ziehen", + "KasmVNC encountered an error:": "KasmVNC hat einen Fehler festgestellt:" +} \ No newline at end of file diff --git a/app/locale/de_LU.json b/app/locale/de_LU.json new file mode 100644 index 0000000..8c22595 --- /dev/null +++ b/app/locale/de_LU.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Verbinden...", + "Disconnecting...": "Verbindung trennen...", + "Reconnecting...": "Wiederverbinden...", + "Internal error": "Interner Fehler", + "Must set host": "Host muss festgelegt werden", + "Connected (encrypted) to ": "Verbunden (verschlüsselt) mit", + "Connected (unencrypted) to ": "Verbunden (unverschlüsselt) mit ", + "Something went wrong, connection is closed": "Etwas ist schief gelaufen, Verbindung ist geschlossen", + "Failed to connect to server": "Verbindung zum Server fehlgeschlagen", + "Disconnected": "Getrennt", + "New connection has been rejected with reason: ": "Neue Verbindung wurde mit Begründung abgelehnt: ", + "New connection has been rejected": "Neue Verbindung wurde abgelehnt", + "Credentials are required": "Anmeldeinformationen sind erforderlich", + "Hide/Show the control bar": "Steuerleiste ausblenden/einblenden", + "Drag": "Ziehen", + "Move/Drag Viewport": "Ansichtsfenster verschieben/ziehen", + "Keyboard": "Klaviatur", + "Show Keyboard": "Tastatur anzeigen", + "Extra keys": "Zusätzliche Schlüssel", + "Show Extra Keys": "Zusätzliche Schlüssel anzeigen", + "Ctrl": "Strg", + "Toggle Ctrl": "Strg umschalten", + "Alt": "Alt", + "Toggle Alt": "Umschalten Alt", + "Toggle Windows": "Fenster umschalten", + "Windows": "Fenster", + "Send Tab": "Tab senden", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Flucht senden", + "Ctrl+Alt+Del": "Strg+Alt+Entf", + "Send Ctrl-Alt-Del": "Strg-Alt-Entf senden", + "Shutdown/Reboot": "Herunterfahren/Neustart", + "Shutdown/Reboot...": "Herunterfahren/Neustart...", + "Power": "Leistung", + "Shutdown": "Abschalten", + "Reboot": "Neustart", + "Reset": "Zurücksetzen", + "Clipboard": "Klemmbrett", + "Clear": "Klar", + "Fullscreen": "Ganzer Bildschirm", + "Settings": "Einstellungen", + "Shared Mode": "Gemeinsamer Modus", + "View Only": "Nur anschauen", + "Clip to Window": "An Fenster anheften", + "Scaling Mode:": "Skalierungsmodus:", + "None": "Keiner", + "Local Scaling": "Lokale Skalierung", + "Remote Resizing": "Remote-Größenänderung", + "Advanced": "Fortschrittlich", + "Quality:": "Qualität:", + "Compression level:": "Komprimierungsstufe:", + "Repeater ID:": "Repeater-ID:", + "WebSocket": "WebSocket", + "Encrypt": "Verschlüsseln", + "Host:": "Gastgeber:", + "Port:": "Hafen:", + "Path:": "Weg:", + "Automatic Reconnect": "Automatische Wiederverbindung", + "Reconnect Delay (ms):": "Wiederverbindungsverzögerung (ms):", + "Show Dot when No Cursor": "Punkt anzeigen, wenn kein Cursor", + "Logging:": "Protokollierung:", + "Version:": "Ausführung:", + "Disconnect": "Trennen", + "Connect": "Verbinden", + "Username:": "Nutzername:", + "Password:": "Passwort:", + "Send Credentials": "Anmeldeinformationen senden", + "Cancel": "Stornieren", + "Keys": "Schlüssel", + "Game Cursor Mode": "Spiel-Cursor-Modus", + "Press Esc Key to Exit Pointer Lock Mode": "Drücken Sie die Esc-Taste, um den Zeigersperrmodus zu verlassen", + "Game Mode paused, click on screen to resume Game Mode.": "Spielmodus angehalten, klicken Sie auf den Bildschirm, um den Spielmodus fortzusetzen.", + "Clipboard Up": "Zwischenablage hoch", + "CLipboard Down": "Zwischenablage runter", + "Clipboard Seamless": "Zwischenablage nahtlos", + "Prefer Local Cursor": "Lokalen Cursor bevorzugen", + "Translate keyboard shortcuts": "Tastaturkürzel übersetzen", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit aktivieren", + "Enable WebP Compression": "WebP-Komprimierung aktivieren", + "Enable Performance Stats": "Leistungsstatistik aktivieren", + "Enable Pointer Lock": "Zeigersperre aktivieren", + "IME Input Mode": "IME-Eingabemodus", + "Show Virtual Keyboard Control": "Steuerung der virtuellen Tastatur anzeigen", + "Toggle Control Panel via Keystrokes": "Systemsteuerung per Tastendruck umschalten", + "Render Native Resolution": "Native Auflösung rendern", + "Keyboard Shortcuts": "Tastatürkürzel", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-Tastaturkürzel aktivieren", + "1 - Toggle Control Panel": "1 - Systemsteuerung umschalten", + "2 - Toggle Game Pointer Mode": "2 - Spielzeigermodus umschalten", + "3 - Toggle Pointer Lock": "3 - Zeigersperre umschalten", + "Stream Quality": "Streamqualität", + "Preset Modes:": "Voreingestellte Modi:", + "Static": "Statisch", + "Low": "Niedrig", + "Medium": "Mittel", + "High": "Hoch", + "Extreme": "Extrem", + "Lossless": "verlustfrei", + "Custom": "Brauch", + "Anti-Aliasing:": "Kantenglättung:", + "Auto Dynamic": "Auto-Dynamik", + "Off": "Aus", + "On": "An", + "Dynamic Quality Min:": "Dynamische Qualität Min.:", + "Dynamic Quality Max:": "Maximale dynamische Qualität:", + "Treat Lossless:": "Verlustlos behandeln:", + "Frame Rate:": "Bildrate:", + "Video JPEG Quality:": "Video-JPEG-Qualität:", + "Video WEBP Quality:": "Video-WEBP-Qualität:", + "Video Area:": "Videobereich:", + "Video Time:": "Videozeit:", + "Video Out Time:": "Video-Out-Zeit:", + "Video Mode Width:": "Breite des Videomodus:", + "Video Mode Height:": "Höhe im Videomodus:", + "Documentation": "Dokumentation", + "Drag Viewport": "Darstellungsfenster ziehen", + "KasmVNC encountered an error:": "KasmVNC hat einen Fehler festgestellt:" +} \ No newline at end of file diff --git a/app/locale/es.json b/app/locale/es.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_AR.json b/app/locale/es_AR.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_AR.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_BO.json b/app/locale/es_BO.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_BO.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_CL.json b/app/locale/es_CL.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_CL.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_CO.json b/app/locale/es_CO.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_CO.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_CR.json b/app/locale/es_CR.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_CR.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_CU.json b/app/locale/es_CU.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_CU.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_DO.json b/app/locale/es_DO.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_DO.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_EC.json b/app/locale/es_EC.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_EC.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_ES.json b/app/locale/es_ES.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_ES.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_GT.json b/app/locale/es_GT.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_GT.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_HN.json b/app/locale/es_HN.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_HN.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_MX.json b/app/locale/es_MX.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_MX.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_NI.json b/app/locale/es_NI.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_NI.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_PA.json b/app/locale/es_PA.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_PA.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_PE.json b/app/locale/es_PE.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_PE.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_PR.json b/app/locale/es_PR.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_PR.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_PY.json b/app/locale/es_PY.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_PY.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_SV.json b/app/locale/es_SV.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_SV.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_US.json b/app/locale/es_US.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_US.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_UY.json b/app/locale/es_UY.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_UY.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/es_VE.json b/app/locale/es_VE.json new file mode 100644 index 0000000..9d7fa3b --- /dev/null +++ b/app/locale/es_VE.json @@ -0,0 +1,131 @@ +{ + "Connecting...": "Conectando...", + "Connected (encrypted) to ": "Conectado (con encriptación) a", + "Connected (unencrypted) to ": "Conectado (sin encriptación) a", + "Disconnecting...": "Desconectando...", + "Disconnected": "Desconectado", + "Must set host": "Debes configurar el host", + "Reconnecting...": "Reconectando...", + "Password is required": "Contraseña es obligatoria", + "Disconnect timeout": "Tiempo de desconexión agotado", + "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", + "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "viewport drag": "Arrastrar la ventana", + "Active Mouse Button": "Botón activo del ratón", + "No mousebutton": "Ningún botón del ratón", + "Left mousebutton": "Botón izquierdo del ratón", + "Middle mousebutton": "Botón central del ratón", + "Right mousebutton": "Botón derecho del ratón", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionales", + "Show Extra Keys": "Mostrar Teclas Adicionales", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pulsar/Soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pulsar/Soltar Alt", + "Send Tab": "Enviar Tabulación", + "Tab": "Tabulación", + "Esc": "Esc", + "Send Escape": "Enviar Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl+Alt+Del", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Encender", + "Shutdown": "Apagar", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeles", + "Clear": "Vaciar", + "Fullscreen": "Pantalla Completa", + "Settings": "Configuraciones", + "Shared Mode": "Modo Compartido", + "View Only": "Solo visualización", + "Clip to Window": "Recortar al tamaño de la ventana", + "Scaling Mode:": "Modo de escalado:", + "None": "Ninguno", + "Local Scaling": "Escalado Local", + "Local Downscaling": "Reducción de escala local", + "Remote Resizing": "Cambio de tamaño remoto", + "Advanced": "Avanzado", + "Local Cursor": "Cursor Local", + "Repeater ID:": "ID del Repetidor", + "WebSocket": "WebSocket", + "Encrypt": "", + "Host:": "Host", + "Port:": "Puesto", + "Path:": "Ruta", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", + "Logging:": "Logging", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Password:": "Contraseña", + "Cancel": "Cancelar", + "Canvas not supported.": "Canvas no está soportado", + "Internal error": "Error interno", + "Something went wrong, connection is closed": "Algo salió mal, la conexión está cerrada", + "Failed to connect to server": "Error al conectar con el servidor", + "New connection has been rejected with reason: ": "La nueva conexión ha sido rechazada por el motivo: ", + "New connection has been rejected": "Nueva conexión ha sido rechazada", + "Credentials are required": "Se requieren credenciales", + "Drag": "Arrastrar", + "Toggle Windows": "Alternar ventanas", + "Windows": "ventanas", + "Quality:": "Calidad:", + "Compression level:": "Nivel de compresión:", + "Show Dot when No Cursor": "Mostrar punto cuando no hay cursor", + "Version:": "Versión:", + "Username:": "Nombre de usuario:", + "Send Credentials": "Enviar Credenciales", + "Keys": "Llaves", + "Game Cursor Mode": "Modo de cursor de juego", + "Press Esc Key to Exit Pointer Lock Mode": "Presione la tecla Esc para salir del modo de bloqueo del puntero", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de juego en pausa, haga clic en la pantalla para reanudar el modo de juego", + "Clipboard Up": "Portapapeles arriba", + "CLipboard Down": "Portapapeles abajo", + "Clipboard Seamless": "Portapapeles sin costuras", + "Prefer Local Cursor": "Preferir cursor local", + "Translate keyboard shortcuts": "Traducir atajos de teclado", + "Enable WebRTC UDP Transit": "Habilitar el tránsito UDP de WebRTC", + "Enable WebP Compression": "Habilitar compresión WebP", + "Enable Performance Stats": "Habilitar estadísticas de rendimiento", + "Enable Pointer Lock": "Habilitar bloqueo de puntero", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar control de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar panel de control a través de pulsaciones de teclas", + "Render Native Resolution": "Procesar resolución nativa", + "Keyboard Shortcuts": "Atajos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Habilitar atajos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de puntero de juego", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueo de puntero", + "Stream Quality": "Calidad de transmisión", + "Preset Modes:": "Modos preestablecidos:", + "Static": "Estático", + "Low": "Bajo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "sin pérdidas", + "Custom": "Costumbre", + "Anti-Aliasing:": "Suavizado:", + "Auto Dynamic": "Auto Dinámica", + "Off": "Apagado", + "On": "En", + "Dynamic Quality Min:": "Calidad dinámica mínima:", + "Dynamic Quality Max:": "Calidad dinámica máxima:", + "Treat Lossless:": "Tratar sin pérdidas:", + "Frame Rate:": "Cuadros por segundo:", + "Video JPEG Quality:": "Calidad JPEG de vídeo:", + "Video WEBP Quality:": "Calidad WEBP del vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tiempo de vídeo:", + "Video Out Time:": "Tiempo de salida del vídeo:", + "Video Mode Width:": "Ancho del modo de vídeo:", + "Video Mode Height:": "Altura del modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar ventana gráfica", + "KasmVNC encountered an error:": "KasmVNC encontró un error:" +} \ No newline at end of file diff --git a/app/locale/et.json b/app/locale/et.json new file mode 100644 index 0000000..acc419f --- /dev/null +++ b/app/locale/et.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ühendamine...", + "Disconnecting...": "Ühendust katkestatakse...", + "Reconnecting...": "Taasühendamine...", + "Internal error": "Sisemine viga", + "Must set host": "Peab hosti määrama", + "Connected (encrypted) to ": "Ühendatud (krüpteeritud) võrguga ", + "Connected (unencrypted) to ": "Ühendatud (krüpteerimata) võrguga ", + "Something went wrong, connection is closed": "Midagi läks valesti, ühendus on suletud", + "Failed to connect to server": "Serveriga ühenduse loomine nurjus", + "Disconnected": "Katkestatud", + "New connection has been rejected with reason: ": "Uus ühendus on tagasi lükatud põhjusel:", + "New connection has been rejected": "Uus ühendus on tagasi lükatud", + "Credentials are required": "Mandaat on nõutav", + "Hide/Show the control bar": "Peida/kuva juhtriba", + "Drag": "Vedama", + "Move/Drag Viewport": "Teisalda/lohistamisvaade", + "Keyboard": "Klaviatuur", + "Show Keyboard": "Kuva klaviatuur", + "Extra keys": "Lisaklahvid", + "Show Extra Keys": "Näita lisaklahve", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Lülita Ctrl", + "Alt": "Alt", + "Toggle Alt": "Lülita Alt", + "Toggle Windows": "Lülita Windowsi sisse", + "Windows": "Windows", + "Send Tab": "Saada vahekaart", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Saada põgenemine", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Saada Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "Võim", + "Shutdown": "Lülita välja", + "Reboot": "Taaskäivitamine", + "Reset": "Lähtesta", + "Clipboard": "Lõikelaud", + "Clear": "Tühjenda", + "Fullscreen": "Täisekraan", + "Settings": "Seaded", + "Shared Mode": "Jagatud režiim", + "View Only": "Ainult vaatamine", + "Clip to Window": "Klip aknasse", + "Scaling Mode:": "Skaleerimisrežiim:", + "None": "Mitte ükski", + "Local Scaling": "Kohalik skaleerimine", + "Remote Resizing": "Suuruse kaugmuutmine", + "Advanced": "Täpsem", + "Quality:": "Kvaliteet:", + "Compression level:": "Tihenduse tase:", + "Repeater ID:": "Repeateri ID:", + "WebSocket": "WebSocket", + "Encrypt": "Krüpti", + "Host:": "Võõrustaja:", + "Port:": "Sadam:", + "Path:": "Tee:", + "Automatic Reconnect": "Automaatne taasühendamine", + "Reconnect Delay (ms):": "Taasühendamise viivitus (ms):", + "Show Dot when No Cursor": "Näita punkti, kui kursorit pole", + "Logging:": "Logimine:", + "Version:": "Versioon:", + "Disconnect": "Katkesta ühendus", + "Connect": "Ühenda", + "Username:": "Kasutajanimi:", + "Password:": "Parool:", + "Send Credentials": "Saada mandaadid", + "Cancel": "Tühista", + "Keys": "Võtmed", + "Game Cursor Mode": "Mängu kursori režiim", + "Press Esc Key to Exit Pointer Lock Mode": "Osuri lukustusrežiimist väljumiseks vajutage klahvi Esc", + "Game Mode paused, click on screen to resume Game Mode.": "Mängurežiim peatatud, mängurežiimi jätkamiseks klõpsake ekraanil.", + "Clipboard Up": "Lõikelaud üles", + "CLipboard Down": "Lõikelaud alla", + "Clipboard Seamless": "Sujuv lõikelaud", + "Prefer Local Cursor": "Eelista kohalikku kursorit", + "Translate keyboard shortcuts": "Tõlgi klaviatuuri otseteed", + "Enable WebRTC UDP Transit": "Luba WebRTC UDP Transit", + "Enable WebP Compression": "Luba WebP tihendamine", + "Enable Performance Stats": "Luba jõudlusstatistika", + "Enable Pointer Lock": "Luba kursori lukk", + "IME Input Mode": "IME sisestusrežiim", + "Show Virtual Keyboard Control": "Kuva virtuaalse klaviatuuri juhtimine", + "Toggle Control Panel via Keystrokes": "Lülita juhtpaneeli klahvivajutuste kaudu sisse", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Klaviatuuri otseteed", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC kiirklahvide lubamine", + "1 - Toggle Control Panel": "1 – juhtpaneeli sisse- ja väljalülitamine", + "2 - Toggle Game Pointer Mode": "2 - Mängu osuti režiimi sisse- ja väljalülitamine", + "3 - Toggle Pointer Lock": "3 – Lülita kursori lukustus sisse", + "Stream Quality": "Voo kvaliteet", + "Preset Modes:": "Eelseadistatud režiimid:", + "Static": "Staatiline", + "Low": "Madal", + "Medium": "Keskmine", + "High": "Kõrge", + "Extreme": "Äärmuslik", + "Lossless": "Kaotusteta", + "Custom": "Kohandatud", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Automaatne dünaamiline", + "Off": "Väljas", + "On": "Peal", + "Dynamic Quality Min:": "Dünaamiline kvaliteet min:", + "Dynamic Quality Max:": "Dünaamiline kvaliteet max:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Kaadrisagedus:", + "Video JPEG Quality:": "Video JPEG kvaliteet:", + "Video WEBP Quality:": "Video WEBP kvaliteet:", + "Video Area:": "Videoala:", + "Video Time:": "Video aeg:", + "Video Out Time:": "Video lõppaeg:", + "Video Mode Width:": "Videorežiimi laius:", + "Video Mode Height:": "Videorežiimi kõrgus:", + "Documentation": "Dokumentatsioon", + "Drag Viewport": "Lohistamisvaade", + "KasmVNC encountered an error:": "KasmVNC-s ilmnes viga:" +} \ No newline at end of file diff --git a/app/locale/et_EE.json b/app/locale/et_EE.json new file mode 100644 index 0000000..acc419f --- /dev/null +++ b/app/locale/et_EE.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ühendamine...", + "Disconnecting...": "Ühendust katkestatakse...", + "Reconnecting...": "Taasühendamine...", + "Internal error": "Sisemine viga", + "Must set host": "Peab hosti määrama", + "Connected (encrypted) to ": "Ühendatud (krüpteeritud) võrguga ", + "Connected (unencrypted) to ": "Ühendatud (krüpteerimata) võrguga ", + "Something went wrong, connection is closed": "Midagi läks valesti, ühendus on suletud", + "Failed to connect to server": "Serveriga ühenduse loomine nurjus", + "Disconnected": "Katkestatud", + "New connection has been rejected with reason: ": "Uus ühendus on tagasi lükatud põhjusel:", + "New connection has been rejected": "Uus ühendus on tagasi lükatud", + "Credentials are required": "Mandaat on nõutav", + "Hide/Show the control bar": "Peida/kuva juhtriba", + "Drag": "Vedama", + "Move/Drag Viewport": "Teisalda/lohistamisvaade", + "Keyboard": "Klaviatuur", + "Show Keyboard": "Kuva klaviatuur", + "Extra keys": "Lisaklahvid", + "Show Extra Keys": "Näita lisaklahve", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Lülita Ctrl", + "Alt": "Alt", + "Toggle Alt": "Lülita Alt", + "Toggle Windows": "Lülita Windowsi sisse", + "Windows": "Windows", + "Send Tab": "Saada vahekaart", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Saada põgenemine", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Saada Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "Võim", + "Shutdown": "Lülita välja", + "Reboot": "Taaskäivitamine", + "Reset": "Lähtesta", + "Clipboard": "Lõikelaud", + "Clear": "Tühjenda", + "Fullscreen": "Täisekraan", + "Settings": "Seaded", + "Shared Mode": "Jagatud režiim", + "View Only": "Ainult vaatamine", + "Clip to Window": "Klip aknasse", + "Scaling Mode:": "Skaleerimisrežiim:", + "None": "Mitte ükski", + "Local Scaling": "Kohalik skaleerimine", + "Remote Resizing": "Suuruse kaugmuutmine", + "Advanced": "Täpsem", + "Quality:": "Kvaliteet:", + "Compression level:": "Tihenduse tase:", + "Repeater ID:": "Repeateri ID:", + "WebSocket": "WebSocket", + "Encrypt": "Krüpti", + "Host:": "Võõrustaja:", + "Port:": "Sadam:", + "Path:": "Tee:", + "Automatic Reconnect": "Automaatne taasühendamine", + "Reconnect Delay (ms):": "Taasühendamise viivitus (ms):", + "Show Dot when No Cursor": "Näita punkti, kui kursorit pole", + "Logging:": "Logimine:", + "Version:": "Versioon:", + "Disconnect": "Katkesta ühendus", + "Connect": "Ühenda", + "Username:": "Kasutajanimi:", + "Password:": "Parool:", + "Send Credentials": "Saada mandaadid", + "Cancel": "Tühista", + "Keys": "Võtmed", + "Game Cursor Mode": "Mängu kursori režiim", + "Press Esc Key to Exit Pointer Lock Mode": "Osuri lukustusrežiimist väljumiseks vajutage klahvi Esc", + "Game Mode paused, click on screen to resume Game Mode.": "Mängurežiim peatatud, mängurežiimi jätkamiseks klõpsake ekraanil.", + "Clipboard Up": "Lõikelaud üles", + "CLipboard Down": "Lõikelaud alla", + "Clipboard Seamless": "Sujuv lõikelaud", + "Prefer Local Cursor": "Eelista kohalikku kursorit", + "Translate keyboard shortcuts": "Tõlgi klaviatuuri otseteed", + "Enable WebRTC UDP Transit": "Luba WebRTC UDP Transit", + "Enable WebP Compression": "Luba WebP tihendamine", + "Enable Performance Stats": "Luba jõudlusstatistika", + "Enable Pointer Lock": "Luba kursori lukk", + "IME Input Mode": "IME sisestusrežiim", + "Show Virtual Keyboard Control": "Kuva virtuaalse klaviatuuri juhtimine", + "Toggle Control Panel via Keystrokes": "Lülita juhtpaneeli klahvivajutuste kaudu sisse", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Klaviatuuri otseteed", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC kiirklahvide lubamine", + "1 - Toggle Control Panel": "1 – juhtpaneeli sisse- ja väljalülitamine", + "2 - Toggle Game Pointer Mode": "2 - Mängu osuti režiimi sisse- ja väljalülitamine", + "3 - Toggle Pointer Lock": "3 – Lülita kursori lukustus sisse", + "Stream Quality": "Voo kvaliteet", + "Preset Modes:": "Eelseadistatud režiimid:", + "Static": "Staatiline", + "Low": "Madal", + "Medium": "Keskmine", + "High": "Kõrge", + "Extreme": "Äärmuslik", + "Lossless": "Kaotusteta", + "Custom": "Kohandatud", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Automaatne dünaamiline", + "Off": "Väljas", + "On": "Peal", + "Dynamic Quality Min:": "Dünaamiline kvaliteet min:", + "Dynamic Quality Max:": "Dünaamiline kvaliteet max:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Kaadrisagedus:", + "Video JPEG Quality:": "Video JPEG kvaliteet:", + "Video WEBP Quality:": "Video WEBP kvaliteet:", + "Video Area:": "Videoala:", + "Video Time:": "Video aeg:", + "Video Out Time:": "Video lõppaeg:", + "Video Mode Width:": "Videorežiimi laius:", + "Video Mode Height:": "Videorežiimi kõrgus:", + "Documentation": "Dokumentatsioon", + "Drag Viewport": "Lohistamisvaade", + "KasmVNC encountered an error:": "KasmVNC-s ilmnes viga:" +} \ No newline at end of file diff --git a/app/locale/eu.json b/app/locale/eu.json new file mode 100644 index 0000000..71016a2 --- /dev/null +++ b/app/locale/eu.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Konektatzen...", + "Disconnecting...": "Deskonektatzen...", + "Reconnecting...": "Berriz konektatzen...", + "Internal error": "Barne akatsa", + "Must set host": "Ostalari ezarri behar da", + "Connected (encrypted) to ": "Konektatuta (zifratuta)", + "Connected (unencrypted) to ": "Konektatuta (zifratu gabe)", + "Something went wrong, connection is closed": "Arazoren bat izan da, konexioa itxita dago", + "Failed to connect to server": "Ezin izan da zerbitzariarekin konektatu", + "Disconnected": "Deskonektatuta", + "New connection has been rejected with reason: ": "Konexio berria arrazoiarekin baztertu da:", + "New connection has been rejected": "Konexio berria baztertu da", + "Credentials are required": "Kredentzialak behar dira", + "Hide/Show the control bar": "Ezkutatu/Erakutsi kontrol-barra", + "Drag": "Arrastatu", + "Move/Drag Viewport": "Mugitu/Arrastatu ikuspegia", + "Keyboard": "Teklatua", + "Show Keyboard": "Erakutsi teklatua", + "Extra keys": "Gako gehigarriak", + "Show Extra Keys": "Erakutsi gako gehigarriak", + "Ctrl": "Ktrl", + "Toggle Ctrl": "Aktibatu Ctrl", + "Alt": "Alt", + "Toggle Alt": "Aktibatu Alt", + "Toggle Windows": "Aktibatu Windows", + "Windows": "Windows", + "Send Tab": "Bidali fitxa", + "Tab": "Fitxa", + "Esc": "Esc", + "Send Escape": "Bidali ihesa", + "Ctrl+Alt+Del": "Ktrl+Alt+Del", + "Send Ctrl-Alt-Del": "Bidali Ctrl-Alt-Del", + "Shutdown/Reboot": "Itzali/Berrabiarazi", + "Shutdown/Reboot...": "Itzali/Berrabiarazi...", + "Power": "Botere", + "Shutdown": "Itzali", + "Reboot": "Berrabiarazi", + "Reset": "Berrezarri", + "Clipboard": "Arbela", + "Clear": "Argi", + "Fullscreen": "Pantaila osoa", + "Settings": "Ezarpenak", + "Shared Mode": "Modu partekatua", + "View Only": "Ikusi bakarrik", + "Clip to Window": "Kliptu leihora", + "Scaling Mode:": "Eskalatzeko modua:", + "None": "Inor ez", + "Local Scaling": "Tokiko eskalatzea", + "Remote Resizing": "Urrutiko tamaina aldatzea", + "Advanced": "Aurreratua", + "Quality:": "Kalitatea:", + "Compression level:": "Konpresio maila:", + "Repeater ID:": "Errepikatzailearen IDa:", + "WebSocket": "WebSocket", + "Encrypt": "Enkriptatu", + "Host:": "Ostalaria:", + "Port:": "Porta:", + "Path:": "Bidea:", + "Automatic Reconnect": "Birkonektatu automatikoa", + "Reconnect Delay (ms):": "Birkonektatzeko atzerapena (ms):", + "Show Dot when No Cursor": "Erakutsi puntua kurtsorerik ez dagoenean", + "Logging:": "Erregistroa:", + "Version:": "Bertsioa:", + "Disconnect": "Deskonektatu", + "Connect": "Konektatu", + "Username:": "Erabiltzaile izena:", + "Password:": "Pasahitza:", + "Send Credentials": "Bidali kredentzialak", + "Cancel": "Utzi", + "Keys": "Giltzak", + "Game Cursor Mode": "Joko kurtsore modua", + "Press Esc Key to Exit Pointer Lock Mode": "Sakatu Esc tekla erakuslea blokeatzeko modua irteteko", + "Game Mode paused, click on screen to resume Game Mode.": "Joko modua pausatu da, egin klik pantailan Joko modua berriro hasteko", + "Clipboard Up": "Arbela gora", + "CLipboard Down": "Arbela behera", + "Clipboard Seamless": "Arbelenik gabe", + "Prefer Local Cursor": "Hobestu tokiko kurtsorea", + "Translate keyboard shortcuts": "Itzuli teklatuko lasterbideak", + "Enable WebRTC UDP Transit": "Gaitu WebRTC UDP Transit", + "Enable WebP Compression": "Gaitu WebP konpresioa", + "Enable Performance Stats": "Gaitu errendimendu-estatistikak", + "Enable Pointer Lock": "Gaitu Erakuslearen blokeoa", + "IME Input Mode": "IME Sarrera modua", + "Show Virtual Keyboard Control": "Erakutsi teklatu birtuala kontrola", + "Toggle Control Panel via Keystrokes": "Aldatu kontrol panela tekla sakatuen bidez", + "Render Native Resolution": "Errendatu jatorrizko ebazpena", + "Keyboard Shortcuts": "Teklatuko lasterbideak", + "Enable KasmVNC Keyboard Shortcuts": "Gaitu KasmVNC teklatu-lasterbideak", + "1 - Toggle Control Panel": "1 - Aldatu kontrol panela", + "2 - Toggle Game Pointer Mode": "2 - Aldatu joko erakuslea modua", + "3 - Toggle Pointer Lock": "3 - Erakuslea blokeatzea", + "Stream Quality": "Korrika-kalitatea", + "Preset Modes:": "Aurrez ezarritako moduak:", + "Static": "Estatikoa", + "Low": "Baxua", + "Medium": "Ertaina", + "High": "Altua", + "Extreme": "Muturreko", + "Lossless": "Galerik gabekoa", + "Custom": "Pertsonalizatua", + "Anti-Aliasing:": "Aliasingaren aurkakoa:", + "Auto Dynamic": "Auto dinamikoa", + "Off": "Desaktibatuta", + "On": "Aktibatuta", + "Dynamic Quality Min:": "Kalitate dinamikoa minimoa:", + "Dynamic Quality Max:": "Kalitate dinamikoa gehienez:", + "Treat Lossless:": "Tratatu Lossless:", + "Frame Rate:": "Fotograma-tasa:", + "Video JPEG Quality:": "Bideoaren JPEG kalitatea:", + "Video WEBP Quality:": "Bideoaren WEBP kalitatea:", + "Video Area:": "Bideo eremua:", + "Video Time:": "Bideoaren denbora:", + "Video Out Time:": "Bideoa ateratzeko ordua:", + "Video Mode Width:": "Bideo moduaren zabalera:", + "Video Mode Height:": "Bideo moduaren altuera:", + "Documentation": "Dokumentazioa", + "Drag Viewport": "Arrastatu ikuspegia", + "KasmVNC encountered an error:": "KasmVNC-k errore bat aurkitu du:" +} \ No newline at end of file diff --git a/app/locale/eu_ES.json b/app/locale/eu_ES.json new file mode 100644 index 0000000..71016a2 --- /dev/null +++ b/app/locale/eu_ES.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Konektatzen...", + "Disconnecting...": "Deskonektatzen...", + "Reconnecting...": "Berriz konektatzen...", + "Internal error": "Barne akatsa", + "Must set host": "Ostalari ezarri behar da", + "Connected (encrypted) to ": "Konektatuta (zifratuta)", + "Connected (unencrypted) to ": "Konektatuta (zifratu gabe)", + "Something went wrong, connection is closed": "Arazoren bat izan da, konexioa itxita dago", + "Failed to connect to server": "Ezin izan da zerbitzariarekin konektatu", + "Disconnected": "Deskonektatuta", + "New connection has been rejected with reason: ": "Konexio berria arrazoiarekin baztertu da:", + "New connection has been rejected": "Konexio berria baztertu da", + "Credentials are required": "Kredentzialak behar dira", + "Hide/Show the control bar": "Ezkutatu/Erakutsi kontrol-barra", + "Drag": "Arrastatu", + "Move/Drag Viewport": "Mugitu/Arrastatu ikuspegia", + "Keyboard": "Teklatua", + "Show Keyboard": "Erakutsi teklatua", + "Extra keys": "Gako gehigarriak", + "Show Extra Keys": "Erakutsi gako gehigarriak", + "Ctrl": "Ktrl", + "Toggle Ctrl": "Aktibatu Ctrl", + "Alt": "Alt", + "Toggle Alt": "Aktibatu Alt", + "Toggle Windows": "Aktibatu Windows", + "Windows": "Windows", + "Send Tab": "Bidali fitxa", + "Tab": "Fitxa", + "Esc": "Esc", + "Send Escape": "Bidali ihesa", + "Ctrl+Alt+Del": "Ktrl+Alt+Del", + "Send Ctrl-Alt-Del": "Bidali Ctrl-Alt-Del", + "Shutdown/Reboot": "Itzali/Berrabiarazi", + "Shutdown/Reboot...": "Itzali/Berrabiarazi...", + "Power": "Botere", + "Shutdown": "Itzali", + "Reboot": "Berrabiarazi", + "Reset": "Berrezarri", + "Clipboard": "Arbela", + "Clear": "Argi", + "Fullscreen": "Pantaila osoa", + "Settings": "Ezarpenak", + "Shared Mode": "Modu partekatua", + "View Only": "Ikusi bakarrik", + "Clip to Window": "Kliptu leihora", + "Scaling Mode:": "Eskalatzeko modua:", + "None": "Inor ez", + "Local Scaling": "Tokiko eskalatzea", + "Remote Resizing": "Urrutiko tamaina aldatzea", + "Advanced": "Aurreratua", + "Quality:": "Kalitatea:", + "Compression level:": "Konpresio maila:", + "Repeater ID:": "Errepikatzailearen IDa:", + "WebSocket": "WebSocket", + "Encrypt": "Enkriptatu", + "Host:": "Ostalaria:", + "Port:": "Porta:", + "Path:": "Bidea:", + "Automatic Reconnect": "Birkonektatu automatikoa", + "Reconnect Delay (ms):": "Birkonektatzeko atzerapena (ms):", + "Show Dot when No Cursor": "Erakutsi puntua kurtsorerik ez dagoenean", + "Logging:": "Erregistroa:", + "Version:": "Bertsioa:", + "Disconnect": "Deskonektatu", + "Connect": "Konektatu", + "Username:": "Erabiltzaile izena:", + "Password:": "Pasahitza:", + "Send Credentials": "Bidali kredentzialak", + "Cancel": "Utzi", + "Keys": "Giltzak", + "Game Cursor Mode": "Joko kurtsore modua", + "Press Esc Key to Exit Pointer Lock Mode": "Sakatu Esc tekla erakuslea blokeatzeko modua irteteko", + "Game Mode paused, click on screen to resume Game Mode.": "Joko modua pausatu da, egin klik pantailan Joko modua berriro hasteko", + "Clipboard Up": "Arbela gora", + "CLipboard Down": "Arbela behera", + "Clipboard Seamless": "Arbelenik gabe", + "Prefer Local Cursor": "Hobestu tokiko kurtsorea", + "Translate keyboard shortcuts": "Itzuli teklatuko lasterbideak", + "Enable WebRTC UDP Transit": "Gaitu WebRTC UDP Transit", + "Enable WebP Compression": "Gaitu WebP konpresioa", + "Enable Performance Stats": "Gaitu errendimendu-estatistikak", + "Enable Pointer Lock": "Gaitu Erakuslearen blokeoa", + "IME Input Mode": "IME Sarrera modua", + "Show Virtual Keyboard Control": "Erakutsi teklatu birtuala kontrola", + "Toggle Control Panel via Keystrokes": "Aldatu kontrol panela tekla sakatuen bidez", + "Render Native Resolution": "Errendatu jatorrizko ebazpena", + "Keyboard Shortcuts": "Teklatuko lasterbideak", + "Enable KasmVNC Keyboard Shortcuts": "Gaitu KasmVNC teklatu-lasterbideak", + "1 - Toggle Control Panel": "1 - Aldatu kontrol panela", + "2 - Toggle Game Pointer Mode": "2 - Aldatu joko erakuslea modua", + "3 - Toggle Pointer Lock": "3 - Erakuslea blokeatzea", + "Stream Quality": "Korrika-kalitatea", + "Preset Modes:": "Aurrez ezarritako moduak:", + "Static": "Estatikoa", + "Low": "Baxua", + "Medium": "Ertaina", + "High": "Altua", + "Extreme": "Muturreko", + "Lossless": "Galerik gabekoa", + "Custom": "Pertsonalizatua", + "Anti-Aliasing:": "Aliasingaren aurkakoa:", + "Auto Dynamic": "Auto dinamikoa", + "Off": "Desaktibatuta", + "On": "Aktibatuta", + "Dynamic Quality Min:": "Kalitate dinamikoa minimoa:", + "Dynamic Quality Max:": "Kalitate dinamikoa gehienez:", + "Treat Lossless:": "Tratatu Lossless:", + "Frame Rate:": "Fotograma-tasa:", + "Video JPEG Quality:": "Bideoaren JPEG kalitatea:", + "Video WEBP Quality:": "Bideoaren WEBP kalitatea:", + "Video Area:": "Bideo eremua:", + "Video Time:": "Bideoaren denbora:", + "Video Out Time:": "Bideoa ateratzeko ordua:", + "Video Mode Width:": "Bideo moduaren zabalera:", + "Video Mode Height:": "Bideo moduaren altuera:", + "Documentation": "Dokumentazioa", + "Drag Viewport": "Arrastatu ikuspegia", + "KasmVNC encountered an error:": "KasmVNC-k errore bat aurkitu du:" +} \ No newline at end of file diff --git a/app/locale/fa.json b/app/locale/fa.json new file mode 100644 index 0000000..614a46d --- /dev/null +++ b/app/locale/fa.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻁﺎﺒﺗﺭﺍ ﯼﺭﺍﺮﻗﺮﺑ", + "Disconnecting...": "ﻁﺎﺒﺗﺭﺍ ﻊﻄﻗ", + "Reconnecting...": "ﺩﺪﺠﻣ ﻞﺻﻭ", + "Internal error": "ﯽﻠﺧﺍﺩ ﯼﺎﻄﺧ", + "Must set host": "ﺩﻮﺷ ﻢﯿﻈﻨﺗ ﺪﯾﺎﺑ ﻥﺎﺑﺰﯿﻣ", + "Connected (encrypted) to ": "ﻪﺑ (ﻩﺪﺷ ﯼﺭﺍﺬﮔﺰﻣﺭ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ﻪﺑ (ﺰﻣﺭ ﻥﻭﺪﺑ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﺖﺳﺍ ﻪﺘﺴﺑ ﻝﺎﺼﺗﺍ ،ﺪﻣﺁ ﺶﯿﭘ ﯽﻠﮑﺸﻣ", + "Failed to connect to server": "ﺪﺸﻧ ﻦﮑﻤﻣ ﺭﻭﺮﺳ ﻪﺑ ﻝﺎﺼﺗﺍ", + "Disconnected": "ﻩﺪﺷ ﻊﻄﻗ", + "New connection has been rejected with reason: ": "ﺖﺳﺍ ﻩﺪﺷ ﺩﺭ ﻞﯿﻟﺩ ﺎﺑ ﺪﯾﺪﺟ ﻁﺎﺒﺗﺭﺍ", + "New connection has been rejected": "ﺖﺳﺍ ﻩﺪﺷ ﺩﺭ ﺪﯾﺪﺟ ﻝﺎﺼﺗﺍ", + "Credentials are required": "ﺖﺳﺍ ﻡﺯﻻ ﮎﺭﺍﺪﻣ", + "Hide/Show the control bar": "ﻝﺮﺘﻨﮐ ﺭﺍﻮﻧ ﺶﯾﺎﻤﻧ/ﻥﺩﺮﮐ ﻥﺎﻬﻨﭘ", + "Drag": "ﻥﺪﯿﺸﮐ", + "Move/Drag Viewport": "Move/Drag Viewport", + "Keyboard": "ﺪﯿﻠﮐ ﻪﺤﻔﺻ", + "Show Keyboard": "ﺪﯿﻠﮐ ﻪﺤﻔﺻ ﺶﯾﺎﻤﻧ", + "Extra keys": "ﯽﻓﺎﺿﺍ ﯼﺎﻫﺪﯿﻠﮐ", + "Show Extra Keys": "ﯽﻓﺎﺿﺍ ﯼﺎﻫﺪﯿﻠﮐ ﺶﯾﺎﻤﻧ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ﺮﯿﯿﻐﺗ", + "Alt": "Alt", + "Toggle Alt": "Alt ﺮﯿﯿﻐﺗ", + "Toggle Windows": "ﺯﻭﺪﻨﯾﻭ ﺮﯿﯿﻐﺗ", + "Windows": "ﺎﻫ ﻩﺮﺠﻨﭘ", + "Send Tab": "ﻪﮔﺮﺑ ﻝﺎﺳﺭﺍ", + "Tab": "ﺐﺗ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺭﺍﺮﻓ ﻝﺎﺳﺭﺍ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺍ", + "Shutdown/Reboot": "ﺩﺪﺠﻣ ﯼﺯﺍﺪﻧﺍ ﻩﺍﺭ/ﻥﺩﺮﮐ ﺵﻮﻣﺎﺧ", + "Shutdown/Reboot...": "ﺩﺪﺠﻣ ﯼﺯﺍﺪﻧﺍ ﻩﺍﺭ/ﻥﺩﺮﮐ ﺵﻮﻣﺎﺧ", + "Power": "ﺕﺭﺪﻗ", + "Shutdown": "ﻥﺪﺷ ﺵﻮﻣﺎﺧ", + "Reboot": "ﺩﺪﺠﻣ ﯼﺯﺍﺪﻧﺍ ﻩﺍﺭ", + "Reset": "ﯽﻧﺎﺸﻧﺯﺎﺑ", + "Clipboard": "ﺩﺭﻮﺑ ﭗﯿﻠﮐ", + "Clear": "ﻥﺩﺮﮐ ﮎﺎﭘ", + "Fullscreen": "ﻪﺤﻔﺻ ﻡﺎﻤﺗ", + "Settings": "ﺕﺎﻤﯿﻈﻨﺗ", + "Shared Mode": "ﯽﮐﺍﺮﺘﺷﺍ ﺖﻟﺎﺣ", + "View Only": "ﻩﺪﻫﺎﺸﻣ ﻂﻘﻓ", + "Clip to Window": "ﻩﺮﺠﻨﭘ ﻪﺑ ﭗﯿﻠﮐ", + "Scaling Mode:": "ﯼﺪﻨﺑ ﺱﺎﯿﻘﻣ ﺖﻟﺎﺣ", + "None": "ﮏﯾ ﭻﯿﻫ", + "Local Scaling": "ﯽﻠﺤﻣ ﯼﺪﻨﺑ ﺱﺎﯿﻘﻣ", + "Remote Resizing": "ﺭﻭﺩ ﻩﺍﺭ ﺯﺍ ﻩﺯﺍﺪﻧﺍ ﺮﯿﯿﻐﺗ", + "Advanced": "ﻪﺘﻓﺮﺸﯿﭘ", + "Quality:": "ﺖﯿﻔﯿﮐ", + "Compression level:": "ﯼﺯﺎﺳ ﻩﺩﺮﺸﻓ ﺢﻄﺳ", + "Repeater ID:": "ﻩﺪﻨﻨﮐ ﺭﺍﺮﮑﺗ ﻪﺳﺎﻨﺷ", + "WebSocket": "ﺖﮐﻮﺳ ﺏﻭ", + "Encrypt": "ﯼﺭﺍﺬﮔﺰﻣﺭ", + "Host:": "ﻥﺎﺑﺰﯿﻣ", + "Port:": "ﺭﺪﻨﺑ", + "Path:": "ﺮﯿﺴﻣ", + "Automatic Reconnect": "ﺭﺎﮐﺩﻮﺧ ﺩﺪﺠﻣ ﻝﺎﺼﺗﺍ", + "Reconnect Delay (ms):": "(ms) ﺩﺪﺠﻣ ﻝﺎﺼﺗﺍ ﺮﯿﺧﺎﺗ", + "Show Dot when No Cursor": "ﺎﻤﻧ ﻥﺎﮑﻣ ﻡﺪﻋ ﺕﺭﻮﺻ ﺭﺩ ﻪﻄﻘﻧ ﺶﯾﺎﻤﻧ", + "Logging:": "ﻢﺘﺴﯿﺳ ﻪﺑ ﺩﻭﺭﻭ", + "Version:": "ﻪﺨﺴﻧ", + "Disconnect": "ﻥﺪﺷ ﻊﻄﻗ", + "Connect": "ﻝﺎﺼﺗﺍ", + "Username:": "ﯼﺮﺑﺭﺎﮐ ﻡﺎﻧ", + "Password:": "ﺭﻮﺒﻋ ﻪﻤﻠﮐ", + "Send Credentials": "ﯼﺭﺎﺒﺘﻋﺍ ﮎﺭﺍﺪﻣ ﻝﺎﺳﺭﺍ", + "Cancel": "ﻮﻐﻟ", + "Keys": "ﺎﻫﺪﯿﻠﮐ", + "Game Cursor Mode": "ﯼﺯﺎﺑ ﺎﻤﻧ ﻥﺎﮑﻣ ﺖﻟﺎﺣ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺪﯿﻫﺩ ﺭﺎﺸﻓ ﺮﮔ ﻩﺭﺎﺷﺍ ﻞﻔﻗ ﺖﻟﺎﺣ ﺯﺍ ﺝﻭﺮﺧ ﯼﺍﺮﺑ ﺍﺭ Esc ﺪﯿﻠﮐ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺪﯿﻨﮐ ﮏﯿﻠﮐ ﻪﺤﻔﺻ ﯼﻭﺭ ﯼﺯﺎﺑ ﺖﻟﺎﺣ ﯼﺮﯿﮔﺮﺳ ﺯﺍ ﯼﺍﺮﺑ ،ﺪﺷ ﻒﻗﻮﺘﻣ ﯼﺯﺎﺑ ﺖﻟﺎﺣ", + "Clipboard Up": "ﺩﺭﻮﺑ ﭗﯿﻠﮐ ﻻﺎﺑ", + "CLipboard Down": "ﻦﯿﯾﺎﭘ ﺩﺭﻮﺑ ﭗﯿﻠﮐ", + "Clipboard Seamless": "ﺯﺭﺩ ﻥﻭﺪﺑ ﺩﺭﻮﺑ ﭗﯿﻠﮐ", + "Prefer Local Cursor": "ﯽﻠﺤﻣ ﺎﻤﻧ ﻥﺎﮑﻣ ﺢﯿﺟﺮﺗ", + "Translate keyboard shortcuts": "ﺪﯿﻠﮐ ﻪﺤﻔﺻ ﯼﺎﻫﺮﺒﻧﺎﯿﻣ ﻪﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻥﺩﺮﮐ ﻝﺎﻌﻓ", + "Enable WebP Compression": "WebP ﯼﺯﺎﺳ ﻩﺩﺮﺸﻓ ﻥﺩﺮﮐ ﻝﺎﻌﻓ", + "Enable Performance Stats": "ﺩﺮﮑﻠﻤﻋ ﺭﺎﻣﺁ ﻥﺩﺮﮐ ﻝﺎﻌﻓ", + "Enable Pointer Lock": "Pointer Lock ﻥﺩﺮﮐ ﻝﺎﻌﻓ", + "IME Input Mode": "IME ﯼﺩﻭﺭﻭ ﺖﻟﺎﺣ", + "Show Virtual Keyboard Control": "ﯼﺯﺎﺠﻣ ﺪﯿﻠﮐ ﻪﺤﻔﺻ ﻝﺮﺘﻨﮐ ﺶﯾﺎﻤﻧ", + "Toggle Control Panel via Keystrokes": "ﺪﯿﻠﮐ ﻥﺩﺍﺩ ﺭﺎﺸﻓ ﻖﯾﺮﻃ ﺯﺍ ﻞﻨﭘ ﻝﺮﺘﻨﮐ ﺮﯿﯿﻐﺗ", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "ﺪﯿﻠﮐ ﻪﺤﻔﺻ ﯼﺎﻫﺮﺒﻧﺎﯿﻣ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺪﯿﻠﮐ ﻪﺤﻔﺻ ﯼﺎﻫﺮﺒﻧﺎﯿﻣ ﻥﺩﺮﮐ ﻝﺎﻌﻓ", + "1 - Toggle Control Panel": "ﺪﯿﻫﺩ ﺮﯿﯿﻐﺗ ﺍﺭ ﻞﻨﭘ ﻝﺮﺘﻨﮐ - 1", + "2 - Toggle Game Pointer Mode": "ﯼﺯﺎﺑ ﺮﮕﻧﺎﺸﻧ ﺖﻟﺎﺣ ﺮﯿﯿﻐﺗ - 2", + "3 - Toggle Pointer Lock": "ﺪﯿﻫﺩ ﺮﯿﯿﻐﺗ ﺍﺭ ﺮﮕﻧﺎﺸﻧ ﻞﻔﻗ - 3", + "Stream Quality": "ﻥﺎﯾﺮﺟ ﺖﯿﻔﯿﮐ", + "Preset Modes:": "ﻩﺪﺷ ﻦﯿﯿﻌﺗ ﺶﯿﭘ ﺯﺍ ﯼﺎﻫ ﺖﻟﺎﺣ", + "Static": "ﺎﺘﺴﯾﺍ", + "Low": "ﻢﮐ", + "Medium": "ﻂﺳﻮﺘﻣ", + "High": "ﻻﺎﺑ", + "Extreme": "ﻁﺮﻔﻣ", + "Lossless": "ﺭﺮﺿ ﯽﺑ", + "Custom": "ﯽﺷﺭﺎﻔﺳ", + "Anti-Aliasing:": "ﮓﻨﯿﺳﺎﯿﻟﺁ ﺪﺿ", + "Auto Dynamic": "ﺭﺎﮐﺩﻮﺧ ﮏﯿﻣﺎﻨﯾﺩ", + "Off": "ﺵﻮﻣﺎﺧ", + "On": "ﺮﺑ", + "Dynamic Quality Min:": "ﺎﯾﻮﭘ ﺖﯿﻔﯿﮐ ﻞﻗﺍﺪﺣ", + "Dynamic Quality Max:": "ﺎﯾﻮﭘ ﺖﯿﻔﯿﮐ ﺮﺜﮐﺍﺪﺣ", + "Treat Lossless:": "ﺭﺮﺿ ﻥﻭﺪﺑ ﻥﺎﻣﺭﺩ", + "Frame Rate:": "ﻢﯾﺮﻓ ﺥﺮﻧ", + "Video JPEG Quality:": "JPEG ﻮﺋﺪﯾﻭ ﺖﯿﻔﯿﮐ", + "Video WEBP Quality:": "ﻮﺋﺪﯾﻭ WEBP ﺖﯿﻔﯿﮐ", + "Video Area:": "ﻮﺋﺪﯾﻭ ﻪﻘﻄﻨﻣ", + "Video Time:": "ﻮﺋﺪﯾﻭ ﻥﺎﻣﺯ", + "Video Out Time:": "ﻮﺋﺪﯾﻭ ﺝﻭﺮﺧ ﻥﺎﻣﺯ", + "Video Mode Width:": "ﻮﺋﺪﯾﻭ ﺖﻟﺎﺣ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﺋﺪﯾﻭ ﺖﻟﺎﺣ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﺕﺍﺪﻨﺘﺴﻣ", + "Drag Viewport": "ﺕﺭﻮﭙﯾﺎﻤﻧ ﮒﺭﺩ", + "KasmVNC encountered an error:": "KasmVNC ﺪﺷ ﻪﺟﺍﻮﻣ ﺎﻄﺧ ﮏﯾ ﺎﺑ:" +} \ No newline at end of file diff --git a/app/locale/fa_IR.json b/app/locale/fa_IR.json new file mode 100644 index 0000000..614a46d --- /dev/null +++ b/app/locale/fa_IR.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻁﺎﺒﺗﺭﺍ ﯼﺭﺍﺮﻗﺮﺑ", + "Disconnecting...": "ﻁﺎﺒﺗﺭﺍ ﻊﻄﻗ", + "Reconnecting...": "ﺩﺪﺠﻣ ﻞﺻﻭ", + "Internal error": "ﯽﻠﺧﺍﺩ ﯼﺎﻄﺧ", + "Must set host": "ﺩﻮﺷ ﻢﯿﻈﻨﺗ ﺪﯾﺎﺑ ﻥﺎﺑﺰﯿﻣ", + "Connected (encrypted) to ": "ﻪﺑ (ﻩﺪﺷ ﯼﺭﺍﺬﮔﺰﻣﺭ) ﻞﺼﺘﻣ", + "Connected (unencrypted) to ": "ﻪﺑ (ﺰﻣﺭ ﻥﻭﺪﺑ) ﻞﺼﺘﻣ", + "Something went wrong, connection is closed": "ﺖﺳﺍ ﻪﺘﺴﺑ ﻝﺎﺼﺗﺍ ،ﺪﻣﺁ ﺶﯿﭘ ﯽﻠﮑﺸﻣ", + "Failed to connect to server": "ﺪﺸﻧ ﻦﮑﻤﻣ ﺭﻭﺮﺳ ﻪﺑ ﻝﺎﺼﺗﺍ", + "Disconnected": "ﻩﺪﺷ ﻊﻄﻗ", + "New connection has been rejected with reason: ": "ﺖﺳﺍ ﻩﺪﺷ ﺩﺭ ﻞﯿﻟﺩ ﺎﺑ ﺪﯾﺪﺟ ﻁﺎﺒﺗﺭﺍ", + "New connection has been rejected": "ﺖﺳﺍ ﻩﺪﺷ ﺩﺭ ﺪﯾﺪﺟ ﻝﺎﺼﺗﺍ", + "Credentials are required": "ﺖﺳﺍ ﻡﺯﻻ ﮎﺭﺍﺪﻣ", + "Hide/Show the control bar": "ﻝﺮﺘﻨﮐ ﺭﺍﻮﻧ ﺶﯾﺎﻤﻧ/ﻥﺩﺮﮐ ﻥﺎﻬﻨﭘ", + "Drag": "ﻥﺪﯿﺸﮐ", + "Move/Drag Viewport": "Move/Drag Viewport", + "Keyboard": "ﺪﯿﻠﮐ ﻪﺤﻔﺻ", + "Show Keyboard": "ﺪﯿﻠﮐ ﻪﺤﻔﺻ ﺶﯾﺎﻤﻧ", + "Extra keys": "ﯽﻓﺎﺿﺍ ﯼﺎﻫﺪﯿﻠﮐ", + "Show Extra Keys": "ﯽﻓﺎﺿﺍ ﯼﺎﻫﺪﯿﻠﮐ ﺶﯾﺎﻤﻧ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ﺮﯿﯿﻐﺗ", + "Alt": "Alt", + "Toggle Alt": "Alt ﺮﯿﯿﻐﺗ", + "Toggle Windows": "ﺯﻭﺪﻨﯾﻭ ﺮﯿﯿﻐﺗ", + "Windows": "ﺎﻫ ﻩﺮﺠﻨﭘ", + "Send Tab": "ﻪﮔﺮﺑ ﻝﺎﺳﺭﺍ", + "Tab": "ﺐﺗ", + "Esc": "ﺝﻭﺮﺧ", + "Send Escape": "ﺭﺍﺮﻓ ﻝﺎﺳﺭﺍ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻝﺎﺳﺭﺍ", + "Shutdown/Reboot": "ﺩﺪﺠﻣ ﯼﺯﺍﺪﻧﺍ ﻩﺍﺭ/ﻥﺩﺮﮐ ﺵﻮﻣﺎﺧ", + "Shutdown/Reboot...": "ﺩﺪﺠﻣ ﯼﺯﺍﺪﻧﺍ ﻩﺍﺭ/ﻥﺩﺮﮐ ﺵﻮﻣﺎﺧ", + "Power": "ﺕﺭﺪﻗ", + "Shutdown": "ﻥﺪﺷ ﺵﻮﻣﺎﺧ", + "Reboot": "ﺩﺪﺠﻣ ﯼﺯﺍﺪﻧﺍ ﻩﺍﺭ", + "Reset": "ﯽﻧﺎﺸﻧﺯﺎﺑ", + "Clipboard": "ﺩﺭﻮﺑ ﭗﯿﻠﮐ", + "Clear": "ﻥﺩﺮﮐ ﮎﺎﭘ", + "Fullscreen": "ﻪﺤﻔﺻ ﻡﺎﻤﺗ", + "Settings": "ﺕﺎﻤﯿﻈﻨﺗ", + "Shared Mode": "ﯽﮐﺍﺮﺘﺷﺍ ﺖﻟﺎﺣ", + "View Only": "ﻩﺪﻫﺎﺸﻣ ﻂﻘﻓ", + "Clip to Window": "ﻩﺮﺠﻨﭘ ﻪﺑ ﭗﯿﻠﮐ", + "Scaling Mode:": "ﯼﺪﻨﺑ ﺱﺎﯿﻘﻣ ﺖﻟﺎﺣ", + "None": "ﮏﯾ ﭻﯿﻫ", + "Local Scaling": "ﯽﻠﺤﻣ ﯼﺪﻨﺑ ﺱﺎﯿﻘﻣ", + "Remote Resizing": "ﺭﻭﺩ ﻩﺍﺭ ﺯﺍ ﻩﺯﺍﺪﻧﺍ ﺮﯿﯿﻐﺗ", + "Advanced": "ﻪﺘﻓﺮﺸﯿﭘ", + "Quality:": "ﺖﯿﻔﯿﮐ", + "Compression level:": "ﯼﺯﺎﺳ ﻩﺩﺮﺸﻓ ﺢﻄﺳ", + "Repeater ID:": "ﻩﺪﻨﻨﮐ ﺭﺍﺮﮑﺗ ﻪﺳﺎﻨﺷ", + "WebSocket": "ﺖﮐﻮﺳ ﺏﻭ", + "Encrypt": "ﯼﺭﺍﺬﮔﺰﻣﺭ", + "Host:": "ﻥﺎﺑﺰﯿﻣ", + "Port:": "ﺭﺪﻨﺑ", + "Path:": "ﺮﯿﺴﻣ", + "Automatic Reconnect": "ﺭﺎﮐﺩﻮﺧ ﺩﺪﺠﻣ ﻝﺎﺼﺗﺍ", + "Reconnect Delay (ms):": "(ms) ﺩﺪﺠﻣ ﻝﺎﺼﺗﺍ ﺮﯿﺧﺎﺗ", + "Show Dot when No Cursor": "ﺎﻤﻧ ﻥﺎﮑﻣ ﻡﺪﻋ ﺕﺭﻮﺻ ﺭﺩ ﻪﻄﻘﻧ ﺶﯾﺎﻤﻧ", + "Logging:": "ﻢﺘﺴﯿﺳ ﻪﺑ ﺩﻭﺭﻭ", + "Version:": "ﻪﺨﺴﻧ", + "Disconnect": "ﻥﺪﺷ ﻊﻄﻗ", + "Connect": "ﻝﺎﺼﺗﺍ", + "Username:": "ﯼﺮﺑﺭﺎﮐ ﻡﺎﻧ", + "Password:": "ﺭﻮﺒﻋ ﻪﻤﻠﮐ", + "Send Credentials": "ﯼﺭﺎﺒﺘﻋﺍ ﮎﺭﺍﺪﻣ ﻝﺎﺳﺭﺍ", + "Cancel": "ﻮﻐﻟ", + "Keys": "ﺎﻫﺪﯿﻠﮐ", + "Game Cursor Mode": "ﯼﺯﺎﺑ ﺎﻤﻧ ﻥﺎﮑﻣ ﺖﻟﺎﺣ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺪﯿﻫﺩ ﺭﺎﺸﻓ ﺮﮔ ﻩﺭﺎﺷﺍ ﻞﻔﻗ ﺖﻟﺎﺣ ﺯﺍ ﺝﻭﺮﺧ ﯼﺍﺮﺑ ﺍﺭ Esc ﺪﯿﻠﮐ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺪﯿﻨﮐ ﮏﯿﻠﮐ ﻪﺤﻔﺻ ﯼﻭﺭ ﯼﺯﺎﺑ ﺖﻟﺎﺣ ﯼﺮﯿﮔﺮﺳ ﺯﺍ ﯼﺍﺮﺑ ،ﺪﺷ ﻒﻗﻮﺘﻣ ﯼﺯﺎﺑ ﺖﻟﺎﺣ", + "Clipboard Up": "ﺩﺭﻮﺑ ﭗﯿﻠﮐ ﻻﺎﺑ", + "CLipboard Down": "ﻦﯿﯾﺎﭘ ﺩﺭﻮﺑ ﭗﯿﻠﮐ", + "Clipboard Seamless": "ﺯﺭﺩ ﻥﻭﺪﺑ ﺩﺭﻮﺑ ﭗﯿﻠﮐ", + "Prefer Local Cursor": "ﯽﻠﺤﻣ ﺎﻤﻧ ﻥﺎﮑﻣ ﺢﯿﺟﺮﺗ", + "Translate keyboard shortcuts": "ﺪﯿﻠﮐ ﻪﺤﻔﺻ ﯼﺎﻫﺮﺒﻧﺎﯿﻣ ﻪﻤﺟﺮﺗ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ﻥﺩﺮﮐ ﻝﺎﻌﻓ", + "Enable WebP Compression": "WebP ﯼﺯﺎﺳ ﻩﺩﺮﺸﻓ ﻥﺩﺮﮐ ﻝﺎﻌﻓ", + "Enable Performance Stats": "ﺩﺮﮑﻠﻤﻋ ﺭﺎﻣﺁ ﻥﺩﺮﮐ ﻝﺎﻌﻓ", + "Enable Pointer Lock": "Pointer Lock ﻥﺩﺮﮐ ﻝﺎﻌﻓ", + "IME Input Mode": "IME ﯼﺩﻭﺭﻭ ﺖﻟﺎﺣ", + "Show Virtual Keyboard Control": "ﯼﺯﺎﺠﻣ ﺪﯿﻠﮐ ﻪﺤﻔﺻ ﻝﺮﺘﻨﮐ ﺶﯾﺎﻤﻧ", + "Toggle Control Panel via Keystrokes": "ﺪﯿﻠﮐ ﻥﺩﺍﺩ ﺭﺎﺸﻓ ﻖﯾﺮﻃ ﺯﺍ ﻞﻨﭘ ﻝﺮﺘﻨﮐ ﺮﯿﯿﻐﺗ", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "ﺪﯿﻠﮐ ﻪﺤﻔﺻ ﯼﺎﻫﺮﺒﻧﺎﯿﻣ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺪﯿﻠﮐ ﻪﺤﻔﺻ ﯼﺎﻫﺮﺒﻧﺎﯿﻣ ﻥﺩﺮﮐ ﻝﺎﻌﻓ", + "1 - Toggle Control Panel": "ﺪﯿﻫﺩ ﺮﯿﯿﻐﺗ ﺍﺭ ﻞﻨﭘ ﻝﺮﺘﻨﮐ - 1", + "2 - Toggle Game Pointer Mode": "ﯼﺯﺎﺑ ﺮﮕﻧﺎﺸﻧ ﺖﻟﺎﺣ ﺮﯿﯿﻐﺗ - 2", + "3 - Toggle Pointer Lock": "ﺪﯿﻫﺩ ﺮﯿﯿﻐﺗ ﺍﺭ ﺮﮕﻧﺎﺸﻧ ﻞﻔﻗ - 3", + "Stream Quality": "ﻥﺎﯾﺮﺟ ﺖﯿﻔﯿﮐ", + "Preset Modes:": "ﻩﺪﺷ ﻦﯿﯿﻌﺗ ﺶﯿﭘ ﺯﺍ ﯼﺎﻫ ﺖﻟﺎﺣ", + "Static": "ﺎﺘﺴﯾﺍ", + "Low": "ﻢﮐ", + "Medium": "ﻂﺳﻮﺘﻣ", + "High": "ﻻﺎﺑ", + "Extreme": "ﻁﺮﻔﻣ", + "Lossless": "ﺭﺮﺿ ﯽﺑ", + "Custom": "ﯽﺷﺭﺎﻔﺳ", + "Anti-Aliasing:": "ﮓﻨﯿﺳﺎﯿﻟﺁ ﺪﺿ", + "Auto Dynamic": "ﺭﺎﮐﺩﻮﺧ ﮏﯿﻣﺎﻨﯾﺩ", + "Off": "ﺵﻮﻣﺎﺧ", + "On": "ﺮﺑ", + "Dynamic Quality Min:": "ﺎﯾﻮﭘ ﺖﯿﻔﯿﮐ ﻞﻗﺍﺪﺣ", + "Dynamic Quality Max:": "ﺎﯾﻮﭘ ﺖﯿﻔﯿﮐ ﺮﺜﮐﺍﺪﺣ", + "Treat Lossless:": "ﺭﺮﺿ ﻥﻭﺪﺑ ﻥﺎﻣﺭﺩ", + "Frame Rate:": "ﻢﯾﺮﻓ ﺥﺮﻧ", + "Video JPEG Quality:": "JPEG ﻮﺋﺪﯾﻭ ﺖﯿﻔﯿﮐ", + "Video WEBP Quality:": "ﻮﺋﺪﯾﻭ WEBP ﺖﯿﻔﯿﮐ", + "Video Area:": "ﻮﺋﺪﯾﻭ ﻪﻘﻄﻨﻣ", + "Video Time:": "ﻮﺋﺪﯾﻭ ﻥﺎﻣﺯ", + "Video Out Time:": "ﻮﺋﺪﯾﻭ ﺝﻭﺮﺧ ﻥﺎﻣﺯ", + "Video Mode Width:": "ﻮﺋﺪﯾﻭ ﺖﻟﺎﺣ ﺽﺮﻋ", + "Video Mode Height:": "ﻮﺋﺪﯾﻭ ﺖﻟﺎﺣ ﻉﺎﻔﺗﺭﺍ", + "Documentation": "ﺕﺍﺪﻨﺘﺴﻣ", + "Drag Viewport": "ﺕﺭﻮﭙﯾﺎﻤﻧ ﮒﺭﺩ", + "KasmVNC encountered an error:": "KasmVNC ﺪﺷ ﻪﺟﺍﻮﻣ ﺎﻄﺧ ﮏﯾ ﺎﺑ:" +} \ No newline at end of file diff --git a/app/locale/fi.json b/app/locale/fi.json new file mode 100644 index 0000000..4cd1fd7 --- /dev/null +++ b/app/locale/fi.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Yhdistetään...", + "Disconnecting...": "Katkaistaan...", + "Reconnecting...": "Yhdistetään uudelleen...", + "Internal error": "Sisäinen virhe", + "Must set host": "Täytyy asettaa isäntä", + "Connected (encrypted) to ": "Yhdistetty (salattu) kohteeseen", + "Connected (unencrypted) to ": "Yhdistetty (salaamaton) kohteeseen", + "Something went wrong, connection is closed": "Jotain meni pieleen, yhteys on suljettu", + "Failed to connect to server": "Yhteyttä palvelimeen ei voitu muodostaa", + "Disconnected": "Katkaistu", + "New connection has been rejected with reason: ": "Uusi yhteys on hylätty syystä:", + "New connection has been rejected": "Uusi yhteys on hylätty", + "Credentials are required": "Kirjaustiedot vaaditaan", + "Hide/Show the control bar": "Piilota/näytä ohjauspalkki", + "Drag": "Raahata", + "Move/Drag Viewport": "Siirrä/vedä-näkymä", + "Keyboard": "Näppäimistö", + "Show Keyboard": "Näytä näppäimistö", + "Extra keys": "Lisäavaimet", + "Show Extra Keys": "Näytä lisänäppäimet", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Vaihda Ctrl", + "Alt": "Alt", + "Toggle Alt": "Vaihda Alt", + "Toggle Windows": "Vaihda Windows", + "Windows": "Windows", + "Send Tab": "Lähetä välilehti", + "Tab": "välilehti", + "Esc": "Poistu", + "Send Escape": "Lähetä pako", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Lähetä Ctrl-Alt-Del", + "Shutdown/Reboot": "Sammuta/käynnistetään uudelleen", + "Shutdown/Reboot...": "Sammuta/käynnistetään uudelleen...", + "Power": "Voima", + "Shutdown": "Sammuttaa", + "Reboot": "Käynnistä uudelleen", + "Reset": "Palauta", + "Clipboard": "Leikepöytä", + "Clear": "Asia selvä", + "Fullscreen": "Koko näyttö", + "Settings": "Asetukset", + "Shared Mode": "Jaettu tila", + "View Only": "Vain katsella", + "Clip to Window": "Leike ikkunaan", + "Scaling Mode:": "Skaalaustila:", + "None": "Ei mitään", + "Local Scaling": "Paikallinen skaalaus", + "Remote Resizing": "Koon etämuutos", + "Advanced": "Pitkälle kehittynyt", + "Quality:": "Laatu:", + "Compression level:": "Pakkaustaso:", + "Repeater ID:": "Toistintunnus:", + "WebSocket": "WebSocket", + "Encrypt": "Salaa", + "Host:": "isäntä:", + "Port:": "Portti:", + "Path:": "Polku:", + "Automatic Reconnect": "Automaattinen uudelleenkytkentä", + "Reconnect Delay (ms):": "Reconnect Delay (ms):", + "Show Dot when No Cursor": "Näytä piste, kun ei ole kohdistinta", + "Logging:": "Lokikirjaus:", + "Version:": "Versio:", + "Disconnect": "Katkaista", + "Connect": "Kytkeä", + "Username:": "Käyttäjänimi:", + "Password:": "Salasana:", + "Send Credentials": "Lähetä valtuustiedot", + "Cancel": "Peruuttaa", + "Keys": "Avaimet", + "Game Cursor Mode": "Pelikohdistintila", + "Press Esc Key to Exit Pointer Lock Mode": "Poistu osoittimen lukitustilasta painamalla Esc-näppäintä", + "Game Mode paused, click on screen to resume Game Mode.": "Pelitila keskeytetty, napsauta näyttöä jatkaaksesi pelitilaa.", + "Clipboard Up": "Leikepöytä ylös", + "CLipboard Down": "Leikepöytä alas", + "Clipboard Seamless": "Leikepöytä saumaton", + "Prefer Local Cursor": "Prefer Local Cursor", + "Translate keyboard shortcuts": "Käännä pikanäppäimet", + "Enable WebRTC UDP Transit": "Ota WebRTC UDP Transit käyttöön", + "Enable WebP Compression": "Ota WebP-pakkaus käyttöön", + "Enable Performance Stats": "Ota suorituskykytilastot käyttöön", + "Enable Pointer Lock": "Ota osoittimen lukitus käyttöön", + "IME Input Mode": "IME-syöttötila", + "Show Virtual Keyboard Control": "Näytä virtuaalinen näppäimistöohjaus", + "Toggle Control Panel via Keystrokes": "Vaihda ohjauspaneelia näppäinpainalluksilla", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Pikanäppäimet", + "Enable KasmVNC Keyboard Shortcuts": "Ota KasmVNC-pikanäppäimet käyttöön", + "1 - Toggle Control Panel": "1 - Vaihda ohjauspaneelia", + "2 - Toggle Game Pointer Mode": "2 - Vaihda pelin osoitintilaa", + "3 - Toggle Pointer Lock": "3 - Vaihda osoittimen lukitus", + "Stream Quality": "Striimin laatu", + "Preset Modes:": "Esiasetetut tilat:", + "Static": "Staattinen", + "Low": "Matala", + "Medium": "Keskitaso", + "High": "Korkea", + "Extreme": "Extreme", + "Lossless": "tappioton", + "Custom": "Mukautettu", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Vinossa", + "On": "Päällä", + "Dynamic Quality Min:": "Dynaaminen laatu min:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Ruudunpäivitysnopeus:", + "Video JPEG Quality:": "Videon JPEG-laatu:", + "Video WEBP Quality:": "Videon WEBP-laatu:", + "Video Area:": "Videoalue:", + "Video Time:": "Videon aika:", + "Video Out Time:": "Videon loppumisaika:", + "Video Mode Width:": "Videotilan leveys:", + "Video Mode Height:": "Videotilan korkeus:", + "Documentation": "Dokumentointi", + "Drag Viewport": "Vedä näkymä", + "KasmVNC encountered an error:": "KasmVNC havaitsi virheen:" +} \ No newline at end of file diff --git a/app/locale/fi_FI.json b/app/locale/fi_FI.json new file mode 100644 index 0000000..4cd1fd7 --- /dev/null +++ b/app/locale/fi_FI.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Yhdistetään...", + "Disconnecting...": "Katkaistaan...", + "Reconnecting...": "Yhdistetään uudelleen...", + "Internal error": "Sisäinen virhe", + "Must set host": "Täytyy asettaa isäntä", + "Connected (encrypted) to ": "Yhdistetty (salattu) kohteeseen", + "Connected (unencrypted) to ": "Yhdistetty (salaamaton) kohteeseen", + "Something went wrong, connection is closed": "Jotain meni pieleen, yhteys on suljettu", + "Failed to connect to server": "Yhteyttä palvelimeen ei voitu muodostaa", + "Disconnected": "Katkaistu", + "New connection has been rejected with reason: ": "Uusi yhteys on hylätty syystä:", + "New connection has been rejected": "Uusi yhteys on hylätty", + "Credentials are required": "Kirjaustiedot vaaditaan", + "Hide/Show the control bar": "Piilota/näytä ohjauspalkki", + "Drag": "Raahata", + "Move/Drag Viewport": "Siirrä/vedä-näkymä", + "Keyboard": "Näppäimistö", + "Show Keyboard": "Näytä näppäimistö", + "Extra keys": "Lisäavaimet", + "Show Extra Keys": "Näytä lisänäppäimet", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Vaihda Ctrl", + "Alt": "Alt", + "Toggle Alt": "Vaihda Alt", + "Toggle Windows": "Vaihda Windows", + "Windows": "Windows", + "Send Tab": "Lähetä välilehti", + "Tab": "välilehti", + "Esc": "Poistu", + "Send Escape": "Lähetä pako", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Lähetä Ctrl-Alt-Del", + "Shutdown/Reboot": "Sammuta/käynnistetään uudelleen", + "Shutdown/Reboot...": "Sammuta/käynnistetään uudelleen...", + "Power": "Voima", + "Shutdown": "Sammuttaa", + "Reboot": "Käynnistä uudelleen", + "Reset": "Palauta", + "Clipboard": "Leikepöytä", + "Clear": "Asia selvä", + "Fullscreen": "Koko näyttö", + "Settings": "Asetukset", + "Shared Mode": "Jaettu tila", + "View Only": "Vain katsella", + "Clip to Window": "Leike ikkunaan", + "Scaling Mode:": "Skaalaustila:", + "None": "Ei mitään", + "Local Scaling": "Paikallinen skaalaus", + "Remote Resizing": "Koon etämuutos", + "Advanced": "Pitkälle kehittynyt", + "Quality:": "Laatu:", + "Compression level:": "Pakkaustaso:", + "Repeater ID:": "Toistintunnus:", + "WebSocket": "WebSocket", + "Encrypt": "Salaa", + "Host:": "isäntä:", + "Port:": "Portti:", + "Path:": "Polku:", + "Automatic Reconnect": "Automaattinen uudelleenkytkentä", + "Reconnect Delay (ms):": "Reconnect Delay (ms):", + "Show Dot when No Cursor": "Näytä piste, kun ei ole kohdistinta", + "Logging:": "Lokikirjaus:", + "Version:": "Versio:", + "Disconnect": "Katkaista", + "Connect": "Kytkeä", + "Username:": "Käyttäjänimi:", + "Password:": "Salasana:", + "Send Credentials": "Lähetä valtuustiedot", + "Cancel": "Peruuttaa", + "Keys": "Avaimet", + "Game Cursor Mode": "Pelikohdistintila", + "Press Esc Key to Exit Pointer Lock Mode": "Poistu osoittimen lukitustilasta painamalla Esc-näppäintä", + "Game Mode paused, click on screen to resume Game Mode.": "Pelitila keskeytetty, napsauta näyttöä jatkaaksesi pelitilaa.", + "Clipboard Up": "Leikepöytä ylös", + "CLipboard Down": "Leikepöytä alas", + "Clipboard Seamless": "Leikepöytä saumaton", + "Prefer Local Cursor": "Prefer Local Cursor", + "Translate keyboard shortcuts": "Käännä pikanäppäimet", + "Enable WebRTC UDP Transit": "Ota WebRTC UDP Transit käyttöön", + "Enable WebP Compression": "Ota WebP-pakkaus käyttöön", + "Enable Performance Stats": "Ota suorituskykytilastot käyttöön", + "Enable Pointer Lock": "Ota osoittimen lukitus käyttöön", + "IME Input Mode": "IME-syöttötila", + "Show Virtual Keyboard Control": "Näytä virtuaalinen näppäimistöohjaus", + "Toggle Control Panel via Keystrokes": "Vaihda ohjauspaneelia näppäinpainalluksilla", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Pikanäppäimet", + "Enable KasmVNC Keyboard Shortcuts": "Ota KasmVNC-pikanäppäimet käyttöön", + "1 - Toggle Control Panel": "1 - Vaihda ohjauspaneelia", + "2 - Toggle Game Pointer Mode": "2 - Vaihda pelin osoitintilaa", + "3 - Toggle Pointer Lock": "3 - Vaihda osoittimen lukitus", + "Stream Quality": "Striimin laatu", + "Preset Modes:": "Esiasetetut tilat:", + "Static": "Staattinen", + "Low": "Matala", + "Medium": "Keskitaso", + "High": "Korkea", + "Extreme": "Extreme", + "Lossless": "tappioton", + "Custom": "Mukautettu", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Vinossa", + "On": "Päällä", + "Dynamic Quality Min:": "Dynaaminen laatu min:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Ruudunpäivitysnopeus:", + "Video JPEG Quality:": "Videon JPEG-laatu:", + "Video WEBP Quality:": "Videon WEBP-laatu:", + "Video Area:": "Videoalue:", + "Video Time:": "Videon aika:", + "Video Out Time:": "Videon loppumisaika:", + "Video Mode Width:": "Videotilan leveys:", + "Video Mode Height:": "Videotilan korkeus:", + "Documentation": "Dokumentointi", + "Drag Viewport": "Vedä näkymä", + "KasmVNC encountered an error:": "KasmVNC havaitsi virheen:" +} \ No newline at end of file diff --git a/app/locale/fr.json b/app/locale/fr.json new file mode 100644 index 0000000..5e9f3ee --- /dev/null +++ b/app/locale/fr.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "De liaison...", + "Disconnecting...": "Déconnexion...", + "Reconnecting...": "Reconnexion...", + "Internal error": "Erreur interne", + "Must set host": "Doit définir l'hôte", + "Connected (encrypted) to ": "Connecté (crypté) à", + "Connected (unencrypted) to ": "Connecté (non crypté) à", + "Something went wrong, connection is closed": "Quelque chose s'est mal passé, la connexion est fermée", + "Failed to connect to server": "Échec de connexion au serveur", + "Disconnected": "Débranché", + "New connection has been rejected with reason: ": "La nouvelle connexion a été rejetée avec raison : ", + "New connection has been rejected": "La nouvelle connexion a été rejetée", + "Credentials are required": "Les justificatifs sont obligatoires", + "Hide/Show the control bar": "Masquer/Afficher la barre de contrôle", + "Drag": "Glisser", + "Move/Drag Viewport": "Déplacer/faire glisser la fenêtre", + "Keyboard": "Clavier", + "Show Keyboard": "Afficher le clavier", + "Extra keys": "Clés supplémentaires", + "Show Extra Keys": "Afficher les clés supplémentaires", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Basculer Ctrl", + "Alt": "Alt", + "Toggle Alt": "Basculer Alt", + "Toggle Windows": "Basculer les fenêtres", + "Windows": "Les fenêtres", + "Send Tab": "Onglet Envoyer", + "Tab": "Languette", + "Esc": "Esc", + "Send Escape": "Envoyer l'évasion", + "Ctrl+Alt+Del": "Ctrl+Alt+Suppr", + "Send Ctrl-Alt-Del": "Envoyer Ctrl-Alt-Suppr", + "Shutdown/Reboot": "Arrêter/Redémarrer", + "Shutdown/Reboot...": "Arrêt/Redémarrage...", + "Power": "Pouvoir", + "Shutdown": "Fermer", + "Reboot": "Redémarrer", + "Reset": "Réinitialiser", + "Clipboard": "Presse-papiers", + "Clear": "Clair", + "Fullscreen": "Plein écran", + "Settings": "Paramètres", + "Shared Mode": "Mode partagé", + "View Only": "Affichage uniquement", + "Clip to Window": "Clip à la fenêtre", + "Scaling Mode:": "Mode de mise à l'échelle :", + "None": "Aucun", + "Local Scaling": " Mise à l'échelle locale ", + "Remote Resizing": "Redimensionnement à distance", + "Advanced": "Avancé", + "Quality:": "Qualité:", + "Compression level:": "Niveau de compression :", + "Repeater ID:": "Identifiant du répéteur :", + "WebSocket": "WebSocket", + "Encrypt": "Crypter", + "Host:": "Héberger:", + "Port:": "Port:", + "Path:": "Chemin:", + "Automatic Reconnect": "Reconnexion automatique", + "Reconnect Delay (ms):": "Délai de reconnexion (ms) :", + "Show Dot when No Cursor": "Afficher le point lorsqu'il n'y a pas de curseur", + "Logging:": "Enregistrement:", + "Version:": "Version:", + "Disconnect": "Déconnecter", + "Connect": "Connecter", + "Username:": "Nom d'utilisateur:", + "Password:": "Mot de passe:", + "Send Credentials": "Envoyer les identifiants", + "Cancel": "Annuler", + "Keys": "Clés", + "Game Cursor Mode": "Mode curseur de jeu", + "Press Esc Key to Exit Pointer Lock Mode": "Appuyez sur la touche Échap pour quitter le mode de verrouillage du pointeur", + "Game Mode paused, click on screen to resume Game Mode.": "Mode jeu en pause, cliquez sur l'écran pour reprendre le mode jeu.", + "Clipboard Up": "Presse-papiers vers le haut", + "CLipboard Down": "Bloc-notes vers le bas", + "Clipboard Seamless": "Presse-papiers sans couture", + "Prefer Local Cursor": "Préférez le curseur local", + "Translate keyboard shortcuts": "Traduire les raccourcis clavier", + "Enable WebRTC UDP Transit": "Activer le transit WebRTC UDP", + "Enable WebP Compression": "Activer la compression WebP", + "Enable Performance Stats": "Activer les statistiques de performances", + "Enable Pointer Lock": "Activer le verrouillage du pointeur", + "IME Input Mode": "Mode d'entrée IME", + "Show Virtual Keyboard Control": "Afficher le contrôle du clavier virtuel", + "Toggle Control Panel via Keystrokes": "Basculer le panneau de configuration via les frappes", + "Render Native Resolution": "Rendre la résolution native", + "Keyboard Shortcuts": "Raccourcis clavier", + "Enable KasmVNC Keyboard Shortcuts": "Activer les raccourcis clavier KasmVNC", + "1 - Toggle Control Panel": "1 - Basculer le panneau de configuration", + "2 - Toggle Game Pointer Mode": "2 - Basculer le mode pointeur de jeu", + "3 - Toggle Pointer Lock": "3 - Basculer le verrouillage du pointeur", + "Stream Quality": "Qualité du flux", + "Preset Modes:": "Modes prédéfinis :", + "Static": "Statique", + "Low": "Faible", + "Medium": "Moyen", + "High": "Haut", + "Extreme": "Extrême", + "Lossless": "Sans perte", + "Custom": "Coutume", + "Anti-Aliasing:": "Anti crénelage:", + "Auto Dynamic": "Dynamique automatique", + "Off": "Désactivé", + "On": "Sur", + "Dynamic Quality Min:": "Qualité dynamique min :", + "Dynamic Quality Max:": "Qualité dynamique max :", + "Treat Lossless:": "Traiter sans perte :", + "Frame Rate:": "Fréquence d'images :", + "Video JPEG Quality:": "Qualité JPEG vidéo :", + "Video WEBP Quality:": "Qualité WEBP de la vidéo :", + "Video Area:": "Zone vidéo :", + "Video Time:": "Heure de la vidéo :", + "Video Out Time:": "Temps de sortie vidéo :", + "Video Mode Width:": "Largeur du mode vidéo :", + "Video Mode Height:": "Hauteur du mode vidéo :", + "Documentation": "Documentation", + "Drag Viewport": "Faire glisser la fenêtre", + "KasmVNC encountered an error:": "KasmVNC a rencontré une erreur :" +} \ No newline at end of file diff --git a/app/locale/fr_BE.json b/app/locale/fr_BE.json new file mode 100644 index 0000000..5e9f3ee --- /dev/null +++ b/app/locale/fr_BE.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "De liaison...", + "Disconnecting...": "Déconnexion...", + "Reconnecting...": "Reconnexion...", + "Internal error": "Erreur interne", + "Must set host": "Doit définir l'hôte", + "Connected (encrypted) to ": "Connecté (crypté) à", + "Connected (unencrypted) to ": "Connecté (non crypté) à", + "Something went wrong, connection is closed": "Quelque chose s'est mal passé, la connexion est fermée", + "Failed to connect to server": "Échec de connexion au serveur", + "Disconnected": "Débranché", + "New connection has been rejected with reason: ": "La nouvelle connexion a été rejetée avec raison : ", + "New connection has been rejected": "La nouvelle connexion a été rejetée", + "Credentials are required": "Les justificatifs sont obligatoires", + "Hide/Show the control bar": "Masquer/Afficher la barre de contrôle", + "Drag": "Glisser", + "Move/Drag Viewport": "Déplacer/faire glisser la fenêtre", + "Keyboard": "Clavier", + "Show Keyboard": "Afficher le clavier", + "Extra keys": "Clés supplémentaires", + "Show Extra Keys": "Afficher les clés supplémentaires", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Basculer Ctrl", + "Alt": "Alt", + "Toggle Alt": "Basculer Alt", + "Toggle Windows": "Basculer les fenêtres", + "Windows": "Les fenêtres", + "Send Tab": "Onglet Envoyer", + "Tab": "Languette", + "Esc": "Esc", + "Send Escape": "Envoyer l'évasion", + "Ctrl+Alt+Del": "Ctrl+Alt+Suppr", + "Send Ctrl-Alt-Del": "Envoyer Ctrl-Alt-Suppr", + "Shutdown/Reboot": "Arrêter/Redémarrer", + "Shutdown/Reboot...": "Arrêt/Redémarrage...", + "Power": "Pouvoir", + "Shutdown": "Fermer", + "Reboot": "Redémarrer", + "Reset": "Réinitialiser", + "Clipboard": "Presse-papiers", + "Clear": "Clair", + "Fullscreen": "Plein écran", + "Settings": "Paramètres", + "Shared Mode": "Mode partagé", + "View Only": "Affichage uniquement", + "Clip to Window": "Clip à la fenêtre", + "Scaling Mode:": "Mode de mise à l'échelle :", + "None": "Aucun", + "Local Scaling": " Mise à l'échelle locale ", + "Remote Resizing": "Redimensionnement à distance", + "Advanced": "Avancé", + "Quality:": "Qualité:", + "Compression level:": "Niveau de compression :", + "Repeater ID:": "Identifiant du répéteur :", + "WebSocket": "WebSocket", + "Encrypt": "Crypter", + "Host:": "Héberger:", + "Port:": "Port:", + "Path:": "Chemin:", + "Automatic Reconnect": "Reconnexion automatique", + "Reconnect Delay (ms):": "Délai de reconnexion (ms) :", + "Show Dot when No Cursor": "Afficher le point lorsqu'il n'y a pas de curseur", + "Logging:": "Enregistrement:", + "Version:": "Version:", + "Disconnect": "Déconnecter", + "Connect": "Connecter", + "Username:": "Nom d'utilisateur:", + "Password:": "Mot de passe:", + "Send Credentials": "Envoyer les identifiants", + "Cancel": "Annuler", + "Keys": "Clés", + "Game Cursor Mode": "Mode curseur de jeu", + "Press Esc Key to Exit Pointer Lock Mode": "Appuyez sur la touche Échap pour quitter le mode de verrouillage du pointeur", + "Game Mode paused, click on screen to resume Game Mode.": "Mode jeu en pause, cliquez sur l'écran pour reprendre le mode jeu.", + "Clipboard Up": "Presse-papiers vers le haut", + "CLipboard Down": "Bloc-notes vers le bas", + "Clipboard Seamless": "Presse-papiers sans couture", + "Prefer Local Cursor": "Préférez le curseur local", + "Translate keyboard shortcuts": "Traduire les raccourcis clavier", + "Enable WebRTC UDP Transit": "Activer le transit WebRTC UDP", + "Enable WebP Compression": "Activer la compression WebP", + "Enable Performance Stats": "Activer les statistiques de performances", + "Enable Pointer Lock": "Activer le verrouillage du pointeur", + "IME Input Mode": "Mode d'entrée IME", + "Show Virtual Keyboard Control": "Afficher le contrôle du clavier virtuel", + "Toggle Control Panel via Keystrokes": "Basculer le panneau de configuration via les frappes", + "Render Native Resolution": "Rendre la résolution native", + "Keyboard Shortcuts": "Raccourcis clavier", + "Enable KasmVNC Keyboard Shortcuts": "Activer les raccourcis clavier KasmVNC", + "1 - Toggle Control Panel": "1 - Basculer le panneau de configuration", + "2 - Toggle Game Pointer Mode": "2 - Basculer le mode pointeur de jeu", + "3 - Toggle Pointer Lock": "3 - Basculer le verrouillage du pointeur", + "Stream Quality": "Qualité du flux", + "Preset Modes:": "Modes prédéfinis :", + "Static": "Statique", + "Low": "Faible", + "Medium": "Moyen", + "High": "Haut", + "Extreme": "Extrême", + "Lossless": "Sans perte", + "Custom": "Coutume", + "Anti-Aliasing:": "Anti crénelage:", + "Auto Dynamic": "Dynamique automatique", + "Off": "Désactivé", + "On": "Sur", + "Dynamic Quality Min:": "Qualité dynamique min :", + "Dynamic Quality Max:": "Qualité dynamique max :", + "Treat Lossless:": "Traiter sans perte :", + "Frame Rate:": "Fréquence d'images :", + "Video JPEG Quality:": "Qualité JPEG vidéo :", + "Video WEBP Quality:": "Qualité WEBP de la vidéo :", + "Video Area:": "Zone vidéo :", + "Video Time:": "Heure de la vidéo :", + "Video Out Time:": "Temps de sortie vidéo :", + "Video Mode Width:": "Largeur du mode vidéo :", + "Video Mode Height:": "Hauteur du mode vidéo :", + "Documentation": "Documentation", + "Drag Viewport": "Faire glisser la fenêtre", + "KasmVNC encountered an error:": "KasmVNC a rencontré une erreur :" +} \ No newline at end of file diff --git a/app/locale/fr_CA.json b/app/locale/fr_CA.json new file mode 100644 index 0000000..5e9f3ee --- /dev/null +++ b/app/locale/fr_CA.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "De liaison...", + "Disconnecting...": "Déconnexion...", + "Reconnecting...": "Reconnexion...", + "Internal error": "Erreur interne", + "Must set host": "Doit définir l'hôte", + "Connected (encrypted) to ": "Connecté (crypté) à", + "Connected (unencrypted) to ": "Connecté (non crypté) à", + "Something went wrong, connection is closed": "Quelque chose s'est mal passé, la connexion est fermée", + "Failed to connect to server": "Échec de connexion au serveur", + "Disconnected": "Débranché", + "New connection has been rejected with reason: ": "La nouvelle connexion a été rejetée avec raison : ", + "New connection has been rejected": "La nouvelle connexion a été rejetée", + "Credentials are required": "Les justificatifs sont obligatoires", + "Hide/Show the control bar": "Masquer/Afficher la barre de contrôle", + "Drag": "Glisser", + "Move/Drag Viewport": "Déplacer/faire glisser la fenêtre", + "Keyboard": "Clavier", + "Show Keyboard": "Afficher le clavier", + "Extra keys": "Clés supplémentaires", + "Show Extra Keys": "Afficher les clés supplémentaires", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Basculer Ctrl", + "Alt": "Alt", + "Toggle Alt": "Basculer Alt", + "Toggle Windows": "Basculer les fenêtres", + "Windows": "Les fenêtres", + "Send Tab": "Onglet Envoyer", + "Tab": "Languette", + "Esc": "Esc", + "Send Escape": "Envoyer l'évasion", + "Ctrl+Alt+Del": "Ctrl+Alt+Suppr", + "Send Ctrl-Alt-Del": "Envoyer Ctrl-Alt-Suppr", + "Shutdown/Reboot": "Arrêter/Redémarrer", + "Shutdown/Reboot...": "Arrêt/Redémarrage...", + "Power": "Pouvoir", + "Shutdown": "Fermer", + "Reboot": "Redémarrer", + "Reset": "Réinitialiser", + "Clipboard": "Presse-papiers", + "Clear": "Clair", + "Fullscreen": "Plein écran", + "Settings": "Paramètres", + "Shared Mode": "Mode partagé", + "View Only": "Affichage uniquement", + "Clip to Window": "Clip à la fenêtre", + "Scaling Mode:": "Mode de mise à l'échelle :", + "None": "Aucun", + "Local Scaling": " Mise à l'échelle locale ", + "Remote Resizing": "Redimensionnement à distance", + "Advanced": "Avancé", + "Quality:": "Qualité:", + "Compression level:": "Niveau de compression :", + "Repeater ID:": "Identifiant du répéteur :", + "WebSocket": "WebSocket", + "Encrypt": "Crypter", + "Host:": "Héberger:", + "Port:": "Port:", + "Path:": "Chemin:", + "Automatic Reconnect": "Reconnexion automatique", + "Reconnect Delay (ms):": "Délai de reconnexion (ms) :", + "Show Dot when No Cursor": "Afficher le point lorsqu'il n'y a pas de curseur", + "Logging:": "Enregistrement:", + "Version:": "Version:", + "Disconnect": "Déconnecter", + "Connect": "Connecter", + "Username:": "Nom d'utilisateur:", + "Password:": "Mot de passe:", + "Send Credentials": "Envoyer les identifiants", + "Cancel": "Annuler", + "Keys": "Clés", + "Game Cursor Mode": "Mode curseur de jeu", + "Press Esc Key to Exit Pointer Lock Mode": "Appuyez sur la touche Échap pour quitter le mode de verrouillage du pointeur", + "Game Mode paused, click on screen to resume Game Mode.": "Mode jeu en pause, cliquez sur l'écran pour reprendre le mode jeu.", + "Clipboard Up": "Presse-papiers vers le haut", + "CLipboard Down": "Bloc-notes vers le bas", + "Clipboard Seamless": "Presse-papiers sans couture", + "Prefer Local Cursor": "Préférez le curseur local", + "Translate keyboard shortcuts": "Traduire les raccourcis clavier", + "Enable WebRTC UDP Transit": "Activer le transit WebRTC UDP", + "Enable WebP Compression": "Activer la compression WebP", + "Enable Performance Stats": "Activer les statistiques de performances", + "Enable Pointer Lock": "Activer le verrouillage du pointeur", + "IME Input Mode": "Mode d'entrée IME", + "Show Virtual Keyboard Control": "Afficher le contrôle du clavier virtuel", + "Toggle Control Panel via Keystrokes": "Basculer le panneau de configuration via les frappes", + "Render Native Resolution": "Rendre la résolution native", + "Keyboard Shortcuts": "Raccourcis clavier", + "Enable KasmVNC Keyboard Shortcuts": "Activer les raccourcis clavier KasmVNC", + "1 - Toggle Control Panel": "1 - Basculer le panneau de configuration", + "2 - Toggle Game Pointer Mode": "2 - Basculer le mode pointeur de jeu", + "3 - Toggle Pointer Lock": "3 - Basculer le verrouillage du pointeur", + "Stream Quality": "Qualité du flux", + "Preset Modes:": "Modes prédéfinis :", + "Static": "Statique", + "Low": "Faible", + "Medium": "Moyen", + "High": "Haut", + "Extreme": "Extrême", + "Lossless": "Sans perte", + "Custom": "Coutume", + "Anti-Aliasing:": "Anti crénelage:", + "Auto Dynamic": "Dynamique automatique", + "Off": "Désactivé", + "On": "Sur", + "Dynamic Quality Min:": "Qualité dynamique min :", + "Dynamic Quality Max:": "Qualité dynamique max :", + "Treat Lossless:": "Traiter sans perte :", + "Frame Rate:": "Fréquence d'images :", + "Video JPEG Quality:": "Qualité JPEG vidéo :", + "Video WEBP Quality:": "Qualité WEBP de la vidéo :", + "Video Area:": "Zone vidéo :", + "Video Time:": "Heure de la vidéo :", + "Video Out Time:": "Temps de sortie vidéo :", + "Video Mode Width:": "Largeur du mode vidéo :", + "Video Mode Height:": "Hauteur du mode vidéo :", + "Documentation": "Documentation", + "Drag Viewport": "Faire glisser la fenêtre", + "KasmVNC encountered an error:": "KasmVNC a rencontré une erreur :" +} \ No newline at end of file diff --git a/app/locale/fr_CH.json b/app/locale/fr_CH.json new file mode 100644 index 0000000..5e9f3ee --- /dev/null +++ b/app/locale/fr_CH.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "De liaison...", + "Disconnecting...": "Déconnexion...", + "Reconnecting...": "Reconnexion...", + "Internal error": "Erreur interne", + "Must set host": "Doit définir l'hôte", + "Connected (encrypted) to ": "Connecté (crypté) à", + "Connected (unencrypted) to ": "Connecté (non crypté) à", + "Something went wrong, connection is closed": "Quelque chose s'est mal passé, la connexion est fermée", + "Failed to connect to server": "Échec de connexion au serveur", + "Disconnected": "Débranché", + "New connection has been rejected with reason: ": "La nouvelle connexion a été rejetée avec raison : ", + "New connection has been rejected": "La nouvelle connexion a été rejetée", + "Credentials are required": "Les justificatifs sont obligatoires", + "Hide/Show the control bar": "Masquer/Afficher la barre de contrôle", + "Drag": "Glisser", + "Move/Drag Viewport": "Déplacer/faire glisser la fenêtre", + "Keyboard": "Clavier", + "Show Keyboard": "Afficher le clavier", + "Extra keys": "Clés supplémentaires", + "Show Extra Keys": "Afficher les clés supplémentaires", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Basculer Ctrl", + "Alt": "Alt", + "Toggle Alt": "Basculer Alt", + "Toggle Windows": "Basculer les fenêtres", + "Windows": "Les fenêtres", + "Send Tab": "Onglet Envoyer", + "Tab": "Languette", + "Esc": "Esc", + "Send Escape": "Envoyer l'évasion", + "Ctrl+Alt+Del": "Ctrl+Alt+Suppr", + "Send Ctrl-Alt-Del": "Envoyer Ctrl-Alt-Suppr", + "Shutdown/Reboot": "Arrêter/Redémarrer", + "Shutdown/Reboot...": "Arrêt/Redémarrage...", + "Power": "Pouvoir", + "Shutdown": "Fermer", + "Reboot": "Redémarrer", + "Reset": "Réinitialiser", + "Clipboard": "Presse-papiers", + "Clear": "Clair", + "Fullscreen": "Plein écran", + "Settings": "Paramètres", + "Shared Mode": "Mode partagé", + "View Only": "Affichage uniquement", + "Clip to Window": "Clip à la fenêtre", + "Scaling Mode:": "Mode de mise à l'échelle :", + "None": "Aucun", + "Local Scaling": " Mise à l'échelle locale ", + "Remote Resizing": "Redimensionnement à distance", + "Advanced": "Avancé", + "Quality:": "Qualité:", + "Compression level:": "Niveau de compression :", + "Repeater ID:": "Identifiant du répéteur :", + "WebSocket": "WebSocket", + "Encrypt": "Crypter", + "Host:": "Héberger:", + "Port:": "Port:", + "Path:": "Chemin:", + "Automatic Reconnect": "Reconnexion automatique", + "Reconnect Delay (ms):": "Délai de reconnexion (ms) :", + "Show Dot when No Cursor": "Afficher le point lorsqu'il n'y a pas de curseur", + "Logging:": "Enregistrement:", + "Version:": "Version:", + "Disconnect": "Déconnecter", + "Connect": "Connecter", + "Username:": "Nom d'utilisateur:", + "Password:": "Mot de passe:", + "Send Credentials": "Envoyer les identifiants", + "Cancel": "Annuler", + "Keys": "Clés", + "Game Cursor Mode": "Mode curseur de jeu", + "Press Esc Key to Exit Pointer Lock Mode": "Appuyez sur la touche Échap pour quitter le mode de verrouillage du pointeur", + "Game Mode paused, click on screen to resume Game Mode.": "Mode jeu en pause, cliquez sur l'écran pour reprendre le mode jeu.", + "Clipboard Up": "Presse-papiers vers le haut", + "CLipboard Down": "Bloc-notes vers le bas", + "Clipboard Seamless": "Presse-papiers sans couture", + "Prefer Local Cursor": "Préférez le curseur local", + "Translate keyboard shortcuts": "Traduire les raccourcis clavier", + "Enable WebRTC UDP Transit": "Activer le transit WebRTC UDP", + "Enable WebP Compression": "Activer la compression WebP", + "Enable Performance Stats": "Activer les statistiques de performances", + "Enable Pointer Lock": "Activer le verrouillage du pointeur", + "IME Input Mode": "Mode d'entrée IME", + "Show Virtual Keyboard Control": "Afficher le contrôle du clavier virtuel", + "Toggle Control Panel via Keystrokes": "Basculer le panneau de configuration via les frappes", + "Render Native Resolution": "Rendre la résolution native", + "Keyboard Shortcuts": "Raccourcis clavier", + "Enable KasmVNC Keyboard Shortcuts": "Activer les raccourcis clavier KasmVNC", + "1 - Toggle Control Panel": "1 - Basculer le panneau de configuration", + "2 - Toggle Game Pointer Mode": "2 - Basculer le mode pointeur de jeu", + "3 - Toggle Pointer Lock": "3 - Basculer le verrouillage du pointeur", + "Stream Quality": "Qualité du flux", + "Preset Modes:": "Modes prédéfinis :", + "Static": "Statique", + "Low": "Faible", + "Medium": "Moyen", + "High": "Haut", + "Extreme": "Extrême", + "Lossless": "Sans perte", + "Custom": "Coutume", + "Anti-Aliasing:": "Anti crénelage:", + "Auto Dynamic": "Dynamique automatique", + "Off": "Désactivé", + "On": "Sur", + "Dynamic Quality Min:": "Qualité dynamique min :", + "Dynamic Quality Max:": "Qualité dynamique max :", + "Treat Lossless:": "Traiter sans perte :", + "Frame Rate:": "Fréquence d'images :", + "Video JPEG Quality:": "Qualité JPEG vidéo :", + "Video WEBP Quality:": "Qualité WEBP de la vidéo :", + "Video Area:": "Zone vidéo :", + "Video Time:": "Heure de la vidéo :", + "Video Out Time:": "Temps de sortie vidéo :", + "Video Mode Width:": "Largeur du mode vidéo :", + "Video Mode Height:": "Hauteur du mode vidéo :", + "Documentation": "Documentation", + "Drag Viewport": "Faire glisser la fenêtre", + "KasmVNC encountered an error:": "KasmVNC a rencontré une erreur :" +} \ No newline at end of file diff --git a/app/locale/fr_FR.json b/app/locale/fr_FR.json new file mode 100644 index 0000000..5e9f3ee --- /dev/null +++ b/app/locale/fr_FR.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "De liaison...", + "Disconnecting...": "Déconnexion...", + "Reconnecting...": "Reconnexion...", + "Internal error": "Erreur interne", + "Must set host": "Doit définir l'hôte", + "Connected (encrypted) to ": "Connecté (crypté) à", + "Connected (unencrypted) to ": "Connecté (non crypté) à", + "Something went wrong, connection is closed": "Quelque chose s'est mal passé, la connexion est fermée", + "Failed to connect to server": "Échec de connexion au serveur", + "Disconnected": "Débranché", + "New connection has been rejected with reason: ": "La nouvelle connexion a été rejetée avec raison : ", + "New connection has been rejected": "La nouvelle connexion a été rejetée", + "Credentials are required": "Les justificatifs sont obligatoires", + "Hide/Show the control bar": "Masquer/Afficher la barre de contrôle", + "Drag": "Glisser", + "Move/Drag Viewport": "Déplacer/faire glisser la fenêtre", + "Keyboard": "Clavier", + "Show Keyboard": "Afficher le clavier", + "Extra keys": "Clés supplémentaires", + "Show Extra Keys": "Afficher les clés supplémentaires", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Basculer Ctrl", + "Alt": "Alt", + "Toggle Alt": "Basculer Alt", + "Toggle Windows": "Basculer les fenêtres", + "Windows": "Les fenêtres", + "Send Tab": "Onglet Envoyer", + "Tab": "Languette", + "Esc": "Esc", + "Send Escape": "Envoyer l'évasion", + "Ctrl+Alt+Del": "Ctrl+Alt+Suppr", + "Send Ctrl-Alt-Del": "Envoyer Ctrl-Alt-Suppr", + "Shutdown/Reboot": "Arrêter/Redémarrer", + "Shutdown/Reboot...": "Arrêt/Redémarrage...", + "Power": "Pouvoir", + "Shutdown": "Fermer", + "Reboot": "Redémarrer", + "Reset": "Réinitialiser", + "Clipboard": "Presse-papiers", + "Clear": "Clair", + "Fullscreen": "Plein écran", + "Settings": "Paramètres", + "Shared Mode": "Mode partagé", + "View Only": "Affichage uniquement", + "Clip to Window": "Clip à la fenêtre", + "Scaling Mode:": "Mode de mise à l'échelle :", + "None": "Aucun", + "Local Scaling": " Mise à l'échelle locale ", + "Remote Resizing": "Redimensionnement à distance", + "Advanced": "Avancé", + "Quality:": "Qualité:", + "Compression level:": "Niveau de compression :", + "Repeater ID:": "Identifiant du répéteur :", + "WebSocket": "WebSocket", + "Encrypt": "Crypter", + "Host:": "Héberger:", + "Port:": "Port:", + "Path:": "Chemin:", + "Automatic Reconnect": "Reconnexion automatique", + "Reconnect Delay (ms):": "Délai de reconnexion (ms) :", + "Show Dot when No Cursor": "Afficher le point lorsqu'il n'y a pas de curseur", + "Logging:": "Enregistrement:", + "Version:": "Version:", + "Disconnect": "Déconnecter", + "Connect": "Connecter", + "Username:": "Nom d'utilisateur:", + "Password:": "Mot de passe:", + "Send Credentials": "Envoyer les identifiants", + "Cancel": "Annuler", + "Keys": "Clés", + "Game Cursor Mode": "Mode curseur de jeu", + "Press Esc Key to Exit Pointer Lock Mode": "Appuyez sur la touche Échap pour quitter le mode de verrouillage du pointeur", + "Game Mode paused, click on screen to resume Game Mode.": "Mode jeu en pause, cliquez sur l'écran pour reprendre le mode jeu.", + "Clipboard Up": "Presse-papiers vers le haut", + "CLipboard Down": "Bloc-notes vers le bas", + "Clipboard Seamless": "Presse-papiers sans couture", + "Prefer Local Cursor": "Préférez le curseur local", + "Translate keyboard shortcuts": "Traduire les raccourcis clavier", + "Enable WebRTC UDP Transit": "Activer le transit WebRTC UDP", + "Enable WebP Compression": "Activer la compression WebP", + "Enable Performance Stats": "Activer les statistiques de performances", + "Enable Pointer Lock": "Activer le verrouillage du pointeur", + "IME Input Mode": "Mode d'entrée IME", + "Show Virtual Keyboard Control": "Afficher le contrôle du clavier virtuel", + "Toggle Control Panel via Keystrokes": "Basculer le panneau de configuration via les frappes", + "Render Native Resolution": "Rendre la résolution native", + "Keyboard Shortcuts": "Raccourcis clavier", + "Enable KasmVNC Keyboard Shortcuts": "Activer les raccourcis clavier KasmVNC", + "1 - Toggle Control Panel": "1 - Basculer le panneau de configuration", + "2 - Toggle Game Pointer Mode": "2 - Basculer le mode pointeur de jeu", + "3 - Toggle Pointer Lock": "3 - Basculer le verrouillage du pointeur", + "Stream Quality": "Qualité du flux", + "Preset Modes:": "Modes prédéfinis :", + "Static": "Statique", + "Low": "Faible", + "Medium": "Moyen", + "High": "Haut", + "Extreme": "Extrême", + "Lossless": "Sans perte", + "Custom": "Coutume", + "Anti-Aliasing:": "Anti crénelage:", + "Auto Dynamic": "Dynamique automatique", + "Off": "Désactivé", + "On": "Sur", + "Dynamic Quality Min:": "Qualité dynamique min :", + "Dynamic Quality Max:": "Qualité dynamique max :", + "Treat Lossless:": "Traiter sans perte :", + "Frame Rate:": "Fréquence d'images :", + "Video JPEG Quality:": "Qualité JPEG vidéo :", + "Video WEBP Quality:": "Qualité WEBP de la vidéo :", + "Video Area:": "Zone vidéo :", + "Video Time:": "Heure de la vidéo :", + "Video Out Time:": "Temps de sortie vidéo :", + "Video Mode Width:": "Largeur du mode vidéo :", + "Video Mode Height:": "Hauteur du mode vidéo :", + "Documentation": "Documentation", + "Drag Viewport": "Faire glisser la fenêtre", + "KasmVNC encountered an error:": "KasmVNC a rencontré une erreur :" +} \ No newline at end of file diff --git a/app/locale/fr_LU.json b/app/locale/fr_LU.json new file mode 100644 index 0000000..5e9f3ee --- /dev/null +++ b/app/locale/fr_LU.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "De liaison...", + "Disconnecting...": "Déconnexion...", + "Reconnecting...": "Reconnexion...", + "Internal error": "Erreur interne", + "Must set host": "Doit définir l'hôte", + "Connected (encrypted) to ": "Connecté (crypté) à", + "Connected (unencrypted) to ": "Connecté (non crypté) à", + "Something went wrong, connection is closed": "Quelque chose s'est mal passé, la connexion est fermée", + "Failed to connect to server": "Échec de connexion au serveur", + "Disconnected": "Débranché", + "New connection has been rejected with reason: ": "La nouvelle connexion a été rejetée avec raison : ", + "New connection has been rejected": "La nouvelle connexion a été rejetée", + "Credentials are required": "Les justificatifs sont obligatoires", + "Hide/Show the control bar": "Masquer/Afficher la barre de contrôle", + "Drag": "Glisser", + "Move/Drag Viewport": "Déplacer/faire glisser la fenêtre", + "Keyboard": "Clavier", + "Show Keyboard": "Afficher le clavier", + "Extra keys": "Clés supplémentaires", + "Show Extra Keys": "Afficher les clés supplémentaires", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Basculer Ctrl", + "Alt": "Alt", + "Toggle Alt": "Basculer Alt", + "Toggle Windows": "Basculer les fenêtres", + "Windows": "Les fenêtres", + "Send Tab": "Onglet Envoyer", + "Tab": "Languette", + "Esc": "Esc", + "Send Escape": "Envoyer l'évasion", + "Ctrl+Alt+Del": "Ctrl+Alt+Suppr", + "Send Ctrl-Alt-Del": "Envoyer Ctrl-Alt-Suppr", + "Shutdown/Reboot": "Arrêter/Redémarrer", + "Shutdown/Reboot...": "Arrêt/Redémarrage...", + "Power": "Pouvoir", + "Shutdown": "Fermer", + "Reboot": "Redémarrer", + "Reset": "Réinitialiser", + "Clipboard": "Presse-papiers", + "Clear": "Clair", + "Fullscreen": "Plein écran", + "Settings": "Paramètres", + "Shared Mode": "Mode partagé", + "View Only": "Affichage uniquement", + "Clip to Window": "Clip à la fenêtre", + "Scaling Mode:": "Mode de mise à l'échelle :", + "None": "Aucun", + "Local Scaling": " Mise à l'échelle locale ", + "Remote Resizing": "Redimensionnement à distance", + "Advanced": "Avancé", + "Quality:": "Qualité:", + "Compression level:": "Niveau de compression :", + "Repeater ID:": "Identifiant du répéteur :", + "WebSocket": "WebSocket", + "Encrypt": "Crypter", + "Host:": "Héberger:", + "Port:": "Port:", + "Path:": "Chemin:", + "Automatic Reconnect": "Reconnexion automatique", + "Reconnect Delay (ms):": "Délai de reconnexion (ms) :", + "Show Dot when No Cursor": "Afficher le point lorsqu'il n'y a pas de curseur", + "Logging:": "Enregistrement:", + "Version:": "Version:", + "Disconnect": "Déconnecter", + "Connect": "Connecter", + "Username:": "Nom d'utilisateur:", + "Password:": "Mot de passe:", + "Send Credentials": "Envoyer les identifiants", + "Cancel": "Annuler", + "Keys": "Clés", + "Game Cursor Mode": "Mode curseur de jeu", + "Press Esc Key to Exit Pointer Lock Mode": "Appuyez sur la touche Échap pour quitter le mode de verrouillage du pointeur", + "Game Mode paused, click on screen to resume Game Mode.": "Mode jeu en pause, cliquez sur l'écran pour reprendre le mode jeu.", + "Clipboard Up": "Presse-papiers vers le haut", + "CLipboard Down": "Bloc-notes vers le bas", + "Clipboard Seamless": "Presse-papiers sans couture", + "Prefer Local Cursor": "Préférez le curseur local", + "Translate keyboard shortcuts": "Traduire les raccourcis clavier", + "Enable WebRTC UDP Transit": "Activer le transit WebRTC UDP", + "Enable WebP Compression": "Activer la compression WebP", + "Enable Performance Stats": "Activer les statistiques de performances", + "Enable Pointer Lock": "Activer le verrouillage du pointeur", + "IME Input Mode": "Mode d'entrée IME", + "Show Virtual Keyboard Control": "Afficher le contrôle du clavier virtuel", + "Toggle Control Panel via Keystrokes": "Basculer le panneau de configuration via les frappes", + "Render Native Resolution": "Rendre la résolution native", + "Keyboard Shortcuts": "Raccourcis clavier", + "Enable KasmVNC Keyboard Shortcuts": "Activer les raccourcis clavier KasmVNC", + "1 - Toggle Control Panel": "1 - Basculer le panneau de configuration", + "2 - Toggle Game Pointer Mode": "2 - Basculer le mode pointeur de jeu", + "3 - Toggle Pointer Lock": "3 - Basculer le verrouillage du pointeur", + "Stream Quality": "Qualité du flux", + "Preset Modes:": "Modes prédéfinis :", + "Static": "Statique", + "Low": "Faible", + "Medium": "Moyen", + "High": "Haut", + "Extreme": "Extrême", + "Lossless": "Sans perte", + "Custom": "Coutume", + "Anti-Aliasing:": "Anti crénelage:", + "Auto Dynamic": "Dynamique automatique", + "Off": "Désactivé", + "On": "Sur", + "Dynamic Quality Min:": "Qualité dynamique min :", + "Dynamic Quality Max:": "Qualité dynamique max :", + "Treat Lossless:": "Traiter sans perte :", + "Frame Rate:": "Fréquence d'images :", + "Video JPEG Quality:": "Qualité JPEG vidéo :", + "Video WEBP Quality:": "Qualité WEBP de la vidéo :", + "Video Area:": "Zone vidéo :", + "Video Time:": "Heure de la vidéo :", + "Video Out Time:": "Temps de sortie vidéo :", + "Video Mode Width:": "Largeur du mode vidéo :", + "Video Mode Height:": "Hauteur du mode vidéo :", + "Documentation": "Documentation", + "Drag Viewport": "Faire glisser la fenêtre", + "KasmVNC encountered an error:": "KasmVNC a rencontré une erreur :" +} \ No newline at end of file diff --git a/app/locale/fy.json b/app/locale/fy.json new file mode 100644 index 0000000..d84948d --- /dev/null +++ b/app/locale/fy.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ferbine...", + "Disconnecting...": "Ferbrûkt ...", + "Reconnecting...": "Opnij ferbinen...", + "Internal error": "Ynterne flater", + "Must set host": "Moat host ynstelle", + "Connected (encrypted) to ": "Ferbûn (fersifere) oan", + "Connected (unencrypted) to ": "Ferbûn (net fersifere) oan", + "Something went wrong, connection is closed": "Der gie der mis, ferbining is sluten", + "Failed to connect to server": "Ferbine mei tsjinner mislearre", + "Disconnected": "Ferbûn", + "New connection has been rejected with reason: ": "Nije ferbining is ôfwiisd mei reden:", + "New connection has been rejected": "Nije ferbining is ôfwiisd", + "Credentials are required": "Referinsjes binne ferplicht", + "Hide/Show the control bar": "De kontrôlebalke ferbergje / sjen litte", + "Drag": "Slep", + "Move/Drag Viewport": "Ferpleats / Sleep Viewport", + "Keyboard": "Toetseboerd", + "Show Keyboard": "Toetseboerd sjen litte", + "Extra keys": "Ekstra toetsen", + "Show Extra Keys": "Toan ekstra toetsen sjen", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Omskeakelje Ctrl", + "Alt": "Alt", + "Toggle Alt": "Alt wikselje", + "Toggle Windows": "Wiskje Windows", + "Windows": "Windows", + "Send Tab": "Tjep ferstjoere", + "Tab": "Tab", + "Esc": "Esk", + "Send Escape": "Stjoer Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Stjoer Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "Krêft", + "Shutdown": "Ofslúte", + "Reboot": "Reboot", + "Reset": "Reset", + "Clipboard": "Klipboard", + "Clear": "Opklearje", + "Fullscreen": "Folslein skerm", + "Settings": "Ynstellings", + "Shared Mode": "Dielde modus", + "View Only": "Allinne sjen", + "Clip to Window": "Klip nei finster", + "Scaling Mode:": "Skaalmodus:", + "None": "Gjin", + "Local Scaling": "Lokale skaalfergrutting", + "Remote Resizing": "Remote Resizing", + "Advanced": "Avansearre", + "Quality:": "Kwaliteit:", + "Compression level:": "Kompresjenivo:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Gasthear:", + "Port:": "Haven:", + "Path:": "Paad:", + "Automatic Reconnect": "Automatysk opnij ferbine", + "Reconnect Delay (ms):": "Reconnect Delay (ms):", + "Show Dot when No Cursor": "Dot sjen litte as gjin rinnerke", + "Logging:": "Logearje:", + "Version:": "Ferzje:", + "Disconnect": "Disconnect", + "Connect": "Ferbine", + "Username:": "Brûkersnamme:", + "Password:": "Wachtwurd:", + "Send Credentials": "Stjoer referinsjes", + "Cancel": "Ofbrekke", + "Keys": "Kaaien", + "Game Cursor Mode": "Game Cursor Mode", + "Press Esc Key to Exit Pointer Lock Mode": "Druk op Esc-toets om de Pointer Lock Mode te ferlitten", + "Game Mode paused, click on screen to resume Game Mode.": "Spulmodus ûnderbrutsen, klikje op it skerm om de spielmodus te hervatten.", + "Clipboard Up": "Klimboerd omheech", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Klipboard Seamless", + "Prefer Local Cursor": "Lokaal rinnerke foarkar", + "Translate keyboard shortcuts": "Oersette toetseboerd fluchtoetsen", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ynskeakelje", + "Enable WebP Compression": "WebP-kompresje ynskeakelje", + "Enable Performance Stats": "Prestaasjestatistiken ynskeakelje", + "Enable Pointer Lock": "Aanwizerslot ynskeakelje", + "IME Input Mode": "IME-ynfiermodus", + "Show Virtual Keyboard Control": "Lit firtuele toetseboerdkontrôle sjen", + "Toggle Control Panel via Keystrokes": "Kontrolpaniel wikselje fia toetsoanslaggen", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Sneltoetsen", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-toetseboerd fluchtoetsen ynskeakelje", + "1 - Toggle Control Panel": "1 - Skeakelje kontrôlepaniel", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Streamkwaliteit", + "Preset Modes:": "Foarynstelde modi:", + "Static": "Statysk", + "Low": "Leech", + "Medium": "Medium", + "High": "Heech", + "Extreme": "Ekstreem", + "Lossless": "Lossless", + "Custom": "Oanpaste", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Út", + "On": "Op", + "Dynamic Quality Min:": "Dynamyske kwaliteit min:", + "Dynamic Quality Max:": "Dynamyske kwaliteit Max:", + "Treat Lossless:": "Behannelje Lossless:", + "Frame Rate:": "Byldsnelheid:", + "Video JPEG Quality:": "Fideo JPEG-kwaliteit:", + "Video WEBP Quality:": "Video WEBP Quality:", + "Video Area:": "Fideogebiet:", + "Video Time:": "Fideotiid:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Breedte fan fideomodus:", + "Video Mode Height:": "Hichte fan fideomodus:", + "Documentation": "Dokumintaasje", + "Drag Viewport": "Sleep Viewport", + "KasmVNC encountered an error:": "KasmVNC tsjinkaam in flater:" +} \ No newline at end of file diff --git a/app/locale/fy_DE.json b/app/locale/fy_DE.json new file mode 100644 index 0000000..d84948d --- /dev/null +++ b/app/locale/fy_DE.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ferbine...", + "Disconnecting...": "Ferbrûkt ...", + "Reconnecting...": "Opnij ferbinen...", + "Internal error": "Ynterne flater", + "Must set host": "Moat host ynstelle", + "Connected (encrypted) to ": "Ferbûn (fersifere) oan", + "Connected (unencrypted) to ": "Ferbûn (net fersifere) oan", + "Something went wrong, connection is closed": "Der gie der mis, ferbining is sluten", + "Failed to connect to server": "Ferbine mei tsjinner mislearre", + "Disconnected": "Ferbûn", + "New connection has been rejected with reason: ": "Nije ferbining is ôfwiisd mei reden:", + "New connection has been rejected": "Nije ferbining is ôfwiisd", + "Credentials are required": "Referinsjes binne ferplicht", + "Hide/Show the control bar": "De kontrôlebalke ferbergje / sjen litte", + "Drag": "Slep", + "Move/Drag Viewport": "Ferpleats / Sleep Viewport", + "Keyboard": "Toetseboerd", + "Show Keyboard": "Toetseboerd sjen litte", + "Extra keys": "Ekstra toetsen", + "Show Extra Keys": "Toan ekstra toetsen sjen", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Omskeakelje Ctrl", + "Alt": "Alt", + "Toggle Alt": "Alt wikselje", + "Toggle Windows": "Wiskje Windows", + "Windows": "Windows", + "Send Tab": "Tjep ferstjoere", + "Tab": "Tab", + "Esc": "Esk", + "Send Escape": "Stjoer Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Stjoer Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "Krêft", + "Shutdown": "Ofslúte", + "Reboot": "Reboot", + "Reset": "Reset", + "Clipboard": "Klipboard", + "Clear": "Opklearje", + "Fullscreen": "Folslein skerm", + "Settings": "Ynstellings", + "Shared Mode": "Dielde modus", + "View Only": "Allinne sjen", + "Clip to Window": "Klip nei finster", + "Scaling Mode:": "Skaalmodus:", + "None": "Gjin", + "Local Scaling": "Lokale skaalfergrutting", + "Remote Resizing": "Remote Resizing", + "Advanced": "Avansearre", + "Quality:": "Kwaliteit:", + "Compression level:": "Kompresjenivo:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Gasthear:", + "Port:": "Haven:", + "Path:": "Paad:", + "Automatic Reconnect": "Automatysk opnij ferbine", + "Reconnect Delay (ms):": "Reconnect Delay (ms):", + "Show Dot when No Cursor": "Dot sjen litte as gjin rinnerke", + "Logging:": "Logearje:", + "Version:": "Ferzje:", + "Disconnect": "Disconnect", + "Connect": "Ferbine", + "Username:": "Brûkersnamme:", + "Password:": "Wachtwurd:", + "Send Credentials": "Stjoer referinsjes", + "Cancel": "Ofbrekke", + "Keys": "Kaaien", + "Game Cursor Mode": "Game Cursor Mode", + "Press Esc Key to Exit Pointer Lock Mode": "Druk op Esc-toets om de Pointer Lock Mode te ferlitten", + "Game Mode paused, click on screen to resume Game Mode.": "Spulmodus ûnderbrutsen, klikje op it skerm om de spielmodus te hervatten.", + "Clipboard Up": "Klimboerd omheech", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Klipboard Seamless", + "Prefer Local Cursor": "Lokaal rinnerke foarkar", + "Translate keyboard shortcuts": "Oersette toetseboerd fluchtoetsen", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ynskeakelje", + "Enable WebP Compression": "WebP-kompresje ynskeakelje", + "Enable Performance Stats": "Prestaasjestatistiken ynskeakelje", + "Enable Pointer Lock": "Aanwizerslot ynskeakelje", + "IME Input Mode": "IME-ynfiermodus", + "Show Virtual Keyboard Control": "Lit firtuele toetseboerdkontrôle sjen", + "Toggle Control Panel via Keystrokes": "Kontrolpaniel wikselje fia toetsoanslaggen", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Sneltoetsen", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-toetseboerd fluchtoetsen ynskeakelje", + "1 - Toggle Control Panel": "1 - Skeakelje kontrôlepaniel", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Streamkwaliteit", + "Preset Modes:": "Foarynstelde modi:", + "Static": "Statysk", + "Low": "Leech", + "Medium": "Medium", + "High": "Heech", + "Extreme": "Ekstreem", + "Lossless": "Lossless", + "Custom": "Oanpaste", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Út", + "On": "Op", + "Dynamic Quality Min:": "Dynamyske kwaliteit min:", + "Dynamic Quality Max:": "Dynamyske kwaliteit Max:", + "Treat Lossless:": "Behannelje Lossless:", + "Frame Rate:": "Byldsnelheid:", + "Video JPEG Quality:": "Fideo JPEG-kwaliteit:", + "Video WEBP Quality:": "Video WEBP Quality:", + "Video Area:": "Fideogebiet:", + "Video Time:": "Fideotiid:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Breedte fan fideomodus:", + "Video Mode Height:": "Hichte fan fideomodus:", + "Documentation": "Dokumintaasje", + "Drag Viewport": "Sleep Viewport", + "KasmVNC encountered an error:": "KasmVNC tsjinkaam in flater:" +} \ No newline at end of file diff --git a/app/locale/fy_NL.json b/app/locale/fy_NL.json new file mode 100644 index 0000000..d84948d --- /dev/null +++ b/app/locale/fy_NL.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ferbine...", + "Disconnecting...": "Ferbrûkt ...", + "Reconnecting...": "Opnij ferbinen...", + "Internal error": "Ynterne flater", + "Must set host": "Moat host ynstelle", + "Connected (encrypted) to ": "Ferbûn (fersifere) oan", + "Connected (unencrypted) to ": "Ferbûn (net fersifere) oan", + "Something went wrong, connection is closed": "Der gie der mis, ferbining is sluten", + "Failed to connect to server": "Ferbine mei tsjinner mislearre", + "Disconnected": "Ferbûn", + "New connection has been rejected with reason: ": "Nije ferbining is ôfwiisd mei reden:", + "New connection has been rejected": "Nije ferbining is ôfwiisd", + "Credentials are required": "Referinsjes binne ferplicht", + "Hide/Show the control bar": "De kontrôlebalke ferbergje / sjen litte", + "Drag": "Slep", + "Move/Drag Viewport": "Ferpleats / Sleep Viewport", + "Keyboard": "Toetseboerd", + "Show Keyboard": "Toetseboerd sjen litte", + "Extra keys": "Ekstra toetsen", + "Show Extra Keys": "Toan ekstra toetsen sjen", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Omskeakelje Ctrl", + "Alt": "Alt", + "Toggle Alt": "Alt wikselje", + "Toggle Windows": "Wiskje Windows", + "Windows": "Windows", + "Send Tab": "Tjep ferstjoere", + "Tab": "Tab", + "Esc": "Esk", + "Send Escape": "Stjoer Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Stjoer Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "Krêft", + "Shutdown": "Ofslúte", + "Reboot": "Reboot", + "Reset": "Reset", + "Clipboard": "Klipboard", + "Clear": "Opklearje", + "Fullscreen": "Folslein skerm", + "Settings": "Ynstellings", + "Shared Mode": "Dielde modus", + "View Only": "Allinne sjen", + "Clip to Window": "Klip nei finster", + "Scaling Mode:": "Skaalmodus:", + "None": "Gjin", + "Local Scaling": "Lokale skaalfergrutting", + "Remote Resizing": "Remote Resizing", + "Advanced": "Avansearre", + "Quality:": "Kwaliteit:", + "Compression level:": "Kompresjenivo:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Gasthear:", + "Port:": "Haven:", + "Path:": "Paad:", + "Automatic Reconnect": "Automatysk opnij ferbine", + "Reconnect Delay (ms):": "Reconnect Delay (ms):", + "Show Dot when No Cursor": "Dot sjen litte as gjin rinnerke", + "Logging:": "Logearje:", + "Version:": "Ferzje:", + "Disconnect": "Disconnect", + "Connect": "Ferbine", + "Username:": "Brûkersnamme:", + "Password:": "Wachtwurd:", + "Send Credentials": "Stjoer referinsjes", + "Cancel": "Ofbrekke", + "Keys": "Kaaien", + "Game Cursor Mode": "Game Cursor Mode", + "Press Esc Key to Exit Pointer Lock Mode": "Druk op Esc-toets om de Pointer Lock Mode te ferlitten", + "Game Mode paused, click on screen to resume Game Mode.": "Spulmodus ûnderbrutsen, klikje op it skerm om de spielmodus te hervatten.", + "Clipboard Up": "Klimboerd omheech", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Klipboard Seamless", + "Prefer Local Cursor": "Lokaal rinnerke foarkar", + "Translate keyboard shortcuts": "Oersette toetseboerd fluchtoetsen", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ynskeakelje", + "Enable WebP Compression": "WebP-kompresje ynskeakelje", + "Enable Performance Stats": "Prestaasjestatistiken ynskeakelje", + "Enable Pointer Lock": "Aanwizerslot ynskeakelje", + "IME Input Mode": "IME-ynfiermodus", + "Show Virtual Keyboard Control": "Lit firtuele toetseboerdkontrôle sjen", + "Toggle Control Panel via Keystrokes": "Kontrolpaniel wikselje fia toetsoanslaggen", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Sneltoetsen", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-toetseboerd fluchtoetsen ynskeakelje", + "1 - Toggle Control Panel": "1 - Skeakelje kontrôlepaniel", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Streamkwaliteit", + "Preset Modes:": "Foarynstelde modi:", + "Static": "Statysk", + "Low": "Leech", + "Medium": "Medium", + "High": "Heech", + "Extreme": "Ekstreem", + "Lossless": "Lossless", + "Custom": "Oanpaste", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Út", + "On": "Op", + "Dynamic Quality Min:": "Dynamyske kwaliteit min:", + "Dynamic Quality Max:": "Dynamyske kwaliteit Max:", + "Treat Lossless:": "Behannelje Lossless:", + "Frame Rate:": "Byldsnelheid:", + "Video JPEG Quality:": "Fideo JPEG-kwaliteit:", + "Video WEBP Quality:": "Video WEBP Quality:", + "Video Area:": "Fideogebiet:", + "Video Time:": "Fideotiid:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Breedte fan fideomodus:", + "Video Mode Height:": "Hichte fan fideomodus:", + "Documentation": "Dokumintaasje", + "Drag Viewport": "Sleep Viewport", + "KasmVNC encountered an error:": "KasmVNC tsjinkaam in flater:" +} \ No newline at end of file diff --git a/app/locale/ga.json b/app/locale/ga.json new file mode 100644 index 0000000..abc1506 --- /dev/null +++ b/app/locale/ga.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ag nascadh...", + "Disconnecting...": "Á dhícheangal...", + "Reconnecting...": "Athcheangail...", + "Internal error": "Earráid inmheánach", + "Must set host": "Ní mór óstach a shocrú", + "Connected (encrypted) to ": "Ceangailte (criptithe) le", + "Connected (unencrypted) to ": "Ceangailte (neamhchriptithe) le", + "Something went wrong, connection is closed": "Tharla earráid, tá an nasc dúnta", + "Failed to connect to server": "Theip ar nascadh leis an bhfreastalaí", + "Disconnected": "Dícheangailte", + "New connection has been rejected with reason: ": "Diúltaíodh do cheangal nua le cúis:", + "New connection has been rejected": "Diúltaíodh do cheangal nua", + "Credentials are required": "Tá dintiúir ag teastáil", + "Hide/Show the control bar": "Folaigh/Taispeáin an barra rialaithe", + "Drag": "Tarraing", + "Move/Drag Viewport": "Bog/Tarraing Viewport", + "Keyboard": "Méarchláir", + "Show Keyboard": "Taispeáin Méarchlár", + "Extra keys": "Eochracha breise", + "Show Extra Keys": "Taispeáin Eochracha Breise", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Scoránaigh Ctrl", + "Alt": "Alt", + "Toggle Alt": "Scoránaigh Alt", + "Toggle Windows": "Scoránaigh Windows", + "Windows": "Windows", + "Send Tab": "Seol Cluaisín", + "Tab": "Cluaisín", + "Esc": "Esc", + "Send Escape": "Seol Éalú", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Seol Ctrl-Alt-Del", + "Shutdown/Reboot": "Múchadh/Atosaigh", + "Shutdown/Reboot...": "Múchadh/Atosaigh...", + "Power": "Cumhacht", + "Shutdown": "Múchadh", + "Reboot": "Atosaigh", + "Reset": "Athshocraigh", + "Clipboard": "gearrthaisce", + "Clear": "Glan", + "Fullscreen": "Scáileán iomlán", + "Settings": "Socruithe", + "Shared Mode": "Mód Comhroinnte", + "View Only": "Amharc Amháin", + "Clip to Window": "Gearrtha go Fuinneog", + "Scaling Mode:": "Mód Scálú:", + "None": "Níl", + "Local Scaling": "Scálú Áitiúil", + "Remote Resizing": "Cianmhéid a Athrú", + "Advanced": "Casta", + "Quality:": "Caighdeán:", + "Compression level:": "Leibhéal comhbhrú:", + "Repeater ID:": "Aitheantas an Athsheoltóra:", + "WebSocket": "Soicéad Gréasáin", + "Encrypt": "Criptigh", + "Host:": "Óstríomhaire:", + "Port:": "Port:", + "Path:": "Conair:", + "Automatic Reconnect": "Athcheangail Uathoibríoch", + "Reconnect Delay (ms):": "Athcheangail Moill (ms):", + "Show Dot when No Cursor": "Taispeáin Dot nuair Gan Cúrsóir", + "Logging:": "Logáil:", + "Version:": "Leagan:", + "Disconnect": "Dícheangail", + "Connect": "Ceangal", + "Username:": "Ainm úsáideora:", + "Password:": "Focal Faire:", + "Send Credentials": "Seol Dintiúir", + "Cancel": "Cealaigh", + "Keys": "Eochracha", + "Game Cursor Mode": "Mód Cúrsóir Cluiche", + "Press Esc Key to Exit Pointer Lock Mode": "Brúigh Esc Key chun Mód Glais Pointeora a Scoir", + "Game Mode paused, click on screen to resume Game Mode.": "Mód Cluiche ar sos, cliceáil ar an scáileán chun Mód Cluiche a atosú.", + "Clipboard Up": "Gearrthaisce Suas", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Gearrthaisce gan uaim", + "Prefer Local Cursor": "Is fearr Cúrsóir Áitiúil", + "Translate keyboard shortcuts": "Aistrigh aicearraí méarchláir", + "Enable WebRTC UDP Transit": "Cumasaigh WebRTC UDP Transit", + "Enable WebP Compression": "Cumasaigh Comhbhrú WebP", + "Enable Performance Stats": "Cumasaigh Staitisticí Feidhmíochta", + "Enable Pointer Lock": "Cumasaigh Pointeoir Glas", + "IME Input Mode": "Mód Ionchuir IME", + "Show Virtual Keyboard Control": "Taispeáin Rialú Méarchlár Fíorúil", + "Toggle Control Panel via Keystrokes": "Scoránaigh an Painéal Rialúcháin trí Eochairbhuillí", + "Render Native Resolution": "Render Taifeach Dúchasach", + "Keyboard Shortcuts": "Aicearraí méarchláir", + "Enable KasmVNC Keyboard Shortcuts": "Cumasaigh Aicearraí Méarchláir KasmVNC", + "1 - Toggle Control Panel": "1 - Scoránaigh Painéal Rialúcháin", + "2 - Toggle Game Pointer Mode": "2 - Scoránaigh Mód Pointeora Cluiche", + "3 - Toggle Pointer Lock": "3 - Scoránaigh Glasáil Pointeora", + "Stream Quality": "Caighdeán Sruth", + "Preset Modes:": "Móid Réamhshocraithe:", + "Static": "Statach", + "Low": "Íseal", + "Medium": "Mheán", + "High": "Ard", + "Extreme": "Extreme", + "Lossless": "gan chailleadh", + "Custom": "Saincheaptha", + "Anti-Aliasing:": "Frith-Aliasing:", + "Auto Dynamic": "Uathdhinimiciúla", + "Off": "as", + "On": "ar", + "Dynamic Quality Min:": "Íosmhéid Cáilíochta Dinimiciúla:", + "Dynamic Quality Max:": "Uasmhéid Cáilíochta Dinimiciúla:", + "Treat Lossless:": "Caitheamh gan chailleadh:", + "Frame Rate:": "Ráta fhráma:", + "Video JPEG Quality:": "Cáilíocht JPEG Físeáin:", + "Video WEBP Quality:": "Cáilíocht WEBP Físeáin:", + "Video Area:": "Réimse Físe:", + "Video Time:": "Am Físe:", + "Video Out Time:": "Fís Amach Am:", + "Video Mode Width:": "Leithead Mhód Físe:", + "Video Mode Height:": "Airde Mód Físe:", + "Documentation": "Doiciméad", + "Drag Viewport": "Tarraing Viewport", + "KasmVNC encountered an error:": "Tharla earráid i KasmVNC:" +} \ No newline at end of file diff --git a/app/locale/ga_IE.json b/app/locale/ga_IE.json new file mode 100644 index 0000000..abc1506 --- /dev/null +++ b/app/locale/ga_IE.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ag nascadh...", + "Disconnecting...": "Á dhícheangal...", + "Reconnecting...": "Athcheangail...", + "Internal error": "Earráid inmheánach", + "Must set host": "Ní mór óstach a shocrú", + "Connected (encrypted) to ": "Ceangailte (criptithe) le", + "Connected (unencrypted) to ": "Ceangailte (neamhchriptithe) le", + "Something went wrong, connection is closed": "Tharla earráid, tá an nasc dúnta", + "Failed to connect to server": "Theip ar nascadh leis an bhfreastalaí", + "Disconnected": "Dícheangailte", + "New connection has been rejected with reason: ": "Diúltaíodh do cheangal nua le cúis:", + "New connection has been rejected": "Diúltaíodh do cheangal nua", + "Credentials are required": "Tá dintiúir ag teastáil", + "Hide/Show the control bar": "Folaigh/Taispeáin an barra rialaithe", + "Drag": "Tarraing", + "Move/Drag Viewport": "Bog/Tarraing Viewport", + "Keyboard": "Méarchláir", + "Show Keyboard": "Taispeáin Méarchlár", + "Extra keys": "Eochracha breise", + "Show Extra Keys": "Taispeáin Eochracha Breise", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Scoránaigh Ctrl", + "Alt": "Alt", + "Toggle Alt": "Scoránaigh Alt", + "Toggle Windows": "Scoránaigh Windows", + "Windows": "Windows", + "Send Tab": "Seol Cluaisín", + "Tab": "Cluaisín", + "Esc": "Esc", + "Send Escape": "Seol Éalú", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Seol Ctrl-Alt-Del", + "Shutdown/Reboot": "Múchadh/Atosaigh", + "Shutdown/Reboot...": "Múchadh/Atosaigh...", + "Power": "Cumhacht", + "Shutdown": "Múchadh", + "Reboot": "Atosaigh", + "Reset": "Athshocraigh", + "Clipboard": "gearrthaisce", + "Clear": "Glan", + "Fullscreen": "Scáileán iomlán", + "Settings": "Socruithe", + "Shared Mode": "Mód Comhroinnte", + "View Only": "Amharc Amháin", + "Clip to Window": "Gearrtha go Fuinneog", + "Scaling Mode:": "Mód Scálú:", + "None": "Níl", + "Local Scaling": "Scálú Áitiúil", + "Remote Resizing": "Cianmhéid a Athrú", + "Advanced": "Casta", + "Quality:": "Caighdeán:", + "Compression level:": "Leibhéal comhbhrú:", + "Repeater ID:": "Aitheantas an Athsheoltóra:", + "WebSocket": "Soicéad Gréasáin", + "Encrypt": "Criptigh", + "Host:": "Óstríomhaire:", + "Port:": "Port:", + "Path:": "Conair:", + "Automatic Reconnect": "Athcheangail Uathoibríoch", + "Reconnect Delay (ms):": "Athcheangail Moill (ms):", + "Show Dot when No Cursor": "Taispeáin Dot nuair Gan Cúrsóir", + "Logging:": "Logáil:", + "Version:": "Leagan:", + "Disconnect": "Dícheangail", + "Connect": "Ceangal", + "Username:": "Ainm úsáideora:", + "Password:": "Focal Faire:", + "Send Credentials": "Seol Dintiúir", + "Cancel": "Cealaigh", + "Keys": "Eochracha", + "Game Cursor Mode": "Mód Cúrsóir Cluiche", + "Press Esc Key to Exit Pointer Lock Mode": "Brúigh Esc Key chun Mód Glais Pointeora a Scoir", + "Game Mode paused, click on screen to resume Game Mode.": "Mód Cluiche ar sos, cliceáil ar an scáileán chun Mód Cluiche a atosú.", + "Clipboard Up": "Gearrthaisce Suas", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Gearrthaisce gan uaim", + "Prefer Local Cursor": "Is fearr Cúrsóir Áitiúil", + "Translate keyboard shortcuts": "Aistrigh aicearraí méarchláir", + "Enable WebRTC UDP Transit": "Cumasaigh WebRTC UDP Transit", + "Enable WebP Compression": "Cumasaigh Comhbhrú WebP", + "Enable Performance Stats": "Cumasaigh Staitisticí Feidhmíochta", + "Enable Pointer Lock": "Cumasaigh Pointeoir Glas", + "IME Input Mode": "Mód Ionchuir IME", + "Show Virtual Keyboard Control": "Taispeáin Rialú Méarchlár Fíorúil", + "Toggle Control Panel via Keystrokes": "Scoránaigh an Painéal Rialúcháin trí Eochairbhuillí", + "Render Native Resolution": "Render Taifeach Dúchasach", + "Keyboard Shortcuts": "Aicearraí méarchláir", + "Enable KasmVNC Keyboard Shortcuts": "Cumasaigh Aicearraí Méarchláir KasmVNC", + "1 - Toggle Control Panel": "1 - Scoránaigh Painéal Rialúcháin", + "2 - Toggle Game Pointer Mode": "2 - Scoránaigh Mód Pointeora Cluiche", + "3 - Toggle Pointer Lock": "3 - Scoránaigh Glasáil Pointeora", + "Stream Quality": "Caighdeán Sruth", + "Preset Modes:": "Móid Réamhshocraithe:", + "Static": "Statach", + "Low": "Íseal", + "Medium": "Mheán", + "High": "Ard", + "Extreme": "Extreme", + "Lossless": "gan chailleadh", + "Custom": "Saincheaptha", + "Anti-Aliasing:": "Frith-Aliasing:", + "Auto Dynamic": "Uathdhinimiciúla", + "Off": "as", + "On": "ar", + "Dynamic Quality Min:": "Íosmhéid Cáilíochta Dinimiciúla:", + "Dynamic Quality Max:": "Uasmhéid Cáilíochta Dinimiciúla:", + "Treat Lossless:": "Caitheamh gan chailleadh:", + "Frame Rate:": "Ráta fhráma:", + "Video JPEG Quality:": "Cáilíocht JPEG Físeáin:", + "Video WEBP Quality:": "Cáilíocht WEBP Físeáin:", + "Video Area:": "Réimse Físe:", + "Video Time:": "Am Físe:", + "Video Out Time:": "Fís Amach Am:", + "Video Mode Width:": "Leithead Mhód Físe:", + "Video Mode Height:": "Airde Mód Físe:", + "Documentation": "Doiciméad", + "Drag Viewport": "Tarraing Viewport", + "KasmVNC encountered an error:": "Tharla earráid i KasmVNC:" +} \ No newline at end of file diff --git a/app/locale/gd.json b/app/locale/gd.json new file mode 100644 index 0000000..3177286 --- /dev/null +++ b/app/locale/gd.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "A' ceangal...", + "Disconnecting...": "A' dì-cheangal...", + "Reconnecting...": "Ag ath-cheangal...", + "Internal error": "Mearachd a-staigh", + "Must set host": "Feumar aoigheachd a shuidheachadh", + "Connected (encrypted) to ": "Ceangailte (crioptaichte) ri", + "Connected (unencrypted) to ": "Ceangailte (gun chrioptachadh) ri", + "Something went wrong, connection is closed": "Chaidh rudeigin ceàrr, tha an ceangal dùinte", + "Failed to connect to server": "Dh'fhàillig le ceangal ris an fhrithealaiche", + "Disconnected": "Dì-cheangail", + "New connection has been rejected with reason: ": "Chaidh ceangal ùr a dhiùltadh le adhbhar:", + "New connection has been rejected": "Chaidh ceangal ùr a dhiùltadh", + "Credentials are required": "Tha feum air teisteanasan", + "Hide/Show the control bar": "Falaich/Seall am bàr-smachd", + "Drag": "Slaod", + "Move/Drag Viewport": "Gluais / Slaod Sealladh-amhairc", + "Keyboard": "Meur-chlàr", + "Show Keyboard": "Seall am meur-chlàr", + "Extra keys": "Iuchraichean a bharrachd", + "Show Extra Keys": "Seall iuchraichean a bharrachd", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Toggle Ctrl", + "Alt": "Alt", + "Toggle Alt": "Tog an Alt", + "Toggle Windows": "Tog Windows", + "Windows": "Windows", + "Send Tab": "Cuir tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Cuir teicheadh", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Cuir Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Ath-thòisich", + "Shutdown/Reboot...": "Dùin sìos/Ath-thòisich...", + "Power": "Cumhachd", + "Shutdown": "Dùin sìos", + "Reboot": "Ath-thòisich", + "Reset": "Ath-shuidhich", + "Clipboard": "Clipboard", + "Clear": "Soilleir", + "Fullscreen": "làn-sgrìn", + "Settings": "Roghainnean", + "Shared Mode": "Modh co-roinnte", + "View Only": "Seall a-mhàin", + "Clip to Window": "Gliog dhan uinneig", + "Scaling Mode:": "Modh sgèileachaidh:", + "None": "Chan eil", + "Local Scaling": "Sgèileadh ionadail", + "Remote Resizing": "Ath-mheudachadh air astar", + "Advanced": "Adhartach", + "Quality:": "Càileachd:", + "Compression level:": "Ìre teannachaidh:", + "Repeater ID:": "ID ath-aithris:", + "WebSocket": "WebSocket", + "Encrypt": "Crioptachadh", + "Host:": "Aoigh:", + "Port:": "Port:", + "Path:": "Slighe:", + "Automatic Reconnect": "Ath-cheangail fèin-ghluasadach", + "Reconnect Delay (ms):": "Ath-cheangail dàil (ms):", + "Show Dot when No Cursor": "Seall dot nuair nach eil cursair ann", + "Logging:": "Logadh:", + "Version:": "Tionndadh:", + "Disconnect": "Dì-cheangail", + "Connect": "Ceangail", + "Username:": "Ainm-cleachdaidh:", + "Password:": "Facal-faire:", + "Send Credentials": "Cuir teisteanasan", + "Cancel": "Sguir dheth", + "Keys": "Iuchraichean", + "Game Cursor Mode": "Modh Cursor Gèam", + "Press Esc Key to Exit Pointer Lock Mode": "Brùth air Esc Key gus am fàg am modh glasaidh comharrachaidh", + "Game Mode paused, click on screen to resume Game Mode.": "Modh geama air a stad, cliog air an sgrion gus Modh Gèam ath-thòiseachadh.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Is fheàrr le cursair ionadail", + "Translate keyboard shortcuts": "Eadar-theangaich ath-ghoiridean meur-chlàir", + "Enable WebRTC UDP Transit": "Cuir an comas WebRTC UDP Transit", + "Enable WebP Compression": "Cuir an comas WebP compression", + "Enable Performance Stats": "Cuir an comas staitistig coileanaidh", + "Enable Pointer Lock": "Cuir an comas Lock Pointer", + "IME Input Mode": "Modh cuir a-steach IME", + "Show Virtual Keyboard Control": "Seall smachd meur-chlàr mas-fhìor", + "Toggle Control Panel via Keystrokes": "Tog Pannal Smachd tro Keystrokes", + "Render Native Resolution": "Render Resolution", + "Keyboard Shortcuts": "Ath-ghoiridean meur-chlàr", + "Enable KasmVNC Keyboard Shortcuts": "Cuir an comas ath-ghoiridean meur-chlàr KasmVNC", + "1 - Toggle Control Panel": "1 - Tog Pannal Smachd", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Tog glas puinger", + "Stream Quality": "Càileachd an t-sruth", + "Preset Modes:": "Modhan ro-shuidhichte:", + "Static": "Statach", + "Low": "Ìosal", + "Medium": "Meadhanach", + "High": "Àrd", + "Extreme": "Airson", + "Lossless": "Gun chall", + "Custom": "Custom", + "Anti-Aliasing:": "An-aghaidh aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "dheth", + "On": "Air adhart", + "Dynamic Quality Min:": "Càileachd fiùghantach as ìsle:", + "Dynamic Quality Max:": "Càileachd fiùghantach as àirde:", + "Treat Lossless:": "Làimhsich gun chall:", + "Frame Rate:": "Reat frèam:", + "Video JPEG Quality:": "Càileachd bhidio JPEG:", + "Video WEBP Quality:": "Càileachd bhidio WEBP:", + "Video Area:": "Raon bhidio:", + "Video Time:": "Ùine bhidio:", + "Video Out Time:": "Àm a-mach bhidio:", + "Video Mode Width:": "Leud modh bhidio:", + "Video Mode Height:": "Àrd modh bhidio:", + "Documentation": "Sgrìobhainn", + "Drag Viewport": "Slaod am port-seallaidh", + "KasmVNC encountered an error:": "Thachair KasmVNC ri mearachd:" +} \ No newline at end of file diff --git a/app/locale/gd_GB.json b/app/locale/gd_GB.json new file mode 100644 index 0000000..3177286 --- /dev/null +++ b/app/locale/gd_GB.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "A' ceangal...", + "Disconnecting...": "A' dì-cheangal...", + "Reconnecting...": "Ag ath-cheangal...", + "Internal error": "Mearachd a-staigh", + "Must set host": "Feumar aoigheachd a shuidheachadh", + "Connected (encrypted) to ": "Ceangailte (crioptaichte) ri", + "Connected (unencrypted) to ": "Ceangailte (gun chrioptachadh) ri", + "Something went wrong, connection is closed": "Chaidh rudeigin ceàrr, tha an ceangal dùinte", + "Failed to connect to server": "Dh'fhàillig le ceangal ris an fhrithealaiche", + "Disconnected": "Dì-cheangail", + "New connection has been rejected with reason: ": "Chaidh ceangal ùr a dhiùltadh le adhbhar:", + "New connection has been rejected": "Chaidh ceangal ùr a dhiùltadh", + "Credentials are required": "Tha feum air teisteanasan", + "Hide/Show the control bar": "Falaich/Seall am bàr-smachd", + "Drag": "Slaod", + "Move/Drag Viewport": "Gluais / Slaod Sealladh-amhairc", + "Keyboard": "Meur-chlàr", + "Show Keyboard": "Seall am meur-chlàr", + "Extra keys": "Iuchraichean a bharrachd", + "Show Extra Keys": "Seall iuchraichean a bharrachd", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Toggle Ctrl", + "Alt": "Alt", + "Toggle Alt": "Tog an Alt", + "Toggle Windows": "Tog Windows", + "Windows": "Windows", + "Send Tab": "Cuir tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Cuir teicheadh", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Cuir Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Ath-thòisich", + "Shutdown/Reboot...": "Dùin sìos/Ath-thòisich...", + "Power": "Cumhachd", + "Shutdown": "Dùin sìos", + "Reboot": "Ath-thòisich", + "Reset": "Ath-shuidhich", + "Clipboard": "Clipboard", + "Clear": "Soilleir", + "Fullscreen": "làn-sgrìn", + "Settings": "Roghainnean", + "Shared Mode": "Modh co-roinnte", + "View Only": "Seall a-mhàin", + "Clip to Window": "Gliog dhan uinneig", + "Scaling Mode:": "Modh sgèileachaidh:", + "None": "Chan eil", + "Local Scaling": "Sgèileadh ionadail", + "Remote Resizing": "Ath-mheudachadh air astar", + "Advanced": "Adhartach", + "Quality:": "Càileachd:", + "Compression level:": "Ìre teannachaidh:", + "Repeater ID:": "ID ath-aithris:", + "WebSocket": "WebSocket", + "Encrypt": "Crioptachadh", + "Host:": "Aoigh:", + "Port:": "Port:", + "Path:": "Slighe:", + "Automatic Reconnect": "Ath-cheangail fèin-ghluasadach", + "Reconnect Delay (ms):": "Ath-cheangail dàil (ms):", + "Show Dot when No Cursor": "Seall dot nuair nach eil cursair ann", + "Logging:": "Logadh:", + "Version:": "Tionndadh:", + "Disconnect": "Dì-cheangail", + "Connect": "Ceangail", + "Username:": "Ainm-cleachdaidh:", + "Password:": "Facal-faire:", + "Send Credentials": "Cuir teisteanasan", + "Cancel": "Sguir dheth", + "Keys": "Iuchraichean", + "Game Cursor Mode": "Modh Cursor Gèam", + "Press Esc Key to Exit Pointer Lock Mode": "Brùth air Esc Key gus am fàg am modh glasaidh comharrachaidh", + "Game Mode paused, click on screen to resume Game Mode.": "Modh geama air a stad, cliog air an sgrion gus Modh Gèam ath-thòiseachadh.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Is fheàrr le cursair ionadail", + "Translate keyboard shortcuts": "Eadar-theangaich ath-ghoiridean meur-chlàir", + "Enable WebRTC UDP Transit": "Cuir an comas WebRTC UDP Transit", + "Enable WebP Compression": "Cuir an comas WebP compression", + "Enable Performance Stats": "Cuir an comas staitistig coileanaidh", + "Enable Pointer Lock": "Cuir an comas Lock Pointer", + "IME Input Mode": "Modh cuir a-steach IME", + "Show Virtual Keyboard Control": "Seall smachd meur-chlàr mas-fhìor", + "Toggle Control Panel via Keystrokes": "Tog Pannal Smachd tro Keystrokes", + "Render Native Resolution": "Render Resolution", + "Keyboard Shortcuts": "Ath-ghoiridean meur-chlàr", + "Enable KasmVNC Keyboard Shortcuts": "Cuir an comas ath-ghoiridean meur-chlàr KasmVNC", + "1 - Toggle Control Panel": "1 - Tog Pannal Smachd", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Tog glas puinger", + "Stream Quality": "Càileachd an t-sruth", + "Preset Modes:": "Modhan ro-shuidhichte:", + "Static": "Statach", + "Low": "Ìosal", + "Medium": "Meadhanach", + "High": "Àrd", + "Extreme": "Airson", + "Lossless": "Gun chall", + "Custom": "Custom", + "Anti-Aliasing:": "An-aghaidh aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "dheth", + "On": "Air adhart", + "Dynamic Quality Min:": "Càileachd fiùghantach as ìsle:", + "Dynamic Quality Max:": "Càileachd fiùghantach as àirde:", + "Treat Lossless:": "Làimhsich gun chall:", + "Frame Rate:": "Reat frèam:", + "Video JPEG Quality:": "Càileachd bhidio JPEG:", + "Video WEBP Quality:": "Càileachd bhidio WEBP:", + "Video Area:": "Raon bhidio:", + "Video Time:": "Ùine bhidio:", + "Video Out Time:": "Àm a-mach bhidio:", + "Video Mode Width:": "Leud modh bhidio:", + "Video Mode Height:": "Àrd modh bhidio:", + "Documentation": "Sgrìobhainn", + "Drag Viewport": "Slaod am port-seallaidh", + "KasmVNC encountered an error:": "Thachair KasmVNC ri mearachd:" +} \ No newline at end of file diff --git a/app/locale/gl.json b/app/locale/gl.json new file mode 100644 index 0000000..c5f6fc7 --- /dev/null +++ b/app/locale/gl.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Conectando...", + "Disconnecting...": "Desconectando...", + "Reconnecting...": "Reconectando...", + "Internal error": "Erro interno", + "Must set host": "Debe establecer o host", + "Connected (encrypted) to ": "Conectado (cifrado) a ", + "Connected (unencrypted) to ": "Conectado (sen cifrar) a ", + "Something went wrong, connection is closed": "Produciuse un erro, a conexión está pechada", + "Failed to connect to server": "Produciuse un erro ao conectar co servidor", + "Disconnected": "Desconectado", + "New connection has been rejected with reason: ": "A nova conexión foi rexeitada polo motivo: ", + "New connection has been rejected": "Rexeitouse a nova conexión", + "Credentials are required": "Requírense credenciais", + "Hide/Show the control bar": "Ocultar/Mostrar a barra de control", + "Drag": "Arrastrar", + "Move/Drag Viewport": "Mover/Arrastrar a xanela", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Chaves extra", + "Show Extra Keys": "Mostrar chaves adicionais", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Alternar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Cambiar Alt", + "Toggle Windows": "Cambiar Windows", + "Windows": "Windows", + "Send Tab": "Enviar pestana", + "Tab": "Pestaña", + "Esc": "ESC", + "Send Escape": "Enviar escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Supr", + "Send Ctrl-Alt-Del": "Enviar Ctrl-Alt-Supr", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Poder", + "Shutdown": "Apagado", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeis", + "Clear": "Limpar", + "Fullscreen": "Pantalla completa", + "Settings": "Configuración", + "Shared Mode": "Modo compartido", + "View Only": "Só vista", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Modo de escalado:", + "None": "Ningún", + "Local Scaling": "Escalación local", + "Remote Resizing": "Redimensionamento remoto", + "Advanced": "Avanzado", + "Quality:": "Calidade:", + "Compression level:": "Nivel de compresión:", + "Repeater ID:": "ID do repetidor:", + "WebSocket": "WebSocket", + "Encrypt": "Cifrar", + "Host:": "Anfitrión:", + "Port:": "Porto:", + "Path:": "Ruta:", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retardo de reconexión (ms):", + "Show Dot when No Cursor": "Mostrar punto cando non hai cursor", + "Logging:": "Rexistro:", + "Version:": "Versión:", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Username:": "Nome de usuario:", + "Password:": "Contrasinal:", + "Send Credentials": "Enviar credenciais", + "Cancel": "Cancelar", + "Keys": "Chaves", + "Game Cursor Mode": "Modo de cursor de xogo", + "Press Esc Key to Exit Pointer Lock Mode": "Preme a tecla Esc para saír do modo de bloqueo do punteiro", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de xogo en pausa, fai clic na pantalla para retomar o modo de xogo", + "Clipboard Up": "Portapapeis arriba", + "CLipboard Down": "Portapapeis abaixo", + "Clipboard Seamless": "Portapapeis sen costuras", + "Prefer Local Cursor": "Preferir o cursor local", + "Translate keyboard shortcuts": "Traducir atallos de teclado", + "Enable WebRTC UDP Transit": "Activar WebRTC UDP Transit", + "Enable WebP Compression": "Activar compresión WebP", + "Enable Performance Stats": "Activar estatísticas de rendemento", + "Enable Pointer Lock": "Activar o bloqueo do punteiro", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar o control do teclado virtual", + "Toggle Control Panel via Keystrokes": "Activar o panel de control mediante as pulsacións de teclas", + "Render Native Resolution": "Renderizar resolución nativa", + "Keyboard Shortcuts": "Atallos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Activar os atallos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar o panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar o modo de punteiro de xogo", + "3 - Toggle Pointer Lock": "3 - Alternar o bloqueo do punteiro", + "Stream Quality": "Calidade do fluxo", + "Preset Modes:": "Modos predefinidos:", + "Static": "estático", + "Low": "Baixo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "Sen perdas", + "Custom": "Personalizado", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Dinámico automático", + "Off": "Desactivado", + "On": "Activado", + "Dynamic Quality Min:": "Calidade dinámica mín.:", + "Dynamic Quality Max:": "Calidade dinámica máxima:", + "Treat Lossless:": "Trata sen perdas:", + "Frame Rate:": "Taxa de fotogramas:", + "Video JPEG Quality:": "Calidade do vídeo JPEG:", + "Video WEBP Quality:": "Calidade do vídeo WEBP:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Hora do vídeo:", + "Video Out Time:": "Hora de saída do vídeo:", + "Video Mode Width:": "Ancho do modo de vídeo:", + "Video Mode Height:": "Altura do modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar a xanela", + "KasmVNC encountered an error:": "KasmVNC atopou un erro:" +} \ No newline at end of file diff --git a/app/locale/gl_ES.json b/app/locale/gl_ES.json new file mode 100644 index 0000000..c5f6fc7 --- /dev/null +++ b/app/locale/gl_ES.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Conectando...", + "Disconnecting...": "Desconectando...", + "Reconnecting...": "Reconectando...", + "Internal error": "Erro interno", + "Must set host": "Debe establecer o host", + "Connected (encrypted) to ": "Conectado (cifrado) a ", + "Connected (unencrypted) to ": "Conectado (sen cifrar) a ", + "Something went wrong, connection is closed": "Produciuse un erro, a conexión está pechada", + "Failed to connect to server": "Produciuse un erro ao conectar co servidor", + "Disconnected": "Desconectado", + "New connection has been rejected with reason: ": "A nova conexión foi rexeitada polo motivo: ", + "New connection has been rejected": "Rexeitouse a nova conexión", + "Credentials are required": "Requírense credenciais", + "Hide/Show the control bar": "Ocultar/Mostrar a barra de control", + "Drag": "Arrastrar", + "Move/Drag Viewport": "Mover/Arrastrar a xanela", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Chaves extra", + "Show Extra Keys": "Mostrar chaves adicionais", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Alternar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Cambiar Alt", + "Toggle Windows": "Cambiar Windows", + "Windows": "Windows", + "Send Tab": "Enviar pestana", + "Tab": "Pestaña", + "Esc": "ESC", + "Send Escape": "Enviar escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Supr", + "Send Ctrl-Alt-Del": "Enviar Ctrl-Alt-Supr", + "Shutdown/Reboot": "Apagar/Reiniciar", + "Shutdown/Reboot...": "Apagar/Reiniciar...", + "Power": "Poder", + "Shutdown": "Apagado", + "Reboot": "Reiniciar", + "Reset": "Restablecer", + "Clipboard": "Portapapeis", + "Clear": "Limpar", + "Fullscreen": "Pantalla completa", + "Settings": "Configuración", + "Shared Mode": "Modo compartido", + "View Only": "Só vista", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Modo de escalado:", + "None": "Ningún", + "Local Scaling": "Escalación local", + "Remote Resizing": "Redimensionamento remoto", + "Advanced": "Avanzado", + "Quality:": "Calidade:", + "Compression level:": "Nivel de compresión:", + "Repeater ID:": "ID do repetidor:", + "WebSocket": "WebSocket", + "Encrypt": "Cifrar", + "Host:": "Anfitrión:", + "Port:": "Porto:", + "Path:": "Ruta:", + "Automatic Reconnect": "Reconexión automática", + "Reconnect Delay (ms):": "Retardo de reconexión (ms):", + "Show Dot when No Cursor": "Mostrar punto cando non hai cursor", + "Logging:": "Rexistro:", + "Version:": "Versión:", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Username:": "Nome de usuario:", + "Password:": "Contrasinal:", + "Send Credentials": "Enviar credenciais", + "Cancel": "Cancelar", + "Keys": "Chaves", + "Game Cursor Mode": "Modo de cursor de xogo", + "Press Esc Key to Exit Pointer Lock Mode": "Preme a tecla Esc para saír do modo de bloqueo do punteiro", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de xogo en pausa, fai clic na pantalla para retomar o modo de xogo", + "Clipboard Up": "Portapapeis arriba", + "CLipboard Down": "Portapapeis abaixo", + "Clipboard Seamless": "Portapapeis sen costuras", + "Prefer Local Cursor": "Preferir o cursor local", + "Translate keyboard shortcuts": "Traducir atallos de teclado", + "Enable WebRTC UDP Transit": "Activar WebRTC UDP Transit", + "Enable WebP Compression": "Activar compresión WebP", + "Enable Performance Stats": "Activar estatísticas de rendemento", + "Enable Pointer Lock": "Activar o bloqueo do punteiro", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar o control do teclado virtual", + "Toggle Control Panel via Keystrokes": "Activar o panel de control mediante as pulsacións de teclas", + "Render Native Resolution": "Renderizar resolución nativa", + "Keyboard Shortcuts": "Atallos de teclado", + "Enable KasmVNC Keyboard Shortcuts": "Activar os atallos de teclado de KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar o panel de control", + "2 - Toggle Game Pointer Mode": "2 - Alternar o modo de punteiro de xogo", + "3 - Toggle Pointer Lock": "3 - Alternar o bloqueo do punteiro", + "Stream Quality": "Calidade do fluxo", + "Preset Modes:": "Modos predefinidos:", + "Static": "estático", + "Low": "Baixo", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "Sen perdas", + "Custom": "Personalizado", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Dinámico automático", + "Off": "Desactivado", + "On": "Activado", + "Dynamic Quality Min:": "Calidade dinámica mín.:", + "Dynamic Quality Max:": "Calidade dinámica máxima:", + "Treat Lossless:": "Trata sen perdas:", + "Frame Rate:": "Taxa de fotogramas:", + "Video JPEG Quality:": "Calidade do vídeo JPEG:", + "Video WEBP Quality:": "Calidade do vídeo WEBP:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Hora do vídeo:", + "Video Out Time:": "Hora de saída do vídeo:", + "Video Mode Width:": "Ancho do modo de vídeo:", + "Video Mode Height:": "Altura do modo de vídeo:", + "Documentation": "Documentación", + "Drag Viewport": "Arrastrar a xanela", + "KasmVNC encountered an error:": "KasmVNC atopou un erro:" +} \ No newline at end of file diff --git a/app/locale/gu.json b/app/locale/gu.json new file mode 100644 index 0000000..da7be34 --- /dev/null +++ b/app/locale/gu.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "જોડાઈ રહ્યું છે...", + "Disconnecting...": "ડિસ્કનેક્ટ કરી રહ્યું છે...", + "Reconnecting...": "ફરીથી કનેક્ટ કરી રહ્યાં છીએ...", + "Internal error": "આંતરિક ભૂલ", + "Must set host": "હોસ્ટ સેટ કરવું આવશ્યક છે", + "Connected (encrypted) to ": "જોડાયેલ (એનક્રિપ્ટેડ) ", + "Connected (unencrypted) to ": "જોડાયેલ (એનક્રિપ્ટ થયેલ નથી) ", + "Something went wrong, connection is closed": "કંઈક ખોટું થયું છે, કનેક્શન બંધ છે", + "Failed to connect to server": "સર્વર સાથે કનેક્ટ કરવામાં નિષ્ફળ", + "Disconnected": "ડિસ્કનેક્ટેડ", + "New connection has been rejected with reason: ": "નવું કનેક્શન કારણ સાથે નકારવામાં આવ્યું છે:", + "New connection has been rejected": "નવું જોડાણ નકારવામાં આવ્યું છે", + "Credentials are required": "પ્રમાણપત્ર જરૂરી છે", + "Hide/Show the control bar": "કંટ્રોલ બાર છુપાવો/બતાવો", + "Drag": "ખેંચો", + "Move/Drag Viewport": "વ્યૂપોર્ટ ખસેડો/ખેંચો", + "Keyboard": "કીબોર્ડ", + "Show Keyboard": "કીબોર્ડ બતાવો", + "Extra keys": "વધારાની ચાવીઓ", + "Show Extra Keys": "વધારાની ચાવીઓ બતાવો", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ટૉગલ કરો", + "Alt": "Alt", + "Toggle Alt": "Alt ટૉગલ કરો", + "Toggle Windows": "વિન્ડોઝ ટૉગલ કરો", + "Windows": "વિન્ડોઝ", + "Send Tab": "ટેબ મોકલો", + "Tab": "ટેબ", + "Esc": "Esc", + "Send Escape": "એસ્કેપ મોકલો", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del મોકલો", + "Shutdown/Reboot": "શટડાઉન/રીબૂટ", + "Shutdown/Reboot...": "શટડાઉન/રીબૂટ...", + "Power": "શક્તિ", + "Shutdown": "બંધ કરો", + "Reboot": "રીબૂટ કરો", + "Reset": "રીસેટ કરો", + "Clipboard": "ક્લિપબોર્ડ", + "Clear": "ચોખ્ખુ", + "Fullscreen": "પૂર્ણ - પટ, આખો પડદો", + "Settings": "સેટિંગ્સ", + "Shared Mode": "શેર્ડ મોડ", + "View Only": "માત્ર જુઓ", + "Clip to Window": "ક્લિપ ટુ વિન્ડો", + "Scaling Mode:": "સ્કેલિંગ મોડ:", + "None": "કોઈ નહિ", + "Local Scaling": "સ્થાનિક સ્કેલિંગ", + "Remote Resizing": "રિમોટ રીસાઇઝીંગ", + "Advanced": "અદ્યતન", + "Quality:": "ગુણવત્તા:", + "Compression level:": "સંકોચન સ્તર:", + "Repeater ID:": "રીપીટર ID:", + "WebSocket": "વેબસોકેટ", + "Encrypt": "એનક્રિપ્ટ", + "Host:": "યજમાન:", + "Port:": "પોર્ટ:", + "Path:": "પાથ:", + "Automatic Reconnect": "ઓટોમેટિક રીકનેક્ટ", + "Reconnect Delay (ms):": "પુનઃજોડાણ વિલંબ (ms):", + "Show Dot when No Cursor": "જ્યારે કર્સર ન હોય ત્યારે ડોટ બતાવો", + "Logging:": "લોગીંગ:", + "Version:": "સંસ્કરણ:", + "Disconnect": "ડિસ્કનેક્ટ કરો", + "Connect": "જોડાવા", + "Username:": "વપરાશકર્તા નામ:", + "Password:": "પાસવર્ડ:", + "Send Credentials": "ઓળખાણપત્રો મોકલો", + "Cancel": "રદ કરો", + "Keys": "ચાવીઓ", + "Game Cursor Mode": "ગેમ કર્સર મોડ", + "Press Esc Key to Exit Pointer Lock Mode": "પોઇન્ટર લોક મોડમાંથી બહાર નીકળવા માટે Esc કી દબાવો", + "Game Mode paused, click on screen to resume Game Mode.": "ગેમ મોડ થોભાવ્યો, ગેમ મોડ ફરી શરૂ કરવા માટે સ્ક્રીન પર ક્લિક કરો.", + "Clipboard Up": "ક્લિપબોર્ડ ઉપર", + "CLipboard Down": "ક્લિપબોર્ડ ડાઉન", + "Clipboard Seamless": "ક્લિપબોર્ડ સીમલેસ", + "Prefer Local Cursor": "સ્થાનિક કર્સરને પ્રાધાન્ય આપો", + "Translate keyboard shortcuts": "કીબોર્ડ શોર્ટકટનો અનુવાદ કરો", + "Enable WebRTC UDP Transit": "WebRTC UDP ટ્રાન્ઝિટ સક્ષમ કરો", + "Enable WebP Compression": "વેબપી કમ્પ્રેશન સક્ષમ કરો", + "Enable Performance Stats": "પ્રદર્શન આંકડા સક્ષમ કરો", + "Enable Pointer Lock": "પોઇન્ટર લોક સક્ષમ કરો", + "IME Input Mode": "IME ઇનપુટ મોડ", + "Show Virtual Keyboard Control": "વર્ચ્યુઅલ કીબોર્ડ નિયંત્રણ બતાવો", + "Toggle Control Panel via Keystrokes": "કીસ્ટ્રોક દ્વારા નિયંત્રણ પેનલને ટૉગલ કરો", + "Render Native Resolution": "મૂળ રીઝોલ્યુશન રેન્ડર કરો", + "Keyboard Shortcuts": "કીબોર્ડ શૉર્ટકટ્સ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC કીબોર્ડ શોર્ટકટ સક્ષમ કરો", + "1 - Toggle Control Panel": "1 - નિયંત્રણ પેનલને ટૉગલ કરો", + "2 - Toggle Game Pointer Mode": "2 - ગેમ પોઇન્ટર મોડને ટૉગલ કરો", + "3 - Toggle Pointer Lock": "3 - પોઇન્ટર લૉકને ટૉગલ કરો", + "Stream Quality": "સ્ટ્રીમ ગુણવત્તા", + "Preset Modes:": "પ્રીસેટ મોડ્સ:", + "Static": "સ્થિર", + "Low": "નીચું", + "Medium": "મધ્યમ", + "High": "ઉચ્ચ", + "Extreme": "આત્યંતિક", + "Lossless": "નુકસાન રહિત", + "Custom": "કસ્ટમ", + "Anti-Aliasing:": "એન્ટી-એલિયાસિંગ:", + "Auto Dynamic": "ઓટો ડાયનેમિક", + "Off": "બંધ", + "On": "ચાલુ", + "Dynamic Quality Min:": "ડાયનેમિક ક્વોલિટી મીન:", + "Dynamic Quality Max:": "ડાયનેમિક ક્વોલિટી મેક્સ:", + "Treat Lossless:": "લોસલેસ સારવાર કરો:", + "Frame Rate:": "ફ્રેમ દર:", + "Video JPEG Quality:": "વિડિઓ JPEG ગુણવત્તા:", + "Video WEBP Quality:": "વીડિયો WEBP ગુણવત્તા:", + "Video Area:": "વિડિયો વિસ્તાર:", + "Video Time:": "વિડિયો સમય:", + "Video Out Time:": "વિડિઓ આઉટ ટાઈમ:", + "Video Mode Width:": "વિડિઓ મોડ પહોળાઈ:", + "Video Mode Height:": "વિડિયો મોડ ઊંચાઈ:", + "Documentation": "દસ્તાવેજીકરણ", + "Drag Viewport": "ડ્રેગ વ્યૂપોર્ટ", + "KasmVNC encountered an error:": "KasmVNC ને એક ભૂલ આવી:" +} \ No newline at end of file diff --git a/app/locale/gu_IN.json b/app/locale/gu_IN.json new file mode 100644 index 0000000..da7be34 --- /dev/null +++ b/app/locale/gu_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "જોડાઈ રહ્યું છે...", + "Disconnecting...": "ડિસ્કનેક્ટ કરી રહ્યું છે...", + "Reconnecting...": "ફરીથી કનેક્ટ કરી રહ્યાં છીએ...", + "Internal error": "આંતરિક ભૂલ", + "Must set host": "હોસ્ટ સેટ કરવું આવશ્યક છે", + "Connected (encrypted) to ": "જોડાયેલ (એનક્રિપ્ટેડ) ", + "Connected (unencrypted) to ": "જોડાયેલ (એનક્રિપ્ટ થયેલ નથી) ", + "Something went wrong, connection is closed": "કંઈક ખોટું થયું છે, કનેક્શન બંધ છે", + "Failed to connect to server": "સર્વર સાથે કનેક્ટ કરવામાં નિષ્ફળ", + "Disconnected": "ડિસ્કનેક્ટેડ", + "New connection has been rejected with reason: ": "નવું કનેક્શન કારણ સાથે નકારવામાં આવ્યું છે:", + "New connection has been rejected": "નવું જોડાણ નકારવામાં આવ્યું છે", + "Credentials are required": "પ્રમાણપત્ર જરૂરી છે", + "Hide/Show the control bar": "કંટ્રોલ બાર છુપાવો/બતાવો", + "Drag": "ખેંચો", + "Move/Drag Viewport": "વ્યૂપોર્ટ ખસેડો/ખેંચો", + "Keyboard": "કીબોર્ડ", + "Show Keyboard": "કીબોર્ડ બતાવો", + "Extra keys": "વધારાની ચાવીઓ", + "Show Extra Keys": "વધારાની ચાવીઓ બતાવો", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ટૉગલ કરો", + "Alt": "Alt", + "Toggle Alt": "Alt ટૉગલ કરો", + "Toggle Windows": "વિન્ડોઝ ટૉગલ કરો", + "Windows": "વિન્ડોઝ", + "Send Tab": "ટેબ મોકલો", + "Tab": "ટેબ", + "Esc": "Esc", + "Send Escape": "એસ્કેપ મોકલો", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del મોકલો", + "Shutdown/Reboot": "શટડાઉન/રીબૂટ", + "Shutdown/Reboot...": "શટડાઉન/રીબૂટ...", + "Power": "શક્તિ", + "Shutdown": "બંધ કરો", + "Reboot": "રીબૂટ કરો", + "Reset": "રીસેટ કરો", + "Clipboard": "ક્લિપબોર્ડ", + "Clear": "ચોખ્ખુ", + "Fullscreen": "પૂર્ણ - પટ, આખો પડદો", + "Settings": "સેટિંગ્સ", + "Shared Mode": "શેર્ડ મોડ", + "View Only": "માત્ર જુઓ", + "Clip to Window": "ક્લિપ ટુ વિન્ડો", + "Scaling Mode:": "સ્કેલિંગ મોડ:", + "None": "કોઈ નહિ", + "Local Scaling": "સ્થાનિક સ્કેલિંગ", + "Remote Resizing": "રિમોટ રીસાઇઝીંગ", + "Advanced": "અદ્યતન", + "Quality:": "ગુણવત્તા:", + "Compression level:": "સંકોચન સ્તર:", + "Repeater ID:": "રીપીટર ID:", + "WebSocket": "વેબસોકેટ", + "Encrypt": "એનક્રિપ્ટ", + "Host:": "યજમાન:", + "Port:": "પોર્ટ:", + "Path:": "પાથ:", + "Automatic Reconnect": "ઓટોમેટિક રીકનેક્ટ", + "Reconnect Delay (ms):": "પુનઃજોડાણ વિલંબ (ms):", + "Show Dot when No Cursor": "જ્યારે કર્સર ન હોય ત્યારે ડોટ બતાવો", + "Logging:": "લોગીંગ:", + "Version:": "સંસ્કરણ:", + "Disconnect": "ડિસ્કનેક્ટ કરો", + "Connect": "જોડાવા", + "Username:": "વપરાશકર્તા નામ:", + "Password:": "પાસવર્ડ:", + "Send Credentials": "ઓળખાણપત્રો મોકલો", + "Cancel": "રદ કરો", + "Keys": "ચાવીઓ", + "Game Cursor Mode": "ગેમ કર્સર મોડ", + "Press Esc Key to Exit Pointer Lock Mode": "પોઇન્ટર લોક મોડમાંથી બહાર નીકળવા માટે Esc કી દબાવો", + "Game Mode paused, click on screen to resume Game Mode.": "ગેમ મોડ થોભાવ્યો, ગેમ મોડ ફરી શરૂ કરવા માટે સ્ક્રીન પર ક્લિક કરો.", + "Clipboard Up": "ક્લિપબોર્ડ ઉપર", + "CLipboard Down": "ક્લિપબોર્ડ ડાઉન", + "Clipboard Seamless": "ક્લિપબોર્ડ સીમલેસ", + "Prefer Local Cursor": "સ્થાનિક કર્સરને પ્રાધાન્ય આપો", + "Translate keyboard shortcuts": "કીબોર્ડ શોર્ટકટનો અનુવાદ કરો", + "Enable WebRTC UDP Transit": "WebRTC UDP ટ્રાન્ઝિટ સક્ષમ કરો", + "Enable WebP Compression": "વેબપી કમ્પ્રેશન સક્ષમ કરો", + "Enable Performance Stats": "પ્રદર્શન આંકડા સક્ષમ કરો", + "Enable Pointer Lock": "પોઇન્ટર લોક સક્ષમ કરો", + "IME Input Mode": "IME ઇનપુટ મોડ", + "Show Virtual Keyboard Control": "વર્ચ્યુઅલ કીબોર્ડ નિયંત્રણ બતાવો", + "Toggle Control Panel via Keystrokes": "કીસ્ટ્રોક દ્વારા નિયંત્રણ પેનલને ટૉગલ કરો", + "Render Native Resolution": "મૂળ રીઝોલ્યુશન રેન્ડર કરો", + "Keyboard Shortcuts": "કીબોર્ડ શૉર્ટકટ્સ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC કીબોર્ડ શોર્ટકટ સક્ષમ કરો", + "1 - Toggle Control Panel": "1 - નિયંત્રણ પેનલને ટૉગલ કરો", + "2 - Toggle Game Pointer Mode": "2 - ગેમ પોઇન્ટર મોડને ટૉગલ કરો", + "3 - Toggle Pointer Lock": "3 - પોઇન્ટર લૉકને ટૉગલ કરો", + "Stream Quality": "સ્ટ્રીમ ગુણવત્તા", + "Preset Modes:": "પ્રીસેટ મોડ્સ:", + "Static": "સ્થિર", + "Low": "નીચું", + "Medium": "મધ્યમ", + "High": "ઉચ્ચ", + "Extreme": "આત્યંતિક", + "Lossless": "નુકસાન રહિત", + "Custom": "કસ્ટમ", + "Anti-Aliasing:": "એન્ટી-એલિયાસિંગ:", + "Auto Dynamic": "ઓટો ડાયનેમિક", + "Off": "બંધ", + "On": "ચાલુ", + "Dynamic Quality Min:": "ડાયનેમિક ક્વોલિટી મીન:", + "Dynamic Quality Max:": "ડાયનેમિક ક્વોલિટી મેક્સ:", + "Treat Lossless:": "લોસલેસ સારવાર કરો:", + "Frame Rate:": "ફ્રેમ દર:", + "Video JPEG Quality:": "વિડિઓ JPEG ગુણવત્તા:", + "Video WEBP Quality:": "વીડિયો WEBP ગુણવત્તા:", + "Video Area:": "વિડિયો વિસ્તાર:", + "Video Time:": "વિડિયો સમય:", + "Video Out Time:": "વિડિઓ આઉટ ટાઈમ:", + "Video Mode Width:": "વિડિઓ મોડ પહોળાઈ:", + "Video Mode Height:": "વિડિયો મોડ ઊંચાઈ:", + "Documentation": "દસ્તાવેજીકરણ", + "Drag Viewport": "ડ્રેગ વ્યૂપોર્ટ", + "KasmVNC encountered an error:": "KasmVNC ને એક ભૂલ આવી:" +} \ No newline at end of file diff --git a/app/locale/ha.json b/app/locale/ha.json new file mode 100644 index 0000000..7e0da28 --- /dev/null +++ b/app/locale/ha.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Haɗin kai...", + "Disconnecting...": "Cire haɗin gwiwa...", + "Reconnecting...": "Sake haɗawa...", + "Internal error": "Kuskuren ciki", + "Must set host": "Dole ne saita masauki", + "Connected (encrypted) to ": "An haɗa (rufewa) zuwa", + "Connected (unencrypted) to ": "An haɗa (ba a ɓoye) zuwa", + "Something went wrong, connection is closed": "Wani abu yayi kuskure, haɗin yana rufe", + "Failed to connect to server": "An kasa haɗi zuwa uwar garken", + "Disconnected": "An katse", + "New connection has been rejected with reason: ": "An ƙi sabon haɗin gwiwa tare da dalili:", + "New connection has been rejected": "An ƙi amincewa da sabon haɗin gwiwa", + "Credentials are required": "Ana buƙatar takaddun shaida", + "Hide/Show the control bar": "Boye/Nuna sandar sarrafawa", + "Drag": "Jawo", + "Move/Drag Viewport": "Matsar / Jawo Viewport", + "Keyboard": "Allon madannai", + "Show Keyboard": "Nuna Allon madannai", + "Extra keys": "Ƙarin makullin", + "Show Extra Keys": "Nuna Karin Maɓallai", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Toggle Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Windows", + "Send Tab": "Aika Tab", + "Tab": "Taba", + "Esc": "Esc", + "Send Escape": "Aika tserewa", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Aika Ctrl-Alt-Del", + "Shutdown/Reboot": "Rufe/Sake yi", + "Shutdown/Reboot...": "Rufe/Sake yi...", + "Power": "Ikon", + "Shutdown": "Rufewa", + "Reboot": "Sake yi", + "Reset": "Sake saiti", + "Clipboard": "Klipboard", + "Clear": "share", + "Fullscreen": "Cikakken kariya", + "Settings": "Settings", + "Shared Mode": "Yanayin Raba", + "View Only": "Duba Kawai", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Yanayin Sikeli:", + "None": "Babu", + "Local Scaling": "Scaling na gida", + "Remote Resizing": "Remote Resizing", + "Advanced": "Na ci gaba", + "Quality:": "Kyauta:", + "Compression level:": "matakin matsawa:", + "Repeater ID:": "Mai maimaita ID:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Mai watsa shiri:", + "Port:": "Port:", + "Path:": "Tafarki:", + "Automatic Reconnect": "Sake haɗawa ta atomatik", + "Reconnect Delay (ms):": "Sake haɗa jinkiri (ms):", + "Show Dot when No Cursor": "Nuna Dot lokacin da Babu siginan kwamfuta", + "Logging:": "Logging:", + "Version:": "Sigar:", + "Disconnect": "Cire haɗin gwiwa", + "Connect": "Haɗa", + "Username:": "Username:", + "Password:": "Password:", + "Send Credentials": "Aika Takardun shaida", + "Cancel": "Soke", + "Keys": "Makullin", + "Game Cursor Mode": "Yanayin Siginan Wasan", + "Press Esc Key to Exit Pointer Lock Mode": "Latsa maɓallin Esc don fita yanayin Kulle mai nuni", + "Game Mode paused, click on screen to resume Game Mode.": "Yanayin wasan ya tsaya, danna kan allo don ci gaba da Yanayin Wasan.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Fifi na gida siginan kwamfuta", + "Translate keyboard shortcuts": "Fassara gajerun hanyoyin keyboard", + "Enable WebRTC UDP Transit": "Kuna Canja Wuta ta WebRTC UDP", + "Enable WebP Compression": "Kaddamar da Matsi na Yanar Gizo", + "Enable Performance Stats": "Kuna Ƙididdiga Ayyuka", + "Enable Pointer Lock": "Enable Makullin Nuni", + "IME Input Mode": "Yanayin shigar da IME", + "Show Virtual Keyboard Control": "Nuna Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "Sauya Control Panel ta hanyar Maɓallin Maɓalli", + "Render Native Resolution": "Samar da Ƙaddamar Ƙarshen Ƙasa", + "Keyboard Shortcuts": "Gajerun hanyoyin Allon madannai", + "Enable KasmVNC Keyboard Shortcuts": "Kunna KasmVNC Gajerun hanyoyin Allon madannai", + "1 - Toggle Control Panel": "1 - Kunna Control Panel", + "2 - Toggle Game Pointer Mode": "2 - Juya Yanayin Nuni Game", + "3 - Toggle Pointer Lock": "3 - Juya Makullin Nuni", + "Stream Quality": "Ingantacciyar Rarraba", + "Preset Modes:": "Hanyoyin da aka saita:", + "Static": "A tsaye", + "Low": "Ƙananan", + "Medium": "Matsakaici", + "High": "Babba", + "Extreme": "Mai girma", + "Lossless": "Rashi", + "Custom": "Al'ada", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "A kashe", + "On": "Kuna", + "Dynamic Quality Min:": "Tsarin inganci Min:", + "Dynamic Quality Max:": "Maxaukaka Ingancin Matsayi:", + "Treat Lossless:": "Maganin Rashin Lafiya:", + "Frame Rate:": "Farashin Ƙimar:", + "Video JPEG Quality:": "Video JPEG Quality:", + "Video WEBP Quality:": "Ingantacciyar WEBP na bidiyo:", + "Video Area:": "Yankin Bidiyo:", + "Video Time:": "Lokacin Bidiyo:", + "Video Out Time:": "Lokacin Fitar Bidiyo:", + "Video Mode Width:": "Nisa Yanayin Bidiyo:", + "Video Mode Height:": "Tsarin Yanayin Bidiyo:", + "Documentation": "Takardu", + "Drag Viewport": "Jawo Viewport", + "KasmVNC encountered an error:": "KasmVNC ya ci karo da kuskure:" +} \ No newline at end of file diff --git a/app/locale/ha_NG.json b/app/locale/ha_NG.json new file mode 100644 index 0000000..7e0da28 --- /dev/null +++ b/app/locale/ha_NG.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Haɗin kai...", + "Disconnecting...": "Cire haɗin gwiwa...", + "Reconnecting...": "Sake haɗawa...", + "Internal error": "Kuskuren ciki", + "Must set host": "Dole ne saita masauki", + "Connected (encrypted) to ": "An haɗa (rufewa) zuwa", + "Connected (unencrypted) to ": "An haɗa (ba a ɓoye) zuwa", + "Something went wrong, connection is closed": "Wani abu yayi kuskure, haɗin yana rufe", + "Failed to connect to server": "An kasa haɗi zuwa uwar garken", + "Disconnected": "An katse", + "New connection has been rejected with reason: ": "An ƙi sabon haɗin gwiwa tare da dalili:", + "New connection has been rejected": "An ƙi amincewa da sabon haɗin gwiwa", + "Credentials are required": "Ana buƙatar takaddun shaida", + "Hide/Show the control bar": "Boye/Nuna sandar sarrafawa", + "Drag": "Jawo", + "Move/Drag Viewport": "Matsar / Jawo Viewport", + "Keyboard": "Allon madannai", + "Show Keyboard": "Nuna Allon madannai", + "Extra keys": "Ƙarin makullin", + "Show Extra Keys": "Nuna Karin Maɓallai", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Toggle Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Windows", + "Send Tab": "Aika Tab", + "Tab": "Taba", + "Esc": "Esc", + "Send Escape": "Aika tserewa", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Aika Ctrl-Alt-Del", + "Shutdown/Reboot": "Rufe/Sake yi", + "Shutdown/Reboot...": "Rufe/Sake yi...", + "Power": "Ikon", + "Shutdown": "Rufewa", + "Reboot": "Sake yi", + "Reset": "Sake saiti", + "Clipboard": "Klipboard", + "Clear": "share", + "Fullscreen": "Cikakken kariya", + "Settings": "Settings", + "Shared Mode": "Yanayin Raba", + "View Only": "Duba Kawai", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Yanayin Sikeli:", + "None": "Babu", + "Local Scaling": "Scaling na gida", + "Remote Resizing": "Remote Resizing", + "Advanced": "Na ci gaba", + "Quality:": "Kyauta:", + "Compression level:": "matakin matsawa:", + "Repeater ID:": "Mai maimaita ID:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Mai watsa shiri:", + "Port:": "Port:", + "Path:": "Tafarki:", + "Automatic Reconnect": "Sake haɗawa ta atomatik", + "Reconnect Delay (ms):": "Sake haɗa jinkiri (ms):", + "Show Dot when No Cursor": "Nuna Dot lokacin da Babu siginan kwamfuta", + "Logging:": "Logging:", + "Version:": "Sigar:", + "Disconnect": "Cire haɗin gwiwa", + "Connect": "Haɗa", + "Username:": "Username:", + "Password:": "Password:", + "Send Credentials": "Aika Takardun shaida", + "Cancel": "Soke", + "Keys": "Makullin", + "Game Cursor Mode": "Yanayin Siginan Wasan", + "Press Esc Key to Exit Pointer Lock Mode": "Latsa maɓallin Esc don fita yanayin Kulle mai nuni", + "Game Mode paused, click on screen to resume Game Mode.": "Yanayin wasan ya tsaya, danna kan allo don ci gaba da Yanayin Wasan.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Fifi na gida siginan kwamfuta", + "Translate keyboard shortcuts": "Fassara gajerun hanyoyin keyboard", + "Enable WebRTC UDP Transit": "Kuna Canja Wuta ta WebRTC UDP", + "Enable WebP Compression": "Kaddamar da Matsi na Yanar Gizo", + "Enable Performance Stats": "Kuna Ƙididdiga Ayyuka", + "Enable Pointer Lock": "Enable Makullin Nuni", + "IME Input Mode": "Yanayin shigar da IME", + "Show Virtual Keyboard Control": "Nuna Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "Sauya Control Panel ta hanyar Maɓallin Maɓalli", + "Render Native Resolution": "Samar da Ƙaddamar Ƙarshen Ƙasa", + "Keyboard Shortcuts": "Gajerun hanyoyin Allon madannai", + "Enable KasmVNC Keyboard Shortcuts": "Kunna KasmVNC Gajerun hanyoyin Allon madannai", + "1 - Toggle Control Panel": "1 - Kunna Control Panel", + "2 - Toggle Game Pointer Mode": "2 - Juya Yanayin Nuni Game", + "3 - Toggle Pointer Lock": "3 - Juya Makullin Nuni", + "Stream Quality": "Ingantacciyar Rarraba", + "Preset Modes:": "Hanyoyin da aka saita:", + "Static": "A tsaye", + "Low": "Ƙananan", + "Medium": "Matsakaici", + "High": "Babba", + "Extreme": "Mai girma", + "Lossless": "Rashi", + "Custom": "Al'ada", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "A kashe", + "On": "Kuna", + "Dynamic Quality Min:": "Tsarin inganci Min:", + "Dynamic Quality Max:": "Maxaukaka Ingancin Matsayi:", + "Treat Lossless:": "Maganin Rashin Lafiya:", + "Frame Rate:": "Farashin Ƙimar:", + "Video JPEG Quality:": "Video JPEG Quality:", + "Video WEBP Quality:": "Ingantacciyar WEBP na bidiyo:", + "Video Area:": "Yankin Bidiyo:", + "Video Time:": "Lokacin Bidiyo:", + "Video Out Time:": "Lokacin Fitar Bidiyo:", + "Video Mode Width:": "Nisa Yanayin Bidiyo:", + "Video Mode Height:": "Tsarin Yanayin Bidiyo:", + "Documentation": "Takardu", + "Drag Viewport": "Jawo Viewport", + "KasmVNC encountered an error:": "KasmVNC ya ci karo da kuskure:" +} \ No newline at end of file diff --git a/app/locale/he.json b/app/locale/he.json new file mode 100644 index 0000000..0befbdd --- /dev/null +++ b/app/locale/he.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "רשֵׁקַמְ", + "Disconnecting...": "קתנתמ", + "Reconnecting...": "שדחמ רבחתמ", + "Internal error": "תימינפ האיגש", + "Must set host": "חראמ רידגהל בייח", + "Connected (encrypted) to ": "ל (ןפצומ) רבוחמ", + "Connected (unencrypted) to ": "ל (ןפצומ אל) רבוחמ", + "Something went wrong, connection is closed": "רגסנ רוביחה ,שבתשה והשמ", + "Failed to connect to server": "תרשל רבחתהל ןויסנ לשכנ", + "Disconnected": "קתָוּנמְ", + "New connection has been rejected with reason: ": "הביס םע החדנ שדח רוביח", + "New connection has been rejected": "החדנ שדח רוביח", + "Credentials are required": "םירושיא םישרדנ", + "Hide/Show the control bar": "הרקבה לגרס תא גצה/רתסה", + "Drag": "רוֹרגלִ", + "Move/Drag Viewport": "טבמ תדוקנ רורג/זזה", + "Keyboard": "תדלקמ", + "Show Keyboard": "תדלקמ גצה", + "Extra keys": "םיפסונ תוחתפמ", + "Show Extra Keys": "םיפסונ תוחתפמ גצה", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ףלחה", + "Alt": "טלא", + "Toggle Alt": "לא ףלחה", + "Toggle Windows": "תונולח תפלחה", + "Windows": "תונולח", + "Send Tab": "הייסיטרכ חלש", + "Tab": "הייסיטרכ", + "Esc": "האיצי", + "Send Escape": "החירב חלש", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del חלש", + "Shutdown/Reboot": "שדחמ לוחתא/יוביכ", + "Shutdown/Reboot...": "לוחתא/יוביכ", + "Power": "חַוֹכּ", + "Shutdown": "תובכל", + "Reboot": "לחֵתאַלְ", + "Reset": "לוּחתאִ", + "Clipboard": "חול", + "Clear": "רורב", + "Fullscreen": "אלמ ךסמ", + "Settings": "תורדגה", + "Shared Mode": "ףתושמ בצמ", + "View Only": "דבלב הייפצל", + "Clip to Window": "ןולחל פילק", + "Scaling Mode:": "הדימ הנק בצמ", + "None": "דחא ףא", + "Local Scaling": "ימוקמ הדימ הנק", + "Remote Resizing": "קוחרמ לדוג יוניש", + "Advanced": "םדֵקַתמִ", + "Quality:": "תוכיא", + "Compression level:": "הסיחד תמר", + "Repeater ID:": "רזוח יוהיז", + "WebSocket": "WebSocket", + "Encrypt": "ןיפצה", + "Host:": "החנמ", + "Port:": "למנ", + "Path:": "ביתִנָ", + "Automatic Reconnect": "תיטמוטוא שדחמ רבחתה", + "Reconnect Delay (ms):": "(ms) שדחמ רוביח תייהשה", + "Show Dot when No Cursor": "ןמס ןיא רשאכ הדוקנ גצה", + "Logging:": "םושיר", + "Version:": "הסָרְגִ", + "Disconnect": "קתֵנַלְ", + "Connect": "רבֵּחַלְ", + "Username:": "שמתשמ םש", + "Password:": "המסיס", + "Send Credentials": "םירושיא חלש", + "Cancel": "לטֵבַלְ", + "Keys": "תוחתפמ", + "Game Cursor Mode": "קחשמ ןמס בצמ", + "Press Esc Key to Exit Pointer Lock Mode": "עיבצמ תליענ בצממ תאצל ידכ Esc שקמ לע ץחל", + "Game Mode paused, click on screen to resume Game Mode.": "קחשמ בצמ תא שדחל ידכ ךסמה לע ץחל ,ההשומ קחשמ בצמ", + "Clipboard Up": "הלעמל חול", + "CLipboard Down": "הטמל חול", + "Clipboard Seamless": "םירפת אלל חול", + "Prefer Local Cursor": "ימוקמ ןמס ףידעה", + "Translate keyboard shortcuts": "םישקמ ירוציק םגרת", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit לעפה", + "Enable WebP Compression": "WebP תסיחד רשפא", + "Enable Performance Stats": "םיעוציב תקיטסיטטס לעפה", + "Enable Pointer Lock": "עיבצמ תליענ רשפא", + "IME Input Mode": "IME טלק בצמ", + "Show Virtual Keyboard Control": "תילאוטריו תדלקמ תרקב גצה", + "Toggle Control Panel via Keystrokes": "תושקה תועצמאב הרקבה חול תפלחה", + "Render Native Resolution": "תירוקמ היצולוזר דוביע", + "Keyboard Shortcuts": "תדלקמב ךרד ירוציק", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC לש םישקמ ירוציק לעפה", + "1 - Toggle Control Panel": "הרקבה חול תא ףלחה - 1", + "2 - Toggle Game Pointer Mode": "קחשמ עיבצמ בצמ ףלחה - 2", + "3 - Toggle Pointer Lock": "עיבצמ תליענ תפלחה - 3", + "Stream Quality": "םרז תוכיא", + "Preset Modes:": "שארמ םירדגומ םיבצמ", + "Static": "יטִטָס", + "Low": "ךוּמנָ", + "Medium": "ינוניב", + "High": "הַוֹבגָ", + "Extreme": "ינוציק", + "Lossless": "תוחפ דיספת", + "Custom": "תישיא םאתומה", + "Anti-Aliasing:": "תומוקע תקלחה", + "Auto Dynamic": "ימניד יטמוטוא", + "Off": "יובכ", + "On": "לעַ", + "Dynamic Quality Min:": "תימניד תוכיא םומינימ", + "Dynamic Quality Max:": "תימניד תוכיא םומיסקמ", + "Treat Lossless:": "ןדבוא אלל לפט", + "Frame Rate:": "םימיירפ בצק", + "Video JPEG Quality:": "JPEG ואדיו תוכיא", + "Video WEBP Quality:": "ואדיו לש WEBP תוכיא", + "Video Area:": "ואדיו רוזא", + "Video Time:": "ואדיו ןמז", + "Video Out Time:": "ןוטרסה לש האיצי ןמז", + "Video Mode Width:": "ואדיו בצמ בחור", + "Video Mode Height:": "ואדיו בצמ הבוג", + "Documentation": "דועית", + "Drag Viewport": "טבמ תדוקנ רורג", + "KasmVNC encountered an error:": "KasmVNC האיגשב לקתנ:" +} \ No newline at end of file diff --git a/app/locale/he_IL.json b/app/locale/he_IL.json new file mode 100644 index 0000000..0befbdd --- /dev/null +++ b/app/locale/he_IL.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "רשֵׁקַמְ", + "Disconnecting...": "קתנתמ", + "Reconnecting...": "שדחמ רבחתמ", + "Internal error": "תימינפ האיגש", + "Must set host": "חראמ רידגהל בייח", + "Connected (encrypted) to ": "ל (ןפצומ) רבוחמ", + "Connected (unencrypted) to ": "ל (ןפצומ אל) רבוחמ", + "Something went wrong, connection is closed": "רגסנ רוביחה ,שבתשה והשמ", + "Failed to connect to server": "תרשל רבחתהל ןויסנ לשכנ", + "Disconnected": "קתָוּנמְ", + "New connection has been rejected with reason: ": "הביס םע החדנ שדח רוביח", + "New connection has been rejected": "החדנ שדח רוביח", + "Credentials are required": "םירושיא םישרדנ", + "Hide/Show the control bar": "הרקבה לגרס תא גצה/רתסה", + "Drag": "רוֹרגלִ", + "Move/Drag Viewport": "טבמ תדוקנ רורג/זזה", + "Keyboard": "תדלקמ", + "Show Keyboard": "תדלקמ גצה", + "Extra keys": "םיפסונ תוחתפמ", + "Show Extra Keys": "םיפסונ תוחתפמ גצה", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ףלחה", + "Alt": "טלא", + "Toggle Alt": "לא ףלחה", + "Toggle Windows": "תונולח תפלחה", + "Windows": "תונולח", + "Send Tab": "הייסיטרכ חלש", + "Tab": "הייסיטרכ", + "Esc": "האיצי", + "Send Escape": "החירב חלש", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del חלש", + "Shutdown/Reboot": "שדחמ לוחתא/יוביכ", + "Shutdown/Reboot...": "לוחתא/יוביכ", + "Power": "חַוֹכּ", + "Shutdown": "תובכל", + "Reboot": "לחֵתאַלְ", + "Reset": "לוּחתאִ", + "Clipboard": "חול", + "Clear": "רורב", + "Fullscreen": "אלמ ךסמ", + "Settings": "תורדגה", + "Shared Mode": "ףתושמ בצמ", + "View Only": "דבלב הייפצל", + "Clip to Window": "ןולחל פילק", + "Scaling Mode:": "הדימ הנק בצמ", + "None": "דחא ףא", + "Local Scaling": "ימוקמ הדימ הנק", + "Remote Resizing": "קוחרמ לדוג יוניש", + "Advanced": "םדֵקַתמִ", + "Quality:": "תוכיא", + "Compression level:": "הסיחד תמר", + "Repeater ID:": "רזוח יוהיז", + "WebSocket": "WebSocket", + "Encrypt": "ןיפצה", + "Host:": "החנמ", + "Port:": "למנ", + "Path:": "ביתִנָ", + "Automatic Reconnect": "תיטמוטוא שדחמ רבחתה", + "Reconnect Delay (ms):": "(ms) שדחמ רוביח תייהשה", + "Show Dot when No Cursor": "ןמס ןיא רשאכ הדוקנ גצה", + "Logging:": "םושיר", + "Version:": "הסָרְגִ", + "Disconnect": "קתֵנַלְ", + "Connect": "רבֵּחַלְ", + "Username:": "שמתשמ םש", + "Password:": "המסיס", + "Send Credentials": "םירושיא חלש", + "Cancel": "לטֵבַלְ", + "Keys": "תוחתפמ", + "Game Cursor Mode": "קחשמ ןמס בצמ", + "Press Esc Key to Exit Pointer Lock Mode": "עיבצמ תליענ בצממ תאצל ידכ Esc שקמ לע ץחל", + "Game Mode paused, click on screen to resume Game Mode.": "קחשמ בצמ תא שדחל ידכ ךסמה לע ץחל ,ההשומ קחשמ בצמ", + "Clipboard Up": "הלעמל חול", + "CLipboard Down": "הטמל חול", + "Clipboard Seamless": "םירפת אלל חול", + "Prefer Local Cursor": "ימוקמ ןמס ףידעה", + "Translate keyboard shortcuts": "םישקמ ירוציק םגרת", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit לעפה", + "Enable WebP Compression": "WebP תסיחד רשפא", + "Enable Performance Stats": "םיעוציב תקיטסיטטס לעפה", + "Enable Pointer Lock": "עיבצמ תליענ רשפא", + "IME Input Mode": "IME טלק בצמ", + "Show Virtual Keyboard Control": "תילאוטריו תדלקמ תרקב גצה", + "Toggle Control Panel via Keystrokes": "תושקה תועצמאב הרקבה חול תפלחה", + "Render Native Resolution": "תירוקמ היצולוזר דוביע", + "Keyboard Shortcuts": "תדלקמב ךרד ירוציק", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC לש םישקמ ירוציק לעפה", + "1 - Toggle Control Panel": "הרקבה חול תא ףלחה - 1", + "2 - Toggle Game Pointer Mode": "קחשמ עיבצמ בצמ ףלחה - 2", + "3 - Toggle Pointer Lock": "עיבצמ תליענ תפלחה - 3", + "Stream Quality": "םרז תוכיא", + "Preset Modes:": "שארמ םירדגומ םיבצמ", + "Static": "יטִטָס", + "Low": "ךוּמנָ", + "Medium": "ינוניב", + "High": "הַוֹבגָ", + "Extreme": "ינוציק", + "Lossless": "תוחפ דיספת", + "Custom": "תישיא םאתומה", + "Anti-Aliasing:": "תומוקע תקלחה", + "Auto Dynamic": "ימניד יטמוטוא", + "Off": "יובכ", + "On": "לעַ", + "Dynamic Quality Min:": "תימניד תוכיא םומינימ", + "Dynamic Quality Max:": "תימניד תוכיא םומיסקמ", + "Treat Lossless:": "ןדבוא אלל לפט", + "Frame Rate:": "םימיירפ בצק", + "Video JPEG Quality:": "JPEG ואדיו תוכיא", + "Video WEBP Quality:": "ואדיו לש WEBP תוכיא", + "Video Area:": "ואדיו רוזא", + "Video Time:": "ואדיו ןמז", + "Video Out Time:": "ןוטרסה לש האיצי ןמז", + "Video Mode Width:": "ואדיו בצמ בחור", + "Video Mode Height:": "ואדיו בצמ הבוג", + "Documentation": "דועית", + "Drag Viewport": "טבמ תדוקנ רורג", + "KasmVNC encountered an error:": "KasmVNC האיגשב לקתנ:" +} \ No newline at end of file diff --git a/app/locale/hi.json b/app/locale/hi.json new file mode 100644 index 0000000..dc7cb5e --- /dev/null +++ b/app/locale/hi.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "जोड़ रहा है...", + "Disconnecting...": "डिस्कनेक्ट हो रहा है...", + "Reconnecting...": "पुनः कनेक्ट हो रहा है...", + "Internal error": "आंतरिक त्रुटि", + "Must set host": "मेजबान सेट करना होगा", + "Connected (encrypted) to ": "कनेक्टेड (एन्क्रिप्टेड) से", + "Connected (unencrypted) to ": "कनेक्ट (अनएन्क्रिप्टेड) से", + "Something went wrong, connection is closed": "कुछ गलत हो गया, कनेक्शन बंद है", + "Failed to connect to server": "सर्वर से कनेक्ट करने में विफल", + "Disconnected": "डिस्कनेक्ट", + "New connection has been rejected with reason: ": "नए कनेक्शन को कारण से अस्वीकार कर दिया गया है:", + "New connection has been rejected": "नया कनेक्शन अस्वीकार कर दिया गया है", + "Credentials are required": "प्रमाणपत्र आवश्यक हैं", + "Hide/Show the control bar": "कंट्रोल बार छुपाएं/दिखाएं", + "Drag": "खींचना", + "Move/Drag Viewport": "मूव/ड्रैग व्यूपोर्ट", + "Keyboard": "कीबोर्ड", + "Show Keyboard": "कीबोर्ड दिखाएं", + "Extra keys": "अतिरिक्त चाबियां", + "Show Extra Keys": "अतिरिक्त कुंजी दिखाएं", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl टॉगल करें", + "Alt": "ऑल्ट", + "Toggle Alt": "टॉगल ऑल्ट", + "Toggle Windows": "विंडो टॉगल करें", + "Windows": "खिड़कियाँ", + "Send Tab": "टैब भेजें", + "Tab": "टैब", + "Esc": "Esc", + "Send Escape": "एस्केप भेजें", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del भेजें", + "Shutdown/Reboot": "शटडाउन / रिबूट", + "Shutdown/Reboot...": "शटडाउन/रिबूट ...", + "Power": "शक्ति", + "Shutdown": "शट डाउन", + "Reboot": "रिबूट", + "Reset": "रीसेट", + "Clipboard": "क्लिपबोर्ड", + "Clear": "साफ़", + "Fullscreen": "पूर्ण स्क्रीन", + "Settings": "समायोजन", + "Shared Mode": "साझा मोड", + "View Only": "केवल देखें", + "Clip to Window": "क्लिप टू विंडो", + "Scaling Mode:": "स्केलिंग मोड:", + "None": "कोई नहीं", + "Local Scaling": "स्थानीय स्केलिंग", + "Remote Resizing": "दूरस्थ आकार बदलना", + "Advanced": "विकसित", + "Quality:": "गुणवत्ता:", + "Compression level:": "संपीड़न स्तर:", + "Repeater ID:": "पुनरावर्तक आईडी:", + "WebSocket": "वेबसॉकेट", + "Encrypt": "एन्क्रिप्ट", + "Host:": "मेज़बान:", + "Port:": "पत्तन:", + "Path:": "पथ:", + "Automatic Reconnect": "स्वचालित पुन: कनेक्ट करें", + "Reconnect Delay (ms):": "रीकनेक्ट विलंब (एमएस):", + "Show Dot when No Cursor": "डॉट दिखाएँ जब कोई कर्सर नहीं", + "Logging:": "लॉगिंग:", + "Version:": "संस्करण:", + "Disconnect": "डिस्कनेक्ट करें", + "Connect": "जोड़ना", + "Username:": "उपयोगकर्ता नाम:", + "Password:": "पासवर्ड:", + "Send Credentials": "साख भेजें", + "Cancel": "रद्द करना", + "Keys": "चांबियाँ", + "Game Cursor Mode": "गेम कर्सर मोड", + "Press Esc Key to Exit Pointer Lock Mode": "पॉइंटर लॉक मोड से बाहर निकलने के लिए Esc कुंजी दबाएं", + "Game Mode paused, click on screen to resume Game Mode.": "गेम मोड रुका हुआ है, गेम मोड फिर से शुरू करने के लिए स्क्रीन पर क्लिक करें।", + "Clipboard Up": "क्लिपबोर्ड ऊपर", + "CLipboard Down": "क्लिपबोर्ड डाउन", + "Clipboard Seamless": "क्लिपबोर्ड सीमलेस", + "Prefer Local Cursor": "स्थानीय कर्सर को प्राथमिकता दें", + "Translate keyboard shortcuts": "कीबोर्ड शॉर्टकट का अनुवाद करें", + "Enable WebRTC UDP Transit": "WebRTC UDP ट्रांज़िट सक्षम करें", + "Enable WebP Compression": "वेबपी संपीड़न सक्षम करें", + "Enable Performance Stats": "प्रदर्शन आँकड़े सक्षम करें", + "Enable Pointer Lock": "पॉइंटर लॉक सक्षम करें", + "IME Input Mode": "आईएमई इनपुट मोड", + "Show Virtual Keyboard Control": "वर्चुअल कीबोर्ड कंट्रोल दिखाएं", + "Toggle Control Panel via Keystrokes": "कीस्ट्रोक्स के माध्यम से नियंत्रण कक्ष टॉगल करें", + "Render Native Resolution": "मूलनिवासी संकल्प प्रस्तुत करें", + "Keyboard Shortcuts": "कुंजीपटल अल्प मार्ग", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC कीबोर्ड शॉर्टकट सक्षम करें", + "1 - Toggle Control Panel": "1 - टॉगल कंट्रोल पैनल", + "2 - Toggle Game Pointer Mode": "2 - टॉगल गेम पॉइंटर मोड", + "3 - Toggle Pointer Lock": "3 - टॉगल पॉइंटर लॉक", + "Stream Quality": "धारा गुणवत्ता", + "Preset Modes:": "प्रीसेट मोड:", + "Static": "स्थैतिक", + "Low": "कम", + "Medium": "मध्यम", + "High": "उच्च", + "Extreme": "चरम", + "Lossless": "दोषरहित", + "Custom": "रिवाज़", + "Anti-Aliasing:": "उपघटन प्रतिरोधी:", + "Auto Dynamic": "ऑटो डायनेमिक", + "Off": "बंद", + "On": "पर", + "Dynamic Quality Min:": "गतिशील गुणवत्ता न्यूनतम:", + "Dynamic Quality Max:": "गतिशील गुणवत्ता अधिकतम:", + "Treat Lossless:": "लापरवाही से इलाज करें:", + "Frame Rate:": "फ्रेम रेट:", + "Video JPEG Quality:": "वीडियो जेपीईजी गुणवत्ता:", + "Video WEBP Quality:": "वीडियो WEBP गुणवत्ता:", + "Video Area:": "वीडियो क्षेत्र:", + "Video Time:": "वीडियो समय:", + "Video Out Time:": "वीडियो आउट टाइम:", + "Video Mode Width:": "वीडियो मोड चौड़ाई:", + "Video Mode Height:": "वीडियो मोड ऊंचाई:", + "Documentation": "दस्तावेज़ीकरण", + "Drag Viewport": "व्यूपोर्ट खींचें", + "KasmVNC encountered an error:": "KasmVNC में एक त्रुटि आई:" +} \ No newline at end of file diff --git a/app/locale/hi_IN.json b/app/locale/hi_IN.json new file mode 100644 index 0000000..dc7cb5e --- /dev/null +++ b/app/locale/hi_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "जोड़ रहा है...", + "Disconnecting...": "डिस्कनेक्ट हो रहा है...", + "Reconnecting...": "पुनः कनेक्ट हो रहा है...", + "Internal error": "आंतरिक त्रुटि", + "Must set host": "मेजबान सेट करना होगा", + "Connected (encrypted) to ": "कनेक्टेड (एन्क्रिप्टेड) से", + "Connected (unencrypted) to ": "कनेक्ट (अनएन्क्रिप्टेड) से", + "Something went wrong, connection is closed": "कुछ गलत हो गया, कनेक्शन बंद है", + "Failed to connect to server": "सर्वर से कनेक्ट करने में विफल", + "Disconnected": "डिस्कनेक्ट", + "New connection has been rejected with reason: ": "नए कनेक्शन को कारण से अस्वीकार कर दिया गया है:", + "New connection has been rejected": "नया कनेक्शन अस्वीकार कर दिया गया है", + "Credentials are required": "प्रमाणपत्र आवश्यक हैं", + "Hide/Show the control bar": "कंट्रोल बार छुपाएं/दिखाएं", + "Drag": "खींचना", + "Move/Drag Viewport": "मूव/ड्रैग व्यूपोर्ट", + "Keyboard": "कीबोर्ड", + "Show Keyboard": "कीबोर्ड दिखाएं", + "Extra keys": "अतिरिक्त चाबियां", + "Show Extra Keys": "अतिरिक्त कुंजी दिखाएं", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl टॉगल करें", + "Alt": "ऑल्ट", + "Toggle Alt": "टॉगल ऑल्ट", + "Toggle Windows": "विंडो टॉगल करें", + "Windows": "खिड़कियाँ", + "Send Tab": "टैब भेजें", + "Tab": "टैब", + "Esc": "Esc", + "Send Escape": "एस्केप भेजें", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del भेजें", + "Shutdown/Reboot": "शटडाउन / रिबूट", + "Shutdown/Reboot...": "शटडाउन/रिबूट ...", + "Power": "शक्ति", + "Shutdown": "शट डाउन", + "Reboot": "रिबूट", + "Reset": "रीसेट", + "Clipboard": "क्लिपबोर्ड", + "Clear": "साफ़", + "Fullscreen": "पूर्ण स्क्रीन", + "Settings": "समायोजन", + "Shared Mode": "साझा मोड", + "View Only": "केवल देखें", + "Clip to Window": "क्लिप टू विंडो", + "Scaling Mode:": "स्केलिंग मोड:", + "None": "कोई नहीं", + "Local Scaling": "स्थानीय स्केलिंग", + "Remote Resizing": "दूरस्थ आकार बदलना", + "Advanced": "विकसित", + "Quality:": "गुणवत्ता:", + "Compression level:": "संपीड़न स्तर:", + "Repeater ID:": "पुनरावर्तक आईडी:", + "WebSocket": "वेबसॉकेट", + "Encrypt": "एन्क्रिप्ट", + "Host:": "मेज़बान:", + "Port:": "पत्तन:", + "Path:": "पथ:", + "Automatic Reconnect": "स्वचालित पुन: कनेक्ट करें", + "Reconnect Delay (ms):": "रीकनेक्ट विलंब (एमएस):", + "Show Dot when No Cursor": "डॉट दिखाएँ जब कोई कर्सर नहीं", + "Logging:": "लॉगिंग:", + "Version:": "संस्करण:", + "Disconnect": "डिस्कनेक्ट करें", + "Connect": "जोड़ना", + "Username:": "उपयोगकर्ता नाम:", + "Password:": "पासवर्ड:", + "Send Credentials": "साख भेजें", + "Cancel": "रद्द करना", + "Keys": "चांबियाँ", + "Game Cursor Mode": "गेम कर्सर मोड", + "Press Esc Key to Exit Pointer Lock Mode": "पॉइंटर लॉक मोड से बाहर निकलने के लिए Esc कुंजी दबाएं", + "Game Mode paused, click on screen to resume Game Mode.": "गेम मोड रुका हुआ है, गेम मोड फिर से शुरू करने के लिए स्क्रीन पर क्लिक करें।", + "Clipboard Up": "क्लिपबोर्ड ऊपर", + "CLipboard Down": "क्लिपबोर्ड डाउन", + "Clipboard Seamless": "क्लिपबोर्ड सीमलेस", + "Prefer Local Cursor": "स्थानीय कर्सर को प्राथमिकता दें", + "Translate keyboard shortcuts": "कीबोर्ड शॉर्टकट का अनुवाद करें", + "Enable WebRTC UDP Transit": "WebRTC UDP ट्रांज़िट सक्षम करें", + "Enable WebP Compression": "वेबपी संपीड़न सक्षम करें", + "Enable Performance Stats": "प्रदर्शन आँकड़े सक्षम करें", + "Enable Pointer Lock": "पॉइंटर लॉक सक्षम करें", + "IME Input Mode": "आईएमई इनपुट मोड", + "Show Virtual Keyboard Control": "वर्चुअल कीबोर्ड कंट्रोल दिखाएं", + "Toggle Control Panel via Keystrokes": "कीस्ट्रोक्स के माध्यम से नियंत्रण कक्ष टॉगल करें", + "Render Native Resolution": "मूलनिवासी संकल्प प्रस्तुत करें", + "Keyboard Shortcuts": "कुंजीपटल अल्प मार्ग", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC कीबोर्ड शॉर्टकट सक्षम करें", + "1 - Toggle Control Panel": "1 - टॉगल कंट्रोल पैनल", + "2 - Toggle Game Pointer Mode": "2 - टॉगल गेम पॉइंटर मोड", + "3 - Toggle Pointer Lock": "3 - टॉगल पॉइंटर लॉक", + "Stream Quality": "धारा गुणवत्ता", + "Preset Modes:": "प्रीसेट मोड:", + "Static": "स्थैतिक", + "Low": "कम", + "Medium": "मध्यम", + "High": "उच्च", + "Extreme": "चरम", + "Lossless": "दोषरहित", + "Custom": "रिवाज़", + "Anti-Aliasing:": "उपघटन प्रतिरोधी:", + "Auto Dynamic": "ऑटो डायनेमिक", + "Off": "बंद", + "On": "पर", + "Dynamic Quality Min:": "गतिशील गुणवत्ता न्यूनतम:", + "Dynamic Quality Max:": "गतिशील गुणवत्ता अधिकतम:", + "Treat Lossless:": "लापरवाही से इलाज करें:", + "Frame Rate:": "फ्रेम रेट:", + "Video JPEG Quality:": "वीडियो जेपीईजी गुणवत्ता:", + "Video WEBP Quality:": "वीडियो WEBP गुणवत्ता:", + "Video Area:": "वीडियो क्षेत्र:", + "Video Time:": "वीडियो समय:", + "Video Out Time:": "वीडियो आउट टाइम:", + "Video Mode Width:": "वीडियो मोड चौड़ाई:", + "Video Mode Height:": "वीडियो मोड ऊंचाई:", + "Documentation": "दस्तावेज़ीकरण", + "Drag Viewport": "व्यूपोर्ट खींचें", + "KasmVNC encountered an error:": "KasmVNC में एक त्रुटि आई:" +} \ No newline at end of file diff --git a/app/locale/hr.json b/app/locale/hr.json new file mode 100644 index 0000000..a78aae6 --- /dev/null +++ b/app/locale/hr.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Povezivanje...", + "Disconnecting...": "Prekid veze...", + "Reconnecting...": "Ponovno povezivanje...", + "Internal error": "Interna greška", + "Must set host": "Moram postaviti domaćina", + "Connected (encrypted) to ": "Povezano (šifrirano) s ", + "Connected (unencrypted) to ": "Povezano (nešifrirano) s ", + "Something went wrong, connection is closed": "Nešto nije u redu, veza je prekinuta", + "Failed to connect to server": "Nije uspjelo povezivanje s poslužiteljem", + "Disconnected": "Isključeno", + "New connection has been rejected with reason: ": "Nova veza je odbijena s razlogom: ", + "New connection has been rejected": "Nova veza je odbijena", + "Credentials are required": "Potrebne su vjerodajnice", + "Hide/Show the control bar": "Sakrij/prikaži kontrolnu traku", + "Drag": "Opterećenje", + "Move/Drag Viewport": "Premjesti/povuci okvir za prikaz", + "Keyboard": "tipkovnica", + "Show Keyboard": "Prikaži tipkovnicu", + "Extra keys": "Dodatni ključevi", + "Show Extra Keys": "Prikaži dodatne tipke", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Prebaci Ctrl", + "Alt": "Alt", + "Toggle Alt": "Prebaci Alt", + "Toggle Windows": "Prebacivanje prozora", + "Windows": "Windows", + "Send Tab": "Pošalji karticu", + "Tab": "Kartica", + "Esc": "Esc", + "Send Escape": "Pošalji Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Pošalji Ctrl-Alt-Del", + "Shutdown/Reboot": "Isključi/ponovno pokreni", + "Shutdown/Reboot...": "Isključi/ponovno pokreni...", + "Power": "Vlast", + "Shutdown": "Ugasiti", + "Reboot": "Ponovno podizanje sustava", + "Reset": "Poništi", + "Clipboard": "Međuspremnik", + "Clear": "Čisto", + "Fullscreen": "Puni zaslon", + "Settings": "Postavke", + "Shared Mode": "Dijeljeni način rada", + "View Only": "Samo pogled", + "Clip to Window": "Klip na prozor", + "Scaling Mode:": "Način skaliranja:", + "None": "ništa", + "Local Scaling": "Lokalno skaliranje", + "Remote Resizing": "Daljinska promjena veličine", + "Advanced": "Napredna", + "Quality:": "Kvaliteta:", + "Compression level:": "Razina kompresije:", + "Repeater ID:": "ID repetitora:", + "WebSocket": "WebSocket", + "Encrypt": "Šifriraj", + "Host:": "Domaćin:", + "Port:": "Luka:", + "Path:": "Staza:", + "Automatic Reconnect": "Automatsko ponovno povezivanje", + "Reconnect Delay (ms):": "Odgoda ponovnog povezivanja (ms):", + "Show Dot when No Cursor": "Prikaži točku kada nema kursora", + "Logging:": "Zapisivanje:", + "Version:": "Verzija:", + "Disconnect": "Prekini vezu", + "Connect": "Spojiti", + "Username:": "Korisničko ime:", + "Password:": "Lozinka:", + "Send Credentials": "Pošalji vjerodajnice", + "Cancel": "Otkazati", + "Keys": "Ključevi", + "Game Cursor Mode": "Način pokazivača igre", + "Press Esc Key to Exit Pointer Lock Mode": "Pritisnite tipku Esc za izlaz iz moda zaključavanja pokazivača", + "Game Mode paused, click on screen to resume Game Mode.": "Game Mode pauziran, kliknite na zaslon za nastavak Game Mode.", + "Clipboard Up": "Međuspremnik gore", + "CLipboard Down": "Međuspremnik dolje", + "Clipboard Seamless": "Bešavni međuspremnik", + "Prefer Local Cursor": "Preferiraj lokalni kursor", + "Translate keyboard shortcuts": "Prevedi tipkovničke prečace", + "Enable WebRTC UDP Transit": "Omogući WebRTC UDP Transit", + "Enable WebP Compression": "Omogući WebP kompresiju", + "Enable Performance Stats": "Omogući statistiku izvedbe", + "Enable Pointer Lock": "Omogući zaključavanje pokazivača", + "IME Input Mode": "IME način unosa", + "Show Virtual Keyboard Control": "Prikaži kontrolu virtualne tipkovnice", + "Toggle Control Panel via Keystrokes": "Prebacivanje upravljačke ploče pomoću tipki", + "Render Native Resolution": "Renderiraj izvornu razlučivost", + "Keyboard Shortcuts": "Tipkovni prečaci", + "Enable KasmVNC Keyboard Shortcuts": "Omogući KasmVNC tipkovničke prečace", + "1 - Toggle Control Panel": "1 - Uključi/isključi upravljačku ploču", + "2 - Toggle Game Pointer Mode": "2 - Uključi/isključi način rada pokazivača igre", + "3 - Toggle Pointer Lock": "3 - Uključi/isključi zaključavanje pokazivača", + "Stream Quality": "Kvaliteta streama", + "Preset Modes:": "Unaprijed postavljeni načini rada:", + "Static": "Statički", + "Low": "nisko", + "Medium": "Srednji", + "High": "visoko", + "Extreme": "ekstremno", + "Lossless": "bez gubitaka", + "Custom": "Prilagođen", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Automatska dinamika", + "Off": "isključeno", + "On": "Na", + "Dynamic Quality Min:": "Minimalna dinamička kvaliteta:", + "Dynamic Quality Max:": "Maksimalna dinamička kvaliteta:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Okvirna stopa:", + "Video JPEG Quality:": "Video JPEG kvaliteta:", + "Video WEBP Quality:": "Video WEBP kvaliteta:", + "Video Area:": "Područje videozapisa:", + "Video Time:": "Vrijeme videozapisa:", + "Video Out Time:": "Vrijeme video izlaza:", + "Video Mode Width:": "Širina video moda:", + "Video Mode Height:": "Visina video načina rada:", + "Documentation": "Dokumentacija", + "Drag Viewport": "Povucite okvir za prikaz", + "KasmVNC encountered an error:": "KasmVNC je naišao na pogrešku:" +} \ No newline at end of file diff --git a/app/locale/hr_HR.json b/app/locale/hr_HR.json new file mode 100644 index 0000000..a78aae6 --- /dev/null +++ b/app/locale/hr_HR.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Povezivanje...", + "Disconnecting...": "Prekid veze...", + "Reconnecting...": "Ponovno povezivanje...", + "Internal error": "Interna greška", + "Must set host": "Moram postaviti domaćina", + "Connected (encrypted) to ": "Povezano (šifrirano) s ", + "Connected (unencrypted) to ": "Povezano (nešifrirano) s ", + "Something went wrong, connection is closed": "Nešto nije u redu, veza je prekinuta", + "Failed to connect to server": "Nije uspjelo povezivanje s poslužiteljem", + "Disconnected": "Isključeno", + "New connection has been rejected with reason: ": "Nova veza je odbijena s razlogom: ", + "New connection has been rejected": "Nova veza je odbijena", + "Credentials are required": "Potrebne su vjerodajnice", + "Hide/Show the control bar": "Sakrij/prikaži kontrolnu traku", + "Drag": "Opterećenje", + "Move/Drag Viewport": "Premjesti/povuci okvir za prikaz", + "Keyboard": "tipkovnica", + "Show Keyboard": "Prikaži tipkovnicu", + "Extra keys": "Dodatni ključevi", + "Show Extra Keys": "Prikaži dodatne tipke", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Prebaci Ctrl", + "Alt": "Alt", + "Toggle Alt": "Prebaci Alt", + "Toggle Windows": "Prebacivanje prozora", + "Windows": "Windows", + "Send Tab": "Pošalji karticu", + "Tab": "Kartica", + "Esc": "Esc", + "Send Escape": "Pošalji Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Pošalji Ctrl-Alt-Del", + "Shutdown/Reboot": "Isključi/ponovno pokreni", + "Shutdown/Reboot...": "Isključi/ponovno pokreni...", + "Power": "Vlast", + "Shutdown": "Ugasiti", + "Reboot": "Ponovno podizanje sustava", + "Reset": "Poništi", + "Clipboard": "Međuspremnik", + "Clear": "Čisto", + "Fullscreen": "Puni zaslon", + "Settings": "Postavke", + "Shared Mode": "Dijeljeni način rada", + "View Only": "Samo pogled", + "Clip to Window": "Klip na prozor", + "Scaling Mode:": "Način skaliranja:", + "None": "ništa", + "Local Scaling": "Lokalno skaliranje", + "Remote Resizing": "Daljinska promjena veličine", + "Advanced": "Napredna", + "Quality:": "Kvaliteta:", + "Compression level:": "Razina kompresije:", + "Repeater ID:": "ID repetitora:", + "WebSocket": "WebSocket", + "Encrypt": "Šifriraj", + "Host:": "Domaćin:", + "Port:": "Luka:", + "Path:": "Staza:", + "Automatic Reconnect": "Automatsko ponovno povezivanje", + "Reconnect Delay (ms):": "Odgoda ponovnog povezivanja (ms):", + "Show Dot when No Cursor": "Prikaži točku kada nema kursora", + "Logging:": "Zapisivanje:", + "Version:": "Verzija:", + "Disconnect": "Prekini vezu", + "Connect": "Spojiti", + "Username:": "Korisničko ime:", + "Password:": "Lozinka:", + "Send Credentials": "Pošalji vjerodajnice", + "Cancel": "Otkazati", + "Keys": "Ključevi", + "Game Cursor Mode": "Način pokazivača igre", + "Press Esc Key to Exit Pointer Lock Mode": "Pritisnite tipku Esc za izlaz iz moda zaključavanja pokazivača", + "Game Mode paused, click on screen to resume Game Mode.": "Game Mode pauziran, kliknite na zaslon za nastavak Game Mode.", + "Clipboard Up": "Međuspremnik gore", + "CLipboard Down": "Međuspremnik dolje", + "Clipboard Seamless": "Bešavni međuspremnik", + "Prefer Local Cursor": "Preferiraj lokalni kursor", + "Translate keyboard shortcuts": "Prevedi tipkovničke prečace", + "Enable WebRTC UDP Transit": "Omogući WebRTC UDP Transit", + "Enable WebP Compression": "Omogući WebP kompresiju", + "Enable Performance Stats": "Omogući statistiku izvedbe", + "Enable Pointer Lock": "Omogući zaključavanje pokazivača", + "IME Input Mode": "IME način unosa", + "Show Virtual Keyboard Control": "Prikaži kontrolu virtualne tipkovnice", + "Toggle Control Panel via Keystrokes": "Prebacivanje upravljačke ploče pomoću tipki", + "Render Native Resolution": "Renderiraj izvornu razlučivost", + "Keyboard Shortcuts": "Tipkovni prečaci", + "Enable KasmVNC Keyboard Shortcuts": "Omogući KasmVNC tipkovničke prečace", + "1 - Toggle Control Panel": "1 - Uključi/isključi upravljačku ploču", + "2 - Toggle Game Pointer Mode": "2 - Uključi/isključi način rada pokazivača igre", + "3 - Toggle Pointer Lock": "3 - Uključi/isključi zaključavanje pokazivača", + "Stream Quality": "Kvaliteta streama", + "Preset Modes:": "Unaprijed postavljeni načini rada:", + "Static": "Statički", + "Low": "nisko", + "Medium": "Srednji", + "High": "visoko", + "Extreme": "ekstremno", + "Lossless": "bez gubitaka", + "Custom": "Prilagođen", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Automatska dinamika", + "Off": "isključeno", + "On": "Na", + "Dynamic Quality Min:": "Minimalna dinamička kvaliteta:", + "Dynamic Quality Max:": "Maksimalna dinamička kvaliteta:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Okvirna stopa:", + "Video JPEG Quality:": "Video JPEG kvaliteta:", + "Video WEBP Quality:": "Video WEBP kvaliteta:", + "Video Area:": "Područje videozapisa:", + "Video Time:": "Vrijeme videozapisa:", + "Video Out Time:": "Vrijeme video izlaza:", + "Video Mode Width:": "Širina video moda:", + "Video Mode Height:": "Visina video načina rada:", + "Documentation": "Dokumentacija", + "Drag Viewport": "Povucite okvir za prikaz", + "KasmVNC encountered an error:": "KasmVNC je naišao na pogrešku:" +} \ No newline at end of file diff --git a/app/locale/ht.json b/app/locale/ht.json new file mode 100644 index 0000000..7f2f5d1 --- /dev/null +++ b/app/locale/ht.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Konekte...", + "Disconnecting...": "Dekonekte...", + "Reconnecting...": "Rekonekte...", + "Internal error": "Erè entèn", + "Must set host": "Ou dwe mete lame", + "Connected (encrypted) to ": "Konekte (kode) ak", + "Connected (unencrypted) to ": "Konekte (ki pa kode) nan", + "Something went wrong, connection is closed": "Yon bagay ale mal, koneksyon fèmen", + "Failed to connect to server": "Echwe pou konekte ak sèvè", + "Disconnected": "Dekonekte", + "New connection has been rejected with reason: ": "Nouvo koneksyon te rejte ak rezon:", + "New connection has been rejected": "Nouvo koneksyon te rejte", + "Credentials are required": "Kredansyèl yo obligatwa", + "Hide/Show the control bar": "Kache/Montre ba kontwòl la", + "Drag": "Trennen", + "Move/Drag Viewport": "Deplase / Trennen Viewport", + "Keyboard": "Klavye", + "Show Keyboard": "Montre klavye", + "Extra keys": "Kle siplemantè", + "Show Extra Keys": "Montre kle siplemantè", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Toggle Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Windows", + "Send Tab": "Voye Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Voye chape", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Voye Ctrl-Alt-Del", + "Shutdown/Reboot": "Arè/Rdemare", + "Shutdown/Reboot...": "Arè/Rdemare...", + "Power": "pouvwa", + "Shutdown": "Fèmen", + "Reboot": "Rdemare", + "Reset": "Reset", + "Clipboard": "Klipboard", + "Clear": "Klè", + "Fullscreen": "Ecran konplè", + "Settings": "Anviwònman", + "Shared Mode": "Mòd pataje", + "View Only": "View sèlman", + "Clip to Window": "Klip nan fenèt", + "Scaling Mode:": "Echèl mòd:", + "None": "Okenn", + "Local Scaling": "Echèl lokal", + "Remote Resizing": "Redimansyon Remote", + "Advanced": "Avanse", + "Quality:": "Kalite:", + "Compression level:": "Nivo konpresyon:", + "Repeater ID:": "Idantifikasyon repetiteur:", + "WebSocket": "WebSocket", + "Encrypt": "Ankripte", + "Host:": "Lame:", + "Port:": "Pò:", + "Path:": "Chemen:", + "Automatic Reconnect": "Rekonekte otomatik", + "Reconnect Delay (ms):": "Rekonekte Reta (ms):", + "Show Dot when No Cursor": "Montre pwen lè pa gen kurseur", + "Logging:": "Enregistrement:", + "Version:": "Vèsyon:", + "Disconnect": "Dekonekte", + "Connect": "Konekte", + "Username:": "Non itilizatè:", + "Password:": "Modpas:", + "Send Credentials": "Voye kalifikasyon yo", + "Cancel": "Anile", + "Keys": "Kle", + "Game Cursor Mode": "Mòd kurseur jwèt", + "Press Esc Key to Exit Pointer Lock Mode": "Peze kle Echap pou sòti nan mòd Lock Pointer", + "Game Mode paused, click on screen to resume Game Mode.": "Mòd jwèt pran yon poz, klike sou ekran an pou rekòmanse mòd jwèt.", + "Clipboard Up": "Klipboard moute", + "CLipboard Down": "Klipboard desann", + "Clipboard Seamless": "Klipboard san pwoblèm", + "Prefer Local Cursor": "Pwofere kurseur lokal", + "Translate keyboard shortcuts": "Tradwi rakoursi klavye", + "Enable WebRTC UDP Transit": "Pèmèt WebRTC UDP Transit", + "Enable WebP Compression": "Pèmèt konpresyon WebP", + "Enable Performance Stats": "Pèmèt estatistik pèfòmans", + "Enable Pointer Lock": "Pèmèt Lock Pointer", + "IME Input Mode": "Mòd Antre IME", + "Show Virtual Keyboard Control": "Montre kontwòl klavye vityèl", + "Toggle Control Panel via Keystrokes": "Toggle Kontwòl Panel atravè Keystrokes", + "Render Native Resolution": "Rann rezolisyon natif natal", + "Keyboard Shortcuts": "Rakoursi klavye", + "Enable KasmVNC Keyboard Shortcuts": "Pèmèt rakoursi klavye KasmVNC", + "1 - Toggle Control Panel": "1 - Activer panèl kontwòl", + "2 - Toggle Game Pointer Mode": "2 - Activer mòd Pointer jwèt", + "3 - Toggle Pointer Lock": "3 - Aktive Pointer Lock", + "Stream Quality": "Kalite kouran", + "Preset Modes:": "Mòd Prereglaj:", + "Static": "Estatik", + "Low": "Ba", + "Medium": "Mwayen", + "High": "Segondè", + "Extreme": "ekstrèm", + "Lossless": "San pèt", + "Custom": "Personnalisé", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Oto dinamik", + "Off": "Ete", + "On": "sou", + "Dynamic Quality Min:": "Dynamic Quality Min:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Trete Lossless:", + "Frame Rate:": "To Frame:", + "Video JPEG Quality:": "Videyo JPEG Kalite:", + "Video WEBP Quality:": "Videyo WEBP Kalite:", + "Video Area:": "Zòn videyo:", + "Video Time:": "Tan videyo:", + "Video Out Time:": "Videyo soti tan:", + "Video Mode Width:": "Lajè mòd videyo:", + "Video Mode Height:": "Watè mòd videyo:", + "Documentation": "Dokimantasyon", + "Drag Viewport": "Trennen Viewport", + "KasmVNC encountered an error:": "KasmVNC te rankontre yon erè:" +} \ No newline at end of file diff --git a/app/locale/ht_HT.json b/app/locale/ht_HT.json new file mode 100644 index 0000000..7f2f5d1 --- /dev/null +++ b/app/locale/ht_HT.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Konekte...", + "Disconnecting...": "Dekonekte...", + "Reconnecting...": "Rekonekte...", + "Internal error": "Erè entèn", + "Must set host": "Ou dwe mete lame", + "Connected (encrypted) to ": "Konekte (kode) ak", + "Connected (unencrypted) to ": "Konekte (ki pa kode) nan", + "Something went wrong, connection is closed": "Yon bagay ale mal, koneksyon fèmen", + "Failed to connect to server": "Echwe pou konekte ak sèvè", + "Disconnected": "Dekonekte", + "New connection has been rejected with reason: ": "Nouvo koneksyon te rejte ak rezon:", + "New connection has been rejected": "Nouvo koneksyon te rejte", + "Credentials are required": "Kredansyèl yo obligatwa", + "Hide/Show the control bar": "Kache/Montre ba kontwòl la", + "Drag": "Trennen", + "Move/Drag Viewport": "Deplase / Trennen Viewport", + "Keyboard": "Klavye", + "Show Keyboard": "Montre klavye", + "Extra keys": "Kle siplemantè", + "Show Extra Keys": "Montre kle siplemantè", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Toggle Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Windows", + "Send Tab": "Voye Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Voye chape", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Voye Ctrl-Alt-Del", + "Shutdown/Reboot": "Arè/Rdemare", + "Shutdown/Reboot...": "Arè/Rdemare...", + "Power": "pouvwa", + "Shutdown": "Fèmen", + "Reboot": "Rdemare", + "Reset": "Reset", + "Clipboard": "Klipboard", + "Clear": "Klè", + "Fullscreen": "Ecran konplè", + "Settings": "Anviwònman", + "Shared Mode": "Mòd pataje", + "View Only": "View sèlman", + "Clip to Window": "Klip nan fenèt", + "Scaling Mode:": "Echèl mòd:", + "None": "Okenn", + "Local Scaling": "Echèl lokal", + "Remote Resizing": "Redimansyon Remote", + "Advanced": "Avanse", + "Quality:": "Kalite:", + "Compression level:": "Nivo konpresyon:", + "Repeater ID:": "Idantifikasyon repetiteur:", + "WebSocket": "WebSocket", + "Encrypt": "Ankripte", + "Host:": "Lame:", + "Port:": "Pò:", + "Path:": "Chemen:", + "Automatic Reconnect": "Rekonekte otomatik", + "Reconnect Delay (ms):": "Rekonekte Reta (ms):", + "Show Dot when No Cursor": "Montre pwen lè pa gen kurseur", + "Logging:": "Enregistrement:", + "Version:": "Vèsyon:", + "Disconnect": "Dekonekte", + "Connect": "Konekte", + "Username:": "Non itilizatè:", + "Password:": "Modpas:", + "Send Credentials": "Voye kalifikasyon yo", + "Cancel": "Anile", + "Keys": "Kle", + "Game Cursor Mode": "Mòd kurseur jwèt", + "Press Esc Key to Exit Pointer Lock Mode": "Peze kle Echap pou sòti nan mòd Lock Pointer", + "Game Mode paused, click on screen to resume Game Mode.": "Mòd jwèt pran yon poz, klike sou ekran an pou rekòmanse mòd jwèt.", + "Clipboard Up": "Klipboard moute", + "CLipboard Down": "Klipboard desann", + "Clipboard Seamless": "Klipboard san pwoblèm", + "Prefer Local Cursor": "Pwofere kurseur lokal", + "Translate keyboard shortcuts": "Tradwi rakoursi klavye", + "Enable WebRTC UDP Transit": "Pèmèt WebRTC UDP Transit", + "Enable WebP Compression": "Pèmèt konpresyon WebP", + "Enable Performance Stats": "Pèmèt estatistik pèfòmans", + "Enable Pointer Lock": "Pèmèt Lock Pointer", + "IME Input Mode": "Mòd Antre IME", + "Show Virtual Keyboard Control": "Montre kontwòl klavye vityèl", + "Toggle Control Panel via Keystrokes": "Toggle Kontwòl Panel atravè Keystrokes", + "Render Native Resolution": "Rann rezolisyon natif natal", + "Keyboard Shortcuts": "Rakoursi klavye", + "Enable KasmVNC Keyboard Shortcuts": "Pèmèt rakoursi klavye KasmVNC", + "1 - Toggle Control Panel": "1 - Activer panèl kontwòl", + "2 - Toggle Game Pointer Mode": "2 - Activer mòd Pointer jwèt", + "3 - Toggle Pointer Lock": "3 - Aktive Pointer Lock", + "Stream Quality": "Kalite kouran", + "Preset Modes:": "Mòd Prereglaj:", + "Static": "Estatik", + "Low": "Ba", + "Medium": "Mwayen", + "High": "Segondè", + "Extreme": "ekstrèm", + "Lossless": "San pèt", + "Custom": "Personnalisé", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Oto dinamik", + "Off": "Ete", + "On": "sou", + "Dynamic Quality Min:": "Dynamic Quality Min:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Trete Lossless:", + "Frame Rate:": "To Frame:", + "Video JPEG Quality:": "Videyo JPEG Kalite:", + "Video WEBP Quality:": "Videyo WEBP Kalite:", + "Video Area:": "Zòn videyo:", + "Video Time:": "Tan videyo:", + "Video Out Time:": "Videyo soti tan:", + "Video Mode Width:": "Lajè mòd videyo:", + "Video Mode Height:": "Watè mòd videyo:", + "Documentation": "Dokimantasyon", + "Drag Viewport": "Trennen Viewport", + "KasmVNC encountered an error:": "KasmVNC te rankontre yon erè:" +} \ No newline at end of file diff --git a/app/locale/hu.json b/app/locale/hu.json new file mode 100644 index 0000000..de0ca1a --- /dev/null +++ b/app/locale/hu.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Csatlakozás...", + "Disconnecting...": "Lekapcsolás...", + "Reconnecting...": "Újracsatlakozás...", + "Internal error": "Belső hiba", + "Must set host": "Be kell állítani a házigazdát", + "Connected (encrypted) to ": "Csatlakoztatva (titkosítva) a következőhöz: ", + "Connected (unencrypted) to ": "Csatlakoztatva (titkosítatlan) a következőhöz: ", + "Something went wrong, connection is closed": "Valami hiba történt, a kapcsolat megszakadt", + "Failed to connect to server": "Nem sikerült csatlakozni a szerverhez", + "Disconnected": "Szétkapcsolt", + "New connection has been rejected with reason: ": "Az új csatlakozást okkal utasították el:", + "New connection has been rejected": "Az új kapcsolat elutasítva", + "Credentials are required": "Megjelenítő adatok szükségesek", + "Hide/Show the control bar": "A vezérlősáv elrejtése/megjelenítése", + "Drag": "Húzás", + "Move/Drag Viewport": "Nézetkép mozgatása/húzása", + "Keyboard": "Billentyűzet", + "Show Keyboard": "Billentyűzet megjelenítése", + "Extra keys": "Extra kulcsok", + "Show Extra Keys": "Extra kulcsok megjelenítése", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl", + "Alt": "Alt", + "Toggle Alt": "Alt váltás", + "Toggle Windows": "Windows váltás", + "Windows": "Ablakok", + "Send Tab": "Send Tab", + "Tab": "Tab", + "Esc": "Kilépés", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del küldése", + "Shutdown/Reboot": "Kikapcsolás/Újraindítás", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "Erő", + "Shutdown": "Leállitás", + "Reboot": "Újraindítás", + "Reset": "Visszaállítás", + "Clipboard": "Vágólap", + "Clear": "Egyértelmű", + "Fullscreen": "Teljes képernyő", + "Settings": "Beállítások", + "Shared Mode": "Megosztott mód", + "View Only": "Csak megtekintésre", + "Clip to Window": "Klip az ablakba", + "Scaling Mode:": "Skálázási mód:", + "None": "Egyik sem", + "Local Scaling": "Helyi méretezés", + "Remote Resizing": "Távoli átméretezés", + "Advanced": "Fejlett", + "Quality:": "Minőség:", + "Compression level:": "Tömörítési szint:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Titkosítás", + "Host:": "Házigazda:", + "Port:": "Kikötő:", + "Path:": "Pálya:", + "Automatic Reconnect": "Automatikus újracsatlakozás", + "Reconnect Delay (ms):": "Újracsatlakozási késleltetés (ms):", + "Show Dot when No Cursor": "Show Dot when No Cursor", + "Logging:": "Fakitermelés:", + "Version:": "Változat:", + "Disconnect": "Leválasztás", + "Connect": "Csatlakozás", + "Username:": "Felhasználónév:", + "Password:": "Jelszó:", + "Send Credentials": "Hitelesítő adatok küldése", + "Cancel": "Megszünteti", + "Keys": "Kulcsok", + "Game Cursor Mode": "Játékkurzor mód", + "Press Esc Key to Exit Pointer Lock Mode": "Nyomja meg az Esc billentyűt a mutatózár módból való kilépéshez", + "Game Mode paused, click on screen to resume Game Mode.": "A játékmód szünetel, kattintson a képernyőre a Játék mód folytatásához.", + "Clipboard Up": "Vágólap fel", + "CLipboard Down": "Vágólap le", + "Clipboard Seamless": "Vágólap zökkenőmentes", + "Prefer Local Cursor": "Helyi kurzor előnyben részesítése", + "Translate keyboard shortcuts": "Billentyűparancsok fordítása", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit engedélyezése", + "Enable WebP Compression": "WebP tömörítés engedélyezése", + "Enable Performance Stats": "Teljesítménystatisztikák engedélyezése", + "Enable Pointer Lock": "Mutatózár engedélyezése", + "IME Input Mode": "IME beviteli mód", + "Show Virtual Keyboard Control": "Virtuális billentyűzetvezérlés megjelenítése", + "Toggle Control Panel via Keystrokes": "Vezérlőpult váltása billentyűleütésekkel", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Gyorsbillentyűket", + "Enable KasmVNC Keyboard Shortcuts": "A KasmVNC billentyűparancsok engedélyezése", + "1 - Toggle Control Panel": "1 - Vezérlőpult váltása", + "2 - Toggle Game Pointer Mode": "2 – Játékmutató mód váltása", + "3 - Toggle Pointer Lock": "3 - Mutatózár váltása", + "Stream Quality": "Streamminőség", + "Preset Modes:": "Előre beállított módok:", + "Static": "Statikus", + "Low": "Alacsony", + "Medium": "Közepes", + "High": "Magas", + "Extreme": "Szélső", + "Lossless": "Veszteségmentes", + "Custom": "Egyedi", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Automatikus dinamikus", + "Off": "Ki", + "On": "Tovább", + "Dynamic Quality Min:": "Minim. dinamikus minőség:", + "Dynamic Quality Max:": "Max. dinamikus minőség:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Filmkocka szám:", + "Video JPEG Quality:": "Videó JPEG minősége:", + "Video WEBP Quality:": "Videó WEBP minősége:", + "Video Area:": "Videóterület:", + "Video Time:": "Videó ideje:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Video mód szélessége:", + "Video Mode Height:": "Videó mód magassága:", + "Documentation": "Dokumentáció", + "Drag Viewport": "Nézetablak húzása", + "KasmVNC encountered an error:": "A KasmVNC hibát észlelt:" +} \ No newline at end of file diff --git a/app/locale/hu_HU.json b/app/locale/hu_HU.json new file mode 100644 index 0000000..de0ca1a --- /dev/null +++ b/app/locale/hu_HU.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Csatlakozás...", + "Disconnecting...": "Lekapcsolás...", + "Reconnecting...": "Újracsatlakozás...", + "Internal error": "Belső hiba", + "Must set host": "Be kell állítani a házigazdát", + "Connected (encrypted) to ": "Csatlakoztatva (titkosítva) a következőhöz: ", + "Connected (unencrypted) to ": "Csatlakoztatva (titkosítatlan) a következőhöz: ", + "Something went wrong, connection is closed": "Valami hiba történt, a kapcsolat megszakadt", + "Failed to connect to server": "Nem sikerült csatlakozni a szerverhez", + "Disconnected": "Szétkapcsolt", + "New connection has been rejected with reason: ": "Az új csatlakozást okkal utasították el:", + "New connection has been rejected": "Az új kapcsolat elutasítva", + "Credentials are required": "Megjelenítő adatok szükségesek", + "Hide/Show the control bar": "A vezérlősáv elrejtése/megjelenítése", + "Drag": "Húzás", + "Move/Drag Viewport": "Nézetkép mozgatása/húzása", + "Keyboard": "Billentyűzet", + "Show Keyboard": "Billentyűzet megjelenítése", + "Extra keys": "Extra kulcsok", + "Show Extra Keys": "Extra kulcsok megjelenítése", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl", + "Alt": "Alt", + "Toggle Alt": "Alt váltás", + "Toggle Windows": "Windows váltás", + "Windows": "Ablakok", + "Send Tab": "Send Tab", + "Tab": "Tab", + "Esc": "Kilépés", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del küldése", + "Shutdown/Reboot": "Kikapcsolás/Újraindítás", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "Erő", + "Shutdown": "Leállitás", + "Reboot": "Újraindítás", + "Reset": "Visszaállítás", + "Clipboard": "Vágólap", + "Clear": "Egyértelmű", + "Fullscreen": "Teljes képernyő", + "Settings": "Beállítások", + "Shared Mode": "Megosztott mód", + "View Only": "Csak megtekintésre", + "Clip to Window": "Klip az ablakba", + "Scaling Mode:": "Skálázási mód:", + "None": "Egyik sem", + "Local Scaling": "Helyi méretezés", + "Remote Resizing": "Távoli átméretezés", + "Advanced": "Fejlett", + "Quality:": "Minőség:", + "Compression level:": "Tömörítési szint:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Titkosítás", + "Host:": "Házigazda:", + "Port:": "Kikötő:", + "Path:": "Pálya:", + "Automatic Reconnect": "Automatikus újracsatlakozás", + "Reconnect Delay (ms):": "Újracsatlakozási késleltetés (ms):", + "Show Dot when No Cursor": "Show Dot when No Cursor", + "Logging:": "Fakitermelés:", + "Version:": "Változat:", + "Disconnect": "Leválasztás", + "Connect": "Csatlakozás", + "Username:": "Felhasználónév:", + "Password:": "Jelszó:", + "Send Credentials": "Hitelesítő adatok küldése", + "Cancel": "Megszünteti", + "Keys": "Kulcsok", + "Game Cursor Mode": "Játékkurzor mód", + "Press Esc Key to Exit Pointer Lock Mode": "Nyomja meg az Esc billentyűt a mutatózár módból való kilépéshez", + "Game Mode paused, click on screen to resume Game Mode.": "A játékmód szünetel, kattintson a képernyőre a Játék mód folytatásához.", + "Clipboard Up": "Vágólap fel", + "CLipboard Down": "Vágólap le", + "Clipboard Seamless": "Vágólap zökkenőmentes", + "Prefer Local Cursor": "Helyi kurzor előnyben részesítése", + "Translate keyboard shortcuts": "Billentyűparancsok fordítása", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit engedélyezése", + "Enable WebP Compression": "WebP tömörítés engedélyezése", + "Enable Performance Stats": "Teljesítménystatisztikák engedélyezése", + "Enable Pointer Lock": "Mutatózár engedélyezése", + "IME Input Mode": "IME beviteli mód", + "Show Virtual Keyboard Control": "Virtuális billentyűzetvezérlés megjelenítése", + "Toggle Control Panel via Keystrokes": "Vezérlőpult váltása billentyűleütésekkel", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Gyorsbillentyűket", + "Enable KasmVNC Keyboard Shortcuts": "A KasmVNC billentyűparancsok engedélyezése", + "1 - Toggle Control Panel": "1 - Vezérlőpult váltása", + "2 - Toggle Game Pointer Mode": "2 – Játékmutató mód váltása", + "3 - Toggle Pointer Lock": "3 - Mutatózár váltása", + "Stream Quality": "Streamminőség", + "Preset Modes:": "Előre beállított módok:", + "Static": "Statikus", + "Low": "Alacsony", + "Medium": "Közepes", + "High": "Magas", + "Extreme": "Szélső", + "Lossless": "Veszteségmentes", + "Custom": "Egyedi", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Automatikus dinamikus", + "Off": "Ki", + "On": "Tovább", + "Dynamic Quality Min:": "Minim. dinamikus minőség:", + "Dynamic Quality Max:": "Max. dinamikus minőség:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Filmkocka szám:", + "Video JPEG Quality:": "Videó JPEG minősége:", + "Video WEBP Quality:": "Videó WEBP minősége:", + "Video Area:": "Videóterület:", + "Video Time:": "Videó ideje:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Video mód szélessége:", + "Video Mode Height:": "Videó mód magassága:", + "Documentation": "Dokumentáció", + "Drag Viewport": "Nézetablak húzása", + "KasmVNC encountered an error:": "A KasmVNC hibát észlelt:" +} \ No newline at end of file diff --git a/app/locale/hy.json b/app/locale/hy.json new file mode 100644 index 0000000..551b5e7 --- /dev/null +++ b/app/locale/hy.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Միանում է…", + "Disconnecting...": "Անջատվում է…", + "Reconnecting...": "Վերամիացում…", + "Internal error": "Ներքին սխալ", + "Must set host": "Պետք է նշանակել հյուրընկալող", + "Connected (encrypted) to ": "Միացված է (գաղտնագրված)", + "Connected (unencrypted) to ": "Միացված է (չկոդավորված)", + "Something went wrong, connection is closed": "Սխալ առաջացավ, կապը փակ է", + "Failed to connect to server": "Չհաջողվեց միանալ սերվերին", + "Disconnected": "Անջատված է", + "New connection has been rejected with reason: ": "Նոր կապը մերժվել է պատճառաբանությամբ.", + "New connection has been rejected": "Նոր կապը մերժվել է.", + "Credentials are required": "Հավատարմագրերը պարտադիր են", + "Hide/Show the control bar": "Թաքցնել/Ցույց տալ կառավարման տողը", + "Drag": "Քաշել", + "Move/Drag Viewport": "Տեղափոխել/քաշել տեսադաշտը", + "Keyboard": "Ստեղնաշար", + "Show Keyboard": "Ցույց տալ ստեղնաշարը", + "Extra keys": "Լրացուցիչ բանալիներ", + "Show Extra Keys": "Ցույց տալ լրացուցիչ բանալիներ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Փոխարկել Ctrl", + "Alt": "Ալտ", + "Toggle Alt": "Փոխարկել Alt", + "Toggle Windows": "Փոխարկել Windows", + "Windows": "Պատուհաններ", + "Send Tab": "Ուղարկել ներդիր", + "Tab": "ներդիր", + "Esc": "Esc", + "Send Escape": "Ուղարկել փախուստ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ուղարկել Ctrl-Alt-Del", + "Shutdown/Reboot": "Անջատում/վերագործարկում", + "Shutdown/Reboot...": "Անջատում/վերագործարկում…", + "Power": "Ուժ", + "Shutdown": "Անջատել", + "Reboot": "Վերագործարկեք", + "Reset": "Վերականգնել", + "Clipboard": "Clipboard", + "Clear": "Մաքուր", + "Fullscreen": "Ամբողջ էկրանով", + "Settings": "Կարգավորումներ", + "Shared Mode": "Համօգտագործվող ռեժիմ", + "View Only": "Միայն դիտել", + "Clip to Window": "Սեղմել պատուհանին", + "Scaling Mode:": "Scaling Mode:", + "None": "Ոչ ոք", + "Local Scaling": "Տեղական մասշտաբավորում", + "Remote Resizing": "Հեռավոր չափափոխում", + "Advanced": "Ընդլայնված", + "Quality:": "Որակ.", + "Compression level:": "Սեղմման մակարդակ.", + "Repeater ID:": "Կրկնիչ ID.", + "WebSocket": "WebSocket", + "Encrypt": "Գաղտնագրել", + "Host:": "Հաղորդավար.", + "Port:": "Պորտ:", + "Path:": "Ճանապարհ.", + "Automatic Reconnect": "Ավտոմատ վերամիացում", + "Reconnect Delay (ms):": "Վերամիացման հետաձգում (ms):", + "Show Dot when No Cursor": "Ցույց տալ կետը, երբ կուրսորը չկա", + "Logging:": "Գրանցում.", + "Version:": "Տարբերակ.", + "Disconnect": "Անջատել", + "Connect": "Միացեք", + "Username:": "Օգտագործողի անունը:", + "Password:": "Գաղտնաբառ.", + "Send Credentials": "Ուղարկել հավատարմագրերը", + "Cancel": "Չեղարկել", + "Keys": "Բանալիններ", + "Game Cursor Mode": "Խաղի կուրսորի ռեժիմը", + "Press Esc Key to Exit Pointer Lock Mode": "Սեղմեք Esc ստեղնը՝ ցուցիչի կողպման ռեժիմից դուրս գալու համար", + "Game Mode paused, click on screen to resume Game Mode.": "Խաղի ռեժիմը դադարեցված է, սեղմեք էկրանին՝ խաղի ռեժիմը վերսկսելու համար:", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Նախընտրել տեղական կուրսորը", + "Translate keyboard shortcuts": "Թարգմանել ստեղնաշարի դյուրանցումները", + "Enable WebRTC UDP Transit": "Միացնել WebRTC UDP տարանցումը", + "Enable WebP Compression": "Միացնել WebP սեղմումը", + "Enable Performance Stats": "Միացնել կատարողականի վիճակագրությունը", + "Enable Pointer Lock": "Միացնել ցուցիչի կողպումը", + "IME Input Mode": "IME մուտքագրման ռեժիմ", + "Show Virtual Keyboard Control": "Ցույց տալ վիրտուալ ստեղնաշարի կառավարումը", + "Toggle Control Panel via Keystrokes": "Փոխարկել կառավարման վահանակը ստեղնաշարի միջոցով", + "Render Native Resolution": "Ներկայացնել հայրենի բանաձեւը", + "Keyboard Shortcuts": "Ստեղնաշարի դյուրանցումներ", + "Enable KasmVNC Keyboard Shortcuts": "Միացնել KasmVNC ստեղնաշարի դյուրանցումները", + "1 - Toggle Control Panel": "1 - միացնել կառավարման վահանակը", + "2 - Toggle Game Pointer Mode": "2 - Փոխարկել խաղի ցուցիչի ռեժիմը", + "3 - Toggle Pointer Lock": "3 - Փոխարկել ցուցիչի կողպեքը", + "Stream Quality": "Հոսքի որակ", + "Preset Modes:": "Նախադրված ռեժիմներ.", + "Static": "Ստատիկ", + "Low": "Ցածր", + "Medium": "Միջին", + "High": "Բարձր", + "Extreme": "Ծայրահեղ", + "Lossless": "Անկորուստ", + "Custom": "Պատվերով", + "Anti-Aliasing:": "Anti-aliasing.", + "Auto Dynamic": "Ավտո դինամիկ", + "Off": "Անջատված", + "On": "Վրա", + "Dynamic Quality Min:": "Dynamic Quality Min:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Breat Lossless:", + "Frame Rate:": "Frame Rate:", + "Video JPEG Quality:": "Տեսանյութի JPEG որակ.", + "Video WEBP Quality:": "Տեսանյութի WEBP որակ.", + "Video Area:": "Տեսանյութի տարածք.", + "Video Time:": "Տեսանյութի ժամանակ.", + "Video Out Time:": "Տեսանյութի թողարկման ժամանակը.", + "Video Mode Width:": "Տեսանյութի ռեժիմի լայնություն.", + "Video Mode Height:": "Տեսանյութի ռեժիմի բարձրություն.", + "Documentation": "Փաստաթղթեր", + "Drag Viewport": "Քաշել տեսադաշտը", + "KasmVNC encountered an error:": "KasmVNC-ն սխալ է հանդիպել." +} \ No newline at end of file diff --git a/app/locale/hy_AM.json b/app/locale/hy_AM.json new file mode 100644 index 0000000..551b5e7 --- /dev/null +++ b/app/locale/hy_AM.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Միանում է…", + "Disconnecting...": "Անջատվում է…", + "Reconnecting...": "Վերամիացում…", + "Internal error": "Ներքին սխալ", + "Must set host": "Պետք է նշանակել հյուրընկալող", + "Connected (encrypted) to ": "Միացված է (գաղտնագրված)", + "Connected (unencrypted) to ": "Միացված է (չկոդավորված)", + "Something went wrong, connection is closed": "Սխալ առաջացավ, կապը փակ է", + "Failed to connect to server": "Չհաջողվեց միանալ սերվերին", + "Disconnected": "Անջատված է", + "New connection has been rejected with reason: ": "Նոր կապը մերժվել է պատճառաբանությամբ.", + "New connection has been rejected": "Նոր կապը մերժվել է.", + "Credentials are required": "Հավատարմագրերը պարտադիր են", + "Hide/Show the control bar": "Թաքցնել/Ցույց տալ կառավարման տողը", + "Drag": "Քաշել", + "Move/Drag Viewport": "Տեղափոխել/քաշել տեսադաշտը", + "Keyboard": "Ստեղնաշար", + "Show Keyboard": "Ցույց տալ ստեղնաշարը", + "Extra keys": "Լրացուցիչ բանալիներ", + "Show Extra Keys": "Ցույց տալ լրացուցիչ բանալիներ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Փոխարկել Ctrl", + "Alt": "Ալտ", + "Toggle Alt": "Փոխարկել Alt", + "Toggle Windows": "Փոխարկել Windows", + "Windows": "Պատուհաններ", + "Send Tab": "Ուղարկել ներդիր", + "Tab": "ներդիր", + "Esc": "Esc", + "Send Escape": "Ուղարկել փախուստ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ուղարկել Ctrl-Alt-Del", + "Shutdown/Reboot": "Անջատում/վերագործարկում", + "Shutdown/Reboot...": "Անջատում/վերագործարկում…", + "Power": "Ուժ", + "Shutdown": "Անջատել", + "Reboot": "Վերագործարկեք", + "Reset": "Վերականգնել", + "Clipboard": "Clipboard", + "Clear": "Մաքուր", + "Fullscreen": "Ամբողջ էկրանով", + "Settings": "Կարգավորումներ", + "Shared Mode": "Համօգտագործվող ռեժիմ", + "View Only": "Միայն դիտել", + "Clip to Window": "Սեղմել պատուհանին", + "Scaling Mode:": "Scaling Mode:", + "None": "Ոչ ոք", + "Local Scaling": "Տեղական մասշտաբավորում", + "Remote Resizing": "Հեռավոր չափափոխում", + "Advanced": "Ընդլայնված", + "Quality:": "Որակ.", + "Compression level:": "Սեղմման մակարդակ.", + "Repeater ID:": "Կրկնիչ ID.", + "WebSocket": "WebSocket", + "Encrypt": "Գաղտնագրել", + "Host:": "Հաղորդավար.", + "Port:": "Պորտ:", + "Path:": "Ճանապարհ.", + "Automatic Reconnect": "Ավտոմատ վերամիացում", + "Reconnect Delay (ms):": "Վերամիացման հետաձգում (ms):", + "Show Dot when No Cursor": "Ցույց տալ կետը, երբ կուրսորը չկա", + "Logging:": "Գրանցում.", + "Version:": "Տարբերակ.", + "Disconnect": "Անջատել", + "Connect": "Միացեք", + "Username:": "Օգտագործողի անունը:", + "Password:": "Գաղտնաբառ.", + "Send Credentials": "Ուղարկել հավատարմագրերը", + "Cancel": "Չեղարկել", + "Keys": "Բանալիններ", + "Game Cursor Mode": "Խաղի կուրսորի ռեժիմը", + "Press Esc Key to Exit Pointer Lock Mode": "Սեղմեք Esc ստեղնը՝ ցուցիչի կողպման ռեժիմից դուրս գալու համար", + "Game Mode paused, click on screen to resume Game Mode.": "Խաղի ռեժիմը դադարեցված է, սեղմեք էկրանին՝ խաղի ռեժիմը վերսկսելու համար:", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Նախընտրել տեղական կուրսորը", + "Translate keyboard shortcuts": "Թարգմանել ստեղնաշարի դյուրանցումները", + "Enable WebRTC UDP Transit": "Միացնել WebRTC UDP տարանցումը", + "Enable WebP Compression": "Միացնել WebP սեղմումը", + "Enable Performance Stats": "Միացնել կատարողականի վիճակագրությունը", + "Enable Pointer Lock": "Միացնել ցուցիչի կողպումը", + "IME Input Mode": "IME մուտքագրման ռեժիմ", + "Show Virtual Keyboard Control": "Ցույց տալ վիրտուալ ստեղնաշարի կառավարումը", + "Toggle Control Panel via Keystrokes": "Փոխարկել կառավարման վահանակը ստեղնաշարի միջոցով", + "Render Native Resolution": "Ներկայացնել հայրենի բանաձեւը", + "Keyboard Shortcuts": "Ստեղնաշարի դյուրանցումներ", + "Enable KasmVNC Keyboard Shortcuts": "Միացնել KasmVNC ստեղնաշարի դյուրանցումները", + "1 - Toggle Control Panel": "1 - միացնել կառավարման վահանակը", + "2 - Toggle Game Pointer Mode": "2 - Փոխարկել խաղի ցուցիչի ռեժիմը", + "3 - Toggle Pointer Lock": "3 - Փոխարկել ցուցիչի կողպեքը", + "Stream Quality": "Հոսքի որակ", + "Preset Modes:": "Նախադրված ռեժիմներ.", + "Static": "Ստատիկ", + "Low": "Ցածր", + "Medium": "Միջին", + "High": "Բարձր", + "Extreme": "Ծայրահեղ", + "Lossless": "Անկորուստ", + "Custom": "Պատվերով", + "Anti-Aliasing:": "Anti-aliasing.", + "Auto Dynamic": "Ավտո դինամիկ", + "Off": "Անջատված", + "On": "Վրա", + "Dynamic Quality Min:": "Dynamic Quality Min:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Breat Lossless:", + "Frame Rate:": "Frame Rate:", + "Video JPEG Quality:": "Տեսանյութի JPEG որակ.", + "Video WEBP Quality:": "Տեսանյութի WEBP որակ.", + "Video Area:": "Տեսանյութի տարածք.", + "Video Time:": "Տեսանյութի ժամանակ.", + "Video Out Time:": "Տեսանյութի թողարկման ժամանակը.", + "Video Mode Width:": "Տեսանյութի ռեժիմի լայնություն.", + "Video Mode Height:": "Տեսանյութի ռեժիմի բարձրություն.", + "Documentation": "Փաստաթղթեր", + "Drag Viewport": "Քաշել տեսադաշտը", + "KasmVNC encountered an error:": "KasmVNC-ն սխալ է հանդիպել." +} \ No newline at end of file diff --git a/app/locale/id.json b/app/locale/id.json new file mode 100644 index 0000000..f72c25b --- /dev/null +++ b/app/locale/id.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Menghubungkan...", + "Disconnecting...": "Memutuskan...", + "Reconnecting...": "Menghubungkan kembali...", + "Internal error": "Kesalahan internal", + "Must set host": "Harus mengatur tuan rumah", + "Connected (encrypted) to ": "Terhubung (terenkripsi) ke ", + "Connected (unencrypted) to ": "Terhubung (tidak terenkripsi) ke ", + "Something went wrong, connection is closed": "Ada yang tidak beres, koneksi ditutup", + "Failed to connect to server": "Gagal terhubung ke server", + "Disconnected": "Terputus", + "New connection has been rejected with reason: ": "Koneksi baru telah ditolak dengan alasan:", + "New connection has been rejected": "Koneksi baru telah ditolak", + "Credentials are required": "Kredensial diperlukan", + "Hide/Show the control bar": "Sembunyikan/Tampilkan bilah kontrol", + "Drag": "Menyeret", + "Move/Drag Viewport": "Pindahkan/Seret Area Pandang", + "Keyboard": "Papan ketik", + "Show Keyboard": "Tampilkan Papan Ketik", + "Extra keys": "Kunci tambahan", + "Show Extra Keys": "Tampilkan Kunci Ekstra", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Beralih Ctrl", + "Alt": "alt", + "Toggle Alt": "Alihkan Alt", + "Toggle Windows": "Beralih Windows", + "Windows": "Jendela", + "Send Tab": "Tab Kirim", + "Tab": "Tab", + "Esc": "ESC", + "Send Escape": "Kirim Pelarian", + "Ctrl+Alt+Del": "Ctrl+Alt+del", + "Send Ctrl-Alt-Del": "Kirim Ctrl-Alt-Del", + "Shutdown/Reboot": "Matikan/Boot Ulang", + "Shutdown/Reboot...": "Matikan/Nyalakan Ulang...", + "Power": "Kekuatan", + "Shutdown": "Matikan", + "Reboot": "Menyalakan ulang", + "Reset": "Mengatur ulang", + "Clipboard": "Papan klip", + "Clear": "Jernih", + "Fullscreen": "Layar penuh", + "Settings": "Pengaturan", + "Shared Mode": "Mode Bersama", + "View Only": "Lihat Saja", + "Clip to Window": "Klip ke Jendela", + "Scaling Mode:": "Mode Penskalaan:", + "None": "Tidak ada", + "Local Scaling": "Penskalaan Lokal", + "Remote Resizing": "Mengubah Ukuran Jarak Jauh", + "Advanced": "Canggih", + "Quality:": "Kualitas:", + "Compression level:": "Tingkat kompresi:", + "Repeater ID:": "ID pengulang:", + "WebSocket": "WebSocket", + "Encrypt": "Enkripsi", + "Host:": "Tuan rumah:", + "Port:": "Pelabuhan:", + "Path:": "Jalur:", + "Automatic Reconnect": "Sambung Ulang Otomatis", + "Reconnect Delay (ms):": "Hubungkan kembali Penundaan (ms):", + "Show Dot when No Cursor": "Tampilkan Titik saat Tidak Ada Kursor", + "Logging:": "Mencatat:", + "Version:": "Versi: kapan:", + "Disconnect": "Memutuskan", + "Connect": "Menghubung", + "Username:": "Nama belakang:", + "Password:": "Kata sandi:", + "Send Credentials": "Kirim Kredensial", + "Cancel": "Membatalkan", + "Keys": "Kunci", + "Game Cursor Mode": "Mode Kursor Permainan", + "Press Esc Key to Exit Pointer Lock Mode": "Tekan Tombol Esc untuk Keluar dari Mode Kunci Penunjuk", + "Game Mode paused, click on screen to resume Game Mode.": "Mode Game dijeda, klik di layar untuk melanjutkan Mode Game.", + "Clipboard Up": "Papan Klip Naik", + "CLipboard Down": "Papan klip Turun", + "Clipboard Seamless": "Papan Klip Mulus", + "Prefer Local Cursor": "Lebih suka Kursor Lokal", + "Translate keyboard shortcuts": "Terjemahkan pintasan keyboard", + "Enable WebRTC UDP Transit": "Aktifkan Transit UDP WebRTC", + "Enable WebP Compression": "Aktifkan Kompresi WebP", + "Enable Performance Stats": "Aktifkan Statistik Performa", + "Enable Pointer Lock": "Aktifkan Kunci Penunjuk", + "IME Input Mode": "Mode Masukan IME", + "Show Virtual Keyboard Control": "Tampilkan Kontrol Keyboard Virtual", + "Toggle Control Panel via Keystrokes": "Beralih Panel Kontrol melalui Keystrokes", + "Render Native Resolution": "Buat Resolusi Asli", + "Keyboard Shortcuts": "Pintasan Keyboard", + "Enable KasmVNC Keyboard Shortcuts": "Aktifkan Pintasan Keyboard KasmVNC", + "1 - Toggle Control Panel": "1 - Alihkan Panel Kontrol", + "2 - Toggle Game Pointer Mode": "2 - Alihkan Mode Penunjuk Permainan", + "3 - Toggle Pointer Lock": "3 - Alihkan Kunci Penunjuk", + "Stream Quality": "Kualitas Aliran", + "Preset Modes:": "Mode Preset:", + "Static": "Statis", + "Low": "Rendah", + "Medium": "Sedang", + "High": "Tinggi", + "Extreme": "Ekstrim", + "Lossless": "Tanpa rugi", + "Custom": "Kebiasaan", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Dinamis Otomatis", + "Off": "Mati", + "On": "Pada", + "Dynamic Quality Min:": "Minimum Kualitas Dinamis:", + "Dynamic Quality Max:": "Kualitas Dinamis Maks:", + "Treat Lossless:": "Perlakukan Tanpa Rugi:", + "Frame Rate:": "Frekuensi Bingkai:", + "Video JPEG Quality:": "Kualitas Video JPEG:", + "Video WEBP Quality:": "Kualitas WEBP Video:", + "Video Area:": "Area Video:", + "Video Time:": "Waktu Video:", + "Video Out Time:": "Waktu Keluar Video:", + "Video Mode Width:": "Lebar Mode Video:", + "Video Mode Height:": "Tinggi Mode Video:", + "Documentation": "Dokumentasi", + "Drag Viewport": "Seret Area Pandang", + "KasmVNC encountered an error:": "KasmVNC mengalami kesalahan:" +} \ No newline at end of file diff --git a/app/locale/id_ID.json b/app/locale/id_ID.json new file mode 100644 index 0000000..f72c25b --- /dev/null +++ b/app/locale/id_ID.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Menghubungkan...", + "Disconnecting...": "Memutuskan...", + "Reconnecting...": "Menghubungkan kembali...", + "Internal error": "Kesalahan internal", + "Must set host": "Harus mengatur tuan rumah", + "Connected (encrypted) to ": "Terhubung (terenkripsi) ke ", + "Connected (unencrypted) to ": "Terhubung (tidak terenkripsi) ke ", + "Something went wrong, connection is closed": "Ada yang tidak beres, koneksi ditutup", + "Failed to connect to server": "Gagal terhubung ke server", + "Disconnected": "Terputus", + "New connection has been rejected with reason: ": "Koneksi baru telah ditolak dengan alasan:", + "New connection has been rejected": "Koneksi baru telah ditolak", + "Credentials are required": "Kredensial diperlukan", + "Hide/Show the control bar": "Sembunyikan/Tampilkan bilah kontrol", + "Drag": "Menyeret", + "Move/Drag Viewport": "Pindahkan/Seret Area Pandang", + "Keyboard": "Papan ketik", + "Show Keyboard": "Tampilkan Papan Ketik", + "Extra keys": "Kunci tambahan", + "Show Extra Keys": "Tampilkan Kunci Ekstra", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Beralih Ctrl", + "Alt": "alt", + "Toggle Alt": "Alihkan Alt", + "Toggle Windows": "Beralih Windows", + "Windows": "Jendela", + "Send Tab": "Tab Kirim", + "Tab": "Tab", + "Esc": "ESC", + "Send Escape": "Kirim Pelarian", + "Ctrl+Alt+Del": "Ctrl+Alt+del", + "Send Ctrl-Alt-Del": "Kirim Ctrl-Alt-Del", + "Shutdown/Reboot": "Matikan/Boot Ulang", + "Shutdown/Reboot...": "Matikan/Nyalakan Ulang...", + "Power": "Kekuatan", + "Shutdown": "Matikan", + "Reboot": "Menyalakan ulang", + "Reset": "Mengatur ulang", + "Clipboard": "Papan klip", + "Clear": "Jernih", + "Fullscreen": "Layar penuh", + "Settings": "Pengaturan", + "Shared Mode": "Mode Bersama", + "View Only": "Lihat Saja", + "Clip to Window": "Klip ke Jendela", + "Scaling Mode:": "Mode Penskalaan:", + "None": "Tidak ada", + "Local Scaling": "Penskalaan Lokal", + "Remote Resizing": "Mengubah Ukuran Jarak Jauh", + "Advanced": "Canggih", + "Quality:": "Kualitas:", + "Compression level:": "Tingkat kompresi:", + "Repeater ID:": "ID pengulang:", + "WebSocket": "WebSocket", + "Encrypt": "Enkripsi", + "Host:": "Tuan rumah:", + "Port:": "Pelabuhan:", + "Path:": "Jalur:", + "Automatic Reconnect": "Sambung Ulang Otomatis", + "Reconnect Delay (ms):": "Hubungkan kembali Penundaan (ms):", + "Show Dot when No Cursor": "Tampilkan Titik saat Tidak Ada Kursor", + "Logging:": "Mencatat:", + "Version:": "Versi: kapan:", + "Disconnect": "Memutuskan", + "Connect": "Menghubung", + "Username:": "Nama belakang:", + "Password:": "Kata sandi:", + "Send Credentials": "Kirim Kredensial", + "Cancel": "Membatalkan", + "Keys": "Kunci", + "Game Cursor Mode": "Mode Kursor Permainan", + "Press Esc Key to Exit Pointer Lock Mode": "Tekan Tombol Esc untuk Keluar dari Mode Kunci Penunjuk", + "Game Mode paused, click on screen to resume Game Mode.": "Mode Game dijeda, klik di layar untuk melanjutkan Mode Game.", + "Clipboard Up": "Papan Klip Naik", + "CLipboard Down": "Papan klip Turun", + "Clipboard Seamless": "Papan Klip Mulus", + "Prefer Local Cursor": "Lebih suka Kursor Lokal", + "Translate keyboard shortcuts": "Terjemahkan pintasan keyboard", + "Enable WebRTC UDP Transit": "Aktifkan Transit UDP WebRTC", + "Enable WebP Compression": "Aktifkan Kompresi WebP", + "Enable Performance Stats": "Aktifkan Statistik Performa", + "Enable Pointer Lock": "Aktifkan Kunci Penunjuk", + "IME Input Mode": "Mode Masukan IME", + "Show Virtual Keyboard Control": "Tampilkan Kontrol Keyboard Virtual", + "Toggle Control Panel via Keystrokes": "Beralih Panel Kontrol melalui Keystrokes", + "Render Native Resolution": "Buat Resolusi Asli", + "Keyboard Shortcuts": "Pintasan Keyboard", + "Enable KasmVNC Keyboard Shortcuts": "Aktifkan Pintasan Keyboard KasmVNC", + "1 - Toggle Control Panel": "1 - Alihkan Panel Kontrol", + "2 - Toggle Game Pointer Mode": "2 - Alihkan Mode Penunjuk Permainan", + "3 - Toggle Pointer Lock": "3 - Alihkan Kunci Penunjuk", + "Stream Quality": "Kualitas Aliran", + "Preset Modes:": "Mode Preset:", + "Static": "Statis", + "Low": "Rendah", + "Medium": "Sedang", + "High": "Tinggi", + "Extreme": "Ekstrim", + "Lossless": "Tanpa rugi", + "Custom": "Kebiasaan", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Dinamis Otomatis", + "Off": "Mati", + "On": "Pada", + "Dynamic Quality Min:": "Minimum Kualitas Dinamis:", + "Dynamic Quality Max:": "Kualitas Dinamis Maks:", + "Treat Lossless:": "Perlakukan Tanpa Rugi:", + "Frame Rate:": "Frekuensi Bingkai:", + "Video JPEG Quality:": "Kualitas Video JPEG:", + "Video WEBP Quality:": "Kualitas WEBP Video:", + "Video Area:": "Area Video:", + "Video Time:": "Waktu Video:", + "Video Out Time:": "Waktu Keluar Video:", + "Video Mode Width:": "Lebar Mode Video:", + "Video Mode Height:": "Tinggi Mode Video:", + "Documentation": "Dokumentasi", + "Drag Viewport": "Seret Area Pandang", + "KasmVNC encountered an error:": "KasmVNC mengalami kesalahan:" +} \ No newline at end of file diff --git a/app/locale/ig.json b/app/locale/ig.json new file mode 100644 index 0000000..947f294 --- /dev/null +++ b/app/locale/ig.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Na-ejikọta...", + "Disconnecting...": "Ịkwụsị njikọ...", + "Reconnecting...": "Na-ejikọta ọzọ...", + "Internal error": "Njehie dị n'ime", + "Must set host": "Ekwesịrị ịtọ onye ọbịa", + "Connected (encrypted) to ": "Ejikọrọ (ezoro ezo) na", + "Connected (unencrypted) to ": "Ejikọrọ (anaghị ezoro ezo) na", + "Something went wrong, connection is closed": "Ọnwere ihe adịghị mma, njikọ emechiela", + "Failed to connect to server": "Ọ dịghị njikọ na ihe nkesa", + "Disconnected": "Ekwụpụrụ", + "New connection has been rejected with reason: ": "Ajụrụ njikọ ọhụrụ n'ihi ihe kpatara ya:", + "New connection has been rejected": "Ajụjụ njikọ ọhụrụ", + "Credentials are required": "Achọrọ nzere", + "Hide/Show the control bar": "Zoo/Gosi akara njikwa", + "Drag": "Dọrọ", + "Move/Drag Viewport": "Bugharịa / Dọrọ nlegharị anya", + "Keyboard": "ahụigodo", + "Show Keyboard": "Gosi ahụigodo", + "Extra keys": "Igodo ọzọ", + "Show Extra Keys": "Gosi mgbakwunye igodo", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Tụgharịa Ctrl", + "Alt": "Alt", + "Toggle Alt": "Tụgharịa Alt", + "Toggle Windows": "Tụgharịa Windows", + "Windows": "Windows", + "Send Tab": "Zipu Tab", + "Tab": "Taabụ", + "Esc": "Esc", + "Send Escape": "Zipu mgbapụ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Zipu Ctrl-Alt-Del", + "Shutdown/Reboot": "Mmechibido / malitegharịa", + "Shutdown/Reboot...": "Mechie / malitegharịa...", + "Power": "Ike", + "Shutdown": "Mechie", + "Reboot": "Malitegharịa ekwentị", + "Reset": "Tọgharia", + "Clipboard": "Klipbọọdụ", + "Clear": "Kpochapụ", + "Fullscreen": "Ihuenyo zuru oke", + "Settings": "Ntọala", + "Shared Mode": "Ụdị Ekekọrịtara", + "View Only": "Lee naanị", + "Clip to Window": "Kpọọ na windo", + "Scaling Mode:": "Ụdị ntọlite:", + "None": "Ọ dịghị", + "Local Scaling": "Ntụle mpaghara", + "Remote Resizing": "Mgbanwe nha anya", + "Advanced": "Ego elu", + "Quality:": "Ọdịmma:", + "Compression level:": "Ọkwa mkpakọ:", + "Repeater ID:": "NJ ugboro ugboro:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Onye ọbịa:", + "Port:": "Ọdụ ụgbọ mmiri:", + "Path:": "Ụzọ:", + "Automatic Reconnect": "njikọ akpaaka", + "Reconnect Delay (ms):": "Tigharịa oge igbu oge (ms):", + "Show Dot when No Cursor": "Gosi ntụpọ mgbe ọ nweghị cursor", + "Logging:": "Ịbanye:", + "Version:": "Ụdị:", + "Disconnect": "Kwụpụ", + "Connect": "Jikọọ", + "Username:": "Aha njirimara:", + "Password:": "Paswọọdụ:", + "Send Credentials": "Zipu nzere", + "Cancel": "Kagbuo", + "Keys": "Igodo", + "Game Cursor Mode": "Ụdị cursor egwuregwu", + "Press Esc Key to Exit Pointer Lock Mode": "pịa igodo Esc ka ịpụ na ọnọdụ mkpọchi ntụnye", + "Game Mode paused, click on screen to resume Game Mode.": "Ụdị egwuregwu kwụsịrị, pịa ihuenyo ka ịmaliteghachi ọnọdụ egwuregwu.", + "Clipboard Up": "Klipbọọdụ Elu", + "CLipboard Down": "Klipbọọdụ ala", + "Clipboard Seamless": "Klipbọọdụ enweghị nkebi", + "Prefer Local Cursor": "Họrọ ihe nhịahụ mpaghara", + "Translate keyboard shortcuts": "Tụgharịa asụsụ mkpirisi ahụigodo", + "Enable WebRTC UDP Transit": "Kwado WebRTC UDP Transit", + "Enable WebP Compression": "Kwado mkpakọ WebP", + "Enable Performance Stats": "Kwado stats arụmọrụ", + "Enable Pointer Lock": "Kwado mkpọchi ntụnye", + "IME Input Mode": "Ụdị ntinye IME", + "Show Virtual Keyboard Control": "Gosi njikwa ahụigodo mebere", + "Toggle Control Panel via Keystrokes": "Tụgharịa Ogwe njikwa site na igodo igodo", + "Render Native Resolution": "Mepụta mkpebi obodo", + "Keyboard Shortcuts": "Ụzọ mkpirisi ahụigodo", + "Enable KasmVNC Keyboard Shortcuts": "Kwado ụzọ mkpirisi ahụigodo KasmVNC", + "1 - Toggle Control Panel": "1 - Gbanwee Ogwe njikwa", + "2 - Toggle Game Pointer Mode": "2 - Gbanwee ụkpụrụ ntụnye egwuregwu", + "3 - Toggle Pointer Lock": "3 - Gbanwee mkpọchi ntụnye", + "Stream Quality": "Ọdịmma Stream", + "Preset Modes:": "Ụdị atọrọ:", + "Static": "Static", + "Low": "Obere", + "Medium": "Ọkara", + "High": "Elu", + "Extreme": "oke", + "Lossless": "Enweghị efu", + "Custom": "Omenala", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Akụkụ na-agbanwe agbanwe", + "Off": "gbanyụọ", + "On": "Na", + "Dynamic Quality Min:": "Njiri mara mma na-agbanwe agbanwe:", + "Dynamic Quality Max:": "Ọdịmma kacha mma:", + "Treat Lossless:": "Mee ihe efu:", + "Frame Rate:": "Ọnụ ego etiti:", + "Video JPEG Quality:": "Video JPEG Ogo:", + "Video WEBP Quality:": "Video WEBP Ogo:", + "Video Area:": "Ebe vidiyo:", + "Video Time:": "Oge vidiyo:", + "Video Out Time:": "Oge Ọpụpụ vidiyo:", + "Video Mode Width:": "Obosara ọnọdụ vidiyo:", + "Video Mode Height:": "Ụdị vidiyo dị elu:", + "Documentation": "Akwụkwọ", + "Drag Viewport": "Dọrọ nlegharị anya", + "KasmVNC encountered an error:": "KasmVNC zutere mperi:" +} \ No newline at end of file diff --git a/app/locale/ig_NG.json b/app/locale/ig_NG.json new file mode 100644 index 0000000..947f294 --- /dev/null +++ b/app/locale/ig_NG.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Na-ejikọta...", + "Disconnecting...": "Ịkwụsị njikọ...", + "Reconnecting...": "Na-ejikọta ọzọ...", + "Internal error": "Njehie dị n'ime", + "Must set host": "Ekwesịrị ịtọ onye ọbịa", + "Connected (encrypted) to ": "Ejikọrọ (ezoro ezo) na", + "Connected (unencrypted) to ": "Ejikọrọ (anaghị ezoro ezo) na", + "Something went wrong, connection is closed": "Ọnwere ihe adịghị mma, njikọ emechiela", + "Failed to connect to server": "Ọ dịghị njikọ na ihe nkesa", + "Disconnected": "Ekwụpụrụ", + "New connection has been rejected with reason: ": "Ajụrụ njikọ ọhụrụ n'ihi ihe kpatara ya:", + "New connection has been rejected": "Ajụjụ njikọ ọhụrụ", + "Credentials are required": "Achọrọ nzere", + "Hide/Show the control bar": "Zoo/Gosi akara njikwa", + "Drag": "Dọrọ", + "Move/Drag Viewport": "Bugharịa / Dọrọ nlegharị anya", + "Keyboard": "ahụigodo", + "Show Keyboard": "Gosi ahụigodo", + "Extra keys": "Igodo ọzọ", + "Show Extra Keys": "Gosi mgbakwunye igodo", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Tụgharịa Ctrl", + "Alt": "Alt", + "Toggle Alt": "Tụgharịa Alt", + "Toggle Windows": "Tụgharịa Windows", + "Windows": "Windows", + "Send Tab": "Zipu Tab", + "Tab": "Taabụ", + "Esc": "Esc", + "Send Escape": "Zipu mgbapụ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Zipu Ctrl-Alt-Del", + "Shutdown/Reboot": "Mmechibido / malitegharịa", + "Shutdown/Reboot...": "Mechie / malitegharịa...", + "Power": "Ike", + "Shutdown": "Mechie", + "Reboot": "Malitegharịa ekwentị", + "Reset": "Tọgharia", + "Clipboard": "Klipbọọdụ", + "Clear": "Kpochapụ", + "Fullscreen": "Ihuenyo zuru oke", + "Settings": "Ntọala", + "Shared Mode": "Ụdị Ekekọrịtara", + "View Only": "Lee naanị", + "Clip to Window": "Kpọọ na windo", + "Scaling Mode:": "Ụdị ntọlite:", + "None": "Ọ dịghị", + "Local Scaling": "Ntụle mpaghara", + "Remote Resizing": "Mgbanwe nha anya", + "Advanced": "Ego elu", + "Quality:": "Ọdịmma:", + "Compression level:": "Ọkwa mkpakọ:", + "Repeater ID:": "NJ ugboro ugboro:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Onye ọbịa:", + "Port:": "Ọdụ ụgbọ mmiri:", + "Path:": "Ụzọ:", + "Automatic Reconnect": "njikọ akpaaka", + "Reconnect Delay (ms):": "Tigharịa oge igbu oge (ms):", + "Show Dot when No Cursor": "Gosi ntụpọ mgbe ọ nweghị cursor", + "Logging:": "Ịbanye:", + "Version:": "Ụdị:", + "Disconnect": "Kwụpụ", + "Connect": "Jikọọ", + "Username:": "Aha njirimara:", + "Password:": "Paswọọdụ:", + "Send Credentials": "Zipu nzere", + "Cancel": "Kagbuo", + "Keys": "Igodo", + "Game Cursor Mode": "Ụdị cursor egwuregwu", + "Press Esc Key to Exit Pointer Lock Mode": "pịa igodo Esc ka ịpụ na ọnọdụ mkpọchi ntụnye", + "Game Mode paused, click on screen to resume Game Mode.": "Ụdị egwuregwu kwụsịrị, pịa ihuenyo ka ịmaliteghachi ọnọdụ egwuregwu.", + "Clipboard Up": "Klipbọọdụ Elu", + "CLipboard Down": "Klipbọọdụ ala", + "Clipboard Seamless": "Klipbọọdụ enweghị nkebi", + "Prefer Local Cursor": "Họrọ ihe nhịahụ mpaghara", + "Translate keyboard shortcuts": "Tụgharịa asụsụ mkpirisi ahụigodo", + "Enable WebRTC UDP Transit": "Kwado WebRTC UDP Transit", + "Enable WebP Compression": "Kwado mkpakọ WebP", + "Enable Performance Stats": "Kwado stats arụmọrụ", + "Enable Pointer Lock": "Kwado mkpọchi ntụnye", + "IME Input Mode": "Ụdị ntinye IME", + "Show Virtual Keyboard Control": "Gosi njikwa ahụigodo mebere", + "Toggle Control Panel via Keystrokes": "Tụgharịa Ogwe njikwa site na igodo igodo", + "Render Native Resolution": "Mepụta mkpebi obodo", + "Keyboard Shortcuts": "Ụzọ mkpirisi ahụigodo", + "Enable KasmVNC Keyboard Shortcuts": "Kwado ụzọ mkpirisi ahụigodo KasmVNC", + "1 - Toggle Control Panel": "1 - Gbanwee Ogwe njikwa", + "2 - Toggle Game Pointer Mode": "2 - Gbanwee ụkpụrụ ntụnye egwuregwu", + "3 - Toggle Pointer Lock": "3 - Gbanwee mkpọchi ntụnye", + "Stream Quality": "Ọdịmma Stream", + "Preset Modes:": "Ụdị atọrọ:", + "Static": "Static", + "Low": "Obere", + "Medium": "Ọkara", + "High": "Elu", + "Extreme": "oke", + "Lossless": "Enweghị efu", + "Custom": "Omenala", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Akụkụ na-agbanwe agbanwe", + "Off": "gbanyụọ", + "On": "Na", + "Dynamic Quality Min:": "Njiri mara mma na-agbanwe agbanwe:", + "Dynamic Quality Max:": "Ọdịmma kacha mma:", + "Treat Lossless:": "Mee ihe efu:", + "Frame Rate:": "Ọnụ ego etiti:", + "Video JPEG Quality:": "Video JPEG Ogo:", + "Video WEBP Quality:": "Video WEBP Ogo:", + "Video Area:": "Ebe vidiyo:", + "Video Time:": "Oge vidiyo:", + "Video Out Time:": "Oge Ọpụpụ vidiyo:", + "Video Mode Width:": "Obosara ọnọdụ vidiyo:", + "Video Mode Height:": "Ụdị vidiyo dị elu:", + "Documentation": "Akwụkwọ", + "Drag Viewport": "Dọrọ nlegharị anya", + "KasmVNC encountered an error:": "KasmVNC zutere mperi:" +} \ No newline at end of file diff --git a/app/locale/is.json b/app/locale/is.json new file mode 100644 index 0000000..b547311 --- /dev/null +++ b/app/locale/is.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Tengir...", + "Disconnecting...": "Aftengdar...", + "Reconnecting...": "Tengist aftur...", + "Internal error": "Innri villa", + "Must set host": "Verður að stilla gestgjafa", + "Connected (encrypted) to ": "Tengt (dulkóðað) við ", + "Connected (unencrypted) to ": "Tengt (ódulkóðað) við ", + "Something went wrong, connection is closed": "Eitthvað fór úrskeiðis, tenging er lokuð", + "Failed to connect to server": "Tókst ekki að tengjast þjóninum", + "Disconnected": "Aftengdur", + "New connection has been rejected with reason: ": "Nýrri tengingu hefur verið hafnað með ástæðu:", + "New connection has been rejected": "Nýrri tengingu hefur verið hafnað", + "Credentials are required": "Leikskilríki eru nauðsynleg", + "Hide/Show the control bar": "Fela/sýna stjórnstikuna", + "Drag": "Draga", + "Move/Drag Viewport": "Færa/draga útsýni", + "Keyboard": "Lyklaborð", + "Show Keyboard": "Sýna lyklaborð", + "Extra keys": "Auka lyklar", + "Show Extra Keys": "Sýna aukalykla", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Slökktu á Ctrl", + "Alt": "Alt", + "Toggle Alt": "Slökkva á Alt", + "Toggle Windows": "Slökkva á Windows", + "Windows": "Windows", + "Send Tab": "Senda flipi", + "Tab": "flipi", + "Esc": "Esc", + "Send Escape": "Senda flýja", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Senda Ctrl-Alt-Del", + "Shutdown/Reboot": "Slökkva/endurræsa", + "Shutdown/Reboot...": "Slökkva/endurræsa...", + "Power": "Máttur", + "Shutdown": "Slökkvun", + "Reboot": "Endurræsa", + "Reset": "Endurstilla", + "Clipboard": "Klippiborð", + "Clear": "Hreinsa", + "Fullscreen": "Allur skjár", + "Settings": "Stillingar", + "Shared Mode": "Deilt stilling", + "View Only": "Aðeins skoða", + "Clip to Window": "Klippa í glugga", + "Scaling Mode:": "Skalunarstilling:", + "None": "Enginn", + "Local Scaling": "Staðbundin mælikvarði", + "Remote Resizing": "Fjarstærðarbreyting", + "Advanced": "Ítarlegri", + "Quality:": "Gæði:", + "Compression level:": "Þjöppunarstig:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "dulkóða", + "Host:": "Gestgjafi:", + "Port:": "Höfn:", + "Path:": "Leið:", + "Automatic Reconnect": "Sjálfvirkt endurtengja", + "Reconnect Delay (ms):": "Töf á endurtengingu (ms):", + "Show Dot when No Cursor": "Sýna punkt þegar enginn bendil", + "Logging:": "Skrá:", + "Version:": "Útgáfa:", + "Disconnect": "Aftengdu", + "Connect": "Tengdu", + "Username:": "Notendanafn:", + "Password:": "Lykilorð:", + "Send Credentials": "Senda skilríki", + "Cancel": "Hætta við", + "Keys": "Lyklar", + "Game Cursor Mode": "Game Bendill Mode", + "Press Esc Key to Exit Pointer Lock Mode": "Ýttu á Esc takkann til að hætta við bendilásstillingu", + "Game Mode paused, click on screen to resume Game Mode.": "Hlé gert á leikjastillingu, smelltu á skjáinn til að halda áfram leikstillingu.", + "Clipboard Up": "Klippborð upp", + "CLipboard Down": "Klippborð niður", + "Clipboard Seamless": "Klemmuspjald óaðfinnanlegur", + "Prefer Local Cursor": "Vel frekar staðbundinn bendil", + "Translate keyboard shortcuts": "Þýða flýtivísa", + "Enable WebRTC UDP Transit": "Virkja WebRTC UDP Transit", + "Enable WebP Compression": "Virkja WebP þjöppun", + "Enable Performance Stats": "Virkja árangurstölfræði", + "Enable Pointer Lock": "Virkja bendilás", + "IME Input Mode": "IME inntaksstilling", + "Show Virtual Keyboard Control": "Sýna sýndarlyklaborðsstýringu", + "Toggle Control Panel via Keystrokes": "Slökktu á stjórnborði með ásláttum", + "Render Native Resolution": "Gefðu upprunalega upplausn", + "Keyboard Shortcuts": "Flýtivísar", + "Enable KasmVNC Keyboard Shortcuts": "Virkja KasmVNC flýtilykla", + "1 - Toggle Control Panel": "1 - Skiptu um stjórnborð", + "2 - Toggle Game Pointer Mode": "2 - Skiptu um leikbendiham", + "3 - Toggle Pointer Lock": "3 - Víxla bendilás", + "Stream Quality": "Streamgæði", + "Preset Modes:": "Forstilltar stillingar:", + "Static": "Static", + "Low": "Lágt", + "Medium": "miðlungs", + "High": "Hár", + "Extreme": "Öfga", + "Lossless": "Taplaust", + "Custom": "Sérsniðin", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Af", + "On": "Á", + "Dynamic Quality Min:": "Dynamísk gæði mín:", + "Dynamic Quality Max:": "Dynamísk gæði hámarks:", + "Treat Lossless:": "Meðhöndla Lossless:", + "Frame Rate:": "Rammatíðni:", + "Video JPEG Quality:": "JPEG myndgæði:", + "Video WEBP Quality:": "Video WEBP gæði:", + "Video Area:": "Myndbandssvæði:", + "Video Time:": "Video Time:", + "Video Out Time:": "Úttími myndbands:", + "Video Mode Width:": "Video Mode Breidd:", + "Video Mode Height:": "Hæð myndbandshams:", + "Documentation": "Skjölun", + "Drag Viewport": "Dragðu útsýnisgátt", + "KasmVNC encountered an error:": "KasmVNC rakst á villu:" +} \ No newline at end of file diff --git a/app/locale/is_IS.json b/app/locale/is_IS.json new file mode 100644 index 0000000..b547311 --- /dev/null +++ b/app/locale/is_IS.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Tengir...", + "Disconnecting...": "Aftengdar...", + "Reconnecting...": "Tengist aftur...", + "Internal error": "Innri villa", + "Must set host": "Verður að stilla gestgjafa", + "Connected (encrypted) to ": "Tengt (dulkóðað) við ", + "Connected (unencrypted) to ": "Tengt (ódulkóðað) við ", + "Something went wrong, connection is closed": "Eitthvað fór úrskeiðis, tenging er lokuð", + "Failed to connect to server": "Tókst ekki að tengjast þjóninum", + "Disconnected": "Aftengdur", + "New connection has been rejected with reason: ": "Nýrri tengingu hefur verið hafnað með ástæðu:", + "New connection has been rejected": "Nýrri tengingu hefur verið hafnað", + "Credentials are required": "Leikskilríki eru nauðsynleg", + "Hide/Show the control bar": "Fela/sýna stjórnstikuna", + "Drag": "Draga", + "Move/Drag Viewport": "Færa/draga útsýni", + "Keyboard": "Lyklaborð", + "Show Keyboard": "Sýna lyklaborð", + "Extra keys": "Auka lyklar", + "Show Extra Keys": "Sýna aukalykla", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Slökktu á Ctrl", + "Alt": "Alt", + "Toggle Alt": "Slökkva á Alt", + "Toggle Windows": "Slökkva á Windows", + "Windows": "Windows", + "Send Tab": "Senda flipi", + "Tab": "flipi", + "Esc": "Esc", + "Send Escape": "Senda flýja", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Senda Ctrl-Alt-Del", + "Shutdown/Reboot": "Slökkva/endurræsa", + "Shutdown/Reboot...": "Slökkva/endurræsa...", + "Power": "Máttur", + "Shutdown": "Slökkvun", + "Reboot": "Endurræsa", + "Reset": "Endurstilla", + "Clipboard": "Klippiborð", + "Clear": "Hreinsa", + "Fullscreen": "Allur skjár", + "Settings": "Stillingar", + "Shared Mode": "Deilt stilling", + "View Only": "Aðeins skoða", + "Clip to Window": "Klippa í glugga", + "Scaling Mode:": "Skalunarstilling:", + "None": "Enginn", + "Local Scaling": "Staðbundin mælikvarði", + "Remote Resizing": "Fjarstærðarbreyting", + "Advanced": "Ítarlegri", + "Quality:": "Gæði:", + "Compression level:": "Þjöppunarstig:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "dulkóða", + "Host:": "Gestgjafi:", + "Port:": "Höfn:", + "Path:": "Leið:", + "Automatic Reconnect": "Sjálfvirkt endurtengja", + "Reconnect Delay (ms):": "Töf á endurtengingu (ms):", + "Show Dot when No Cursor": "Sýna punkt þegar enginn bendil", + "Logging:": "Skrá:", + "Version:": "Útgáfa:", + "Disconnect": "Aftengdu", + "Connect": "Tengdu", + "Username:": "Notendanafn:", + "Password:": "Lykilorð:", + "Send Credentials": "Senda skilríki", + "Cancel": "Hætta við", + "Keys": "Lyklar", + "Game Cursor Mode": "Game Bendill Mode", + "Press Esc Key to Exit Pointer Lock Mode": "Ýttu á Esc takkann til að hætta við bendilásstillingu", + "Game Mode paused, click on screen to resume Game Mode.": "Hlé gert á leikjastillingu, smelltu á skjáinn til að halda áfram leikstillingu.", + "Clipboard Up": "Klippborð upp", + "CLipboard Down": "Klippborð niður", + "Clipboard Seamless": "Klemmuspjald óaðfinnanlegur", + "Prefer Local Cursor": "Vel frekar staðbundinn bendil", + "Translate keyboard shortcuts": "Þýða flýtivísa", + "Enable WebRTC UDP Transit": "Virkja WebRTC UDP Transit", + "Enable WebP Compression": "Virkja WebP þjöppun", + "Enable Performance Stats": "Virkja árangurstölfræði", + "Enable Pointer Lock": "Virkja bendilás", + "IME Input Mode": "IME inntaksstilling", + "Show Virtual Keyboard Control": "Sýna sýndarlyklaborðsstýringu", + "Toggle Control Panel via Keystrokes": "Slökktu á stjórnborði með ásláttum", + "Render Native Resolution": "Gefðu upprunalega upplausn", + "Keyboard Shortcuts": "Flýtivísar", + "Enable KasmVNC Keyboard Shortcuts": "Virkja KasmVNC flýtilykla", + "1 - Toggle Control Panel": "1 - Skiptu um stjórnborð", + "2 - Toggle Game Pointer Mode": "2 - Skiptu um leikbendiham", + "3 - Toggle Pointer Lock": "3 - Víxla bendilás", + "Stream Quality": "Streamgæði", + "Preset Modes:": "Forstilltar stillingar:", + "Static": "Static", + "Low": "Lágt", + "Medium": "miðlungs", + "High": "Hár", + "Extreme": "Öfga", + "Lossless": "Taplaust", + "Custom": "Sérsniðin", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Af", + "On": "Á", + "Dynamic Quality Min:": "Dynamísk gæði mín:", + "Dynamic Quality Max:": "Dynamísk gæði hámarks:", + "Treat Lossless:": "Meðhöndla Lossless:", + "Frame Rate:": "Rammatíðni:", + "Video JPEG Quality:": "JPEG myndgæði:", + "Video WEBP Quality:": "Video WEBP gæði:", + "Video Area:": "Myndbandssvæði:", + "Video Time:": "Video Time:", + "Video Out Time:": "Úttími myndbands:", + "Video Mode Width:": "Video Mode Breidd:", + "Video Mode Height:": "Hæð myndbandshams:", + "Documentation": "Skjölun", + "Drag Viewport": "Dragðu útsýnisgátt", + "KasmVNC encountered an error:": "KasmVNC rakst á villu:" +} \ No newline at end of file diff --git a/app/locale/it.json b/app/locale/it.json new file mode 100644 index 0000000..2db6749 --- /dev/null +++ b/app/locale/it.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Collegamento...", + "Disconnecting...": "Disconnessione...", + "Reconnecting...": "Riconnessione...", + "Internal error": "Errore interno", + "Must set host": "Devi impostare l'host", + "Connected (encrypted) to ": "Connesso (crittografato) a ", + "Connected (unencrypted) to ": "Connesso (non crittografato) a ", + "Something went wrong, connection is closed": "Qualcosa è andato storto, la connessione è chiusa", + "Failed to connect to server": "Impossibile connettersi al server", + "Disconnected": "Disconnesso", + "New connection has been rejected with reason: ": "Nuova connessione rifiutata con motivo: ", + "New connection has been rejected": "La nuova connessione è stata rifiutata", + "Credentials are required": "Le credenziali sono necessarie", + "Hide/Show the control bar": "Nascondi/Mostra la barra di controllo", + "Drag": "Lagna", + "Move/Drag Viewport": "Sposta/Trascina finestra", + "Keyboard": "Tastiera", + "Show Keyboard": "Mostra tastiera", + "Extra keys": "Chiavi extra", + "Show Extra Keys": "Mostra chiavi extra", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Commuta Ctrl", + "Alt": "Alt", + "Toggle Alt": "Attiva/disattiva ALT", + "Toggle Windows": "Attiva/disattiva Windows", + "Windows": "Finestre", + "Send Tab": "Scheda Invia", + "Tab": "Scheda", + "Esc": "Esc", + "Send Escape": "Invia fuga", + "Ctrl+Alt+Del": "Ctrl+Alt+Canc", + "Send Ctrl-Alt-Del": "Invia Ctrl-Alt-Canc", + "Shutdown/Reboot": "Arresta/Riavvia", + "Shutdown/Reboot...": "Arresta/Riavvia...", + "Power": "Energia", + "Shutdown": "Fermare", + "Reboot": "Riavviare", + "Reset": "Ripristina", + "Clipboard": "Appunti", + "Clear": "Chiaro", + "Fullscreen": "A schermo intero", + "Settings": "Impostazioni", + "Shared Mode": "Modalità condivisa", + "View Only": "Visualizzare solamente", + "Clip to Window": "Aggancia alla finestra", + "Scaling Mode:": "Modalità ridimensionamento:", + "None": "Nessuno", + "Local Scaling": "Ridimensionamento locale", + "Remote Resizing": "Ridimensionamento remoto", + "Advanced": "Avanzate", + "Quality:": "Qualità:", + "Compression level:": "Livello di compressione:", + "Repeater ID:": "ID ripetitore:", + "WebSocket": "WebSocket", + "Encrypt": "Crittografare", + "Host:": "Ospite:", + "Port:": "Porta:", + "Path:": "Sentiero:", + "Automatic Reconnect": "Riconnessione automatica", + "Reconnect Delay (ms):": "Ritardo riconnessione (ms):", + "Show Dot when No Cursor": "Mostra punto quando nessun cursore", + "Logging:": "Registrazione:", + "Version:": "Versione:", + "Disconnect": "Disconnetti", + "Connect": "Collegare", + "Username:": "Nome utente:", + "Password:": "Parola d'ordine:", + "Send Credentials": "Invia credenziali", + "Cancel": "Annulla", + "Keys": "Chiavi", + "Game Cursor Mode": "Modalità cursore di gioco", + "Press Esc Key to Exit Pointer Lock Mode": "Premi il tasto Esc per uscire dalla modalità di blocco del puntatore", + "Game Mode paused, click on screen to resume Game Mode.": "Modalità di gioco in pausa, fai clic sullo schermo per riprendere la modalità di gioco.", + "Clipboard Up": "Appunti in alto", + "CLipboard Down": "Appunti giù", + "Clipboard Seamless": "Appunti senza soluzione di continuità", + "Prefer Local Cursor": "Preferisci cursore locale", + "Translate keyboard shortcuts": "Traduci scorciatoie da tastiera", + "Enable WebRTC UDP Transit": "Abilita transito UDP WebRTC", + "Enable WebP Compression": "Abilita compressione WebP", + "Enable Performance Stats": "Abilita statistiche sul rendimento", + "Enable Pointer Lock": "Abilita blocco puntatore", + "IME Input Mode": "Modalità di immissione IME", + "Show Virtual Keyboard Control": "Mostra il controllo della tastiera virtuale", + "Toggle Control Panel via Keystrokes": "Attiva/disattiva pannello di controllo tramite sequenze di tasti", + "Render Native Resolution": "Risoluzione nativa del rendering", + "Keyboard Shortcuts": "Tasti rapidi", + "Enable KasmVNC Keyboard Shortcuts": "Abilita le scorciatoie da tastiera di KasmVNC", + "1 - Toggle Control Panel": "1 - Attiva/disattiva pannello di controllo", + "2 - Toggle Game Pointer Mode": "2 - Attiva/disattiva modalità puntatore di gioco", + "3 - Toggle Pointer Lock": "3 - Attiva/disattiva il blocco del puntatore", + "Stream Quality": "Qualità del flusso", + "Preset Modes:": "Modalità predefinite:", + "Static": "Statico", + "Low": "Basso", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Estremo", + "Lossless": "Senza perdita", + "Custom": "Costume", + "Anti-Aliasing:": "Anti aliasing:", + "Auto Dynamic": "Dinamica automatica", + "Off": "Spento", + "On": "SU", + "Dynamic Quality Min:": "Qualità dinamica minima:", + "Dynamic Quality Max:": "Qualità dinamica massima:", + "Treat Lossless:": "Tratta senza perdita:", + "Frame Rate:": "Frequenza dei fotogrammi:", + "Video JPEG Quality:": "Qualità JPEG video:", + "Video WEBP Quality:": "Qualità WEBP video:", + "Video Area:": "Area video:", + "Video Time:": "Tempo video:", + "Video Out Time:": "Tempo uscita video:", + "Video Mode Width:": "Larghezza modalità video:", + "Video Mode Height:": "Altezza modalità video:", + "Documentation": "Documentazione", + "Drag Viewport": "Trascina finestra", + "KasmVNC encountered an error:": "KasmVNC ha rilevato un errore:" +} \ No newline at end of file diff --git a/app/locale/it_CH.json b/app/locale/it_CH.json new file mode 100644 index 0000000..2db6749 --- /dev/null +++ b/app/locale/it_CH.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Collegamento...", + "Disconnecting...": "Disconnessione...", + "Reconnecting...": "Riconnessione...", + "Internal error": "Errore interno", + "Must set host": "Devi impostare l'host", + "Connected (encrypted) to ": "Connesso (crittografato) a ", + "Connected (unencrypted) to ": "Connesso (non crittografato) a ", + "Something went wrong, connection is closed": "Qualcosa è andato storto, la connessione è chiusa", + "Failed to connect to server": "Impossibile connettersi al server", + "Disconnected": "Disconnesso", + "New connection has been rejected with reason: ": "Nuova connessione rifiutata con motivo: ", + "New connection has been rejected": "La nuova connessione è stata rifiutata", + "Credentials are required": "Le credenziali sono necessarie", + "Hide/Show the control bar": "Nascondi/Mostra la barra di controllo", + "Drag": "Lagna", + "Move/Drag Viewport": "Sposta/Trascina finestra", + "Keyboard": "Tastiera", + "Show Keyboard": "Mostra tastiera", + "Extra keys": "Chiavi extra", + "Show Extra Keys": "Mostra chiavi extra", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Commuta Ctrl", + "Alt": "Alt", + "Toggle Alt": "Attiva/disattiva ALT", + "Toggle Windows": "Attiva/disattiva Windows", + "Windows": "Finestre", + "Send Tab": "Scheda Invia", + "Tab": "Scheda", + "Esc": "Esc", + "Send Escape": "Invia fuga", + "Ctrl+Alt+Del": "Ctrl+Alt+Canc", + "Send Ctrl-Alt-Del": "Invia Ctrl-Alt-Canc", + "Shutdown/Reboot": "Arresta/Riavvia", + "Shutdown/Reboot...": "Arresta/Riavvia...", + "Power": "Energia", + "Shutdown": "Fermare", + "Reboot": "Riavviare", + "Reset": "Ripristina", + "Clipboard": "Appunti", + "Clear": "Chiaro", + "Fullscreen": "A schermo intero", + "Settings": "Impostazioni", + "Shared Mode": "Modalità condivisa", + "View Only": "Visualizzare solamente", + "Clip to Window": "Aggancia alla finestra", + "Scaling Mode:": "Modalità ridimensionamento:", + "None": "Nessuno", + "Local Scaling": "Ridimensionamento locale", + "Remote Resizing": "Ridimensionamento remoto", + "Advanced": "Avanzate", + "Quality:": "Qualità:", + "Compression level:": "Livello di compressione:", + "Repeater ID:": "ID ripetitore:", + "WebSocket": "WebSocket", + "Encrypt": "Crittografare", + "Host:": "Ospite:", + "Port:": "Porta:", + "Path:": "Sentiero:", + "Automatic Reconnect": "Riconnessione automatica", + "Reconnect Delay (ms):": "Ritardo riconnessione (ms):", + "Show Dot when No Cursor": "Mostra punto quando nessun cursore", + "Logging:": "Registrazione:", + "Version:": "Versione:", + "Disconnect": "Disconnetti", + "Connect": "Collegare", + "Username:": "Nome utente:", + "Password:": "Parola d'ordine:", + "Send Credentials": "Invia credenziali", + "Cancel": "Annulla", + "Keys": "Chiavi", + "Game Cursor Mode": "Modalità cursore di gioco", + "Press Esc Key to Exit Pointer Lock Mode": "Premi il tasto Esc per uscire dalla modalità di blocco del puntatore", + "Game Mode paused, click on screen to resume Game Mode.": "Modalità di gioco in pausa, fai clic sullo schermo per riprendere la modalità di gioco.", + "Clipboard Up": "Appunti in alto", + "CLipboard Down": "Appunti giù", + "Clipboard Seamless": "Appunti senza soluzione di continuità", + "Prefer Local Cursor": "Preferisci cursore locale", + "Translate keyboard shortcuts": "Traduci scorciatoie da tastiera", + "Enable WebRTC UDP Transit": "Abilita transito UDP WebRTC", + "Enable WebP Compression": "Abilita compressione WebP", + "Enable Performance Stats": "Abilita statistiche sul rendimento", + "Enable Pointer Lock": "Abilita blocco puntatore", + "IME Input Mode": "Modalità di immissione IME", + "Show Virtual Keyboard Control": "Mostra il controllo della tastiera virtuale", + "Toggle Control Panel via Keystrokes": "Attiva/disattiva pannello di controllo tramite sequenze di tasti", + "Render Native Resolution": "Risoluzione nativa del rendering", + "Keyboard Shortcuts": "Tasti rapidi", + "Enable KasmVNC Keyboard Shortcuts": "Abilita le scorciatoie da tastiera di KasmVNC", + "1 - Toggle Control Panel": "1 - Attiva/disattiva pannello di controllo", + "2 - Toggle Game Pointer Mode": "2 - Attiva/disattiva modalità puntatore di gioco", + "3 - Toggle Pointer Lock": "3 - Attiva/disattiva il blocco del puntatore", + "Stream Quality": "Qualità del flusso", + "Preset Modes:": "Modalità predefinite:", + "Static": "Statico", + "Low": "Basso", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Estremo", + "Lossless": "Senza perdita", + "Custom": "Costume", + "Anti-Aliasing:": "Anti aliasing:", + "Auto Dynamic": "Dinamica automatica", + "Off": "Spento", + "On": "SU", + "Dynamic Quality Min:": "Qualità dinamica minima:", + "Dynamic Quality Max:": "Qualità dinamica massima:", + "Treat Lossless:": "Tratta senza perdita:", + "Frame Rate:": "Frequenza dei fotogrammi:", + "Video JPEG Quality:": "Qualità JPEG video:", + "Video WEBP Quality:": "Qualità WEBP video:", + "Video Area:": "Area video:", + "Video Time:": "Tempo video:", + "Video Out Time:": "Tempo uscita video:", + "Video Mode Width:": "Larghezza modalità video:", + "Video Mode Height:": "Altezza modalità video:", + "Documentation": "Documentazione", + "Drag Viewport": "Trascina finestra", + "KasmVNC encountered an error:": "KasmVNC ha rilevato un errore:" +} \ No newline at end of file diff --git a/app/locale/it_IT.json b/app/locale/it_IT.json new file mode 100644 index 0000000..2db6749 --- /dev/null +++ b/app/locale/it_IT.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Collegamento...", + "Disconnecting...": "Disconnessione...", + "Reconnecting...": "Riconnessione...", + "Internal error": "Errore interno", + "Must set host": "Devi impostare l'host", + "Connected (encrypted) to ": "Connesso (crittografato) a ", + "Connected (unencrypted) to ": "Connesso (non crittografato) a ", + "Something went wrong, connection is closed": "Qualcosa è andato storto, la connessione è chiusa", + "Failed to connect to server": "Impossibile connettersi al server", + "Disconnected": "Disconnesso", + "New connection has been rejected with reason: ": "Nuova connessione rifiutata con motivo: ", + "New connection has been rejected": "La nuova connessione è stata rifiutata", + "Credentials are required": "Le credenziali sono necessarie", + "Hide/Show the control bar": "Nascondi/Mostra la barra di controllo", + "Drag": "Lagna", + "Move/Drag Viewport": "Sposta/Trascina finestra", + "Keyboard": "Tastiera", + "Show Keyboard": "Mostra tastiera", + "Extra keys": "Chiavi extra", + "Show Extra Keys": "Mostra chiavi extra", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Commuta Ctrl", + "Alt": "Alt", + "Toggle Alt": "Attiva/disattiva ALT", + "Toggle Windows": "Attiva/disattiva Windows", + "Windows": "Finestre", + "Send Tab": "Scheda Invia", + "Tab": "Scheda", + "Esc": "Esc", + "Send Escape": "Invia fuga", + "Ctrl+Alt+Del": "Ctrl+Alt+Canc", + "Send Ctrl-Alt-Del": "Invia Ctrl-Alt-Canc", + "Shutdown/Reboot": "Arresta/Riavvia", + "Shutdown/Reboot...": "Arresta/Riavvia...", + "Power": "Energia", + "Shutdown": "Fermare", + "Reboot": "Riavviare", + "Reset": "Ripristina", + "Clipboard": "Appunti", + "Clear": "Chiaro", + "Fullscreen": "A schermo intero", + "Settings": "Impostazioni", + "Shared Mode": "Modalità condivisa", + "View Only": "Visualizzare solamente", + "Clip to Window": "Aggancia alla finestra", + "Scaling Mode:": "Modalità ridimensionamento:", + "None": "Nessuno", + "Local Scaling": "Ridimensionamento locale", + "Remote Resizing": "Ridimensionamento remoto", + "Advanced": "Avanzate", + "Quality:": "Qualità:", + "Compression level:": "Livello di compressione:", + "Repeater ID:": "ID ripetitore:", + "WebSocket": "WebSocket", + "Encrypt": "Crittografare", + "Host:": "Ospite:", + "Port:": "Porta:", + "Path:": "Sentiero:", + "Automatic Reconnect": "Riconnessione automatica", + "Reconnect Delay (ms):": "Ritardo riconnessione (ms):", + "Show Dot when No Cursor": "Mostra punto quando nessun cursore", + "Logging:": "Registrazione:", + "Version:": "Versione:", + "Disconnect": "Disconnetti", + "Connect": "Collegare", + "Username:": "Nome utente:", + "Password:": "Parola d'ordine:", + "Send Credentials": "Invia credenziali", + "Cancel": "Annulla", + "Keys": "Chiavi", + "Game Cursor Mode": "Modalità cursore di gioco", + "Press Esc Key to Exit Pointer Lock Mode": "Premi il tasto Esc per uscire dalla modalità di blocco del puntatore", + "Game Mode paused, click on screen to resume Game Mode.": "Modalità di gioco in pausa, fai clic sullo schermo per riprendere la modalità di gioco.", + "Clipboard Up": "Appunti in alto", + "CLipboard Down": "Appunti giù", + "Clipboard Seamless": "Appunti senza soluzione di continuità", + "Prefer Local Cursor": "Preferisci cursore locale", + "Translate keyboard shortcuts": "Traduci scorciatoie da tastiera", + "Enable WebRTC UDP Transit": "Abilita transito UDP WebRTC", + "Enable WebP Compression": "Abilita compressione WebP", + "Enable Performance Stats": "Abilita statistiche sul rendimento", + "Enable Pointer Lock": "Abilita blocco puntatore", + "IME Input Mode": "Modalità di immissione IME", + "Show Virtual Keyboard Control": "Mostra il controllo della tastiera virtuale", + "Toggle Control Panel via Keystrokes": "Attiva/disattiva pannello di controllo tramite sequenze di tasti", + "Render Native Resolution": "Risoluzione nativa del rendering", + "Keyboard Shortcuts": "Tasti rapidi", + "Enable KasmVNC Keyboard Shortcuts": "Abilita le scorciatoie da tastiera di KasmVNC", + "1 - Toggle Control Panel": "1 - Attiva/disattiva pannello di controllo", + "2 - Toggle Game Pointer Mode": "2 - Attiva/disattiva modalità puntatore di gioco", + "3 - Toggle Pointer Lock": "3 - Attiva/disattiva il blocco del puntatore", + "Stream Quality": "Qualità del flusso", + "Preset Modes:": "Modalità predefinite:", + "Static": "Statico", + "Low": "Basso", + "Medium": "Medio", + "High": "Alto", + "Extreme": "Estremo", + "Lossless": "Senza perdita", + "Custom": "Costume", + "Anti-Aliasing:": "Anti aliasing:", + "Auto Dynamic": "Dinamica automatica", + "Off": "Spento", + "On": "SU", + "Dynamic Quality Min:": "Qualità dinamica minima:", + "Dynamic Quality Max:": "Qualità dinamica massima:", + "Treat Lossless:": "Tratta senza perdita:", + "Frame Rate:": "Frequenza dei fotogrammi:", + "Video JPEG Quality:": "Qualità JPEG video:", + "Video WEBP Quality:": "Qualità WEBP video:", + "Video Area:": "Area video:", + "Video Time:": "Tempo video:", + "Video Out Time:": "Tempo uscita video:", + "Video Mode Width:": "Larghezza modalità video:", + "Video Mode Height:": "Altezza modalità video:", + "Documentation": "Documentazione", + "Drag Viewport": "Trascina finestra", + "KasmVNC encountered an error:": "KasmVNC ha rilevato un errore:" +} \ No newline at end of file diff --git a/app/locale/ja.json b/app/locale/ja.json new file mode 100644 index 0000000..0e2658c --- /dev/null +++ b/app/locale/ja.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "接続しています...", + "Disconnecting...": "切断しています...", + "Reconnecting...": "再接続しています...", + "Internal error": "内部エラー", + "Must set host": "ホストを設定する必要があります", + "Connected (encrypted) to ": "接続しました (暗号化済み): ", + "Connected (unencrypted) to ": "接続しました (暗号化されていません): ", + "Something went wrong, connection is closed": "何らかの問題で、接続が閉じられました", + "Failed to connect to server": "サーバーへの接続に失敗しました", + "Disconnected": "切断しました", + "New connection has been rejected with reason: ": "新規接続は次の理由で拒否されました: ", + "New connection has been rejected": "新規接続は拒否されました", + "Credentials are required": "資格情報が必要です", + "Hide/Show the control bar": "コントロールバーを隠す/表示する", + "Drag": "ドラッグ", + "Move/Drag Viewport": "ビューポートを移動/ドラッグ", + "Keyboard": "キーボード", + "Show Keyboard": "キーボードを表示", + "Extra keys": "追加キー", + "Show Extra Keys": "追加キーを表示", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl キーを切り替え", + "Alt": "Alt", + "Toggle Alt": "Alt キーを切り替え", + "Toggle Windows": "Windows キーを切り替え", + "Windows": "Windows", + "Send Tab": "Tab キーを送信", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Escape キーを送信", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del を送信", + "Shutdown/Reboot": "シャットダウン/再起動", + "Shutdown/Reboot...": "シャットダウン/再起動...", + "Power": "電源", + "Shutdown": "シャットダウン", + "Reboot": "再起動", + "Reset": "リセット", + "Clipboard": "クリップボード", + "Clear": "クリア", + "Fullscreen": "全画面表示", + "Settings": "設定", + "Shared Mode": "共有モード", + "View Only": "表示のみ", + "Clip to Window": "ウィンドウにクリップ", + "Scaling Mode:": "スケーリングモード:", + "None": "なし", + "Local Scaling": "ローカルスケーリング", + "Remote Resizing": "リモートでリサイズ", + "Advanced": "高度", + "Quality:": "品質:", + "Compression level:": "圧縮レベル:", + "Repeater ID:": "リピーター ID:", + "WebSocket": "WebSocket", + "Encrypt": "暗号化", + "Host:": "ホスト:", + "Port:": "ポート:", + "Path:": "パス:", + "Automatic Reconnect": "自動再接続", + "Reconnect Delay (ms):": "再接続する遅延 (ミリ秒):", + "Show Dot when No Cursor": "カーソルがないときにドットを表示", + "Logging:": "ロギング:", + "Version:": "バージョン:", + "Disconnect": "切断", + "Connect": "接続", + "Username:": "ユーザー名:", + "Password:": "パスワード:", + "Send Credentials": "資格情報を送信", + "Cancel": "キャンセル", + "Keys": "「キー」", + "Game Cursor Mode": "「ゲームカーソルモード」", + "Press Esc Key to Exit Pointer Lock Mode": "「ポインターロックモードを終了するには Esc キーを押してください」", + "Game Mode paused, click on screen to resume Game Mode.": "「ゲームモードが一時停止しました。ゲームモードを再開するには画面をクリックしてください。」", + "Clipboard Up": "「クリップボードアップ」", + "CLipboard Down": "「クリップボードダウン」", + "Clipboard Seamless": "「クリップボード シームレス」", + "Prefer Local Cursor": "「ローカルカーソルを優先」", + "Translate keyboard shortcuts": "「キーボード ショートカットを翻訳する」", + "Enable WebRTC UDP Transit": "「WebRTC UDP トランジットを有効にする」", + "Enable WebP Compression": "「WebP圧縮を有効にする」", + "Enable Performance Stats": "「パフォーマンス統計を有効にする」", + "Enable Pointer Lock": "「ポインタロックを有効にする」", + "IME Input Mode": "「IME入力モード」", + "Show Virtual Keyboard Control": "「仮想キーボード コントロールを表示」", + "Toggle Control Panel via Keystrokes": "「キーストロークによるコントロール パネルの切り替え」", + "Render Native Resolution": "「ネイティブ解像度をレンダリング」", + "Keyboard Shortcuts": "キーボードショートカット", + "Enable KasmVNC Keyboard Shortcuts": "「KasmVNC キーボード ショートカットを有効にする」", + "1 - Toggle Control Panel": "「1 - コントロール パネルの切り替え」", + "2 - Toggle Game Pointer Mode": "「2 - ゲーム ポインター モードの切り替え」", + "3 - Toggle Pointer Lock": "「3 - ポインターロックの切り替え」", + "Stream Quality": "「ストリーム品質」", + "Preset Modes:": "「プリセットモード:」", + "Static": "静的", + "Low": "低い", + "Medium": "中くらい", + "High": "高い", + "Extreme": "過激", + "Lossless": "無損失の", + "Custom": "カスタム", + "Anti-Aliasing:": "アンチエイリアシング:", + "Auto Dynamic": "「オートダイナミック」", + "Off": "オフ", + "On": "の上", + "Dynamic Quality Min:": "「動的品質最小:」", + "Dynamic Quality Max:": "「動的品質最大:」", + "Treat Lossless:": "「ロスレス処理:」", + "Frame Rate:": "フレームレート:", + "Video JPEG Quality:": "「ビデオ JPEG 品質:」", + "Video WEBP Quality:": "「ビデオ WEBP 品質:」", + "Video Area:": "「動画エリア:」", + "Video Time:": "「ビデオ時間:」", + "Video Out Time:": "「ビデオ出力時間:」", + "Video Mode Width:": "「ビデオモード幅:」", + "Video Mode Height:": "「ビデオモードの高さ:」", + "Documentation": "ドキュメンテーション", + "Drag Viewport": "「ビューポートをドラッグ」", + "KasmVNC encountered an error:": "「KasmVNC でエラーが発生しました:」" +} \ No newline at end of file diff --git a/app/locale/ja_JP.json b/app/locale/ja_JP.json new file mode 100644 index 0000000..0e2658c --- /dev/null +++ b/app/locale/ja_JP.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "接続しています...", + "Disconnecting...": "切断しています...", + "Reconnecting...": "再接続しています...", + "Internal error": "内部エラー", + "Must set host": "ホストを設定する必要があります", + "Connected (encrypted) to ": "接続しました (暗号化済み): ", + "Connected (unencrypted) to ": "接続しました (暗号化されていません): ", + "Something went wrong, connection is closed": "何らかの問題で、接続が閉じられました", + "Failed to connect to server": "サーバーへの接続に失敗しました", + "Disconnected": "切断しました", + "New connection has been rejected with reason: ": "新規接続は次の理由で拒否されました: ", + "New connection has been rejected": "新規接続は拒否されました", + "Credentials are required": "資格情報が必要です", + "Hide/Show the control bar": "コントロールバーを隠す/表示する", + "Drag": "ドラッグ", + "Move/Drag Viewport": "ビューポートを移動/ドラッグ", + "Keyboard": "キーボード", + "Show Keyboard": "キーボードを表示", + "Extra keys": "追加キー", + "Show Extra Keys": "追加キーを表示", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl キーを切り替え", + "Alt": "Alt", + "Toggle Alt": "Alt キーを切り替え", + "Toggle Windows": "Windows キーを切り替え", + "Windows": "Windows", + "Send Tab": "Tab キーを送信", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Escape キーを送信", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del を送信", + "Shutdown/Reboot": "シャットダウン/再起動", + "Shutdown/Reboot...": "シャットダウン/再起動...", + "Power": "電源", + "Shutdown": "シャットダウン", + "Reboot": "再起動", + "Reset": "リセット", + "Clipboard": "クリップボード", + "Clear": "クリア", + "Fullscreen": "全画面表示", + "Settings": "設定", + "Shared Mode": "共有モード", + "View Only": "表示のみ", + "Clip to Window": "ウィンドウにクリップ", + "Scaling Mode:": "スケーリングモード:", + "None": "なし", + "Local Scaling": "ローカルスケーリング", + "Remote Resizing": "リモートでリサイズ", + "Advanced": "高度", + "Quality:": "品質:", + "Compression level:": "圧縮レベル:", + "Repeater ID:": "リピーター ID:", + "WebSocket": "WebSocket", + "Encrypt": "暗号化", + "Host:": "ホスト:", + "Port:": "ポート:", + "Path:": "パス:", + "Automatic Reconnect": "自動再接続", + "Reconnect Delay (ms):": "再接続する遅延 (ミリ秒):", + "Show Dot when No Cursor": "カーソルがないときにドットを表示", + "Logging:": "ロギング:", + "Version:": "バージョン:", + "Disconnect": "切断", + "Connect": "接続", + "Username:": "ユーザー名:", + "Password:": "パスワード:", + "Send Credentials": "資格情報を送信", + "Cancel": "キャンセル", + "Keys": "「キー」", + "Game Cursor Mode": "「ゲームカーソルモード」", + "Press Esc Key to Exit Pointer Lock Mode": "「ポインターロックモードを終了するには Esc キーを押してください」", + "Game Mode paused, click on screen to resume Game Mode.": "「ゲームモードが一時停止しました。ゲームモードを再開するには画面をクリックしてください。」", + "Clipboard Up": "「クリップボードアップ」", + "CLipboard Down": "「クリップボードダウン」", + "Clipboard Seamless": "「クリップボード シームレス」", + "Prefer Local Cursor": "「ローカルカーソルを優先」", + "Translate keyboard shortcuts": "「キーボード ショートカットを翻訳する」", + "Enable WebRTC UDP Transit": "「WebRTC UDP トランジットを有効にする」", + "Enable WebP Compression": "「WebP圧縮を有効にする」", + "Enable Performance Stats": "「パフォーマンス統計を有効にする」", + "Enable Pointer Lock": "「ポインタロックを有効にする」", + "IME Input Mode": "「IME入力モード」", + "Show Virtual Keyboard Control": "「仮想キーボード コントロールを表示」", + "Toggle Control Panel via Keystrokes": "「キーストロークによるコントロール パネルの切り替え」", + "Render Native Resolution": "「ネイティブ解像度をレンダリング」", + "Keyboard Shortcuts": "キーボードショートカット", + "Enable KasmVNC Keyboard Shortcuts": "「KasmVNC キーボード ショートカットを有効にする」", + "1 - Toggle Control Panel": "「1 - コントロール パネルの切り替え」", + "2 - Toggle Game Pointer Mode": "「2 - ゲーム ポインター モードの切り替え」", + "3 - Toggle Pointer Lock": "「3 - ポインターロックの切り替え」", + "Stream Quality": "「ストリーム品質」", + "Preset Modes:": "「プリセットモード:」", + "Static": "静的", + "Low": "低い", + "Medium": "中くらい", + "High": "高い", + "Extreme": "過激", + "Lossless": "無損失の", + "Custom": "カスタム", + "Anti-Aliasing:": "アンチエイリアシング:", + "Auto Dynamic": "「オートダイナミック」", + "Off": "オフ", + "On": "の上", + "Dynamic Quality Min:": "「動的品質最小:」", + "Dynamic Quality Max:": "「動的品質最大:」", + "Treat Lossless:": "「ロスレス処理:」", + "Frame Rate:": "フレームレート:", + "Video JPEG Quality:": "「ビデオ JPEG 品質:」", + "Video WEBP Quality:": "「ビデオ WEBP 品質:」", + "Video Area:": "「動画エリア:」", + "Video Time:": "「ビデオ時間:」", + "Video Out Time:": "「ビデオ出力時間:」", + "Video Mode Width:": "「ビデオモード幅:」", + "Video Mode Height:": "「ビデオモードの高さ:」", + "Documentation": "ドキュメンテーション", + "Drag Viewport": "「ビューポートをドラッグ」", + "KasmVNC encountered an error:": "「KasmVNC でエラーが発生しました:」" +} \ No newline at end of file diff --git a/app/locale/ka.json b/app/locale/ka.json new file mode 100644 index 0000000..4369b66 --- /dev/null +++ b/app/locale/ka.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "დაკავშირება...", + "Disconnecting...": "გათიშვა...", + "Reconnecting...": "ხელახლა დაკავშირება...", + "Internal error": "შინაგანი შეცდომა", + "Must set host": "აუცილებელი მასპინძელი", + "Connected (encrypted) to ": "დაკავშირებულია (დაშიფრულია)", + "Connected (unencrypted) to ": "დაკავშირებულია (დაშიფრული)", + "Something went wrong, connection is closed": "რაღაც შეცდომა მოხდა, კავშირი დახურულია", + "Failed to connect to server": "ვერ დაკავშირება სერვერთან", + "Disconnected": "გათიშული", + "New connection has been rejected with reason: ": "ახალი კავშირი უარყოფილია მიზეზით:", + "New connection has been rejected": "ახალი კავშირი უარყოფილია", + "Credentials are required": "აუცილებელია რწმუნებათა სიგელები", + "Hide/Show the control bar": "საკონტროლო ზოლის დამალვა/ჩვენება", + "Drag": "გადაათრიე", + "Move/Drag Viewport": "გადაადგილება/ჩაათრიე ხედის პორტი", + "Keyboard": "კლავიატურა", + "Show Keyboard": "კლავიატურის ჩვენება", + "Extra keys": "დამატებითი გასაღებები", + "Show Extra Keys": "დამატებითი კლავიშების ჩვენება", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl-ის გადართვა", + "Alt": "ალტ", + "Toggle Alt": "გადართვა Alt", + "Toggle Windows": "გადართვა Windows", + "Windows": "Windows", + "Send Tab": "ჩანართის გაგზავნა", + "Tab": "ჩანართი", + "Esc": "Esc", + "Send Escape": "გაქცევის გაგზავნა", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "გაგზავნა Ctrl-Alt-Del", + "Shutdown/Reboot": "გამორთვა/გადატვირთვა", + "Shutdown/Reboot...": "გამორთვა/გადატვირთვა...", + "Power": "Ძალა", + "Shutdown": "Გათიშვა", + "Reboot": "გადატვირთვა", + "Reset": "გადატვირთვა", + "Clipboard": "გაცვლის ბუფერი", + "Clear": "გასუფთავება", + "Fullscreen": "Მთლიანი ეკრანი", + "Settings": "პარამეტრები", + "Shared Mode": "გაზიარებული რეჟიმი", + "View Only": "მხოლოდ ნახვა", + "Clip to Window": "გადაჭერა ფანჯარაში", + "Scaling Mode:": "სკალირების რეჟიმი:", + "None": "არცერთი", + "Local Scaling": "ლოკალური სკალირება", + "Remote Resizing": "დისტანციური ზომის შეცვლა", + "Advanced": "Მოწინავე", + "Quality:": "ხარისხი:", + "Compression level:": "შეკუმშვის დონე:", + "Repeater ID:": "გამეორების ID:", + "WebSocket": "ვებსოკეტი", + "Encrypt": "დაშიფვრა", + "Host:": "მასპინძელი:", + "Port:": "პორტი:", + "Path:": "გზა:", + "Automatic Reconnect": "ავტომატური ხელახლა დაკავშირება", + "Reconnect Delay (ms):": "ხელახლა დაკავშირების დაყოვნება (ms):", + "Show Dot when No Cursor": "პუნქტის ჩვენება, როდესაც კურსორი არ არის", + "Logging:": "მოწერა:", + "Version:": "ვერსია:", + "Disconnect": "გათიშვა", + "Connect": "დაკავშირება", + "Username:": "მომხმარებლის სახელი:", + "Password:": "პაროლი:", + "Send Credentials": "სერთიფიკატების გაგზავნა", + "Cancel": "გაუქმება", + "Keys": "Გასაღებები", + "Game Cursor Mode": "თამაშის კურსორის რეჟიმი", + "Press Esc Key to Exit Pointer Lock Mode": "დააჭირეთ Esc ღილაკს პოინტერის დაბლოკვის რეჟიმიდან გასასვლელად", + "Game Mode paused, click on screen to resume Game Mode.": "თამაშის რეჟიმი შეჩერებულია, დააწკაპუნეთ ეკრანზე თამაშის რეჟიმის გასაგრძელებლად.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard ქვემოთ", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "მირჩევთ ლოკალურ კურსორს", + "Translate keyboard shortcuts": "კლავიატურის მალსახმობების თარგმნა", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit-ის ჩართვა", + "Enable WebP Compression": "WebP შეკუმშვის ჩართვა", + "Enable Performance Stats": "ჩართეთ შესრულების სტატისტიკა", + "Enable Pointer Lock": "Pointer Lock-ის ჩართვა", + "IME Input Mode": "IME შეყვანის რეჟიმი", + "Show Virtual Keyboard Control": "ვირტუალური კლავიატურის კონტროლის ჩვენება", + "Toggle Control Panel via Keystrokes": "პანელის გადართვა კლავიშების საშუალებით", + "Render Native Resolution": "რენდერი Native Resolution", + "Keyboard Shortcuts": "კლავიატურის მალსახმობები", + "Enable KasmVNC Keyboard Shortcuts": "ჩართეთ KasmVNC კლავიატურის მალსახმობები", + "1 - Toggle Control Panel": "1 - საკონტროლო პანელის გადართვა", + "2 - Toggle Game Pointer Mode": "2 - თამაშის მაჩვენებლის რეჟიმის გადართვა", + "3 - Toggle Pointer Lock": "3 - გადართვა Pointer Lock", + "Stream Quality": "ნაკადის ხარისხი", + "Preset Modes:": "წინასწარ დაყენებული რეჟიმები:", + "Static": "სტატიკური", + "Low": "დაბალი", + "Medium": "საშუალო", + "High": "მაღალი", + "Extreme": "ექსტრემალური", + "Lossless": "დაკარგული", + "Custom": "ჩვეულებრივი", + "Anti-Aliasing:": "ანტი-ალიასინგი:", + "Auto Dynamic": "ავტო დინამიური", + "Off": "გამორთული", + "On": "ჩართული", + "Dynamic Quality Min:": "დინამიური ხარისხის მინიმალური:", + "Dynamic Quality Max:": "დინამიური ხარისხის მაქს:", + "Treat Lossless:": "მკურნალობა Lossless:", + "Frame Rate:": "Კადრების სიხშირე:", + "Video JPEG Quality:": "ვიდეოს JPEG ხარისხი:", + "Video WEBP Quality:": "ვიდეოს WEBP ხარისხი:", + "Video Area:": "ვიდეო ზონა:", + "Video Time:": "ვიდეოს დრო:", + "Video Out Time:": "ვიდეოს გამოსვლის დრო:", + "Video Mode Width:": "ვიდეო რეჟიმის სიგანე:", + "Video Mode Height:": "ვიდეო რეჟიმის სიმაღლე:", + "Documentation": "დოკუმენტაცია", + "Drag Viewport": "გადაათრიეთ ხედის პორტი", + "KasmVNC encountered an error:": "KasmVNC შეექმნა შეცდომა:" +} \ No newline at end of file diff --git a/app/locale/ka_GE.json b/app/locale/ka_GE.json new file mode 100644 index 0000000..4369b66 --- /dev/null +++ b/app/locale/ka_GE.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "დაკავშირება...", + "Disconnecting...": "გათიშვა...", + "Reconnecting...": "ხელახლა დაკავშირება...", + "Internal error": "შინაგანი შეცდომა", + "Must set host": "აუცილებელი მასპინძელი", + "Connected (encrypted) to ": "დაკავშირებულია (დაშიფრულია)", + "Connected (unencrypted) to ": "დაკავშირებულია (დაშიფრული)", + "Something went wrong, connection is closed": "რაღაც შეცდომა მოხდა, კავშირი დახურულია", + "Failed to connect to server": "ვერ დაკავშირება სერვერთან", + "Disconnected": "გათიშული", + "New connection has been rejected with reason: ": "ახალი კავშირი უარყოფილია მიზეზით:", + "New connection has been rejected": "ახალი კავშირი უარყოფილია", + "Credentials are required": "აუცილებელია რწმუნებათა სიგელები", + "Hide/Show the control bar": "საკონტროლო ზოლის დამალვა/ჩვენება", + "Drag": "გადაათრიე", + "Move/Drag Viewport": "გადაადგილება/ჩაათრიე ხედის პორტი", + "Keyboard": "კლავიატურა", + "Show Keyboard": "კლავიატურის ჩვენება", + "Extra keys": "დამატებითი გასაღებები", + "Show Extra Keys": "დამატებითი კლავიშების ჩვენება", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl-ის გადართვა", + "Alt": "ალტ", + "Toggle Alt": "გადართვა Alt", + "Toggle Windows": "გადართვა Windows", + "Windows": "Windows", + "Send Tab": "ჩანართის გაგზავნა", + "Tab": "ჩანართი", + "Esc": "Esc", + "Send Escape": "გაქცევის გაგზავნა", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "გაგზავნა Ctrl-Alt-Del", + "Shutdown/Reboot": "გამორთვა/გადატვირთვა", + "Shutdown/Reboot...": "გამორთვა/გადატვირთვა...", + "Power": "Ძალა", + "Shutdown": "Გათიშვა", + "Reboot": "გადატვირთვა", + "Reset": "გადატვირთვა", + "Clipboard": "გაცვლის ბუფერი", + "Clear": "გასუფთავება", + "Fullscreen": "Მთლიანი ეკრანი", + "Settings": "პარამეტრები", + "Shared Mode": "გაზიარებული რეჟიმი", + "View Only": "მხოლოდ ნახვა", + "Clip to Window": "გადაჭერა ფანჯარაში", + "Scaling Mode:": "სკალირების რეჟიმი:", + "None": "არცერთი", + "Local Scaling": "ლოკალური სკალირება", + "Remote Resizing": "დისტანციური ზომის შეცვლა", + "Advanced": "Მოწინავე", + "Quality:": "ხარისხი:", + "Compression level:": "შეკუმშვის დონე:", + "Repeater ID:": "გამეორების ID:", + "WebSocket": "ვებსოკეტი", + "Encrypt": "დაშიფვრა", + "Host:": "მასპინძელი:", + "Port:": "პორტი:", + "Path:": "გზა:", + "Automatic Reconnect": "ავტომატური ხელახლა დაკავშირება", + "Reconnect Delay (ms):": "ხელახლა დაკავშირების დაყოვნება (ms):", + "Show Dot when No Cursor": "პუნქტის ჩვენება, როდესაც კურსორი არ არის", + "Logging:": "მოწერა:", + "Version:": "ვერსია:", + "Disconnect": "გათიშვა", + "Connect": "დაკავშირება", + "Username:": "მომხმარებლის სახელი:", + "Password:": "პაროლი:", + "Send Credentials": "სერთიფიკატების გაგზავნა", + "Cancel": "გაუქმება", + "Keys": "Გასაღებები", + "Game Cursor Mode": "თამაშის კურსორის რეჟიმი", + "Press Esc Key to Exit Pointer Lock Mode": "დააჭირეთ Esc ღილაკს პოინტერის დაბლოკვის რეჟიმიდან გასასვლელად", + "Game Mode paused, click on screen to resume Game Mode.": "თამაშის რეჟიმი შეჩერებულია, დააწკაპუნეთ ეკრანზე თამაშის რეჟიმის გასაგრძელებლად.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard ქვემოთ", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "მირჩევთ ლოკალურ კურსორს", + "Translate keyboard shortcuts": "კლავიატურის მალსახმობების თარგმნა", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit-ის ჩართვა", + "Enable WebP Compression": "WebP შეკუმშვის ჩართვა", + "Enable Performance Stats": "ჩართეთ შესრულების სტატისტიკა", + "Enable Pointer Lock": "Pointer Lock-ის ჩართვა", + "IME Input Mode": "IME შეყვანის რეჟიმი", + "Show Virtual Keyboard Control": "ვირტუალური კლავიატურის კონტროლის ჩვენება", + "Toggle Control Panel via Keystrokes": "პანელის გადართვა კლავიშების საშუალებით", + "Render Native Resolution": "რენდერი Native Resolution", + "Keyboard Shortcuts": "კლავიატურის მალსახმობები", + "Enable KasmVNC Keyboard Shortcuts": "ჩართეთ KasmVNC კლავიატურის მალსახმობები", + "1 - Toggle Control Panel": "1 - საკონტროლო პანელის გადართვა", + "2 - Toggle Game Pointer Mode": "2 - თამაშის მაჩვენებლის რეჟიმის გადართვა", + "3 - Toggle Pointer Lock": "3 - გადართვა Pointer Lock", + "Stream Quality": "ნაკადის ხარისხი", + "Preset Modes:": "წინასწარ დაყენებული რეჟიმები:", + "Static": "სტატიკური", + "Low": "დაბალი", + "Medium": "საშუალო", + "High": "მაღალი", + "Extreme": "ექსტრემალური", + "Lossless": "დაკარგული", + "Custom": "ჩვეულებრივი", + "Anti-Aliasing:": "ანტი-ალიასინგი:", + "Auto Dynamic": "ავტო დინამიური", + "Off": "გამორთული", + "On": "ჩართული", + "Dynamic Quality Min:": "დინამიური ხარისხის მინიმალური:", + "Dynamic Quality Max:": "დინამიური ხარისხის მაქს:", + "Treat Lossless:": "მკურნალობა Lossless:", + "Frame Rate:": "Კადრების სიხშირე:", + "Video JPEG Quality:": "ვიდეოს JPEG ხარისხი:", + "Video WEBP Quality:": "ვიდეოს WEBP ხარისხი:", + "Video Area:": "ვიდეო ზონა:", + "Video Time:": "ვიდეოს დრო:", + "Video Out Time:": "ვიდეოს გამოსვლის დრო:", + "Video Mode Width:": "ვიდეო რეჟიმის სიგანე:", + "Video Mode Height:": "ვიდეო რეჟიმის სიმაღლე:", + "Documentation": "დოკუმენტაცია", + "Drag Viewport": "გადაათრიეთ ხედის პორტი", + "KasmVNC encountered an error:": "KasmVNC შეექმნა შეცდომა:" +} \ No newline at end of file diff --git a/app/locale/kk.json b/app/locale/kk.json new file mode 100644 index 0000000..bea5eb9 --- /dev/null +++ b/app/locale/kk.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Қосылуда...", + "Disconnecting...": "Ажыратылуда...", + "Reconnecting...": "Қайта қосылуда...", + "Internal error": "Ішкі қате", + "Must set host": "Хост орнату керек", + "Connected (encrypted) to ": "Қосылған (шифрланған)", + "Connected (unencrypted) to ": "Қосылған (шифрланбаған)", + "Something went wrong, connection is closed": "Бірдеңе дұрыс болмады, байланыс жабылды", + "Failed to connect to server": "Серверге қосылу мүмкін болмады", + "Disconnected": "Ажыратылған", + "New connection has been rejected with reason: ": "Жаңа қосылым себеппен қабылданбады:", + "New connection has been rejected": "Жаңа қосылым қабылданбады", + "Credentials are required": "Тіркелгі деректері қажет", + "Hide/Show the control bar": "Басқару жолағын жасыру/көрсету", + "Drag": "Сүйреу", + "Move/Drag Viewport": "Көру алаңын жылжыту/сүйреп апару", + "Keyboard": "Пернетақта", + "Show Keyboard": "Пернетақтаны көрсету", + "Extra keys": "Қосымша кілттер", + "Show Extra Keys": "Қосымша кілттерді көрсету", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl-ді ауыстырып қосу", + "Alt": "Альт", + "Toggle Alt": "Alt түймесін ауыстыру", + "Toggle Windows": "Windows жүйесін ауыстыру", + "Windows": "Windows", + "Send Tab": "Жіберу қойындысы", + "Tab": "Қойынды", + "Esc": "Шығу", + "Send Escape": "Қашуды жіберу", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del жіберу", + "Shutdown/Reboot": "Өшіру/қайта жүктеу", + "Shutdown/Reboot...": "Өшіру/қайта жүктеу...", + "Power": "Күш", + "Shutdown": "Жабу", + "Reboot": "Қайта жүктеу", + "Reset": "Қалпына келтіру", + "Clipboard": "Буфер", + "Clear": "Таза", + "Fullscreen": "Толық экран", + "Settings": "Параметрлер", + "Shared Mode": "Ортақ режим", + "View Only": "Тек көру", + "Clip to Window": "Терезеге клип", + "Scaling Mode:": "Масштабтау режимі:", + "None": "Жоқ", + "Local Scaling": "Жергілікті масштабтау", + "Remote Resizing": "Қашықтан өлшемін өзгерту", + "Advanced": "Озат", + "Quality:": "Сапа:", + "Compression level:": "Сығу деңгейі:", + "Repeater ID:": "Қайталаушы идентификаторы:", + "WebSocket": "WebSocket", + "Encrypt": "Шифрлау", + "Host:": "Хост:", + "Port:": "Порт:", + "Path:": "Жол:", + "Automatic Reconnect": "Автоматты қайта қосу", + "Reconnect Delay (ms):": "Қайта қосылу кідірісі (мс):", + "Show Dot when No Cursor": "Меңзер жоқ кезде нүктені көрсету", + "Logging:": "Тіркеу:", + "Version:": "Нұсқа:", + "Disconnect": "Ажырату", + "Connect": "Қосылу", + "Username:": "Пайдаланушы аты:", + "Password:": "Пароль:", + "Send Credentials": "Тіркелгі деректерін жіберу", + "Cancel": "Болдырмау", + "Keys": "Кілттер", + "Game Cursor Mode": "Ойын курсоры режимі", + "Press Esc Key to Exit Pointer Lock Mode": "Меңзерді құлыптау режимінен шығу үшін Esc пернесін басыңыз", + "Game Mode paused, click on screen to resume Game Mode.": "Ойын режимі кідіртілді, ойын режимін жалғастыру үшін экранды басыңыз.", + "Clipboard Up": "Аралық сақтағыш жоғары", + "CLipboard Down": "Аралық буфер төмен", + "Clipboard Seamless": "Аралық сақтағыш біртұтас", + "Prefer Local Cursor": "Жергілікті курсорға артықшылық беру", + "Translate keyboard shortcuts": "Пернелер тіркесімін аудару", + "Enable WebRTC UDP Transit": "WebRTC UDP транзитін қосу", + "Enable WebP Compression": "WebP қысуын қосу", + "Enable Performance Stats": "Өнімділік статистикасын қосу", + "Enable Pointer Lock": "Меңзер құлпын қосу", + "IME Input Mode": "IME енгізу режимі", + "Show Virtual Keyboard Control": "Виртуалды пернетақтаны басқаруды көрсету", + "Toggle Control Panel via Keystrokes": "Басқару тақтасын пернелерді басу арқылы ауыстыру", + "Render Native Resolution": "Негізгі ажыратымдылықты көрсету", + "Keyboard Shortcuts": "Пернелер тіркесімі", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC пернелер тіркесімін қосу", + "1 - Toggle Control Panel": "1 - Басқару тақтасын ауыстыру", + "2 - Toggle Game Pointer Mode": "2 - Ойын көрсеткіші режимін ауыстыру", + "3 - Toggle Pointer Lock": "3 - Меңзер құлпын ауыстыру", + "Stream Quality": "Ағынның сапасы", + "Preset Modes:": "Алдын ала орнатылған режимдер:", + "Static": "Статикалық", + "Low": "Төмен", + "Medium": "Орташа", + "High": "Жоғары", + "Extreme": "Төтенше", + "Lossless": "Шығыссыз", + "Custom": "Тапсырыс", + "Anti-Aliasing:": "Бөренелеуге қарсы:", + "Auto Dynamic": "Авто динамикалық", + "Off": "Өшірулі", + "On": "Қосулы", + "Dynamic Quality Min:": "Динамикалық сапа минимум:", + "Dynamic Quality Max:": "Динамикалық сапа максимум:", + "Treat Lossless:": "Шығынсыз емдеу:", + "Frame Rate:": "Кадр жиілігі:", + "Video JPEG Quality:": "Бейне JPEG сапасы:", + "Video WEBP Quality:": "Бейне WEBP сапасы:", + "Video Area:": "Бейне аймағы:", + "Video Time:": "Бейне уақыты:", + "Video Out Time:": "Бейненің шығу уақыты:", + "Video Mode Width:": "Бейне режимінің ені:", + "Video Mode Height:": "Бейне режимінің биіктігі:", + "Documentation": "Құжаттама", + "Drag Viewport": "Көру алаңын сүйреу", + "KasmVNC encountered an error:": "KasmVNC қатеге тап болды:" +} \ No newline at end of file diff --git a/app/locale/kk_KZ.json b/app/locale/kk_KZ.json new file mode 100644 index 0000000..bea5eb9 --- /dev/null +++ b/app/locale/kk_KZ.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Қосылуда...", + "Disconnecting...": "Ажыратылуда...", + "Reconnecting...": "Қайта қосылуда...", + "Internal error": "Ішкі қате", + "Must set host": "Хост орнату керек", + "Connected (encrypted) to ": "Қосылған (шифрланған)", + "Connected (unencrypted) to ": "Қосылған (шифрланбаған)", + "Something went wrong, connection is closed": "Бірдеңе дұрыс болмады, байланыс жабылды", + "Failed to connect to server": "Серверге қосылу мүмкін болмады", + "Disconnected": "Ажыратылған", + "New connection has been rejected with reason: ": "Жаңа қосылым себеппен қабылданбады:", + "New connection has been rejected": "Жаңа қосылым қабылданбады", + "Credentials are required": "Тіркелгі деректері қажет", + "Hide/Show the control bar": "Басқару жолағын жасыру/көрсету", + "Drag": "Сүйреу", + "Move/Drag Viewport": "Көру алаңын жылжыту/сүйреп апару", + "Keyboard": "Пернетақта", + "Show Keyboard": "Пернетақтаны көрсету", + "Extra keys": "Қосымша кілттер", + "Show Extra Keys": "Қосымша кілттерді көрсету", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl-ді ауыстырып қосу", + "Alt": "Альт", + "Toggle Alt": "Alt түймесін ауыстыру", + "Toggle Windows": "Windows жүйесін ауыстыру", + "Windows": "Windows", + "Send Tab": "Жіберу қойындысы", + "Tab": "Қойынды", + "Esc": "Шығу", + "Send Escape": "Қашуды жіберу", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del жіберу", + "Shutdown/Reboot": "Өшіру/қайта жүктеу", + "Shutdown/Reboot...": "Өшіру/қайта жүктеу...", + "Power": "Күш", + "Shutdown": "Жабу", + "Reboot": "Қайта жүктеу", + "Reset": "Қалпына келтіру", + "Clipboard": "Буфер", + "Clear": "Таза", + "Fullscreen": "Толық экран", + "Settings": "Параметрлер", + "Shared Mode": "Ортақ режим", + "View Only": "Тек көру", + "Clip to Window": "Терезеге клип", + "Scaling Mode:": "Масштабтау режимі:", + "None": "Жоқ", + "Local Scaling": "Жергілікті масштабтау", + "Remote Resizing": "Қашықтан өлшемін өзгерту", + "Advanced": "Озат", + "Quality:": "Сапа:", + "Compression level:": "Сығу деңгейі:", + "Repeater ID:": "Қайталаушы идентификаторы:", + "WebSocket": "WebSocket", + "Encrypt": "Шифрлау", + "Host:": "Хост:", + "Port:": "Порт:", + "Path:": "Жол:", + "Automatic Reconnect": "Автоматты қайта қосу", + "Reconnect Delay (ms):": "Қайта қосылу кідірісі (мс):", + "Show Dot when No Cursor": "Меңзер жоқ кезде нүктені көрсету", + "Logging:": "Тіркеу:", + "Version:": "Нұсқа:", + "Disconnect": "Ажырату", + "Connect": "Қосылу", + "Username:": "Пайдаланушы аты:", + "Password:": "Пароль:", + "Send Credentials": "Тіркелгі деректерін жіберу", + "Cancel": "Болдырмау", + "Keys": "Кілттер", + "Game Cursor Mode": "Ойын курсоры режимі", + "Press Esc Key to Exit Pointer Lock Mode": "Меңзерді құлыптау режимінен шығу үшін Esc пернесін басыңыз", + "Game Mode paused, click on screen to resume Game Mode.": "Ойын режимі кідіртілді, ойын режимін жалғастыру үшін экранды басыңыз.", + "Clipboard Up": "Аралық сақтағыш жоғары", + "CLipboard Down": "Аралық буфер төмен", + "Clipboard Seamless": "Аралық сақтағыш біртұтас", + "Prefer Local Cursor": "Жергілікті курсорға артықшылық беру", + "Translate keyboard shortcuts": "Пернелер тіркесімін аудару", + "Enable WebRTC UDP Transit": "WebRTC UDP транзитін қосу", + "Enable WebP Compression": "WebP қысуын қосу", + "Enable Performance Stats": "Өнімділік статистикасын қосу", + "Enable Pointer Lock": "Меңзер құлпын қосу", + "IME Input Mode": "IME енгізу режимі", + "Show Virtual Keyboard Control": "Виртуалды пернетақтаны басқаруды көрсету", + "Toggle Control Panel via Keystrokes": "Басқару тақтасын пернелерді басу арқылы ауыстыру", + "Render Native Resolution": "Негізгі ажыратымдылықты көрсету", + "Keyboard Shortcuts": "Пернелер тіркесімі", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC пернелер тіркесімін қосу", + "1 - Toggle Control Panel": "1 - Басқару тақтасын ауыстыру", + "2 - Toggle Game Pointer Mode": "2 - Ойын көрсеткіші режимін ауыстыру", + "3 - Toggle Pointer Lock": "3 - Меңзер құлпын ауыстыру", + "Stream Quality": "Ағынның сапасы", + "Preset Modes:": "Алдын ала орнатылған режимдер:", + "Static": "Статикалық", + "Low": "Төмен", + "Medium": "Орташа", + "High": "Жоғары", + "Extreme": "Төтенше", + "Lossless": "Шығыссыз", + "Custom": "Тапсырыс", + "Anti-Aliasing:": "Бөренелеуге қарсы:", + "Auto Dynamic": "Авто динамикалық", + "Off": "Өшірулі", + "On": "Қосулы", + "Dynamic Quality Min:": "Динамикалық сапа минимум:", + "Dynamic Quality Max:": "Динамикалық сапа максимум:", + "Treat Lossless:": "Шығынсыз емдеу:", + "Frame Rate:": "Кадр жиілігі:", + "Video JPEG Quality:": "Бейне JPEG сапасы:", + "Video WEBP Quality:": "Бейне WEBP сапасы:", + "Video Area:": "Бейне аймағы:", + "Video Time:": "Бейне уақыты:", + "Video Out Time:": "Бейненің шығу уақыты:", + "Video Mode Width:": "Бейне режимінің ені:", + "Video Mode Height:": "Бейне режимінің биіктігі:", + "Documentation": "Құжаттама", + "Drag Viewport": "Көру алаңын сүйреу", + "KasmVNC encountered an error:": "KasmVNC қатеге тап болды:" +} \ No newline at end of file diff --git a/app/locale/km.json b/app/locale/km.json new file mode 100644 index 0000000..0e4bfa8 --- /dev/null +++ b/app/locale/km.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "កំពុងភ្ជាប់ ... ", + "Disconnecting...": "កំពុងផ្ដាច់...", + "Reconnecting...": "កំពុងភ្ជាប់ឡើងវិញ ... ", + "Internal error": "កំហុសខាងក្នុង", + "Must set host": "ត្រូវតែកំណត់ម្ចាស់ផ្ទះ", + "Connected (encrypted) to ": "បានភ្ជាប់ (អ៊ិនគ្រីប) ទៅ", + "Connected (unencrypted) to ": "បានភ្ជាប់ (មិនបានអ៊ិនគ្រីប) ទៅ", + "Something went wrong, connection is closed": "មានអ្វីមួយខុសប្រក្រតី ការតភ្ជាប់ត្រូវបានបិទ", + "Failed to connect to server": "បានបរាជ័យក្នុងការតភ្ជាប់ទៅម៉ាស៊ីនមេ", + "Disconnected": "ផ្តាច់", + "New connection has been rejected with reason: ": "ការតភ្ជាប់ថ្មីត្រូវបានបដិសេធដោយមានហេតុផល ៖", + "New connection has been rejected": "ការតភ្ជាប់ថ្មីត្រូវបានបដិសេធ", + "Credentials are required": "តម្រូវឱ្យមានការបញ្ជាក់អត្តសញ្ញាណ", + "Hide/Show the control bar": "លាក់/បង្ហាញរបារបញ្ជា", + "Drag": "អូស", + "Move/Drag Viewport": "ផ្លាស់ទី/អូសច្រកទិដ្ឋភាព", + "Keyboard": "ក្តារចុច", + "Show Keyboard": "បង្ហាញក្តារចុច", + "Extra keys": "គ្រាប់ចុចបន្ថែម", + "Show Extra Keys": "បង្ហាញសោបន្ថែម", + "Ctrl": "បញ្ជា", + "Toggle Ctrl": "បិទ/បើក Ctrl", + "Alt": "Alt", + "Toggle Alt": "បិទ/បើក Alt", + "Toggle Windows": "បិទ/បើក Windows", + "Windows": "វីនដូ", + "Send Tab": "ផ្ញើផ្ទាំង", + "Tab": "ផ្ទាំង", + "Esc": "អេស", + "Send Escape": "ផ្ញើការរត់គេចខ្លួន", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "ផ្ញើ Ctrl-Alt-Del", + "Shutdown/Reboot": "បិទ/ចាប់ផ្ដើមឡើងវិញ", + "Shutdown/Reboot...": "បិទ / ចាប់ផ្តើមឡើងវិញ ... ", + "Power": "ថាមពល", + "Shutdown": "បិទ", + "Reboot": "ចាប់ផ្ដើមឡើងវិញ", + "Reset": "កំណត់ឡើងវិញ", + "Clipboard": "ក្ដារតម្បៀតខ្ទាស់", + "Clear": "ច្បាស់", + "Fullscreen": "ពេញអេក្រង់", + "Settings": "ការកំណត់", + "Shared Mode": "របៀបចែករំលែក", + "View Only": "មើលតែប៉ុណ្ណោះ", + "Clip to Window": "ឃ្លីបទៅបង្អួច", + "Scaling Mode:": "របៀបធ្វើមាត្រដ្ឋាន៖", + "None": "គ្មាន", + "Local Scaling": "ការធ្វើមាត្រដ្ឋានក្នុងស្រុក", + "Remote Resizing": "ការផ្លាស់ប្តូរទំហំពីចម្ងាយ", + "Advanced": "កម្រិតខ្ពស់", + "Quality:": "គុណភាព៖", + "Compression level:": "កម្រិតបង្ហាប់៖", + "Repeater ID:": "លេខសម្គាល់អ្នកធ្វើម្តងទៀត៖", + "WebSocket": "WebSocket", + "Encrypt": "អ៊ិនគ្រីប", + "Host:": "ម្ចាស់ផ្ទះ៖", + "Port:": "ច្រក៖", + "Path:": "ផ្លូវ៖", + "Automatic Reconnect": "ភ្ជាប់ឡើងវិញដោយស្វ័យប្រវត្តិ", + "Reconnect Delay (ms):": "ភ្ជាប់ការពន្យារពេលឡើងវិញ (ms):", + "Show Dot when No Cursor": "បង្ហាញចំណុចនៅពេលគ្មានទស្សន៍ទ្រនិច", + "Logging:": "កត់ត្រា៖", + "Version:": "កំណែ៖", + "Disconnect": "ផ្តាច់", + "Connect": "ភ្ជាប់", + "Username:": "ឈ្មោះអ្នកប្រើប្រាស់:", + "Password:": "ពាក្យសម្ងាត់៖", + "Send Credentials": "ផ្ញើលិខិតបញ្ជាក់", + "Cancel": "បោះបង់", + "Keys": "សោ", + "Game Cursor Mode": "របៀបទស្សន៍ទ្រនិចហ្គេម", + "Press Esc Key to Exit Pointer Lock Mode": "ចុចគ្រាប់ចុច Esc ដើម្បីចេញពីរបៀបចាក់សោទ្រនិច", + "Game Mode paused, click on screen to resume Game Mode.": "បានផ្អាកមុខងារហ្គេម ចុចលើអេក្រង់ដើម្បីបន្តមុខងារហ្គេម។", + "Clipboard Up": "ក្ដារតម្បៀតខ្ទាស់ឡើង", + "CLipboard Down": "ក្ដារតម្បៀតខ្ទាស់ចុះក្រោម", + "Clipboard Seamless": "ក្តារតម្បៀតខ្ទាស់", + "Prefer Local Cursor": "ចូលចិត្តទស្សន៍ទ្រនិចមូលដ្ឋាន", + "Translate keyboard shortcuts": "បកប្រែផ្លូវកាត់ក្តារចុច", + "Enable WebRTC UDP Transit": "បើកដំណើរការ WebRTC UDP Transit", + "Enable WebP Compression": "បើកការបង្ហាប់ WebP", + "Enable Performance Stats": "បើកដំណើរការស្ថិតិ", + "Enable Pointer Lock": "បើកការចាក់សោទ្រនិច", + "IME Input Mode": "របៀបបញ្ចូល IME", + "Show Virtual Keyboard Control": "បង្ហាញការគ្រប់គ្រងក្តារចុចនិម្មិត", + "Toggle Control Panel via Keystrokes": "បិទ/បើកផ្ទាំងបញ្ជាតាមរយៈការចុចគ្រាប់ចុច", + "Render Native Resolution": "បង្ហាញដំណោះស្រាយដើម", + "Keyboard Shortcuts": "ផ្លូវកាត់ក្តារចុច", + "Enable KasmVNC Keyboard Shortcuts": "បើកផ្លូវកាត់ក្តារចុច KasmVNC", + "1 - Toggle Control Panel": "1 - បិទបើកផ្ទាំងបញ្ជា", + "2 - Toggle Game Pointer Mode": "2 - បិទបើករបៀបទ្រនិចហ្គេម", + "3 - Toggle Pointer Lock": "3 - បិទ/បើក ទ្រនិចចាក់សោ", + "Stream Quality": "គុណភាពស្ទ្រីម", + "Preset Modes:": "របៀបកំណត់ជាមុន៖", + "Static": "ឋិតិវន្ត", + "Low": "ទាប", + "Medium": "មធ្យម", + "High": "ខ្ពស់", + "Extreme": "ខ្លាំង", + "Lossless": "គ្មានការខាតបង់", + "Custom": "ផ្ទាល់ខ្លួន", + "Anti-Aliasing:": "ប្រឆាំងឈ្មោះក្លែងក្លាយ៖", + "Auto Dynamic": "ឌីណាមិកស្វ័យប្រវត្តិ", + "Off": "បិទ", + "On": "បើក", + "Dynamic Quality Min:": "គុណភាពថាមវន្តអប្បបរមា៖", + "Dynamic Quality Max:": "គុណភាពថាមវន្តអតិបរមា៖", + "Treat Lossless:": "ព្យាបាលការខាតបង់:", + "Frame Rate:": "អត្រាស៊ុម៖", + "Video JPEG Quality:": "គុណភាព JPEG វីដេអូ៖", + "Video WEBP Quality:": "គុណភាព WEBP វីដេអូ៖", + "Video Area:": "តំបន់វីដេអូ៖", + "Video Time:": "ម៉ោងវីដេអូ៖", + "Video Out Time:": "ម៉ោងចេញវីដេអូ៖", + "Video Mode Width:": "ទទឹងរបៀបវីដេអូ៖", + "Video Mode Height:": "កម្ពស់របៀបវីដេអូ៖", + "Documentation": "ឯកសារ", + "Drag Viewport": "ច្រកទិដ្ឋភាពអូស", + "KasmVNC encountered an error:": "KasmVNC បានជួបប្រទះបញ្ហាមួយ៖" +} \ No newline at end of file diff --git a/app/locale/km_KH.json b/app/locale/km_KH.json new file mode 100644 index 0000000..0e4bfa8 --- /dev/null +++ b/app/locale/km_KH.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "កំពុងភ្ជាប់ ... ", + "Disconnecting...": "កំពុងផ្ដាច់...", + "Reconnecting...": "កំពុងភ្ជាប់ឡើងវិញ ... ", + "Internal error": "កំហុសខាងក្នុង", + "Must set host": "ត្រូវតែកំណត់ម្ចាស់ផ្ទះ", + "Connected (encrypted) to ": "បានភ្ជាប់ (អ៊ិនគ្រីប) ទៅ", + "Connected (unencrypted) to ": "បានភ្ជាប់ (មិនបានអ៊ិនគ្រីប) ទៅ", + "Something went wrong, connection is closed": "មានអ្វីមួយខុសប្រក្រតី ការតភ្ជាប់ត្រូវបានបិទ", + "Failed to connect to server": "បានបរាជ័យក្នុងការតភ្ជាប់ទៅម៉ាស៊ីនមេ", + "Disconnected": "ផ្តាច់", + "New connection has been rejected with reason: ": "ការតភ្ជាប់ថ្មីត្រូវបានបដិសេធដោយមានហេតុផល ៖", + "New connection has been rejected": "ការតភ្ជាប់ថ្មីត្រូវបានបដិសេធ", + "Credentials are required": "តម្រូវឱ្យមានការបញ្ជាក់អត្តសញ្ញាណ", + "Hide/Show the control bar": "លាក់/បង្ហាញរបារបញ្ជា", + "Drag": "អូស", + "Move/Drag Viewport": "ផ្លាស់ទី/អូសច្រកទិដ្ឋភាព", + "Keyboard": "ក្តារចុច", + "Show Keyboard": "បង្ហាញក្តារចុច", + "Extra keys": "គ្រាប់ចុចបន្ថែម", + "Show Extra Keys": "បង្ហាញសោបន្ថែម", + "Ctrl": "បញ្ជា", + "Toggle Ctrl": "បិទ/បើក Ctrl", + "Alt": "Alt", + "Toggle Alt": "បិទ/បើក Alt", + "Toggle Windows": "បិទ/បើក Windows", + "Windows": "វីនដូ", + "Send Tab": "ផ្ញើផ្ទាំង", + "Tab": "ផ្ទាំង", + "Esc": "អេស", + "Send Escape": "ផ្ញើការរត់គេចខ្លួន", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "ផ្ញើ Ctrl-Alt-Del", + "Shutdown/Reboot": "បិទ/ចាប់ផ្ដើមឡើងវិញ", + "Shutdown/Reboot...": "បិទ / ចាប់ផ្តើមឡើងវិញ ... ", + "Power": "ថាមពល", + "Shutdown": "បិទ", + "Reboot": "ចាប់ផ្ដើមឡើងវិញ", + "Reset": "កំណត់ឡើងវិញ", + "Clipboard": "ក្ដារតម្បៀតខ្ទាស់", + "Clear": "ច្បាស់", + "Fullscreen": "ពេញអេក្រង់", + "Settings": "ការកំណត់", + "Shared Mode": "របៀបចែករំលែក", + "View Only": "មើលតែប៉ុណ្ណោះ", + "Clip to Window": "ឃ្លីបទៅបង្អួច", + "Scaling Mode:": "របៀបធ្វើមាត្រដ្ឋាន៖", + "None": "គ្មាន", + "Local Scaling": "ការធ្វើមាត្រដ្ឋានក្នុងស្រុក", + "Remote Resizing": "ការផ្លាស់ប្តូរទំហំពីចម្ងាយ", + "Advanced": "កម្រិតខ្ពស់", + "Quality:": "គុណភាព៖", + "Compression level:": "កម្រិតបង្ហាប់៖", + "Repeater ID:": "លេខសម្គាល់អ្នកធ្វើម្តងទៀត៖", + "WebSocket": "WebSocket", + "Encrypt": "អ៊ិនគ្រីប", + "Host:": "ម្ចាស់ផ្ទះ៖", + "Port:": "ច្រក៖", + "Path:": "ផ្លូវ៖", + "Automatic Reconnect": "ភ្ជាប់ឡើងវិញដោយស្វ័យប្រវត្តិ", + "Reconnect Delay (ms):": "ភ្ជាប់ការពន្យារពេលឡើងវិញ (ms):", + "Show Dot when No Cursor": "បង្ហាញចំណុចនៅពេលគ្មានទស្សន៍ទ្រនិច", + "Logging:": "កត់ត្រា៖", + "Version:": "កំណែ៖", + "Disconnect": "ផ្តាច់", + "Connect": "ភ្ជាប់", + "Username:": "ឈ្មោះអ្នកប្រើប្រាស់:", + "Password:": "ពាក្យសម្ងាត់៖", + "Send Credentials": "ផ្ញើលិខិតបញ្ជាក់", + "Cancel": "បោះបង់", + "Keys": "សោ", + "Game Cursor Mode": "របៀបទស្សន៍ទ្រនិចហ្គេម", + "Press Esc Key to Exit Pointer Lock Mode": "ចុចគ្រាប់ចុច Esc ដើម្បីចេញពីរបៀបចាក់សោទ្រនិច", + "Game Mode paused, click on screen to resume Game Mode.": "បានផ្អាកមុខងារហ្គេម ចុចលើអេក្រង់ដើម្បីបន្តមុខងារហ្គេម។", + "Clipboard Up": "ក្ដារតម្បៀតខ្ទាស់ឡើង", + "CLipboard Down": "ក្ដារតម្បៀតខ្ទាស់ចុះក្រោម", + "Clipboard Seamless": "ក្តារតម្បៀតខ្ទាស់", + "Prefer Local Cursor": "ចូលចិត្តទស្សន៍ទ្រនិចមូលដ្ឋាន", + "Translate keyboard shortcuts": "បកប្រែផ្លូវកាត់ក្តារចុច", + "Enable WebRTC UDP Transit": "បើកដំណើរការ WebRTC UDP Transit", + "Enable WebP Compression": "បើកការបង្ហាប់ WebP", + "Enable Performance Stats": "បើកដំណើរការស្ថិតិ", + "Enable Pointer Lock": "បើកការចាក់សោទ្រនិច", + "IME Input Mode": "របៀបបញ្ចូល IME", + "Show Virtual Keyboard Control": "បង្ហាញការគ្រប់គ្រងក្តារចុចនិម្មិត", + "Toggle Control Panel via Keystrokes": "បិទ/បើកផ្ទាំងបញ្ជាតាមរយៈការចុចគ្រាប់ចុច", + "Render Native Resolution": "បង្ហាញដំណោះស្រាយដើម", + "Keyboard Shortcuts": "ផ្លូវកាត់ក្តារចុច", + "Enable KasmVNC Keyboard Shortcuts": "បើកផ្លូវកាត់ក្តារចុច KasmVNC", + "1 - Toggle Control Panel": "1 - បិទបើកផ្ទាំងបញ្ជា", + "2 - Toggle Game Pointer Mode": "2 - បិទបើករបៀបទ្រនិចហ្គេម", + "3 - Toggle Pointer Lock": "3 - បិទ/បើក ទ្រនិចចាក់សោ", + "Stream Quality": "គុណភាពស្ទ្រីម", + "Preset Modes:": "របៀបកំណត់ជាមុន៖", + "Static": "ឋិតិវន្ត", + "Low": "ទាប", + "Medium": "មធ្យម", + "High": "ខ្ពស់", + "Extreme": "ខ្លាំង", + "Lossless": "គ្មានការខាតបង់", + "Custom": "ផ្ទាល់ខ្លួន", + "Anti-Aliasing:": "ប្រឆាំងឈ្មោះក្លែងក្លាយ៖", + "Auto Dynamic": "ឌីណាមិកស្វ័យប្រវត្តិ", + "Off": "បិទ", + "On": "បើក", + "Dynamic Quality Min:": "គុណភាពថាមវន្តអប្បបរមា៖", + "Dynamic Quality Max:": "គុណភាពថាមវន្តអតិបរមា៖", + "Treat Lossless:": "ព្យាបាលការខាតបង់:", + "Frame Rate:": "អត្រាស៊ុម៖", + "Video JPEG Quality:": "គុណភាព JPEG វីដេអូ៖", + "Video WEBP Quality:": "គុណភាព WEBP វីដេអូ៖", + "Video Area:": "តំបន់វីដេអូ៖", + "Video Time:": "ម៉ោងវីដេអូ៖", + "Video Out Time:": "ម៉ោងចេញវីដេអូ៖", + "Video Mode Width:": "ទទឹងរបៀបវីដេអូ៖", + "Video Mode Height:": "កម្ពស់របៀបវីដេអូ៖", + "Documentation": "ឯកសារ", + "Drag Viewport": "ច្រកទិដ្ឋភាពអូស", + "KasmVNC encountered an error:": "KasmVNC បានជួបប្រទះបញ្ហាមួយ៖" +} \ No newline at end of file diff --git a/app/locale/kn.json b/app/locale/kn.json new file mode 100644 index 0000000..db3b3be --- /dev/null +++ b/app/locale/kn.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ...", + "Disconnecting...": "ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗುತ್ತಿದೆ...", + "Reconnecting...": "ಮರುಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ...", + "Internal error": "ಆಂತರಿಕ ದೋಷ", + "Must set host": "ಹೋಸ್ಟ್ ಅನ್ನು ಹೊಂದಿಸಬೇಕು", + "Connected (encrypted) to ": "ಸಂಪರ್ಕಿಸಲಾಗಿದೆ (ಎನ್u200cಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ)", + "Connected (unencrypted) to ": "ಸಂಪರ್ಕಿಸಲಾಗಿದೆ (ಎನ್u200cಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿಲ್ಲ)", + "Something went wrong, connection is closed": "ಏನೋ ತಪ್ಪಾಗಿದೆ, ಸಂಪರ್ಕವನ್ನು ಮುಚ್ಚಲಾಗಿದೆ", + "Failed to connect to server": "ಸರ್ವರ್u200cಗೆ ಸಂಪರ್ಕಿಸಲು ವಿಫಲವಾಗಿದೆ", + "Disconnected": "ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ", + "New connection has been rejected with reason: ": "ಹೊಸ ಸಂಪರ್ಕವನ್ನು ಕಾರಣದೊಂದಿಗೆ ತಿರಸ್ಕರಿಸಲಾಗಿದೆ:", + "New connection has been rejected": "ಹೊಸ ಸಂಪರ್ಕವನ್ನು ತಿರಸ್ಕರಿಸಲಾಗಿದೆ", + "Credentials are required": "ರುಜುವಾತುಗಳು ಅಗತ್ಯವಿದೆ", + "Hide/Show the control bar": "ಕಂಟ್ರೋಲ್ ಬಾರ್ ಅನ್ನು ಮರೆಮಾಡಿ / ತೋರಿಸು", + "Drag": "ಎಳೆಯಿರಿ", + "Move/Drag Viewport": "ಮೂವ್/ಡ್ರ್ಯಾಗ್ ವ್ಯೂಪೋರ್ಟ್", + "Keyboard": "ಕೀಬೋರ್ಡ್", + "Show Keyboard": "ಕೀಬೋರ್ಡ್ ತೋರಿಸು", + "Extra keys": "ಹೆಚ್ಚುವರಿ ಕೀಗಳು", + "Show Extra Keys": "ಹೆಚ್ಚುವರಿ ಕೀಗಳನ್ನು ತೋರಿಸು", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ಅನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "Alt": "ಆಲ್ಟ್", + "Toggle Alt": "ಆಲ್ಟ್ ಅನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "Toggle Windows": "ವಿಂಡೋಸ್ ಅನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "Windows": "ವಿಂಡೋಸ್", + "Send Tab": "ಟ್ಯಾಬ್ ಕಳುಹಿಸಿ", + "Tab": "ಟ್ಯಾಬ್", + "Esc": "Esc", + "Send Escape": "ಎಸ್ಕೇಪ್ ಕಳುಹಿಸಿ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ಕಳುಹಿಸಿ", + "Shutdown/Reboot": "ಸ್ಥಗಿತಗೊಳಿಸುವಿಕೆ/ರೀಬೂಟ್", + "Shutdown/Reboot...": "ಶಟ್u200cಡೌನ್/ರೀಬೂಟ್...", + "Power": "ಶಕ್ತಿ", + "Shutdown": "ಮುಚ್ಚಲಾಯಿತು", + "Reboot": "ರೀಬೂಟ್", + "Reset": "ಮರುಹೊಂದಿಸಿ", + "Clipboard": "ಕ್ಲಿಪ್ಬೋರ್ಡ್", + "Clear": "ಸ್ಪಷ್ಟ", + "Fullscreen": "ಪೂರ್ಣ ಪರದೆ", + "Settings": "ಸಂಯೋಜನೆಗಳು", + "Shared Mode": "ಹಂಚಿದ ಮೋಡ್", + "View Only": "ವೀಕ್ಷಣೆ ಮಾತ್ರ", + "Clip to Window": "ಕಿಟಕಿಗೆ ಕ್ಲಿಪ್ ಮಾಡಿ", + "Scaling Mode:": "ಸ್ಕೇಲಿಂಗ್ ಮೋಡ್:", + "None": "ಯಾವುದೂ", + "Local Scaling": "ಸ್ಥಳೀಯ ಸ್ಕೇಲಿಂಗ್", + "Remote Resizing": "ರಿಮೋಟ್ ಮರುಗಾತ್ರಗೊಳಿಸುವಿಕೆ", + "Advanced": "ಸುಧಾರಿತ", + "Quality:": "ಗುಣಮಟ್ಟ:", + "Compression level:": "ಸಂಕೋಚನ ಮಟ್ಟ:", + "Repeater ID:": "ಪುನರಾವರ್ತಕ ID:", + "WebSocket": "ವೆಬ್ಸಾಕೆಟ್", + "Encrypt": "ಎನ್ಕ್ರಿಪ್ಟ್", + "Host:": "ಅತಿಥೆಯ:", + "Port:": "ಬಂದರು:", + "Path:": "ಮಾರ್ಗ:", + "Automatic Reconnect": "ಸ್ವಯಂಚಾಲಿತ ಮರುಸಂಪರ್ಕ", + "Reconnect Delay (ms):": "ಮರುಸಂಪರ್ಕ ವಿಳಂಬ (ಮಿಸೆಸ್):", + "Show Dot when No Cursor": "ಕರ್ಸರ್ ಇಲ್ಲದಿದ್ದಾಗ ಡಾಟ್ ತೋರಿಸು", + "Logging:": "ಲಾಗಿಂಗ್:", + "Version:": "ಆವೃತ್ತಿ:", + "Disconnect": "ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಿ", + "Connect": "ಸಂಪರ್ಕ", + "Username:": "ಬಳಕೆದಾರ ಹೆಸರು:", + "Password:": "ಗುಪ್ತಪದ:", + "Send Credentials": "ರುಜುವಾತುಗಳನ್ನು ಕಳುಹಿಸಿ", + "Cancel": "ರದ್ದುಮಾಡು", + "Keys": "ಕೀಗಳು", + "Game Cursor Mode": "ಗೇಮ್ ಕರ್ಸರ್ ಮೋಡ್", + "Press Esc Key to Exit Pointer Lock Mode": "ಪಾಯಿಂಟರ್ ಲಾಕ್ ಮೋಡ್u200cನಿಂದ ನಿರ್ಗಮಿಸಲು Esc ಕೀಲಿಯನ್ನು ಒತ್ತಿರಿ", + "Game Mode paused, click on screen to resume Game Mode.": "ಗೇಮ್ ಮೋಡ್ ಅನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ, ಗೇಮ್ ಮೋಡ್ ಅನ್ನು ಪುನರಾರಂಭಿಸಲು ಪರದೆಯ ಮೇಲೆ ಕ್ಲಿಕ್ ಮಾಡಿ.", + "Clipboard Up": "ಕ್ಲಿಪ್ಬೋರ್ಡ್ ಅಪ್", + "CLipboard Down": "ಕ್ಲಿಪ್ಬೋರ್ಡ್ ಡೌನ್", + "Clipboard Seamless": "ಕ್ಲಿಪ್ಬೋರ್ಡ್ ತಡೆರಹಿತ", + "Prefer Local Cursor": "ಸ್ಥಳೀಯ ಕರ್ಸರ್ ಆದ್ಯತೆ", + "Translate keyboard shortcuts": "ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್u200cಕಟ್u200cಗಳನ್ನು ಅನುವಾದಿಸಿ", + "Enable WebRTC UDP Transit": "WebRTC UDP ಟ್ರಾನ್ಸಿಟ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "Enable WebP Compression": "ವೆಬ್ಪಿ ಕಂಪ್ರೆಷನ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "Enable Performance Stats": "ಕಾರ್ಯಕ್ಷಮತೆಯ ಅಂಕಿಅಂಶಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "Enable Pointer Lock": "ಪಾಯಿಂಟರ್ ಲಾಕ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "IME Input Mode": "IME ಇನ್u200cಪುಟ್ ಮೋಡ್", + "Show Virtual Keyboard Control": "ವರ್ಚುವಲ್ ಕೀಬೋರ್ಡ್ ನಿಯಂತ್ರಣವನ್ನು ತೋರಿಸು", + "Toggle Control Panel via Keystrokes": "ಕೀಸ್ಟ್ರೋಕ್u200cಗಳ ಮೂಲಕ ನಿಯಂತ್ರಣ ಫಲಕವನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "Render Native Resolution": "ಸ್ಥಳೀಯ ರೆಸಲ್ಯೂಶನ್ ನಿರೂಪಿಸು", + "Keyboard Shortcuts": "ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್u200cಕಟ್u200cಗಳು", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್u200cಕಟ್u200cಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "1 - Toggle Control Panel": "1 - ನಿಯಂತ್ರಣ ಫಲಕವನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "2 - Toggle Game Pointer Mode": "2 - ಟಾಗಲ್ ಗೇಮ್ ಪಾಯಿಂಟರ್ ಮೋಡ್", + "3 - Toggle Pointer Lock": "3 - ಟಾಗಲ್ ಪಾಯಿಂಟರ್ ಲಾಕ್", + "Stream Quality": "ಸ್ಟ್ರೀಮ್ ಗುಣಮಟ್ಟ", + "Preset Modes:": "ಪ್ರಿಸೆಟ್ ಮೋಡ್u200cಗಳು:", + "Static": "ಸ್ಥಿರ", + "Low": "ಕಡಿಮೆ", + "Medium": "ಮಾಧ್ಯಮ", + "High": "ಹೆಚ್ಚು", + "Extreme": "ಅತ್ಯಂತ", + "Lossless": "ನಷ್ಟವಿಲ್ಲದ", + "Custom": "ಕಸ್ಟಮ್", + "Anti-Aliasing:": "ವಿರೋಧಿ ಉಪನಾಮ:", + "Auto Dynamic": "ಆಟೋ ಡೈನಾಮಿಕ್", + "Off": "ಆರಿಸಿ", + "On": "ಆನ್", + "Dynamic Quality Min:": "ಡೈನಾಮಿಕ್ ಗುಣಮಟ್ಟ ಕನಿಷ್ಠ:", + "Dynamic Quality Max:": "ಡೈನಾಮಿಕ್ ಕ್ವಾಲಿಟಿ ಮ್ಯಾಕ್ಸ್:", + "Treat Lossless:": "ಲಾಸ್ಲೆಸ್ ಟ್ರೀಟ್:", + "Frame Rate:": "ಚೌಕಟ್ಟು ಬೆಲೆ:", + "Video JPEG Quality:": "ವೀಡಿಯೊ JPEG ಗುಣಮಟ್ಟ:", + "Video WEBP Quality:": "ವೀಡಿಯೊ WEBP ಗುಣಮಟ್ಟ:", + "Video Area:": "ವೀಡಿಯೊ ಪ್ರದೇಶ:", + "Video Time:": "ವೀಡಿಯೊ ಸಮಯ:", + "Video Out Time:": "ವೀಡಿಯೊ ಔಟ್ ಟೈಮ್:", + "Video Mode Width:": "ವೀಡಿಯೊ ಮೋಡ್ ಅಗಲ:", + "Video Mode Height:": "ವೀಡಿಯೊ ಮೋಡ್ ಎತ್ತರ:", + "Documentation": "ದಾಖಲೆ", + "Drag Viewport": "ಡ್ರ್ಯಾಗ್ ವ್ಯೂಪೋರ್ಟ್", + "KasmVNC encountered an error:": "KasmVNC ದೋಷವನ್ನು ಎದುರಿಸಿದೆ:" +} \ No newline at end of file diff --git a/app/locale/kn_IN.json b/app/locale/kn_IN.json new file mode 100644 index 0000000..db3b3be --- /dev/null +++ b/app/locale/kn_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ...", + "Disconnecting...": "ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗುತ್ತಿದೆ...", + "Reconnecting...": "ಮರುಸಂಪರ್ಕಿಸಲಾಗುತ್ತಿದೆ...", + "Internal error": "ಆಂತರಿಕ ದೋಷ", + "Must set host": "ಹೋಸ್ಟ್ ಅನ್ನು ಹೊಂದಿಸಬೇಕು", + "Connected (encrypted) to ": "ಸಂಪರ್ಕಿಸಲಾಗಿದೆ (ಎನ್u200cಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ)", + "Connected (unencrypted) to ": "ಸಂಪರ್ಕಿಸಲಾಗಿದೆ (ಎನ್u200cಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿಲ್ಲ)", + "Something went wrong, connection is closed": "ಏನೋ ತಪ್ಪಾಗಿದೆ, ಸಂಪರ್ಕವನ್ನು ಮುಚ್ಚಲಾಗಿದೆ", + "Failed to connect to server": "ಸರ್ವರ್u200cಗೆ ಸಂಪರ್ಕಿಸಲು ವಿಫಲವಾಗಿದೆ", + "Disconnected": "ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ", + "New connection has been rejected with reason: ": "ಹೊಸ ಸಂಪರ್ಕವನ್ನು ಕಾರಣದೊಂದಿಗೆ ತಿರಸ್ಕರಿಸಲಾಗಿದೆ:", + "New connection has been rejected": "ಹೊಸ ಸಂಪರ್ಕವನ್ನು ತಿರಸ್ಕರಿಸಲಾಗಿದೆ", + "Credentials are required": "ರುಜುವಾತುಗಳು ಅಗತ್ಯವಿದೆ", + "Hide/Show the control bar": "ಕಂಟ್ರೋಲ್ ಬಾರ್ ಅನ್ನು ಮರೆಮಾಡಿ / ತೋರಿಸು", + "Drag": "ಎಳೆಯಿರಿ", + "Move/Drag Viewport": "ಮೂವ್/ಡ್ರ್ಯಾಗ್ ವ್ಯೂಪೋರ್ಟ್", + "Keyboard": "ಕೀಬೋರ್ಡ್", + "Show Keyboard": "ಕೀಬೋರ್ಡ್ ತೋರಿಸು", + "Extra keys": "ಹೆಚ್ಚುವರಿ ಕೀಗಳು", + "Show Extra Keys": "ಹೆಚ್ಚುವರಿ ಕೀಗಳನ್ನು ತೋರಿಸು", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ಅನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "Alt": "ಆಲ್ಟ್", + "Toggle Alt": "ಆಲ್ಟ್ ಅನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "Toggle Windows": "ವಿಂಡೋಸ್ ಅನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "Windows": "ವಿಂಡೋಸ್", + "Send Tab": "ಟ್ಯಾಬ್ ಕಳುಹಿಸಿ", + "Tab": "ಟ್ಯಾಬ್", + "Esc": "Esc", + "Send Escape": "ಎಸ್ಕೇಪ್ ಕಳುಹಿಸಿ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ಕಳುಹಿಸಿ", + "Shutdown/Reboot": "ಸ್ಥಗಿತಗೊಳಿಸುವಿಕೆ/ರೀಬೂಟ್", + "Shutdown/Reboot...": "ಶಟ್u200cಡೌನ್/ರೀಬೂಟ್...", + "Power": "ಶಕ್ತಿ", + "Shutdown": "ಮುಚ್ಚಲಾಯಿತು", + "Reboot": "ರೀಬೂಟ್", + "Reset": "ಮರುಹೊಂದಿಸಿ", + "Clipboard": "ಕ್ಲಿಪ್ಬೋರ್ಡ್", + "Clear": "ಸ್ಪಷ್ಟ", + "Fullscreen": "ಪೂರ್ಣ ಪರದೆ", + "Settings": "ಸಂಯೋಜನೆಗಳು", + "Shared Mode": "ಹಂಚಿದ ಮೋಡ್", + "View Only": "ವೀಕ್ಷಣೆ ಮಾತ್ರ", + "Clip to Window": "ಕಿಟಕಿಗೆ ಕ್ಲಿಪ್ ಮಾಡಿ", + "Scaling Mode:": "ಸ್ಕೇಲಿಂಗ್ ಮೋಡ್:", + "None": "ಯಾವುದೂ", + "Local Scaling": "ಸ್ಥಳೀಯ ಸ್ಕೇಲಿಂಗ್", + "Remote Resizing": "ರಿಮೋಟ್ ಮರುಗಾತ್ರಗೊಳಿಸುವಿಕೆ", + "Advanced": "ಸುಧಾರಿತ", + "Quality:": "ಗುಣಮಟ್ಟ:", + "Compression level:": "ಸಂಕೋಚನ ಮಟ್ಟ:", + "Repeater ID:": "ಪುನರಾವರ್ತಕ ID:", + "WebSocket": "ವೆಬ್ಸಾಕೆಟ್", + "Encrypt": "ಎನ್ಕ್ರಿಪ್ಟ್", + "Host:": "ಅತಿಥೆಯ:", + "Port:": "ಬಂದರು:", + "Path:": "ಮಾರ್ಗ:", + "Automatic Reconnect": "ಸ್ವಯಂಚಾಲಿತ ಮರುಸಂಪರ್ಕ", + "Reconnect Delay (ms):": "ಮರುಸಂಪರ್ಕ ವಿಳಂಬ (ಮಿಸೆಸ್):", + "Show Dot when No Cursor": "ಕರ್ಸರ್ ಇಲ್ಲದಿದ್ದಾಗ ಡಾಟ್ ತೋರಿಸು", + "Logging:": "ಲಾಗಿಂಗ್:", + "Version:": "ಆವೃತ್ತಿ:", + "Disconnect": "ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಿ", + "Connect": "ಸಂಪರ್ಕ", + "Username:": "ಬಳಕೆದಾರ ಹೆಸರು:", + "Password:": "ಗುಪ್ತಪದ:", + "Send Credentials": "ರುಜುವಾತುಗಳನ್ನು ಕಳುಹಿಸಿ", + "Cancel": "ರದ್ದುಮಾಡು", + "Keys": "ಕೀಗಳು", + "Game Cursor Mode": "ಗೇಮ್ ಕರ್ಸರ್ ಮೋಡ್", + "Press Esc Key to Exit Pointer Lock Mode": "ಪಾಯಿಂಟರ್ ಲಾಕ್ ಮೋಡ್u200cನಿಂದ ನಿರ್ಗಮಿಸಲು Esc ಕೀಲಿಯನ್ನು ಒತ್ತಿರಿ", + "Game Mode paused, click on screen to resume Game Mode.": "ಗೇಮ್ ಮೋಡ್ ಅನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ, ಗೇಮ್ ಮೋಡ್ ಅನ್ನು ಪುನರಾರಂಭಿಸಲು ಪರದೆಯ ಮೇಲೆ ಕ್ಲಿಕ್ ಮಾಡಿ.", + "Clipboard Up": "ಕ್ಲಿಪ್ಬೋರ್ಡ್ ಅಪ್", + "CLipboard Down": "ಕ್ಲಿಪ್ಬೋರ್ಡ್ ಡೌನ್", + "Clipboard Seamless": "ಕ್ಲಿಪ್ಬೋರ್ಡ್ ತಡೆರಹಿತ", + "Prefer Local Cursor": "ಸ್ಥಳೀಯ ಕರ್ಸರ್ ಆದ್ಯತೆ", + "Translate keyboard shortcuts": "ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್u200cಕಟ್u200cಗಳನ್ನು ಅನುವಾದಿಸಿ", + "Enable WebRTC UDP Transit": "WebRTC UDP ಟ್ರಾನ್ಸಿಟ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "Enable WebP Compression": "ವೆಬ್ಪಿ ಕಂಪ್ರೆಷನ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "Enable Performance Stats": "ಕಾರ್ಯಕ್ಷಮತೆಯ ಅಂಕಿಅಂಶಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "Enable Pointer Lock": "ಪಾಯಿಂಟರ್ ಲಾಕ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "IME Input Mode": "IME ಇನ್u200cಪುಟ್ ಮೋಡ್", + "Show Virtual Keyboard Control": "ವರ್ಚುವಲ್ ಕೀಬೋರ್ಡ್ ನಿಯಂತ್ರಣವನ್ನು ತೋರಿಸು", + "Toggle Control Panel via Keystrokes": "ಕೀಸ್ಟ್ರೋಕ್u200cಗಳ ಮೂಲಕ ನಿಯಂತ್ರಣ ಫಲಕವನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "Render Native Resolution": "ಸ್ಥಳೀಯ ರೆಸಲ್ಯೂಶನ್ ನಿರೂಪಿಸು", + "Keyboard Shortcuts": "ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್u200cಕಟ್u200cಗಳು", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ಕೀಬೋರ್ಡ್ ಶಾರ್ಟ್u200cಕಟ್u200cಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ", + "1 - Toggle Control Panel": "1 - ನಿಯಂತ್ರಣ ಫಲಕವನ್ನು ಟಾಗಲ್ ಮಾಡಿ", + "2 - Toggle Game Pointer Mode": "2 - ಟಾಗಲ್ ಗೇಮ್ ಪಾಯಿಂಟರ್ ಮೋಡ್", + "3 - Toggle Pointer Lock": "3 - ಟಾಗಲ್ ಪಾಯಿಂಟರ್ ಲಾಕ್", + "Stream Quality": "ಸ್ಟ್ರೀಮ್ ಗುಣಮಟ್ಟ", + "Preset Modes:": "ಪ್ರಿಸೆಟ್ ಮೋಡ್u200cಗಳು:", + "Static": "ಸ್ಥಿರ", + "Low": "ಕಡಿಮೆ", + "Medium": "ಮಾಧ್ಯಮ", + "High": "ಹೆಚ್ಚು", + "Extreme": "ಅತ್ಯಂತ", + "Lossless": "ನಷ್ಟವಿಲ್ಲದ", + "Custom": "ಕಸ್ಟಮ್", + "Anti-Aliasing:": "ವಿರೋಧಿ ಉಪನಾಮ:", + "Auto Dynamic": "ಆಟೋ ಡೈನಾಮಿಕ್", + "Off": "ಆರಿಸಿ", + "On": "ಆನ್", + "Dynamic Quality Min:": "ಡೈನಾಮಿಕ್ ಗುಣಮಟ್ಟ ಕನಿಷ್ಠ:", + "Dynamic Quality Max:": "ಡೈನಾಮಿಕ್ ಕ್ವಾಲಿಟಿ ಮ್ಯಾಕ್ಸ್:", + "Treat Lossless:": "ಲಾಸ್ಲೆಸ್ ಟ್ರೀಟ್:", + "Frame Rate:": "ಚೌಕಟ್ಟು ಬೆಲೆ:", + "Video JPEG Quality:": "ವೀಡಿಯೊ JPEG ಗುಣಮಟ್ಟ:", + "Video WEBP Quality:": "ವೀಡಿಯೊ WEBP ಗುಣಮಟ್ಟ:", + "Video Area:": "ವೀಡಿಯೊ ಪ್ರದೇಶ:", + "Video Time:": "ವೀಡಿಯೊ ಸಮಯ:", + "Video Out Time:": "ವೀಡಿಯೊ ಔಟ್ ಟೈಮ್:", + "Video Mode Width:": "ವೀಡಿಯೊ ಮೋಡ್ ಅಗಲ:", + "Video Mode Height:": "ವೀಡಿಯೊ ಮೋಡ್ ಎತ್ತರ:", + "Documentation": "ದಾಖಲೆ", + "Drag Viewport": "ಡ್ರ್ಯಾಗ್ ವ್ಯೂಪೋರ್ಟ್", + "KasmVNC encountered an error:": "KasmVNC ದೋಷವನ್ನು ಎದುರಿಸಿದೆ:" +} \ No newline at end of file diff --git a/app/locale/ko.json b/app/locale/ko.json new file mode 100644 index 0000000..09c47dc --- /dev/null +++ b/app/locale/ko.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "연결중...", + "Disconnecting...": "연결 해제중...", + "Reconnecting...": "재연결중...", + "Internal error": "내부 오류", + "Must set host": "호스트는 설정되어야 합니다.", + "Connected (encrypted) to ": "다음과 (암호화되어) 연결되었습니다:", + "Connected (unencrypted) to ": "다음과 (암호화 없이) 연결되었습니다:", + "Something went wrong, connection is closed": "무언가 잘못되었습니다, 연결이 닫혔습니다.", + "Failed to connect to server": "서버에 연결하지 못했습니다.", + "Disconnected": "연결이 해제되었습니다.", + "New connection has been rejected with reason: ": "새 연결이 다음 이유로 거부되었습니다:", + "New connection has been rejected": "새 연결이 거부되었습니다.", + "Password is required": "비밀번호가 필요합니다.", + "Hide/Show the control bar": "컨트롤 바 숨기기/보이기", + "Move/Drag Viewport": "움직이기/드래그 뷰포트", + "viewport drag": "뷰포트 드래그", + "Active Mouse Button": "마우스 버튼 활성화", + "No mousebutton": "마우스 버튼 없음", + "Left mousebutton": "왼쪽 마우스 버튼", + "Middle mousebutton": "중간 마우스 버튼", + "Right mousebutton": "오른쪽 마우스 버튼", + "Keyboard": "키보드", + "Show Keyboard": "키보드 보이기", + "Extra keys": "기타 키들", + "Show Extra Keys": "기타 키들 보이기", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl 켜기/끄기", + "Alt": "Alt", + "Toggle Alt": "Alt 켜기/끄기", + "Send Tab": "Tab 보내기", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Esc 보내기", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl+Alt+Del 보내기", + "Shutdown/Reboot": "셧다운/리붓", + "Shutdown/Reboot...": "셧다운/리붓...", + "Power": "전원", + "Shutdown": "셧다운", + "Reboot": "리붓", + "Reset": "리셋", + "Clipboard": "클립보드", + "Clear": "지우기", + "Fullscreen": "전체화면", + "Settings": "설정", + "Shared Mode": "공유 모드", + "View Only": "보기 전용", + "Clip to Window": "창에 클립", + "Scaling Mode:": "스케일링 모드:", + "None": "없음", + "Local Scaling": "로컬 스케일링", + "Remote Resizing": "원격 크기 조절", + "Advanced": "고급", + "Repeater ID:": "중계 ID", + "WebSocket": "웹소켓", + "Encrypt": "암호화", + "Host:": "호스트:", + "Port:": "포트:", + "Path:": "위치:", + "Automatic Reconnect": "자동 재연결", + "Reconnect Delay (ms):": "재연결 지연 시간 (ms)", + "Logging:": "로깅", + "Disconnect": "연결 해제", + "Connect": "연결", + "Password:": "비밀번호:", + "Send Password": "비밀번호 전송", + "Cancel": "취소", + "Credentials are required": "\"자격 증명이 필요합니다\"", + "Drag": "견인", + "Toggle Windows": "\"창 전환\"", + "Windows": "창", + "Quality:": "\"품질:\"", + "Compression level:": "압축 수준:", + "Show Dot when No Cursor": "\"커서가 없을 때 점 표시\"", + "Version:": "버전:", + "Username:": "사용자 이름:", + "Send Credentials": "자격증명 보내기", + "Keys": "열쇠", + "Game Cursor Mode": "게임 커서 모드", + "Press Esc Key to Exit Pointer Lock Mode": "\"포인터 잠금 모드를 종료하려면 Esc 키를 누르십시오\"", + "Game Mode paused, click on screen to resume Game Mode.": "\"게임 모드가 일시 중지되었습니다. 게임 모드를 다시 시작하려면 화면을 클릭하십시오.\"", + "Clipboard Up": "클립보드 위로", + "CLipboard Down": "클립보드 아래로", + "Clipboard Seamless": "\"클립보드 원활한\"", + "Prefer Local Cursor": "\"로컬 커서 선호\"", + "Translate keyboard shortcuts": "단축키 번역", + "Enable WebRTC UDP Transit": "\"WebRTC UDP 전송 활성화\"", + "Enable WebP Compression": "\"WebP 압축 활성화\"", + "Enable Performance Stats": "\"성능 통계 활성화\"", + "Enable Pointer Lock": "\"포인터 잠금 활성화\"", + "IME Input Mode": "IME 입력 모드", + "Show Virtual Keyboard Control": "\"가상 키보드 제어 표시\"", + "Toggle Control Panel via Keystrokes": "\"키 입력을 통한 제어판 전환\"", + "Render Native Resolution": "\"기본 해상도 렌더링\"", + "Keyboard Shortcuts": "키보드 단축키", + "Enable KasmVNC Keyboard Shortcuts": "\"KasmVNC 키보드 단축키 활성화\"", + "1 - Toggle Control Panel": "\"1 - 제어판 전환\"", + "2 - Toggle Game Pointer Mode": "\"2 - 게임 포인터 모드 전환\"", + "3 - Toggle Pointer Lock": "\"3 - 포인터 잠금 전환\"", + "Stream Quality": "\"스트림 품질\"", + "Preset Modes:": "사전 설정 모드:", + "Static": "공전", + "Low": "낮은", + "Medium": "중간", + "High": "높은", + "Extreme": "\"극심한\"", + "Lossless": "무손실", + "Custom": "관습", + "Anti-Aliasing:": "안티 앨리어싱:", + "Auto Dynamic": "오토 다이내믹", + "Off": "끄다", + "On": "에", + "Dynamic Quality Min:": "\"최소 동적 품질:\"", + "Dynamic Quality Max:": "\"동적 품질 최대:\"", + "Treat Lossless:": "무손실 치료:", + "Frame Rate:": "\"프레임 속도:\"", + "Video JPEG Quality:": "\"비디오 JPEG 품질:\"", + "Video WEBP Quality:": "\"비디오 WEBP 품질:\"", + "Video Area:": "비디오 영역:", + "Video Time:": "비디오 시간:", + "Video Out Time:": "비디오 종료 시간:", + "Video Mode Width:": "비디오 모드 너비:", + "Video Mode Height:": "비디오 모드 높이:", + "Documentation": "선적 서류 비치", + "Drag Viewport": "드래그 뷰포트", + "KasmVNC encountered an error:": "KasmVNC에 오류가 발생했습니다:" +} \ No newline at end of file diff --git a/app/locale/ko_KR.json b/app/locale/ko_KR.json new file mode 100644 index 0000000..09c47dc --- /dev/null +++ b/app/locale/ko_KR.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "연결중...", + "Disconnecting...": "연결 해제중...", + "Reconnecting...": "재연결중...", + "Internal error": "내부 오류", + "Must set host": "호스트는 설정되어야 합니다.", + "Connected (encrypted) to ": "다음과 (암호화되어) 연결되었습니다:", + "Connected (unencrypted) to ": "다음과 (암호화 없이) 연결되었습니다:", + "Something went wrong, connection is closed": "무언가 잘못되었습니다, 연결이 닫혔습니다.", + "Failed to connect to server": "서버에 연결하지 못했습니다.", + "Disconnected": "연결이 해제되었습니다.", + "New connection has been rejected with reason: ": "새 연결이 다음 이유로 거부되었습니다:", + "New connection has been rejected": "새 연결이 거부되었습니다.", + "Password is required": "비밀번호가 필요합니다.", + "Hide/Show the control bar": "컨트롤 바 숨기기/보이기", + "Move/Drag Viewport": "움직이기/드래그 뷰포트", + "viewport drag": "뷰포트 드래그", + "Active Mouse Button": "마우스 버튼 활성화", + "No mousebutton": "마우스 버튼 없음", + "Left mousebutton": "왼쪽 마우스 버튼", + "Middle mousebutton": "중간 마우스 버튼", + "Right mousebutton": "오른쪽 마우스 버튼", + "Keyboard": "키보드", + "Show Keyboard": "키보드 보이기", + "Extra keys": "기타 키들", + "Show Extra Keys": "기타 키들 보이기", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl 켜기/끄기", + "Alt": "Alt", + "Toggle Alt": "Alt 켜기/끄기", + "Send Tab": "Tab 보내기", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Esc 보내기", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl+Alt+Del 보내기", + "Shutdown/Reboot": "셧다운/리붓", + "Shutdown/Reboot...": "셧다운/리붓...", + "Power": "전원", + "Shutdown": "셧다운", + "Reboot": "리붓", + "Reset": "리셋", + "Clipboard": "클립보드", + "Clear": "지우기", + "Fullscreen": "전체화면", + "Settings": "설정", + "Shared Mode": "공유 모드", + "View Only": "보기 전용", + "Clip to Window": "창에 클립", + "Scaling Mode:": "스케일링 모드:", + "None": "없음", + "Local Scaling": "로컬 스케일링", + "Remote Resizing": "원격 크기 조절", + "Advanced": "고급", + "Repeater ID:": "중계 ID", + "WebSocket": "웹소켓", + "Encrypt": "암호화", + "Host:": "호스트:", + "Port:": "포트:", + "Path:": "위치:", + "Automatic Reconnect": "자동 재연결", + "Reconnect Delay (ms):": "재연결 지연 시간 (ms)", + "Logging:": "로깅", + "Disconnect": "연결 해제", + "Connect": "연결", + "Password:": "비밀번호:", + "Send Password": "비밀번호 전송", + "Cancel": "취소", + "Credentials are required": "\"자격 증명이 필요합니다\"", + "Drag": "견인", + "Toggle Windows": "\"창 전환\"", + "Windows": "창", + "Quality:": "\"품질:\"", + "Compression level:": "압축 수준:", + "Show Dot when No Cursor": "\"커서가 없을 때 점 표시\"", + "Version:": "버전:", + "Username:": "사용자 이름:", + "Send Credentials": "자격증명 보내기", + "Keys": "열쇠", + "Game Cursor Mode": "게임 커서 모드", + "Press Esc Key to Exit Pointer Lock Mode": "\"포인터 잠금 모드를 종료하려면 Esc 키를 누르십시오\"", + "Game Mode paused, click on screen to resume Game Mode.": "\"게임 모드가 일시 중지되었습니다. 게임 모드를 다시 시작하려면 화면을 클릭하십시오.\"", + "Clipboard Up": "클립보드 위로", + "CLipboard Down": "클립보드 아래로", + "Clipboard Seamless": "\"클립보드 원활한\"", + "Prefer Local Cursor": "\"로컬 커서 선호\"", + "Translate keyboard shortcuts": "단축키 번역", + "Enable WebRTC UDP Transit": "\"WebRTC UDP 전송 활성화\"", + "Enable WebP Compression": "\"WebP 압축 활성화\"", + "Enable Performance Stats": "\"성능 통계 활성화\"", + "Enable Pointer Lock": "\"포인터 잠금 활성화\"", + "IME Input Mode": "IME 입력 모드", + "Show Virtual Keyboard Control": "\"가상 키보드 제어 표시\"", + "Toggle Control Panel via Keystrokes": "\"키 입력을 통한 제어판 전환\"", + "Render Native Resolution": "\"기본 해상도 렌더링\"", + "Keyboard Shortcuts": "키보드 단축키", + "Enable KasmVNC Keyboard Shortcuts": "\"KasmVNC 키보드 단축키 활성화\"", + "1 - Toggle Control Panel": "\"1 - 제어판 전환\"", + "2 - Toggle Game Pointer Mode": "\"2 - 게임 포인터 모드 전환\"", + "3 - Toggle Pointer Lock": "\"3 - 포인터 잠금 전환\"", + "Stream Quality": "\"스트림 품질\"", + "Preset Modes:": "사전 설정 모드:", + "Static": "공전", + "Low": "낮은", + "Medium": "중간", + "High": "높은", + "Extreme": "\"극심한\"", + "Lossless": "무손실", + "Custom": "관습", + "Anti-Aliasing:": "안티 앨리어싱:", + "Auto Dynamic": "오토 다이내믹", + "Off": "끄다", + "On": "에", + "Dynamic Quality Min:": "\"최소 동적 품질:\"", + "Dynamic Quality Max:": "\"동적 품질 최대:\"", + "Treat Lossless:": "무손실 치료:", + "Frame Rate:": "\"프레임 속도:\"", + "Video JPEG Quality:": "\"비디오 JPEG 품질:\"", + "Video WEBP Quality:": "\"비디오 WEBP 품질:\"", + "Video Area:": "비디오 영역:", + "Video Time:": "비디오 시간:", + "Video Out Time:": "비디오 종료 시간:", + "Video Mode Width:": "비디오 모드 너비:", + "Video Mode Height:": "비디오 모드 높이:", + "Documentation": "선적 서류 비치", + "Drag Viewport": "드래그 뷰포트", + "KasmVNC encountered an error:": "KasmVNC에 오류가 발생했습니다:" +} \ No newline at end of file diff --git a/app/locale/ku.json b/app/locale/ku.json new file mode 100644 index 0000000..33fc6a5 --- /dev/null +++ b/app/locale/ku.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Girêdayîn...", + "Disconnecting...": "Qetkirin...", + "Reconnecting...": "Ji nû ve girêdan...", + "Internal error": "Çewtiya navxweyî", + "Must set host": "Divê mêvandar were danîn", + "Connected (encrypted) to ": "Pêwendî (şîfrekirî) bi", + "Connected (unencrypted) to ": "Pêwendî (neşîfrekirî) bi", + "Something went wrong, connection is closed": "Tiştek xelet derket, têkilî girtî ye", + "Failed to connect to server": "Girêdana bi serverê re têk çû", + "Disconnected": "Qet kirin", + "New connection has been rejected with reason: ": "Pêwendiya nû bi sedem hate red kirin:", + "New connection has been rejected": "Têkiliya nû hat redkirin", + "Credentials are required": "Peymanname hewce ne", + "Hide/Show the control bar": "Bara kontrolê veşêre/nîşan bide", + "Drag": "Xwêrvekişandin", + "Move/Drag Viewport": "Gove/Drag Viewport", + "Keyboard": "Kilawye", + "Show Keyboard": "Klavyeyê nîşan bide", + "Extra keys": "Bişkojkên Zêde", + "Show Extra Keys": "Bişkojkên Zêde Nîşan Bide", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl biguherîne", + "Alt": "Alt", + "Toggle Alt": "Alt biguherîne", + "Toggle Windows": "Windows biguherîne", + "Windows": "Windows", + "Send Tab": "Tab bişîne", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del bişîne", + "Shutdown/Reboot": "Girtin/Ji nû ve destpêkirinê", + "Shutdown/Reboot...": "Seqandin/Ji nû ve destpêkirin...", + "Power": "Erk", + "Shutdown": "Temirandin", + "Reboot": "Reboot", + "Reset": "Reset", + "Clipboard": "Clipboard", + "Clear": "Zelal", + "Fullscreen": "Temû ekran", + "Settings": "Settings", + "Shared Mode": "Moda Parvekirî", + "View Only": "Tenê Dîtin", + "Clip to Window": "Klîp berbi pencereyê", + "Scaling Mode:": "Moda Scaling:", + "None": "Netû", + "Local Scaling": "Pêkanîna Herêmî", + "Remote Resizing": "Ji Dûr Veguherandin", + "Advanced": "Pêşveçû", + "Quality:": "Çêwe:", + "Compression level:": "Asta compression:", + "Repeater ID:": "Nasnameya dubareker:", + "WebSocket": "WebSocket", + "Encrypt": "Şîfrekirin", + "Host:": "Mazûban:", + "Port:": "Bender:", + "Path:": "Şop:", + "Automatic Reconnect": "Ji nû ve girêdana otomatîk", + "Reconnect Delay (ms):": "Derengiya ji nû ve girêdanê (ms):", + "Show Dot when No Cursor": "Dema ku Kursor tunebe xalê nîşan bide", + "Logging:": "Têketin:", + "Version:": "Awa:", + "Disconnect": "Hevqetandin", + "Connect": "Bihevgirêdan", + "Username:": "Navê bikarhêner:", + "Password:": "Şîfre:", + "Send Credentials": "Send Nasname", + "Cancel": "Bişûndekirin", + "Keys": "Bişkoj", + "Game Cursor Mode": "Moda nîşankerê lîstikê", + "Press Esc Key to Exit Pointer Lock Mode": "Bişkojka Esc bikirtînin da ku hûn ji moda kilîtkirina nîşankerê derkevin", + "Game Mode paused, click on screen to resume Game Mode.": "Moda lîstikê rawestiya, li ser ekranê bikirtînin da ku moda lîstikê ji nû ve bidin destpêkirin.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Nivîsa herêmî tercîh bikin", + "Translate keyboard shortcuts": "Kurtereyên klavyeyê wergerîne", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit çalak bike", + "Enable WebP Compression": "Compression WebP çalak bike", + "Enable Performance Stats": "Amarên Performansê çalak bikin", + "Enable Pointer Lock": "Girtina nîşanê çalak bike", + "IME Input Mode": "Moda Ketina IME", + "Show Virtual Keyboard Control": "Kontrola Klavyeya Virtual nîşan bide", + "Toggle Control Panel via Keystrokes": "Panela Kontrolê bi Bişkojka Bişkojka Veguhezîne", + "Render Native Resolution": "Çareseriya xwecihî bidin", + "Keyboard Shortcuts": "Kurteyên Klavyeyê", + "Enable KasmVNC Keyboard Shortcuts": "Kurteyên Klavyeyê KasmVNC çalak bike", + "1 - Toggle Control Panel": "1 - Panela Kontrolê Biguherîne", + "2 - Toggle Game Pointer Mode": "2 - Moda Nîşana Lîstikê Biguherîne", + "3 - Toggle Pointer Lock": "3 - Girtina Nîşanê Veguherîne", + "Stream Quality": "Qalîteya Stream", + "Preset Modes:": "Modes Preset:", + "Static": "Statîk", + "Low": "Nizm", + "Medium": "Medya", + "High": "Bilind", + "Extreme": "Bêfêhm zêde", + "Lossless": "Bê windahî", + "Custom": "Hûnbunî", + "Anti-Aliasing:": "Dij-Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Ji", + "On": "Li", + "Dynamic Quality Min:": "Min Qalîteya Dînamîk:", + "Dynamic Quality Max:": "Maksê Qalîteya Dînamîk:", + "Treat Lossless:": "Bê windahî derman bikin:", + "Frame Rate:": "Rêjeya Çarçoveyê:", + "Video JPEG Quality:": "Qalîteya JPEG ya Vîdyoyê:", + "Video WEBP Quality:": "Qalîteya WEBP ya Vîdyoyê:", + "Video Area:": "Herêma Vîdyoyê:", + "Video Time:": "Dema Vîdyoyê:", + "Video Out Time:": "Dema Derketina Vîdyoyê:", + "Video Mode Width:": "Pirahiya Moda Vîdyoyê:", + "Video Mode Height:": "Bilindahiya Moda Vîdyoyê:", + "Documentation": "Belgekirin", + "Drag Viewport": "Portê Dîmenê Kaş bikin", + "KasmVNC encountered an error:": "KasmVNC rastî xeletiyek hat:" +} \ No newline at end of file diff --git a/app/locale/ku_TR.json b/app/locale/ku_TR.json new file mode 100644 index 0000000..33fc6a5 --- /dev/null +++ b/app/locale/ku_TR.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Girêdayîn...", + "Disconnecting...": "Qetkirin...", + "Reconnecting...": "Ji nû ve girêdan...", + "Internal error": "Çewtiya navxweyî", + "Must set host": "Divê mêvandar were danîn", + "Connected (encrypted) to ": "Pêwendî (şîfrekirî) bi", + "Connected (unencrypted) to ": "Pêwendî (neşîfrekirî) bi", + "Something went wrong, connection is closed": "Tiştek xelet derket, têkilî girtî ye", + "Failed to connect to server": "Girêdana bi serverê re têk çû", + "Disconnected": "Qet kirin", + "New connection has been rejected with reason: ": "Pêwendiya nû bi sedem hate red kirin:", + "New connection has been rejected": "Têkiliya nû hat redkirin", + "Credentials are required": "Peymanname hewce ne", + "Hide/Show the control bar": "Bara kontrolê veşêre/nîşan bide", + "Drag": "Xwêrvekişandin", + "Move/Drag Viewport": "Gove/Drag Viewport", + "Keyboard": "Kilawye", + "Show Keyboard": "Klavyeyê nîşan bide", + "Extra keys": "Bişkojkên Zêde", + "Show Extra Keys": "Bişkojkên Zêde Nîşan Bide", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl biguherîne", + "Alt": "Alt", + "Toggle Alt": "Alt biguherîne", + "Toggle Windows": "Windows biguherîne", + "Windows": "Windows", + "Send Tab": "Tab bişîne", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del bişîne", + "Shutdown/Reboot": "Girtin/Ji nû ve destpêkirinê", + "Shutdown/Reboot...": "Seqandin/Ji nû ve destpêkirin...", + "Power": "Erk", + "Shutdown": "Temirandin", + "Reboot": "Reboot", + "Reset": "Reset", + "Clipboard": "Clipboard", + "Clear": "Zelal", + "Fullscreen": "Temû ekran", + "Settings": "Settings", + "Shared Mode": "Moda Parvekirî", + "View Only": "Tenê Dîtin", + "Clip to Window": "Klîp berbi pencereyê", + "Scaling Mode:": "Moda Scaling:", + "None": "Netû", + "Local Scaling": "Pêkanîna Herêmî", + "Remote Resizing": "Ji Dûr Veguherandin", + "Advanced": "Pêşveçû", + "Quality:": "Çêwe:", + "Compression level:": "Asta compression:", + "Repeater ID:": "Nasnameya dubareker:", + "WebSocket": "WebSocket", + "Encrypt": "Şîfrekirin", + "Host:": "Mazûban:", + "Port:": "Bender:", + "Path:": "Şop:", + "Automatic Reconnect": "Ji nû ve girêdana otomatîk", + "Reconnect Delay (ms):": "Derengiya ji nû ve girêdanê (ms):", + "Show Dot when No Cursor": "Dema ku Kursor tunebe xalê nîşan bide", + "Logging:": "Têketin:", + "Version:": "Awa:", + "Disconnect": "Hevqetandin", + "Connect": "Bihevgirêdan", + "Username:": "Navê bikarhêner:", + "Password:": "Şîfre:", + "Send Credentials": "Send Nasname", + "Cancel": "Bişûndekirin", + "Keys": "Bişkoj", + "Game Cursor Mode": "Moda nîşankerê lîstikê", + "Press Esc Key to Exit Pointer Lock Mode": "Bişkojka Esc bikirtînin da ku hûn ji moda kilîtkirina nîşankerê derkevin", + "Game Mode paused, click on screen to resume Game Mode.": "Moda lîstikê rawestiya, li ser ekranê bikirtînin da ku moda lîstikê ji nû ve bidin destpêkirin.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Nivîsa herêmî tercîh bikin", + "Translate keyboard shortcuts": "Kurtereyên klavyeyê wergerîne", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit çalak bike", + "Enable WebP Compression": "Compression WebP çalak bike", + "Enable Performance Stats": "Amarên Performansê çalak bikin", + "Enable Pointer Lock": "Girtina nîşanê çalak bike", + "IME Input Mode": "Moda Ketina IME", + "Show Virtual Keyboard Control": "Kontrola Klavyeya Virtual nîşan bide", + "Toggle Control Panel via Keystrokes": "Panela Kontrolê bi Bişkojka Bişkojka Veguhezîne", + "Render Native Resolution": "Çareseriya xwecihî bidin", + "Keyboard Shortcuts": "Kurteyên Klavyeyê", + "Enable KasmVNC Keyboard Shortcuts": "Kurteyên Klavyeyê KasmVNC çalak bike", + "1 - Toggle Control Panel": "1 - Panela Kontrolê Biguherîne", + "2 - Toggle Game Pointer Mode": "2 - Moda Nîşana Lîstikê Biguherîne", + "3 - Toggle Pointer Lock": "3 - Girtina Nîşanê Veguherîne", + "Stream Quality": "Qalîteya Stream", + "Preset Modes:": "Modes Preset:", + "Static": "Statîk", + "Low": "Nizm", + "Medium": "Medya", + "High": "Bilind", + "Extreme": "Bêfêhm zêde", + "Lossless": "Bê windahî", + "Custom": "Hûnbunî", + "Anti-Aliasing:": "Dij-Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Ji", + "On": "Li", + "Dynamic Quality Min:": "Min Qalîteya Dînamîk:", + "Dynamic Quality Max:": "Maksê Qalîteya Dînamîk:", + "Treat Lossless:": "Bê windahî derman bikin:", + "Frame Rate:": "Rêjeya Çarçoveyê:", + "Video JPEG Quality:": "Qalîteya JPEG ya Vîdyoyê:", + "Video WEBP Quality:": "Qalîteya WEBP ya Vîdyoyê:", + "Video Area:": "Herêma Vîdyoyê:", + "Video Time:": "Dema Vîdyoyê:", + "Video Out Time:": "Dema Derketina Vîdyoyê:", + "Video Mode Width:": "Pirahiya Moda Vîdyoyê:", + "Video Mode Height:": "Bilindahiya Moda Vîdyoyê:", + "Documentation": "Belgekirin", + "Drag Viewport": "Portê Dîmenê Kaş bikin", + "KasmVNC encountered an error:": "KasmVNC rastî xeletiyek hat:" +} \ No newline at end of file diff --git a/app/locale/ky.json b/app/locale/ky.json new file mode 100644 index 0000000..4869ec6 --- /dev/null +++ b/app/locale/ky.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Туташтырылууда...", + "Disconnecting...": "Ажыратууда...", + "Reconnecting...": "Кайра туташуу...", + "Internal error": "Ички ката", + "Must set host": "Хостту орнотуу керек", + "Connected (encrypted) to ": "Туташкан (шифрленген)", + "Connected (unencrypted) to ": "Туташкан (шифрленбеген)", + "Something went wrong, connection is closed": "Бир жерден ката кетти, байланыш жабылды", + "Failed to connect to server": "Серверге туташпай калды", + "Disconnected": "Ажыратылды", + "New connection has been rejected with reason: ": "Жаңы байланыш себеп менен четке кагылды:", + "New connection has been rejected": "Жаңы байланыш четке кагылды", + "Credentials are required": "Ишенимдүү маалымат талап кылынат", + "Hide/Show the control bar": "Башкаруу тилкесин жашыруу/көрсөтүү", + "Drag": "Сүрөө", + "Move/Drag Viewport": "Көрүү портун жылдыруу/сүйрөө", + "Keyboard": "Клавиатура", + "Show Keyboard": "Клавиатураны көрсөтүү", + "Extra keys": "Кошумча ачкычтар", + "Show Extra Keys": "Кошумча ачкычтарды көрсөтүү", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Которуу/күйгүзүү Ctrl", + "Alt": "Alt", + "Toggle Alt": "Alt-күйгүзүү", + "Toggle Windows": "Windows которуштуруу", + "Windows": "Windows", + "Send Tab": "Өтмөктү жөнөтүү", + "Tab": "Өтмөк", + "Esc": "Esc", + "Send Escape": "Качуу жөнөтүү", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del жөнөтүү", + "Shutdown/Reboot": "Өчүрүү/кайра жүктөө", + "Shutdown/Reboot...": "Өчүрүү/кайра жүктөө...", + "Power": "Күч", + "Shutdown": "Өчүрүү", + "Reboot": "Кайра жүктөө", + "Reset": "Калыбына келтирүү", + "Clipboard": "Алмашуу буфери", + "Clear": "Таза", + "Fullscreen": "Толук экран", + "Settings": "Орнотуулар", + "Shared Mode": "Бөлүшүлгөн режим", + "View Only": "Көрүү гана", + "Clip to Window": "Клиптен терезеге", + "Scaling Mode:": "Масштабтоо режими:", + "None": "Жок", + "Local Scaling": "Жергиликтүү масштабдоо", + "Remote Resizing": "Алыстан өлчөмдү өзгөртүү", + "Advanced": "Өркүндөтүлгөн", + "Quality:": "Сапат:", + "Compression level:": "Кысуу деңгээли:", + "Repeater ID:": "Кайталоочу ID:", + "WebSocket": "WebSocket", + "Encrypt": "Шифрлөө", + "Host:": "Алып баруучу:", + "Port:": "Порт:", + "Path:": "Жол:", + "Automatic Reconnect": "Автоматтык кайра туташуу", + "Reconnect Delay (ms):": "Кайра туташуу кечигүү (мс):", + "Show Dot when No Cursor": "Курсор жок болгондо чекитти көрсөтүү", + "Logging:": "Жургузуу:", + "Version:": "Версия:", + "Disconnect": "Ажырат", + "Connect": "Байланыш", + "Username:": "Колдонуучунун аты:", + "Password:": "Купуя сөз:", + "Send Credentials": "Ишенимдүү маалыматтарды жөнөтүү", + "Cancel": "Жокко чыгаруу", + "Keys": "Ачкычтар", + "Game Cursor Mode": "Оюн курсор режими", + "Press Esc Key to Exit Pointer Lock Mode": " Көрсөткүчтү бөгөттөө режиминен чыгуу үчүн Esc баскычын басыңыз", + "Game Mode paused, click on screen to resume Game Mode.": "Оюн режими тындырылды, оюн режимин улантуу үчүн экранды басыңыз.", + "Clipboard Up": "Алмашуу буфери", + "CLipboard Down": "Алмашуу буфери", + "Clipboard Seamless": "Алмашуу буфери кемчиликсиз", + "Prefer Local Cursor": "Жергиликтүү курсорго артыкчылык берүү", + "Translate keyboard shortcuts": "Клавиатура тез жолдорун которуу", + "Enable WebRTC UDP Transit": "WebRTC UDP транзитин иштетүү", + "Enable WebP Compression": "WebP кысуусун иштетүү", + "Enable Performance Stats": "Аткаруу статистикасын иштетүү", + "Enable Pointer Lock": "Көрсөткүч кулпусун иштетүү", + "IME Input Mode": "IME киргизүү режими", + "Show Virtual Keyboard Control": "Виртуалдык баскычтопту башкарууну көрсөтүү", + "Toggle Control Panel via Keystrokes": "Баскыруу панелин баскычтар аркылуу которуу", + "Render Native Resolution": "Түпкү резолюцияны көрсөтүү", + "Keyboard Shortcuts": "Клавиатуранын жарлыктары", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC баскычтопту иштетүү", + "1 - Toggle Control Panel": "1 - Башкаруу панелин которуу", + "2 - Toggle Game Pointer Mode": "2 - Оюн көрсөткүчү режимин которуштуруу", + "3 - Toggle Pointer Lock": "3 - Көрсөткүч кулпусун которуштуруу", + "Stream Quality": "Агымдын сапаты", + "Preset Modes:": "Алдын ала коюлган режимдер:", + "Static": "Статикалык", + "Low": "Төмөн", + "Medium": "Орто", + "High": "Жогорку", + "Extreme": "Экстремалдуу", + "Lossless": "Жоготуусуз", + "Custom": "Бажы", + "Anti-Aliasing:": "Анти-алясинг:", + "Auto Dynamic": "Авто динамикалык", + "Off": "Өчүк", + "On": "Күйүк", + "Dynamic Quality Min:": "Динамикалык сапат Минималдуу:", + "Dynamic Quality Max:": "Динамикалык сапат Макс:", + "Treat Lossless:": "Жоготуусуз мамиле кылуу:", + "Frame Rate:": "Кадр жыштыгы:", + "Video JPEG Quality:": "Video JPEG сапаты:", + "Video WEBP Quality:": "Видео WEBP сапаты:", + "Video Area:": "Видео аймагы:", + "Video Time:": "Видео убактысы:", + "Video Out Time:": "Видео чыгуу убактысы:", + "Video Mode Width:": "Видео режиминин туурасы:", + "Video Mode Height:": "Видео режиминин бийиктиги:", + "Documentation": "Документтер", + "Drag Viewport": "Көрүү портун сүйрөө", + "KasmVNC encountered an error:": "KasmVNC катага туш болду:" +} \ No newline at end of file diff --git a/app/locale/ky_KG.json b/app/locale/ky_KG.json new file mode 100644 index 0000000..4869ec6 --- /dev/null +++ b/app/locale/ky_KG.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Туташтырылууда...", + "Disconnecting...": "Ажыратууда...", + "Reconnecting...": "Кайра туташуу...", + "Internal error": "Ички ката", + "Must set host": "Хостту орнотуу керек", + "Connected (encrypted) to ": "Туташкан (шифрленген)", + "Connected (unencrypted) to ": "Туташкан (шифрленбеген)", + "Something went wrong, connection is closed": "Бир жерден ката кетти, байланыш жабылды", + "Failed to connect to server": "Серверге туташпай калды", + "Disconnected": "Ажыратылды", + "New connection has been rejected with reason: ": "Жаңы байланыш себеп менен четке кагылды:", + "New connection has been rejected": "Жаңы байланыш четке кагылды", + "Credentials are required": "Ишенимдүү маалымат талап кылынат", + "Hide/Show the control bar": "Башкаруу тилкесин жашыруу/көрсөтүү", + "Drag": "Сүрөө", + "Move/Drag Viewport": "Көрүү портун жылдыруу/сүйрөө", + "Keyboard": "Клавиатура", + "Show Keyboard": "Клавиатураны көрсөтүү", + "Extra keys": "Кошумча ачкычтар", + "Show Extra Keys": "Кошумча ачкычтарды көрсөтүү", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Которуу/күйгүзүү Ctrl", + "Alt": "Alt", + "Toggle Alt": "Alt-күйгүзүү", + "Toggle Windows": "Windows которуштуруу", + "Windows": "Windows", + "Send Tab": "Өтмөктү жөнөтүү", + "Tab": "Өтмөк", + "Esc": "Esc", + "Send Escape": "Качуу жөнөтүү", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del жөнөтүү", + "Shutdown/Reboot": "Өчүрүү/кайра жүктөө", + "Shutdown/Reboot...": "Өчүрүү/кайра жүктөө...", + "Power": "Күч", + "Shutdown": "Өчүрүү", + "Reboot": "Кайра жүктөө", + "Reset": "Калыбына келтирүү", + "Clipboard": "Алмашуу буфери", + "Clear": "Таза", + "Fullscreen": "Толук экран", + "Settings": "Орнотуулар", + "Shared Mode": "Бөлүшүлгөн режим", + "View Only": "Көрүү гана", + "Clip to Window": "Клиптен терезеге", + "Scaling Mode:": "Масштабтоо режими:", + "None": "Жок", + "Local Scaling": "Жергиликтүү масштабдоо", + "Remote Resizing": "Алыстан өлчөмдү өзгөртүү", + "Advanced": "Өркүндөтүлгөн", + "Quality:": "Сапат:", + "Compression level:": "Кысуу деңгээли:", + "Repeater ID:": "Кайталоочу ID:", + "WebSocket": "WebSocket", + "Encrypt": "Шифрлөө", + "Host:": "Алып баруучу:", + "Port:": "Порт:", + "Path:": "Жол:", + "Automatic Reconnect": "Автоматтык кайра туташуу", + "Reconnect Delay (ms):": "Кайра туташуу кечигүү (мс):", + "Show Dot when No Cursor": "Курсор жок болгондо чекитти көрсөтүү", + "Logging:": "Жургузуу:", + "Version:": "Версия:", + "Disconnect": "Ажырат", + "Connect": "Байланыш", + "Username:": "Колдонуучунун аты:", + "Password:": "Купуя сөз:", + "Send Credentials": "Ишенимдүү маалыматтарды жөнөтүү", + "Cancel": "Жокко чыгаруу", + "Keys": "Ачкычтар", + "Game Cursor Mode": "Оюн курсор режими", + "Press Esc Key to Exit Pointer Lock Mode": " Көрсөткүчтү бөгөттөө режиминен чыгуу үчүн Esc баскычын басыңыз", + "Game Mode paused, click on screen to resume Game Mode.": "Оюн режими тындырылды, оюн режимин улантуу үчүн экранды басыңыз.", + "Clipboard Up": "Алмашуу буфери", + "CLipboard Down": "Алмашуу буфери", + "Clipboard Seamless": "Алмашуу буфери кемчиликсиз", + "Prefer Local Cursor": "Жергиликтүү курсорго артыкчылык берүү", + "Translate keyboard shortcuts": "Клавиатура тез жолдорун которуу", + "Enable WebRTC UDP Transit": "WebRTC UDP транзитин иштетүү", + "Enable WebP Compression": "WebP кысуусун иштетүү", + "Enable Performance Stats": "Аткаруу статистикасын иштетүү", + "Enable Pointer Lock": "Көрсөткүч кулпусун иштетүү", + "IME Input Mode": "IME киргизүү режими", + "Show Virtual Keyboard Control": "Виртуалдык баскычтопту башкарууну көрсөтүү", + "Toggle Control Panel via Keystrokes": "Баскыруу панелин баскычтар аркылуу которуу", + "Render Native Resolution": "Түпкү резолюцияны көрсөтүү", + "Keyboard Shortcuts": "Клавиатуранын жарлыктары", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC баскычтопту иштетүү", + "1 - Toggle Control Panel": "1 - Башкаруу панелин которуу", + "2 - Toggle Game Pointer Mode": "2 - Оюн көрсөткүчү режимин которуштуруу", + "3 - Toggle Pointer Lock": "3 - Көрсөткүч кулпусун которуштуруу", + "Stream Quality": "Агымдын сапаты", + "Preset Modes:": "Алдын ала коюлган режимдер:", + "Static": "Статикалык", + "Low": "Төмөн", + "Medium": "Орто", + "High": "Жогорку", + "Extreme": "Экстремалдуу", + "Lossless": "Жоготуусуз", + "Custom": "Бажы", + "Anti-Aliasing:": "Анти-алясинг:", + "Auto Dynamic": "Авто динамикалык", + "Off": "Өчүк", + "On": "Күйүк", + "Dynamic Quality Min:": "Динамикалык сапат Минималдуу:", + "Dynamic Quality Max:": "Динамикалык сапат Макс:", + "Treat Lossless:": "Жоготуусуз мамиле кылуу:", + "Frame Rate:": "Кадр жыштыгы:", + "Video JPEG Quality:": "Video JPEG сапаты:", + "Video WEBP Quality:": "Видео WEBP сапаты:", + "Video Area:": "Видео аймагы:", + "Video Time:": "Видео убактысы:", + "Video Out Time:": "Видео чыгуу убактысы:", + "Video Mode Width:": "Видео режиминин туурасы:", + "Video Mode Height:": "Видео режиминин бийиктиги:", + "Documentation": "Документтер", + "Drag Viewport": "Көрүү портун сүйрөө", + "KasmVNC encountered an error:": "KasmVNC катага туш болду:" +} \ No newline at end of file diff --git a/app/locale/lb.json b/app/locale/lb.json new file mode 100644 index 0000000..0a22a8c --- /dev/null +++ b/app/locale/lb.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Verbindung ...", + "Disconnecting...": "Trennen ...", + "Reconnecting...": "Reconnectéieren ...", + "Internal error": "Interne Feeler", + "Must set host": "Muss Host setzen", + "Connected (encrypted) to ": "Verbonne (verschlësselt) op ", + "Connected (unencrypted) to ": "Verbonne (net verschlësselte) op ", + "Something went wrong, connection is closed": "Eppes ass falsch gaang, d'Verbindung ass zou", + "Failed to connect to server": "Konnt mam Server net konnektéieren", + "Disconnected": "Ofgekoppelt", + "New connection has been rejected with reason: ": "Nei Verbindung gouf mat Grond refuséiert:", + "New connection has been rejected": "Nei Verbindung gouf refuséiert", + "Credentials are required": "Umeldungsinformatiounen sinn erfuerderlech", + "Hide/Show the control bar": "D'Kontrollbar verstoppen / weisen", + "Drag": "Drag", + "Move/Drag Viewport": "Move / Drag Viewport", + "Keyboard": "Tastatur", + "Show Keyboard": "Tastatur weisen", + "Extra keys": "Extra Schlësselen", + "Show Extra Keys": "Weis Extra Keys", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl wiesselen", + "Alt": "Alt", + "Toggle Alt": "Alt wiesselen", + "Toggle Windows": "Windows wiesselen", + "Windows": "Windows", + "Send Tab": "Send Tab", + "Tab": "Tab", + "Esc": "Esch", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Schécken Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown / Restart", + "Shutdown/Reboot...": "Shutdown/Restart...", + "Power": "Muecht", + "Shutdown": "Ausmaachen", + "Reboot": "Neistarten", + "Reset": "Reset", + "Clipboard": "Clipboard", + "Clear": "Kloer", + "Fullscreen": "Vollscreen", + "Settings": "Astellungen", + "Shared Mode": "Gedeelt Modus", + "View Only": "Nëmmen kucken", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Scaling Mode:", + "None": "Keen", + "Local Scaling": "Lokal Skaléieren", + "Remote Resizing": "Remote Resizing", + "Advanced": "Fortgeschratt", + "Quality:": "Qualitéit:", + "Compression level:": "Kompressiounsniveau:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Verschlësselung", + "Host:": "Host:", + "Port:": "Port:", + "Path:": "Wee:", + "Automatic Reconnect": "Automatesch Reconnect", + "Reconnect Delay (ms):": "Reconnect Delay (ms):", + "Show Dot when No Cursor": "Show Punkt wann kee Cursor", + "Logging:": "Logéieren:", + "Version:": "Versioun:", + "Disconnect": "Disconnect", + "Connect": "Connect", + "Username:": "Benotzernumm:", + "Password:": "Passwuert:", + "Send Credentials": "Schéckt Umeldungsinformatiounen", + "Cancel": "Ofbriechen", + "Keys": "Schlësselen", + "Game Cursor Mode": "Spill Cursor Modus", + "Press Esc Key to Exit Pointer Lock Mode": "Dréckt Esc Schlëssel fir de Pointer Lock Mode ze verloossen", + "Game Mode paused, click on screen to resume Game Mode.": "Spillmodus pauséiert, klickt op Écran fir de Spillmodus erëmzefannen.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Lokal Cursor léiwer", + "Translate keyboard shortcuts": "Tastatur Ofkiirzungen iwwersetzen", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit aktivéieren", + "Enable WebP Compression": "Enable WebP Compression", + "Enable Performance Stats": "Leeschtungsstatistik aktivéieren", + "Enable Pointer Lock": "Enable Pointer Lock", + "IME Input Mode": "IME Input Modus", + "Show Virtual Keyboard Control": "Show Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "Kontrollpanel iwwer Tastatur wiesselen", + "Render Native Resolution": "Rend Native Resolution", + "Keyboard Shortcuts": "Tastatur Ofkiirzungen", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC Tastatur Ofkiirzungen aktivéieren", + "1 - Toggle Control Panel": "1 - Toggle Control Panel", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Stream Qualitéit", + "Preset Modes:": "Preset Modi:", + "Static": "Statesch", + "Low": "Niddereg", + "Medium": "Mëttel", + "High": "Héich", + "Extreme": "Extrem", + "Lossless": "Lossless", + "Custom": "Custom", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Off", + "On": "op", + "Dynamic Quality Min:": "Dynamic Qualitéit Min:", + "Dynamic Quality Max:": "Dynamic Qualitéit Max:", + "Treat Lossless:": "Behandelt Lossless:", + "Frame Rate:": "Frame Rate:", + "Video JPEG Quality:": "Video JPEG Qualitéit:", + "Video WEBP Quality:": "Video WEBP Qualitéit:", + "Video Area:": "Video Beräich:", + "Video Time:": "Video Zäit:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Video Modus Breet:", + "Video Mode Height:": "Video Modus Héicht:", + "Documentation": "Dokumentatioun", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "KasmVNC huet e Feeler begéint:" +} \ No newline at end of file diff --git a/app/locale/lb_LU.json b/app/locale/lb_LU.json new file mode 100644 index 0000000..0a22a8c --- /dev/null +++ b/app/locale/lb_LU.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Verbindung ...", + "Disconnecting...": "Trennen ...", + "Reconnecting...": "Reconnectéieren ...", + "Internal error": "Interne Feeler", + "Must set host": "Muss Host setzen", + "Connected (encrypted) to ": "Verbonne (verschlësselt) op ", + "Connected (unencrypted) to ": "Verbonne (net verschlësselte) op ", + "Something went wrong, connection is closed": "Eppes ass falsch gaang, d'Verbindung ass zou", + "Failed to connect to server": "Konnt mam Server net konnektéieren", + "Disconnected": "Ofgekoppelt", + "New connection has been rejected with reason: ": "Nei Verbindung gouf mat Grond refuséiert:", + "New connection has been rejected": "Nei Verbindung gouf refuséiert", + "Credentials are required": "Umeldungsinformatiounen sinn erfuerderlech", + "Hide/Show the control bar": "D'Kontrollbar verstoppen / weisen", + "Drag": "Drag", + "Move/Drag Viewport": "Move / Drag Viewport", + "Keyboard": "Tastatur", + "Show Keyboard": "Tastatur weisen", + "Extra keys": "Extra Schlësselen", + "Show Extra Keys": "Weis Extra Keys", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl wiesselen", + "Alt": "Alt", + "Toggle Alt": "Alt wiesselen", + "Toggle Windows": "Windows wiesselen", + "Windows": "Windows", + "Send Tab": "Send Tab", + "Tab": "Tab", + "Esc": "Esch", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Schécken Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown / Restart", + "Shutdown/Reboot...": "Shutdown/Restart...", + "Power": "Muecht", + "Shutdown": "Ausmaachen", + "Reboot": "Neistarten", + "Reset": "Reset", + "Clipboard": "Clipboard", + "Clear": "Kloer", + "Fullscreen": "Vollscreen", + "Settings": "Astellungen", + "Shared Mode": "Gedeelt Modus", + "View Only": "Nëmmen kucken", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Scaling Mode:", + "None": "Keen", + "Local Scaling": "Lokal Skaléieren", + "Remote Resizing": "Remote Resizing", + "Advanced": "Fortgeschratt", + "Quality:": "Qualitéit:", + "Compression level:": "Kompressiounsniveau:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Verschlësselung", + "Host:": "Host:", + "Port:": "Port:", + "Path:": "Wee:", + "Automatic Reconnect": "Automatesch Reconnect", + "Reconnect Delay (ms):": "Reconnect Delay (ms):", + "Show Dot when No Cursor": "Show Punkt wann kee Cursor", + "Logging:": "Logéieren:", + "Version:": "Versioun:", + "Disconnect": "Disconnect", + "Connect": "Connect", + "Username:": "Benotzernumm:", + "Password:": "Passwuert:", + "Send Credentials": "Schéckt Umeldungsinformatiounen", + "Cancel": "Ofbriechen", + "Keys": "Schlësselen", + "Game Cursor Mode": "Spill Cursor Modus", + "Press Esc Key to Exit Pointer Lock Mode": "Dréckt Esc Schlëssel fir de Pointer Lock Mode ze verloossen", + "Game Mode paused, click on screen to resume Game Mode.": "Spillmodus pauséiert, klickt op Écran fir de Spillmodus erëmzefannen.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Lokal Cursor léiwer", + "Translate keyboard shortcuts": "Tastatur Ofkiirzungen iwwersetzen", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit aktivéieren", + "Enable WebP Compression": "Enable WebP Compression", + "Enable Performance Stats": "Leeschtungsstatistik aktivéieren", + "Enable Pointer Lock": "Enable Pointer Lock", + "IME Input Mode": "IME Input Modus", + "Show Virtual Keyboard Control": "Show Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "Kontrollpanel iwwer Tastatur wiesselen", + "Render Native Resolution": "Rend Native Resolution", + "Keyboard Shortcuts": "Tastatur Ofkiirzungen", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC Tastatur Ofkiirzungen aktivéieren", + "1 - Toggle Control Panel": "1 - Toggle Control Panel", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Stream Qualitéit", + "Preset Modes:": "Preset Modi:", + "Static": "Statesch", + "Low": "Niddereg", + "Medium": "Mëttel", + "High": "Héich", + "Extreme": "Extrem", + "Lossless": "Lossless", + "Custom": "Custom", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Off", + "On": "op", + "Dynamic Quality Min:": "Dynamic Qualitéit Min:", + "Dynamic Quality Max:": "Dynamic Qualitéit Max:", + "Treat Lossless:": "Behandelt Lossless:", + "Frame Rate:": "Frame Rate:", + "Video JPEG Quality:": "Video JPEG Qualitéit:", + "Video WEBP Quality:": "Video WEBP Qualitéit:", + "Video Area:": "Video Beräich:", + "Video Time:": "Video Zäit:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Video Modus Breet:", + "Video Mode Height:": "Video Modus Héicht:", + "Documentation": "Dokumentatioun", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "KasmVNC huet e Feeler begéint:" +} \ No newline at end of file diff --git a/app/locale/lo.json b/app/locale/lo.json new file mode 100644 index 0000000..3cb256b --- /dev/null +++ b/app/locale/lo.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ກຳລັງເຊື່ອມຕໍ່...", + "Disconnecting...": "ກຳລັງຕັດການເຊື່ອມຕໍ່...", + "Reconnecting...": "ກຳລັງເຊື່ອມຕໍ່ຄືນໃໝ່...", + "Internal error": "ຄວາມຜິດພາດພາຍໃນ", + "Must set host": "ຕ້ອງຕັ້ງເຈົ້າພາບ", + "Connected (encrypted) to ": "ເຊື່ອມຕໍ່ (ເຂົ້າລະຫັດ) ກັບ", + "Connected (unencrypted) to ": "ເຊື່ອມຕໍ່ (ບໍ່ໄດ້ເຂົ້າລະຫັດ) ກັບ", + "Something went wrong, connection is closed": "ມີບາງຢ່າງຜິດພາດ, ການເຊື່ອມຕໍ່ຖືກປິດ", + "Failed to connect to server": "ເຊື່ອມຕໍ່ກັບເຊີບເວີບໍ່ສຳເລັດ", + "Disconnected": "ຕັດການເຊື່ອມຕໍ່", + "New connection has been rejected with reason: ": "ການເຊື່ອມຕໍ່ໃຫມ່ໄດ້ຖືກປະຕິເສດດ້ວຍເຫດຜົນ:", + "New connection has been rejected": "ການເຊື່ອມຕໍ່ໃຫມ່ໄດ້ຖືກປະຕິເສດ", + "Credentials are required": "ຕ້ອງການຂໍ້ມູນປະຈໍາຕົວ", + "Hide/Show the control bar": "ເຊື່ອງ/ສະແດງແຖບຄວບຄຸມ", + "Drag": "ລາກ", + "Move/Drag Viewport": "ຍ້າຍ/ລາກ Viewport", + "Keyboard": "ແປ້ນພິມ", + "Show Keyboard": "ສະແດງແປ້ນພິມ", + "Extra keys": "ກະແຈພິເສດ", + "Show Extra Keys": "ສະແດງລະຫັດພິເສດ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "ສະຫຼັບ Ctrl", + "Alt": "Alt", + "Toggle Alt": "ສະຫຼັບ Alt", + "Toggle Windows": "ສະຫຼັບ Windows", + "Windows": "Windows", + "Send Tab": "ສົ່ງແຖບ", + "Tab": "ແຖບ", + "Esc": "Esc", + "Send Escape": "ສົ່ງຫນີ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "ສົ່ງ Ctrl-Alt-Del", + "Shutdown/Reboot": "ປິດ/ປິດເປີດໃໝ່", + "Shutdown/Reboot...": "ປິດ/ປິດເປີດໃໝ່...", + "Power": "ພະລັງງານ", + "Shutdown": "ປິດເຄື່ອງ", + "Reboot": "ປິດເປີດໃໝ່", + "Reset": "ຣີເຊັດ", + "Clipboard": "ຄລິບບອດ", + "Clear": "ຈະແຈ້ງ", + "Fullscreen": "ເຕັມຈໍ", + "Settings": "ການຕັ້ງຄ່າ", + "Shared Mode": "ຮູບແບບທີ່ແບ່ງປັນ", + "View Only": "ເບິ່ງເທົ່ານັ້ນ", + "Clip to Window": "ຄລິບໃສ່ປ່ອງຢ້ຽມ", + "Scaling Mode:": "ຮູບແບບການປັບຂະຫນາດ:", + "None": "ບໍ່ມີ", + "Local Scaling": "ການຂະຫຍາຍທ້ອງຖິ່ນ", + "Remote Resizing": "ການປັບຂະຫນາດໄລຍະໄກ", + "Advanced": "ຂັ້ນສູງ", + "Quality:": "ຄຸນນະພາບ:", + "Compression level:": "ລະດັບການບີບອັດ:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "ເຂົ້າລະຫັດ", + "Host:": "ເຈົ້າພາບ:", + "Port:": "ພອດ:", + "Path:": "ເສັ້ນທາງ:", + "Automatic Reconnect": "ເຊື່ອມຕໍ່ອັດຕະໂນມັດ", + "Reconnect Delay (ms):": "ເຊື່ອມຕໍ່ຄືນໃໝ່ການຊັກຊ້າ (ms):", + "Show Dot when No Cursor": "ສະແດງຈຸດໃນເວລາທີ່ບໍ່ມີຕົວກະພິບ", + "Logging:": "ບັນທຶກ:", + "Version:": "ຮຸ່ນ:", + "Disconnect": "ຕັດການເຊື່ອມຕໍ່", + "Connect": "ເຊື່ອມຕໍ່", + "Username:": "ຊື່ຜູ້ໃຊ້:", + "Password:": "ລະຫັດຜ່ານ:", + "Send Credentials": "ສົ່ງຂໍ້ມູນປະຈໍາຕົວ", + "Cancel": "ຍົກເລີກ", + "Keys": "ກະແຈ", + "Game Cursor Mode": "ຮູບແບບຕົວກະພິບເກມ", + "Press Esc Key to Exit Pointer Lock Mode": "ກົດປຸ່ມ Esc ເພື່ອອອກຈາກໂຫມດລັອກຕົວຊີ້", + "Game Mode paused, click on screen to resume Game Mode.": "ໂໝດເກມຢຸດຊົ່ວຄາວ, ຄລິກທີ່ໜ້າຈໍເພື່ອສືບຕໍ່ໂໝດເກມ.", + "Clipboard Up": "ຄລິບບອດຂຶ້ນ", + "CLipboard Down": "ຄລິບບອດລົງ", + "Clipboard Seamless": "ຄລິບບອດບໍ່ມີຮອຍຕໍ່", + "Prefer Local Cursor": "ຕ້ອງການຕົວກະພິບທ້ອງຖິ່ນ", + "Translate keyboard shortcuts": "ແປແປ້ນພິມລັດ", + "Enable WebRTC UDP Transit": "ເປີດໃຊ້ WebRTC UDP Transit", + "Enable WebP Compression": "ເປີດໃຊ້ WebP Compression", + "Enable Performance Stats": "ເປີດໃຊ້ສະຖິຕິການປະຕິບັດ", + "Enable Pointer Lock": "ເປີດໃຊ້ການລັອກຕົວຊີ້", + "IME Input Mode": "ຮູບແບບການປ້ອນຂໍ້ມູນ IME", + "Show Virtual Keyboard Control": "ສະແດງການຄວບຄຸມແປ້ນພິມສະເໝືອນ", + "Toggle Control Panel via Keystrokes": "ສະຫຼັບແຜງຄວບຄຸມດ້ວຍການກົດແປ້ນພິມ", + "Render Native Resolution": "ສະແດງຄວາມລະອຽດເດີມ", + "Keyboard Shortcuts": "ທາງລັດແປ້ນພິມ", + "Enable KasmVNC Keyboard Shortcuts": "ເປີດໃຊ້ປຸ່ມລັດ KasmVNC", + "1 - Toggle Control Panel": "1 - ສະຫຼັບແຜງຄວບຄຸມ", + "2 - Toggle Game Pointer Mode": "2 - ສະຫຼັບໂໝດຕົວຊີ້ເກມ", + "3 - Toggle Pointer Lock": "3 - ສະຫຼັບຕົວຊີ້ຕົວຊີ້", + "Stream Quality": "ຄຸນນະພາບການຖ່າຍທອດ", + "Preset Modes:": "ໂໝດທີ່ຕັ້ງໄວ້ລ່ວງໜ້າ:", + "Static": "ຄົງທີ່", + "Low": "ຕໍ່າ", + "Medium": "ຂະຫນາດກາງ", + "High": "ສູງ", + "Extreme": "ທີ່ສຸດ", + "Lossless": "ສູນເສຍ", + "Custom": "ກຳນົດເອງ", + "Anti-Aliasing:": "ການຕ້ານການນາມແຝງ:", + "Auto Dynamic": "ໄດນາມິກອັດຕະໂນມັດ", + "Off": "ປິດ", + "On": "ເປີດ", + "Dynamic Quality Min:": "ຄຸນະພາບຕ່ຳສຸດແບບໄດນາມິກ:", + "Dynamic Quality Max:": "ຄຸນນະພາບສູງສຸດແບບໄດນາມິກ:", + "Treat Lossless:": "ຮັກສາການສູນເສຍ:", + "Frame Rate:": "ອັດຕາກອບ:", + "Video JPEG Quality:": "ຄຸນນະພາບ JPEG ວິດີໂອ:", + "Video WEBP Quality:": "ວິດີໂອຄຸນນະພາບ WEBP:", + "Video Area:": "ພື້ນທີ່ວິດີໂອ:", + "Video Time:": "ເວລາວິດີໂອ:", + "Video Out Time:": "ເວລາອອກວິດີໂອ:", + "Video Mode Width:": "ຄວາມກວ້າງຂອງໂໝດວິດີໂອ:", + "Video Mode Height:": "ຄວາມສູງຂອງໂໝດວິດີໂອ:", + "Documentation": "ເອກະສານ", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "KasmVNC ພົບຂໍ້ຜິດພາດ:" +} \ No newline at end of file diff --git a/app/locale/lo_LA.json b/app/locale/lo_LA.json new file mode 100644 index 0000000..3cb256b --- /dev/null +++ b/app/locale/lo_LA.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ກຳລັງເຊື່ອມຕໍ່...", + "Disconnecting...": "ກຳລັງຕັດການເຊື່ອມຕໍ່...", + "Reconnecting...": "ກຳລັງເຊື່ອມຕໍ່ຄືນໃໝ່...", + "Internal error": "ຄວາມຜິດພາດພາຍໃນ", + "Must set host": "ຕ້ອງຕັ້ງເຈົ້າພາບ", + "Connected (encrypted) to ": "ເຊື່ອມຕໍ່ (ເຂົ້າລະຫັດ) ກັບ", + "Connected (unencrypted) to ": "ເຊື່ອມຕໍ່ (ບໍ່ໄດ້ເຂົ້າລະຫັດ) ກັບ", + "Something went wrong, connection is closed": "ມີບາງຢ່າງຜິດພາດ, ການເຊື່ອມຕໍ່ຖືກປິດ", + "Failed to connect to server": "ເຊື່ອມຕໍ່ກັບເຊີບເວີບໍ່ສຳເລັດ", + "Disconnected": "ຕັດການເຊື່ອມຕໍ່", + "New connection has been rejected with reason: ": "ການເຊື່ອມຕໍ່ໃຫມ່ໄດ້ຖືກປະຕິເສດດ້ວຍເຫດຜົນ:", + "New connection has been rejected": "ການເຊື່ອມຕໍ່ໃຫມ່ໄດ້ຖືກປະຕິເສດ", + "Credentials are required": "ຕ້ອງການຂໍ້ມູນປະຈໍາຕົວ", + "Hide/Show the control bar": "ເຊື່ອງ/ສະແດງແຖບຄວບຄຸມ", + "Drag": "ລາກ", + "Move/Drag Viewport": "ຍ້າຍ/ລາກ Viewport", + "Keyboard": "ແປ້ນພິມ", + "Show Keyboard": "ສະແດງແປ້ນພິມ", + "Extra keys": "ກະແຈພິເສດ", + "Show Extra Keys": "ສະແດງລະຫັດພິເສດ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "ສະຫຼັບ Ctrl", + "Alt": "Alt", + "Toggle Alt": "ສະຫຼັບ Alt", + "Toggle Windows": "ສະຫຼັບ Windows", + "Windows": "Windows", + "Send Tab": "ສົ່ງແຖບ", + "Tab": "ແຖບ", + "Esc": "Esc", + "Send Escape": "ສົ່ງຫນີ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "ສົ່ງ Ctrl-Alt-Del", + "Shutdown/Reboot": "ປິດ/ປິດເປີດໃໝ່", + "Shutdown/Reboot...": "ປິດ/ປິດເປີດໃໝ່...", + "Power": "ພະລັງງານ", + "Shutdown": "ປິດເຄື່ອງ", + "Reboot": "ປິດເປີດໃໝ່", + "Reset": "ຣີເຊັດ", + "Clipboard": "ຄລິບບອດ", + "Clear": "ຈະແຈ້ງ", + "Fullscreen": "ເຕັມຈໍ", + "Settings": "ການຕັ້ງຄ່າ", + "Shared Mode": "ຮູບແບບທີ່ແບ່ງປັນ", + "View Only": "ເບິ່ງເທົ່ານັ້ນ", + "Clip to Window": "ຄລິບໃສ່ປ່ອງຢ້ຽມ", + "Scaling Mode:": "ຮູບແບບການປັບຂະຫນາດ:", + "None": "ບໍ່ມີ", + "Local Scaling": "ການຂະຫຍາຍທ້ອງຖິ່ນ", + "Remote Resizing": "ການປັບຂະຫນາດໄລຍະໄກ", + "Advanced": "ຂັ້ນສູງ", + "Quality:": "ຄຸນນະພາບ:", + "Compression level:": "ລະດັບການບີບອັດ:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "ເຂົ້າລະຫັດ", + "Host:": "ເຈົ້າພາບ:", + "Port:": "ພອດ:", + "Path:": "ເສັ້ນທາງ:", + "Automatic Reconnect": "ເຊື່ອມຕໍ່ອັດຕະໂນມັດ", + "Reconnect Delay (ms):": "ເຊື່ອມຕໍ່ຄືນໃໝ່ການຊັກຊ້າ (ms):", + "Show Dot when No Cursor": "ສະແດງຈຸດໃນເວລາທີ່ບໍ່ມີຕົວກະພິບ", + "Logging:": "ບັນທຶກ:", + "Version:": "ຮຸ່ນ:", + "Disconnect": "ຕັດການເຊື່ອມຕໍ່", + "Connect": "ເຊື່ອມຕໍ່", + "Username:": "ຊື່ຜູ້ໃຊ້:", + "Password:": "ລະຫັດຜ່ານ:", + "Send Credentials": "ສົ່ງຂໍ້ມູນປະຈໍາຕົວ", + "Cancel": "ຍົກເລີກ", + "Keys": "ກະແຈ", + "Game Cursor Mode": "ຮູບແບບຕົວກະພິບເກມ", + "Press Esc Key to Exit Pointer Lock Mode": "ກົດປຸ່ມ Esc ເພື່ອອອກຈາກໂຫມດລັອກຕົວຊີ້", + "Game Mode paused, click on screen to resume Game Mode.": "ໂໝດເກມຢຸດຊົ່ວຄາວ, ຄລິກທີ່ໜ້າຈໍເພື່ອສືບຕໍ່ໂໝດເກມ.", + "Clipboard Up": "ຄລິບບອດຂຶ້ນ", + "CLipboard Down": "ຄລິບບອດລົງ", + "Clipboard Seamless": "ຄລິບບອດບໍ່ມີຮອຍຕໍ່", + "Prefer Local Cursor": "ຕ້ອງການຕົວກະພິບທ້ອງຖິ່ນ", + "Translate keyboard shortcuts": "ແປແປ້ນພິມລັດ", + "Enable WebRTC UDP Transit": "ເປີດໃຊ້ WebRTC UDP Transit", + "Enable WebP Compression": "ເປີດໃຊ້ WebP Compression", + "Enable Performance Stats": "ເປີດໃຊ້ສະຖິຕິການປະຕິບັດ", + "Enable Pointer Lock": "ເປີດໃຊ້ການລັອກຕົວຊີ້", + "IME Input Mode": "ຮູບແບບການປ້ອນຂໍ້ມູນ IME", + "Show Virtual Keyboard Control": "ສະແດງການຄວບຄຸມແປ້ນພິມສະເໝືອນ", + "Toggle Control Panel via Keystrokes": "ສະຫຼັບແຜງຄວບຄຸມດ້ວຍການກົດແປ້ນພິມ", + "Render Native Resolution": "ສະແດງຄວາມລະອຽດເດີມ", + "Keyboard Shortcuts": "ທາງລັດແປ້ນພິມ", + "Enable KasmVNC Keyboard Shortcuts": "ເປີດໃຊ້ປຸ່ມລັດ KasmVNC", + "1 - Toggle Control Panel": "1 - ສະຫຼັບແຜງຄວບຄຸມ", + "2 - Toggle Game Pointer Mode": "2 - ສະຫຼັບໂໝດຕົວຊີ້ເກມ", + "3 - Toggle Pointer Lock": "3 - ສະຫຼັບຕົວຊີ້ຕົວຊີ້", + "Stream Quality": "ຄຸນນະພາບການຖ່າຍທອດ", + "Preset Modes:": "ໂໝດທີ່ຕັ້ງໄວ້ລ່ວງໜ້າ:", + "Static": "ຄົງທີ່", + "Low": "ຕໍ່າ", + "Medium": "ຂະຫນາດກາງ", + "High": "ສູງ", + "Extreme": "ທີ່ສຸດ", + "Lossless": "ສູນເສຍ", + "Custom": "ກຳນົດເອງ", + "Anti-Aliasing:": "ການຕ້ານການນາມແຝງ:", + "Auto Dynamic": "ໄດນາມິກອັດຕະໂນມັດ", + "Off": "ປິດ", + "On": "ເປີດ", + "Dynamic Quality Min:": "ຄຸນະພາບຕ່ຳສຸດແບບໄດນາມິກ:", + "Dynamic Quality Max:": "ຄຸນນະພາບສູງສຸດແບບໄດນາມິກ:", + "Treat Lossless:": "ຮັກສາການສູນເສຍ:", + "Frame Rate:": "ອັດຕາກອບ:", + "Video JPEG Quality:": "ຄຸນນະພາບ JPEG ວິດີໂອ:", + "Video WEBP Quality:": "ວິດີໂອຄຸນນະພາບ WEBP:", + "Video Area:": "ພື້ນທີ່ວິດີໂອ:", + "Video Time:": "ເວລາວິດີໂອ:", + "Video Out Time:": "ເວລາອອກວິດີໂອ:", + "Video Mode Width:": "ຄວາມກວ້າງຂອງໂໝດວິດີໂອ:", + "Video Mode Height:": "ຄວາມສູງຂອງໂໝດວິດີໂອ:", + "Documentation": "ເອກະສານ", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "KasmVNC ພົບຂໍ້ຜິດພາດ:" +} \ No newline at end of file diff --git a/app/locale/lt.json b/app/locale/lt.json new file mode 100644 index 0000000..1ae91bf --- /dev/null +++ b/app/locale/lt.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Prisijungiama...", + "Disconnecting...": "Atjungiama...", + "Reconnecting...": "Prisijungiama iš naujo...", + "Internal error": "Vidinė klaida", + "Must set host": "Turi nustatyti šeimininką", + "Connected (encrypted) to ": "Prisijungta (užšifruota) prie", + "Connected (unencrypted) to ": "Prisijungta (nešifruota) prie", + "Something went wrong, connection is closed": "Kažkas ne taip, ryšys nutrauktas", + "Failed to connect to server": "Nepavyko prisijungti prie serverio", + "Disconnected": "Atjungtas", + "New connection has been rejected with reason: ": "Naujas ryšys buvo atmestas dėl priežasties:", + "New connection has been rejected": "Naujas ryšys buvo atmestas", + "Credentials are required": "Reikalingi kredencialai", + "Hide/Show the control bar": "Slėpti / rodyti valdymo juostą", + "Drag": "vilkti", + "Move/Drag Viewport": "Perkelti / vilkti peržiūros sritį", + "Keyboard": "Klaviatūra", + "Show Keyboard": "Rodyti klaviatūrą", + "Extra keys": "Papildomi raktai", + "Show Extra Keys": "Rodyti papildomus klavišus", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Perjungti Ctrl", + "Alt": "Alt", + "Toggle Alt": "Perjungti Alt", + "Toggle Windows": "Perjungti Windows", + "Windows": "Windows", + "Send Tab": "Siųsti skirtuką", + "Tab": "skirtukas", + "Esc": "Esc", + "Send Escape": "Siųsti pabėgimą", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Siųsti Ctrl-Alt-Del", + "Shutdown/Reboot": "Išjungti / paleisti iš naujo", + "Shutdown/Reboot...": "Išjungti / paleisti iš naujo...", + "Power": "Galia", + "Shutdown": "Išjungti", + "Reboot": "Paleisti iš naujo", + "Reset": "Atstatyti", + "Clipboard": "Iškarpinė", + "Clear": "Išvalyti", + "Fullscreen": "Per visą ekraną", + "Settings": "Nustatymai", + "Shared Mode": "Bendrinamas režimas", + "View Only": "Tik peržiūrėti", + "Clip to Window": "Klipas į langą", + "Scaling Mode:": "Mastelio keitimo režimas:", + "None": "Nė vienas", + "Local Scaling": "Vietinis mastelio keitimas", + "Remote Resizing": "Nuotolinis dydžio keitimas", + "Advanced": "Išplėstinė", + "Quality:": "Kokybė:", + "Compression level:": "Suspaudimo lygis:", + "Repeater ID:": "Kartotuvo ID:", + "WebSocket": "WebSocket", + "Encrypt": "Šifruoti", + "Host:": "Šeimininkas:", + "Port:": "Uostas:", + "Path:": "Kelias:", + "Automatic Reconnect": "Automatinis pakartotinis prisijungimas", + "Reconnect Delay (ms):": "Reconnect Delay (ms):", + "Show Dot when No Cursor": "Rodyti tašką, kai nėra žymeklio", + "Logging:": "Žurnalas:", + "Version:": "Versija:", + "Disconnect": "Atjungti", + "Connect": "Prisijungti", + "Username:": "Vartotojo vardas:", + "Password:": "Slaptažodis:", + "Send Credentials": "Siųsti kredencialus", + "Cancel": "Atšaukti", + "Keys": "Raktai", + "Game Cursor Mode": "Žaidimo žymeklio režimas", + "Press Esc Key to Exit Pointer Lock Mode": "Paspauskite Esc klavišą, kad išeitumėte iš žymeklio užrakto režimo", + "Game Mode paused, click on screen to resume Game Mode.": "Žaidimo režimas pristabdytas, spustelėkite ekraną, kad atnaujintumėte žaidimo režimą.", + "Clipboard Up": "Iškarpinė aukštyn", + "CLipboard Down": "Nuomėta mainų sritis", + "Clipboard Seamless": "Besiūlė iškarpinė", + "Prefer Local Cursor": "Pirmenybė teikiama vietiniam žymekliui", + "Translate keyboard shortcuts": "Išversti sparčiuosius klavišus", + "Enable WebRTC UDP Transit": "Įgalinti WebRTC UDP tranzitą", + "Enable WebP Compression": "Įgalinti WebP glaudinimą", + "Enable Performance Stats": "Įgalinti našumo statistiką", + "Enable Pointer Lock": "Įjungti rodyklės užraktą", + "IME Input Mode": "IME įvesties režimas", + "Show Virtual Keyboard Control": "Rodyti virtualios klaviatūros valdymą", + "Toggle Control Panel via Keystrokes": "Perjungti valdymo skydelį klavišų paspaudimais", + "Render Native Resolution": "Pateikti vietinę skiriamąją gebą", + "Keyboard Shortcuts": "Klaviatūros nuorodos", + "Enable KasmVNC Keyboard Shortcuts": "Įgalinti KasmVNC sparčiuosius klavišus", + "1 - Toggle Control Panel": "1 – perjungti valdymo skydelį", + "2 - Toggle Game Pointer Mode": "2 – perjungti žaidimo žymeklio režimą", + "3 - Toggle Pointer Lock": "3 – perjungti žymeklio užraktą", + "Stream Quality": "Srauto kokybė", + "Preset Modes:": "Iš anksto nustatyti režimai:", + "Static": "Statinis", + "Low": "Žemas", + "Medium": "Vidutinis", + "High": "aukštas", + "Extreme": "Ekstremalus", + "Lossless": "be nuostolių", + "Custom": "Custom", + "Anti-Aliasing:": "Anti-aliasing", + "Auto Dynamic": "Auto Dynamic", + "Off": "Išjungta", + "On": "Įjungta", + "Dynamic Quality Min:": "Min. dinaminė kokybė:", + "Dynamic Quality Max:": "Maksimali dinaminė kokybė:", + "Treat Lossless:": "Treatless Lossless:", + "Frame Rate:": "Kadrų dažnis:", + "Video JPEG Quality:": "Vaizdo JPEG kokybė:", + "Video WEBP Quality:": "Vaizdo įrašo WEBP kokybė:", + "Video Area:": "Vaizdo įrašų sritis:", + "Video Time:": "Vaizdo įrašo laikas:", + "Video Out Time:": "Vaizdo įrašo pasibaigimo laikas:", + "Video Mode Width:": "Vaizdo režimo plotis:", + "Video Mode Height:": "Vaizdo režimo aukštis:", + "Documentation": "Dokumentacija", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "KasmVNC susidūrė su klaida:" +} \ No newline at end of file diff --git a/app/locale/lt_LT.json b/app/locale/lt_LT.json new file mode 100644 index 0000000..1ae91bf --- /dev/null +++ b/app/locale/lt_LT.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Prisijungiama...", + "Disconnecting...": "Atjungiama...", + "Reconnecting...": "Prisijungiama iš naujo...", + "Internal error": "Vidinė klaida", + "Must set host": "Turi nustatyti šeimininką", + "Connected (encrypted) to ": "Prisijungta (užšifruota) prie", + "Connected (unencrypted) to ": "Prisijungta (nešifruota) prie", + "Something went wrong, connection is closed": "Kažkas ne taip, ryšys nutrauktas", + "Failed to connect to server": "Nepavyko prisijungti prie serverio", + "Disconnected": "Atjungtas", + "New connection has been rejected with reason: ": "Naujas ryšys buvo atmestas dėl priežasties:", + "New connection has been rejected": "Naujas ryšys buvo atmestas", + "Credentials are required": "Reikalingi kredencialai", + "Hide/Show the control bar": "Slėpti / rodyti valdymo juostą", + "Drag": "vilkti", + "Move/Drag Viewport": "Perkelti / vilkti peržiūros sritį", + "Keyboard": "Klaviatūra", + "Show Keyboard": "Rodyti klaviatūrą", + "Extra keys": "Papildomi raktai", + "Show Extra Keys": "Rodyti papildomus klavišus", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Perjungti Ctrl", + "Alt": "Alt", + "Toggle Alt": "Perjungti Alt", + "Toggle Windows": "Perjungti Windows", + "Windows": "Windows", + "Send Tab": "Siųsti skirtuką", + "Tab": "skirtukas", + "Esc": "Esc", + "Send Escape": "Siųsti pabėgimą", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Siųsti Ctrl-Alt-Del", + "Shutdown/Reboot": "Išjungti / paleisti iš naujo", + "Shutdown/Reboot...": "Išjungti / paleisti iš naujo...", + "Power": "Galia", + "Shutdown": "Išjungti", + "Reboot": "Paleisti iš naujo", + "Reset": "Atstatyti", + "Clipboard": "Iškarpinė", + "Clear": "Išvalyti", + "Fullscreen": "Per visą ekraną", + "Settings": "Nustatymai", + "Shared Mode": "Bendrinamas režimas", + "View Only": "Tik peržiūrėti", + "Clip to Window": "Klipas į langą", + "Scaling Mode:": "Mastelio keitimo režimas:", + "None": "Nė vienas", + "Local Scaling": "Vietinis mastelio keitimas", + "Remote Resizing": "Nuotolinis dydžio keitimas", + "Advanced": "Išplėstinė", + "Quality:": "Kokybė:", + "Compression level:": "Suspaudimo lygis:", + "Repeater ID:": "Kartotuvo ID:", + "WebSocket": "WebSocket", + "Encrypt": "Šifruoti", + "Host:": "Šeimininkas:", + "Port:": "Uostas:", + "Path:": "Kelias:", + "Automatic Reconnect": "Automatinis pakartotinis prisijungimas", + "Reconnect Delay (ms):": "Reconnect Delay (ms):", + "Show Dot when No Cursor": "Rodyti tašką, kai nėra žymeklio", + "Logging:": "Žurnalas:", + "Version:": "Versija:", + "Disconnect": "Atjungti", + "Connect": "Prisijungti", + "Username:": "Vartotojo vardas:", + "Password:": "Slaptažodis:", + "Send Credentials": "Siųsti kredencialus", + "Cancel": "Atšaukti", + "Keys": "Raktai", + "Game Cursor Mode": "Žaidimo žymeklio režimas", + "Press Esc Key to Exit Pointer Lock Mode": "Paspauskite Esc klavišą, kad išeitumėte iš žymeklio užrakto režimo", + "Game Mode paused, click on screen to resume Game Mode.": "Žaidimo režimas pristabdytas, spustelėkite ekraną, kad atnaujintumėte žaidimo režimą.", + "Clipboard Up": "Iškarpinė aukštyn", + "CLipboard Down": "Nuomėta mainų sritis", + "Clipboard Seamless": "Besiūlė iškarpinė", + "Prefer Local Cursor": "Pirmenybė teikiama vietiniam žymekliui", + "Translate keyboard shortcuts": "Išversti sparčiuosius klavišus", + "Enable WebRTC UDP Transit": "Įgalinti WebRTC UDP tranzitą", + "Enable WebP Compression": "Įgalinti WebP glaudinimą", + "Enable Performance Stats": "Įgalinti našumo statistiką", + "Enable Pointer Lock": "Įjungti rodyklės užraktą", + "IME Input Mode": "IME įvesties režimas", + "Show Virtual Keyboard Control": "Rodyti virtualios klaviatūros valdymą", + "Toggle Control Panel via Keystrokes": "Perjungti valdymo skydelį klavišų paspaudimais", + "Render Native Resolution": "Pateikti vietinę skiriamąją gebą", + "Keyboard Shortcuts": "Klaviatūros nuorodos", + "Enable KasmVNC Keyboard Shortcuts": "Įgalinti KasmVNC sparčiuosius klavišus", + "1 - Toggle Control Panel": "1 – perjungti valdymo skydelį", + "2 - Toggle Game Pointer Mode": "2 – perjungti žaidimo žymeklio režimą", + "3 - Toggle Pointer Lock": "3 – perjungti žymeklio užraktą", + "Stream Quality": "Srauto kokybė", + "Preset Modes:": "Iš anksto nustatyti režimai:", + "Static": "Statinis", + "Low": "Žemas", + "Medium": "Vidutinis", + "High": "aukštas", + "Extreme": "Ekstremalus", + "Lossless": "be nuostolių", + "Custom": "Custom", + "Anti-Aliasing:": "Anti-aliasing", + "Auto Dynamic": "Auto Dynamic", + "Off": "Išjungta", + "On": "Įjungta", + "Dynamic Quality Min:": "Min. dinaminė kokybė:", + "Dynamic Quality Max:": "Maksimali dinaminė kokybė:", + "Treat Lossless:": "Treatless Lossless:", + "Frame Rate:": "Kadrų dažnis:", + "Video JPEG Quality:": "Vaizdo JPEG kokybė:", + "Video WEBP Quality:": "Vaizdo įrašo WEBP kokybė:", + "Video Area:": "Vaizdo įrašų sritis:", + "Video Time:": "Vaizdo įrašo laikas:", + "Video Out Time:": "Vaizdo įrašo pasibaigimo laikas:", + "Video Mode Width:": "Vaizdo režimo plotis:", + "Video Mode Height:": "Vaizdo režimo aukštis:", + "Documentation": "Dokumentacija", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "KasmVNC susidūrė su klaida:" +} \ No newline at end of file diff --git a/app/locale/lv.json b/app/locale/lv.json new file mode 100644 index 0000000..4d65765 --- /dev/null +++ b/app/locale/lv.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Notiek savienojuma izveide...", + "Disconnecting...": "Notiek savienojuma atvienošana...", + "Reconnecting...": "Notiek savienojuma atjaunošana...", + "Internal error": "Iekšēja kļūda", + "Must set host": "Jāiestata saimniekdators", + "Connected (encrypted) to ": "Savienots (šifrēts) ar", + "Connected (unencrypted) to ": "Savienots (nešifrēts) ar ", + "Something went wrong, connection is closed": "Kaut kas nogāja greizi, savienojums ir slēgts", + "Failed to connect to server": "Neizdevās izveidot savienojumu ar serveri", + "Disconnected": "Atvienots", + "New connection has been rejected with reason: ": "Jauns savienojums ir noraidīts ar iemeslu:", + "New connection has been rejected": "Jauns savienojums ir noraidīts", + "Credentials are required": "Ir nepieciešami akreditācijas dati", + "Hide/Show the control bar": "Paslēpt/rādīt vadības joslu", + "Drag": "velciet", + "Move/Drag Viewport": "Pārvietot/velciet skata logs", + "Keyboard": "Tastatūra", + "Show Keyboard": "Rādīt tastatūru", + "Extra keys": "Papildu atslēgas", + "Show Extra Keys": "Rādīt papildu atslēgas", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pārslēgt Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pārslēgt Alt", + "Toggle Windows": "Pārslēgt Windows", + "Windows": "Windows", + "Send Tab": "Sūtīt cilni", + "Tab": "Cilne", + "Esc": "Esc", + "Send Escape": "Sūtīt bēgšanu", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Sūtīt Ctrl-Alt-Del", + "Shutdown/Reboot": "Izslēgšana/atsāknēšana", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "Spēks", + "Shutdown": "Izslēgt", + "Reboot": "Reboot", + "Reset": "Atiestatīt", + "Clipboard": "Starpliktuve", + "Clear": "Notīrīt", + "Fullscreen": "Pilnekrāna režīms", + "Settings": "Iestatījumi", + "Shared Mode": "Koplietotais režīms", + "View Only": "Tikai skatīt", + "Clip to Window": "Klips uz logu", + "Scaling Mode:": "Mērogošanas režīms:", + "None": "Neviens", + "Local Scaling": "Vietējā mērogošana", + "Remote Resizing": "Attālā izmēra maiņa", + "Advanced": "Papildu", + "Quality:": "Kvalitāte:", + "Compression level:": "Kompresijas līmenis:", + "Repeater ID:": "Atkārtotāja ID:", + "WebSocket": "WebSocket", + "Encrypt": "Šifrēt", + "Host:": "Saimnieks:", + "Port:": "Ports:", + "Path:": "Ceļš:", + "Automatic Reconnect": "Automātiska atkārtota savienošana", + "Reconnect Delay (ms):": "Atkārtota savienojuma aizkave (ms):", + "Show Dot when No Cursor": "Rādīt punktu, kad nav kursora", + "Logging:": "Reģistrācija:", + "Version:": "Versija:", + "Disconnect": "Atvienot", + "Connect": "Savienot", + "Username:": "Lietotājvārds:", + "Password:": "Parole:", + "Send Credentials": "Sūtīt akreditācijas datus", + "Cancel": "Atcelt", + "Keys": "Atslēgas", + "Game Cursor Mode": "Spēles kursora režīms", + "Press Esc Key to Exit Pointer Lock Mode": "Nospiediet taustiņu Esc, lai izietu no rādītāja bloķēšanas režīma", + "Game Mode paused, click on screen to resume Game Mode.": "Spēles režīms apturēts, noklikšķiniet uz ekrāna, lai atsāktu spēles režīmu.", + "Clipboard Up": "Starpliktuve uz augšu", + "CLipboard Down": "Starpliktuve uz leju", + "Clipboard Seamless": "Bezšuvju starpliktuves", + "Prefer Local Cursor": "Priekšroku lokālajam kursoram", + "Translate keyboard shortcuts": "Tulkot īsinājumtaustiņus", + "Enable WebRTC UDP Transit": "Iespējot WebRTC UDP Transit", + "Enable WebP Compression": "Iespējot WebP saspiešanu", + "Enable Performance Stats": "Iespējot veiktspējas statistiku", + "Enable Pointer Lock": "Iespējot rādītāja bloķēšanu", + "IME Input Mode": "IME ievades režīms", + "Show Virtual Keyboard Control": "Rādīt virtuālās tastatūras vadību", + "Toggle Control Panel via Keystrokes": "Pārslēgt vadības paneli, izmantojot taustiņsitienus", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Tastatūras īsinājumtaustiņi", + "Enable KasmVNC Keyboard Shortcuts": "Iespējot KasmVNC īsinājumtaustiņus", + "1 - Toggle Control Panel": "1 — pārslēgt vadības paneli", + "2 - Toggle Game Pointer Mode": "2 — pārslēgt spēles rādītāja režīmu", + "3 - Toggle Pointer Lock": "3 — pārslēgt rādītāja bloķēšanu", + "Stream Quality": "Straumes kvalitāte", + "Preset Modes:": "Iepriekš iestatītie režīmi:", + "Static": "Statisks", + "Low": "Zems", + "Medium": "Vidējs", + "High": "Augsti", + "Extreme": "Ekstrēms", + "Lossless": "Bez zaudējumiem", + "Custom": "Pielāgots", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Izslēgts", + "On": "Ieslēgts", + "Dynamic Quality Min:": "Minimālā dinamiskā kvalitāte:", + "Dynamic Quality Max:": "Maksimālā dinamiskā kvalitāte:", + "Treat Lossless:": "Ārstēt bez zaudējumiem:", + "Frame Rate:": "Kadru ātrums:", + "Video JPEG Quality:": "Video JPEG kvalitāte:", + "Video WEBP Quality:": "Video WEBP kvalitāte:", + "Video Area:": "Video apgabals:", + "Video Time:": "Video laiks:", + "Video Out Time:": "Video izlaiduma laiks:", + "Video Mode Width:": "Video režīma platums:", + "Video Mode Height:": "Video režīma augstums:", + "Documentation": "Dokumentācija", + "Drag Viewport": "Velciet skata logu", + "KasmVNC encountered an error:": "KasmVNC radās kļūda:" +} \ No newline at end of file diff --git a/app/locale/lv_LV.json b/app/locale/lv_LV.json new file mode 100644 index 0000000..4d65765 --- /dev/null +++ b/app/locale/lv_LV.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Notiek savienojuma izveide...", + "Disconnecting...": "Notiek savienojuma atvienošana...", + "Reconnecting...": "Notiek savienojuma atjaunošana...", + "Internal error": "Iekšēja kļūda", + "Must set host": "Jāiestata saimniekdators", + "Connected (encrypted) to ": "Savienots (šifrēts) ar", + "Connected (unencrypted) to ": "Savienots (nešifrēts) ar ", + "Something went wrong, connection is closed": "Kaut kas nogāja greizi, savienojums ir slēgts", + "Failed to connect to server": "Neizdevās izveidot savienojumu ar serveri", + "Disconnected": "Atvienots", + "New connection has been rejected with reason: ": "Jauns savienojums ir noraidīts ar iemeslu:", + "New connection has been rejected": "Jauns savienojums ir noraidīts", + "Credentials are required": "Ir nepieciešami akreditācijas dati", + "Hide/Show the control bar": "Paslēpt/rādīt vadības joslu", + "Drag": "velciet", + "Move/Drag Viewport": "Pārvietot/velciet skata logs", + "Keyboard": "Tastatūra", + "Show Keyboard": "Rādīt tastatūru", + "Extra keys": "Papildu atslēgas", + "Show Extra Keys": "Rādīt papildu atslēgas", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pārslēgt Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pārslēgt Alt", + "Toggle Windows": "Pārslēgt Windows", + "Windows": "Windows", + "Send Tab": "Sūtīt cilni", + "Tab": "Cilne", + "Esc": "Esc", + "Send Escape": "Sūtīt bēgšanu", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Sūtīt Ctrl-Alt-Del", + "Shutdown/Reboot": "Izslēgšana/atsāknēšana", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "Spēks", + "Shutdown": "Izslēgt", + "Reboot": "Reboot", + "Reset": "Atiestatīt", + "Clipboard": "Starpliktuve", + "Clear": "Notīrīt", + "Fullscreen": "Pilnekrāna režīms", + "Settings": "Iestatījumi", + "Shared Mode": "Koplietotais režīms", + "View Only": "Tikai skatīt", + "Clip to Window": "Klips uz logu", + "Scaling Mode:": "Mērogošanas režīms:", + "None": "Neviens", + "Local Scaling": "Vietējā mērogošana", + "Remote Resizing": "Attālā izmēra maiņa", + "Advanced": "Papildu", + "Quality:": "Kvalitāte:", + "Compression level:": "Kompresijas līmenis:", + "Repeater ID:": "Atkārtotāja ID:", + "WebSocket": "WebSocket", + "Encrypt": "Šifrēt", + "Host:": "Saimnieks:", + "Port:": "Ports:", + "Path:": "Ceļš:", + "Automatic Reconnect": "Automātiska atkārtota savienošana", + "Reconnect Delay (ms):": "Atkārtota savienojuma aizkave (ms):", + "Show Dot when No Cursor": "Rādīt punktu, kad nav kursora", + "Logging:": "Reģistrācija:", + "Version:": "Versija:", + "Disconnect": "Atvienot", + "Connect": "Savienot", + "Username:": "Lietotājvārds:", + "Password:": "Parole:", + "Send Credentials": "Sūtīt akreditācijas datus", + "Cancel": "Atcelt", + "Keys": "Atslēgas", + "Game Cursor Mode": "Spēles kursora režīms", + "Press Esc Key to Exit Pointer Lock Mode": "Nospiediet taustiņu Esc, lai izietu no rādītāja bloķēšanas režīma", + "Game Mode paused, click on screen to resume Game Mode.": "Spēles režīms apturēts, noklikšķiniet uz ekrāna, lai atsāktu spēles režīmu.", + "Clipboard Up": "Starpliktuve uz augšu", + "CLipboard Down": "Starpliktuve uz leju", + "Clipboard Seamless": "Bezšuvju starpliktuves", + "Prefer Local Cursor": "Priekšroku lokālajam kursoram", + "Translate keyboard shortcuts": "Tulkot īsinājumtaustiņus", + "Enable WebRTC UDP Transit": "Iespējot WebRTC UDP Transit", + "Enable WebP Compression": "Iespējot WebP saspiešanu", + "Enable Performance Stats": "Iespējot veiktspējas statistiku", + "Enable Pointer Lock": "Iespējot rādītāja bloķēšanu", + "IME Input Mode": "IME ievades režīms", + "Show Virtual Keyboard Control": "Rādīt virtuālās tastatūras vadību", + "Toggle Control Panel via Keystrokes": "Pārslēgt vadības paneli, izmantojot taustiņsitienus", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Tastatūras īsinājumtaustiņi", + "Enable KasmVNC Keyboard Shortcuts": "Iespējot KasmVNC īsinājumtaustiņus", + "1 - Toggle Control Panel": "1 — pārslēgt vadības paneli", + "2 - Toggle Game Pointer Mode": "2 — pārslēgt spēles rādītāja režīmu", + "3 - Toggle Pointer Lock": "3 — pārslēgt rādītāja bloķēšanu", + "Stream Quality": "Straumes kvalitāte", + "Preset Modes:": "Iepriekš iestatītie režīmi:", + "Static": "Statisks", + "Low": "Zems", + "Medium": "Vidējs", + "High": "Augsti", + "Extreme": "Ekstrēms", + "Lossless": "Bez zaudējumiem", + "Custom": "Pielāgots", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Izslēgts", + "On": "Ieslēgts", + "Dynamic Quality Min:": "Minimālā dinamiskā kvalitāte:", + "Dynamic Quality Max:": "Maksimālā dinamiskā kvalitāte:", + "Treat Lossless:": "Ārstēt bez zaudējumiem:", + "Frame Rate:": "Kadru ātrums:", + "Video JPEG Quality:": "Video JPEG kvalitāte:", + "Video WEBP Quality:": "Video WEBP kvalitāte:", + "Video Area:": "Video apgabals:", + "Video Time:": "Video laiks:", + "Video Out Time:": "Video izlaiduma laiks:", + "Video Mode Width:": "Video režīma platums:", + "Video Mode Height:": "Video režīma augstums:", + "Documentation": "Dokumentācija", + "Drag Viewport": "Velciet skata logu", + "KasmVNC encountered an error:": "KasmVNC radās kļūda:" +} \ No newline at end of file diff --git a/app/locale/mg.json b/app/locale/mg.json new file mode 100644 index 0000000..60655c3 --- /dev/null +++ b/app/locale/mg.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Mifandray...", + "Disconnecting...": "Misaraka...", + "Reconnecting...": "Mifandray indray...", + "Internal error": "Error anatiny", + "Must set host": "Tsy maintsy mametraka mpampiantrano", + "Connected (encrypted) to ": "Mifandray (nafenina) amin'ny", + "Connected (unencrypted) to ": "Mifandray (tsy misy encryption) amin'ny", + "Something went wrong, connection is closed": "Nisy tsy nety, nikatona ny fifandraisana", + "Failed to connect to server": "Tsy afaka nifandray tamin'ny mpizara", + "Disconnected": "Tapaka", + "New connection has been rejected with reason: ": "Ny fifandraisana vaovao dia nolavina noho ny antony:", + "New connection has been rejected": "Nolavina ny fifandraisana vaovao", + "Credentials are required": "Ilaina ny fahazoan-dàlana", + "Hide/Show the control bar": "Afeno/Asehoy ny bara fanaraha-maso", + "Drag": "Drag", + "Move/Drag Viewport": "Move/Drag Viewport", + "Keyboard": "Kyboard", + "Show Keyboard": "Asehoy ny kitendry", + "Extra keys": "Klay fanampiny", + "Show Extra Keys": "Asehoy ny fanalahidy fanampiny", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Toggle Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Windows", + "Send Tab": "Send Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Alefaso escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Alefaso Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Atsaharo / Avereno ...", + "Power": "Hery", + "Shutdown": "Hidio", + "Reboot": "Reboot", + "Reset": "Mamerina", + "Clipboard": "Clipboard", + "Clear": "Mazava", + "Fullscreen": "Mameno efijery", + "Settings": "Settings", + "Shared Mode": "Mode zaraina", + "View Only": "Jereo ihany", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Scaling Mode:", + "None": "Tsy misy", + "Local Scaling": "Scaling eo an-toerana", + "Remote Resizing": "Fanovàna lavitra", + "Advanced": "Advanced", + "Quality:": "Qualité:", + "Compression level:": "Ambaratonga famatrarana:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Host:", + "Port:": "Port:", + "Path:": "Lalana:", + "Automatic Reconnect": "Reconnect automatique", + "Reconnect Delay (ms):": "Avereno ny fahatarana (ms):", + "Show Dot when No Cursor": "Asehoy ny teboka rehefa tsy misy cursor", + "Logging:": "Logging:", + "Version:": "Dikan-teny:", + "Disconnect": "Disconnect", + "Connect": "Mifandray", + "Username:": "Username:", + "Password:": "Tenimiafina:", + "Send Credentials": "Alefaso ny fahazoan-dàlana", + "Cancel": "Afohy", + "Keys": "Keys", + "Game Cursor Mode": "Lalao Cursor Mode", + "Press Esc Key to Exit Pointer Lock Mode": "Tsindrio ny lakilen'ny Esc mba hialana amin'ny fomba hidin'ny fanondro", + "Game Mode paused, click on screen to resume Game Mode.": "Niato ny lalao lalao, tsindrio eo amin'ny efijery mba hanohy ny lalao lalao.", + "Clipboard Up": "Clipboard miakatra", + "CLipboard Down": "Clipboard Midina", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Tianao ny Cursor eo an-toerana", + "Translate keyboard shortcuts": "Handika hitsin-dàlana kitendry", + "Enable WebRTC UDP Transit": "Alefaso ny WebRTC UDP Transit", + "Enable WebP Compression": "Avelao ny WebP Compression", + "Enable Performance Stats": "Enable Performance Stats", + "Enable Pointer Lock": "Enable Pointer Lock", + "IME Input Mode": "Mode fampidirana IME", + "Show Virtual Keyboard Control": "Asehoy ny fanaraha-maso kitendry virtoaly", + "Toggle Control Panel via Keystrokes": "Toggle Control Panel amin'ny alalan'ny Keystrokes", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Shortcuts keyboard", + "Enable KasmVNC Keyboard Shortcuts": "Avelao ny KasmVNC Keyboard Shortcuts", + "1 - Toggle Control Panel": "1 - Toggle Control Panel", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Kalitaon'ny Stream", + "Preset Modes:": "Modely preset:", + "Static": "Statika", + "Low": "Ambany", + "Medium": "Medium", + "High": "Avo", + "Extreme": "Extreme", + "Lossless": "Tsy very", + "Custom": "Custom", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Efa", + "On": "Eny", + "Dynamic Quality Min:": "Quité Dynamic Min:", + "Dynamic Quality Max:": "Max Quality Dynamic:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Tamin'ny Frame:", + "Video JPEG Quality:": "Kalitao JPEG Video:", + "Video WEBP Quality:": "Kalitaon'ny horonan-tsary WEBP:", + "Video Area:": "Faritra Video:", + "Video Time:": "Fotoan'ny horonan-tsary:", + "Video Out Time:": "Fotoam-potoana hivoahan'ny horonan-tsary:", + "Video Mode Width:": "Sakan'ny Video Mode:", + "Video Mode Height:": "Haavo maodely video:", + "Documentation": "Dokumentation", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "Nahita hadisoana ny KasmVNC:" +} \ No newline at end of file diff --git a/app/locale/mg_MG.json b/app/locale/mg_MG.json new file mode 100644 index 0000000..60655c3 --- /dev/null +++ b/app/locale/mg_MG.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Mifandray...", + "Disconnecting...": "Misaraka...", + "Reconnecting...": "Mifandray indray...", + "Internal error": "Error anatiny", + "Must set host": "Tsy maintsy mametraka mpampiantrano", + "Connected (encrypted) to ": "Mifandray (nafenina) amin'ny", + "Connected (unencrypted) to ": "Mifandray (tsy misy encryption) amin'ny", + "Something went wrong, connection is closed": "Nisy tsy nety, nikatona ny fifandraisana", + "Failed to connect to server": "Tsy afaka nifandray tamin'ny mpizara", + "Disconnected": "Tapaka", + "New connection has been rejected with reason: ": "Ny fifandraisana vaovao dia nolavina noho ny antony:", + "New connection has been rejected": "Nolavina ny fifandraisana vaovao", + "Credentials are required": "Ilaina ny fahazoan-dàlana", + "Hide/Show the control bar": "Afeno/Asehoy ny bara fanaraha-maso", + "Drag": "Drag", + "Move/Drag Viewport": "Move/Drag Viewport", + "Keyboard": "Kyboard", + "Show Keyboard": "Asehoy ny kitendry", + "Extra keys": "Klay fanampiny", + "Show Extra Keys": "Asehoy ny fanalahidy fanampiny", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Toggle Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Windows", + "Send Tab": "Send Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Alefaso escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Alefaso Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Atsaharo / Avereno ...", + "Power": "Hery", + "Shutdown": "Hidio", + "Reboot": "Reboot", + "Reset": "Mamerina", + "Clipboard": "Clipboard", + "Clear": "Mazava", + "Fullscreen": "Mameno efijery", + "Settings": "Settings", + "Shared Mode": "Mode zaraina", + "View Only": "Jereo ihany", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Scaling Mode:", + "None": "Tsy misy", + "Local Scaling": "Scaling eo an-toerana", + "Remote Resizing": "Fanovàna lavitra", + "Advanced": "Advanced", + "Quality:": "Qualité:", + "Compression level:": "Ambaratonga famatrarana:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Host:", + "Port:": "Port:", + "Path:": "Lalana:", + "Automatic Reconnect": "Reconnect automatique", + "Reconnect Delay (ms):": "Avereno ny fahatarana (ms):", + "Show Dot when No Cursor": "Asehoy ny teboka rehefa tsy misy cursor", + "Logging:": "Logging:", + "Version:": "Dikan-teny:", + "Disconnect": "Disconnect", + "Connect": "Mifandray", + "Username:": "Username:", + "Password:": "Tenimiafina:", + "Send Credentials": "Alefaso ny fahazoan-dàlana", + "Cancel": "Afohy", + "Keys": "Keys", + "Game Cursor Mode": "Lalao Cursor Mode", + "Press Esc Key to Exit Pointer Lock Mode": "Tsindrio ny lakilen'ny Esc mba hialana amin'ny fomba hidin'ny fanondro", + "Game Mode paused, click on screen to resume Game Mode.": "Niato ny lalao lalao, tsindrio eo amin'ny efijery mba hanohy ny lalao lalao.", + "Clipboard Up": "Clipboard miakatra", + "CLipboard Down": "Clipboard Midina", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Tianao ny Cursor eo an-toerana", + "Translate keyboard shortcuts": "Handika hitsin-dàlana kitendry", + "Enable WebRTC UDP Transit": "Alefaso ny WebRTC UDP Transit", + "Enable WebP Compression": "Avelao ny WebP Compression", + "Enable Performance Stats": "Enable Performance Stats", + "Enable Pointer Lock": "Enable Pointer Lock", + "IME Input Mode": "Mode fampidirana IME", + "Show Virtual Keyboard Control": "Asehoy ny fanaraha-maso kitendry virtoaly", + "Toggle Control Panel via Keystrokes": "Toggle Control Panel amin'ny alalan'ny Keystrokes", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Shortcuts keyboard", + "Enable KasmVNC Keyboard Shortcuts": "Avelao ny KasmVNC Keyboard Shortcuts", + "1 - Toggle Control Panel": "1 - Toggle Control Panel", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Kalitaon'ny Stream", + "Preset Modes:": "Modely preset:", + "Static": "Statika", + "Low": "Ambany", + "Medium": "Medium", + "High": "Avo", + "Extreme": "Extreme", + "Lossless": "Tsy very", + "Custom": "Custom", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Efa", + "On": "Eny", + "Dynamic Quality Min:": "Quité Dynamic Min:", + "Dynamic Quality Max:": "Max Quality Dynamic:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Tamin'ny Frame:", + "Video JPEG Quality:": "Kalitao JPEG Video:", + "Video WEBP Quality:": "Kalitaon'ny horonan-tsary WEBP:", + "Video Area:": "Faritra Video:", + "Video Time:": "Fotoan'ny horonan-tsary:", + "Video Out Time:": "Fotoam-potoana hivoahan'ny horonan-tsary:", + "Video Mode Width:": "Sakan'ny Video Mode:", + "Video Mode Height:": "Haavo maodely video:", + "Documentation": "Dokumentation", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "Nahita hadisoana ny KasmVNC:" +} \ No newline at end of file diff --git a/app/locale/mi.json b/app/locale/mi.json new file mode 100644 index 0000000..daaa4ca --- /dev/null +++ b/app/locale/mi.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "E hono ana...", + "Disconnecting...": "Kei te momotu...", + "Reconnecting...": "Kei te hono ano...", + "Internal error": "Hapa o roto", + "Must set host": "Me whakarite kaihautu", + "Connected (encrypted) to ": "Kua hono (whakamuna) ki ", + "Connected (unencrypted) to ": "Kua hono (kore whakamuna) ki ", + "Something went wrong, connection is closed": "I hapa tetahi mea, kua kati te hononga", + "Failed to connect to server": "I rahua te hono ki te tūmau", + "Disconnected": "Kua Momotu", + "New connection has been rejected with reason: ": "Kua paopaohia te hononga hou me te take:", + "New connection has been rejected": "Kua paopaohia te hononga hou", + "Credentials are required": "Me whai tohu tohu", + "Hide/Show the control bar": "Huna/Whakaatuhia te pae mana", + "Drag": "Toia", + "Move/Drag Viewport": "Nuku/Toia Tauranga Tirohanga", + "Keyboard": "Papapātuhi", + "Show Keyboard": "Whakaatu Papapātuhi", + "Extra keys": "Tahi taapiri", + "Show Extra Keys": "Whakaatuhia nga Kī Anō", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Tahuri Ctrl", + "Alt": "Alt", + "Toggle Alt": "Tahuri Alt", + "Toggle Windows": "Tahuri Windows", + "Windows": "Windows", + "Send Tab": "Tukua Ripa", + "Tab": "Ripa", + "Esc": "Esc", + "Send Escape": "Tukua Mawhiti", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Tukua Ctrl-Alt-Del", + "Shutdown/Reboot": "Whakaweto/Whakahou", + "Shutdown/Reboot...": "Whakaweto/Whakahou...", + "Power": "Mana", + "Shutdown": "Whakaweto", + "Reboot": "Whakahou", + "Reset": "Tautuhi", + "Clipboard": "Papa Topenga", + "Clear": "Maama", + "Fullscreen": "Mata Katoa", + "Settings": "Tautuhinga", + "Shared Mode": "Aratau tiritahi", + "View Only": "Tirohia Anake", + "Clip to Window": "Tope ki te Matapihi", + "Scaling Mode:": "Aratau Tauine:", + "None": "Karekau", + "Local Scaling": "Whakatauine Paetata", + "Remote Resizing": "Te Rahinga Mamao", + "Advanced": "Arā Atu Anō", + "Quality:": "Kounga:", + "Compression level:": "Taumata kōpeketanga:", + "Repeater ID:": "Tuuturu ID:", + "WebSocket": "Tukutuku", + "Encrypt": "Whakamuna", + "Host:": "Kaihautū:", + "Port:": "Tauranga:", + "Path:": "Ara:", + "Automatic Reconnect": "Tuhono Aunoa", + "Reconnect Delay (ms):": "Tuhono A Taarua (ms):", + "Show Dot when No Cursor": "Whakaatu Ira ina Kore he Pehu", + "Logging:": "Te takiuru:", + "Version:": "Putanga:", + "Disconnect": "Momotu", + "Connect": "Hono", + "Username:": "Ingoa Kaiwhakamahi:", + "Password:": "Kupuhipa:", + "Send Credentials": "Tukua Taipitopito", + "Cancel": "Whakakore", + "Keys": "Kī", + "Game Cursor Mode": "Aratau Pehu Kemu", + "Press Esc Key to Exit Pointer Lock Mode": "Pēhia te Kī Esc ki te puta i te Aratau Maukati Tohu", + "Game Mode paused, click on screen to resume Game Mode.": "Kua okioki te Aratau Keemu, pawhiria te mata ki te whakaara ano i te Aratau Keemu.", + "Clipboard Up": "Papa Topenga ki runga", + "CLipboard Down": "Papa Topa ki Raro", + "Clipboard Seamless": "Papa Topenga Kore", + "Prefer Local Cursor": "Me pai ki te Pehu Paetata", + "Translate keyboard shortcuts": "Whakamaorihia nga pokatata papapātuhi", + "Enable WebRTC UDP Transit": "Whakahohea te Tukutuku UDP WebRTC", + "Enable WebP Compression": "Whakahohehia te Kopeke Tukutuku", + "Enable Performance Stats": "Whakahohehia nga Tauanga Mahinga", + "Enable Pointer Lock": "Whakahohe Maukati Tohu", + "IME Input Mode": "Aratau Whakauru IME", + "Show Virtual Keyboard Control": "Whakaatu Mana Papapātuhi Mariko", + "Toggle Control Panel via Keystrokes": "Tahurihia te Paewhiri Mana ma te Patua", + "Render Native Resolution": "Whakaahua Whakatau Maori", + "Keyboard Shortcuts": "Pokatata Papapātuhi", + "Enable KasmVNC Keyboard Shortcuts": "Whakahohehia nga Pokatata Papapātuhi KasmVNC", + "1 - Toggle Control Panel": "1 - Takahuri Paewhiri Mana", + "2 - Toggle Game Pointer Mode": "2 - Takahuri Aratau Aratohu Kēmu", + "3 - Toggle Pointer Lock": "3 - Takahuri Maukati Aratohu", + "Stream Quality": "Kounga Rerema", + "Preset Modes:": "Aratau Tatūkē:", + "Static": "Patika", + "Low": "Paheke", + "Medium": "Waenga", + "High": "Teitei", + "Extreme": "Tino rawa", + "Lossless": "Ngarokore", + "Custom": " Ritenga ", + "Anti-Aliasing:": "Ati-Aliasing:", + "Auto Dynamic": "Hini Aunoa", + "Off": "Wehe", + "On": "Kei", + "Dynamic Quality Min:": "Min Kounga Hihiko:", + "Dynamic Quality Max:": "Mōrahi Kounga Hihiko:", + "Treat Lossless:": "Whakaaro Ngarokore:", + "Frame Rate:": "Rere Tapare:", + "Video JPEG Quality:": "Kounga JPEG Ataata:", + "Video WEBP Quality:": "Kounga WEBP Ataata:", + "Video Area:": "Horahanga Ataata:", + "Video Time:": "Wā Ataata:", + "Video Out Time:": "Wā Whakaputa Ataata:", + "Video Mode Width:": "Aratau Ataata Whānui:", + "Video Mode Height:": "Teitei Aratau Ataata:", + "Documentation": "Tuhinga", + "Drag Viewport": "Toia Tauranga Tirohanga", + "KasmVNC encountered an error:": "I hapa a KasmVNC:" +} \ No newline at end of file diff --git a/app/locale/mi_NZ.json b/app/locale/mi_NZ.json new file mode 100644 index 0000000..daaa4ca --- /dev/null +++ b/app/locale/mi_NZ.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "E hono ana...", + "Disconnecting...": "Kei te momotu...", + "Reconnecting...": "Kei te hono ano...", + "Internal error": "Hapa o roto", + "Must set host": "Me whakarite kaihautu", + "Connected (encrypted) to ": "Kua hono (whakamuna) ki ", + "Connected (unencrypted) to ": "Kua hono (kore whakamuna) ki ", + "Something went wrong, connection is closed": "I hapa tetahi mea, kua kati te hononga", + "Failed to connect to server": "I rahua te hono ki te tūmau", + "Disconnected": "Kua Momotu", + "New connection has been rejected with reason: ": "Kua paopaohia te hononga hou me te take:", + "New connection has been rejected": "Kua paopaohia te hononga hou", + "Credentials are required": "Me whai tohu tohu", + "Hide/Show the control bar": "Huna/Whakaatuhia te pae mana", + "Drag": "Toia", + "Move/Drag Viewport": "Nuku/Toia Tauranga Tirohanga", + "Keyboard": "Papapātuhi", + "Show Keyboard": "Whakaatu Papapātuhi", + "Extra keys": "Tahi taapiri", + "Show Extra Keys": "Whakaatuhia nga Kī Anō", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Tahuri Ctrl", + "Alt": "Alt", + "Toggle Alt": "Tahuri Alt", + "Toggle Windows": "Tahuri Windows", + "Windows": "Windows", + "Send Tab": "Tukua Ripa", + "Tab": "Ripa", + "Esc": "Esc", + "Send Escape": "Tukua Mawhiti", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Tukua Ctrl-Alt-Del", + "Shutdown/Reboot": "Whakaweto/Whakahou", + "Shutdown/Reboot...": "Whakaweto/Whakahou...", + "Power": "Mana", + "Shutdown": "Whakaweto", + "Reboot": "Whakahou", + "Reset": "Tautuhi", + "Clipboard": "Papa Topenga", + "Clear": "Maama", + "Fullscreen": "Mata Katoa", + "Settings": "Tautuhinga", + "Shared Mode": "Aratau tiritahi", + "View Only": "Tirohia Anake", + "Clip to Window": "Tope ki te Matapihi", + "Scaling Mode:": "Aratau Tauine:", + "None": "Karekau", + "Local Scaling": "Whakatauine Paetata", + "Remote Resizing": "Te Rahinga Mamao", + "Advanced": "Arā Atu Anō", + "Quality:": "Kounga:", + "Compression level:": "Taumata kōpeketanga:", + "Repeater ID:": "Tuuturu ID:", + "WebSocket": "Tukutuku", + "Encrypt": "Whakamuna", + "Host:": "Kaihautū:", + "Port:": "Tauranga:", + "Path:": "Ara:", + "Automatic Reconnect": "Tuhono Aunoa", + "Reconnect Delay (ms):": "Tuhono A Taarua (ms):", + "Show Dot when No Cursor": "Whakaatu Ira ina Kore he Pehu", + "Logging:": "Te takiuru:", + "Version:": "Putanga:", + "Disconnect": "Momotu", + "Connect": "Hono", + "Username:": "Ingoa Kaiwhakamahi:", + "Password:": "Kupuhipa:", + "Send Credentials": "Tukua Taipitopito", + "Cancel": "Whakakore", + "Keys": "Kī", + "Game Cursor Mode": "Aratau Pehu Kemu", + "Press Esc Key to Exit Pointer Lock Mode": "Pēhia te Kī Esc ki te puta i te Aratau Maukati Tohu", + "Game Mode paused, click on screen to resume Game Mode.": "Kua okioki te Aratau Keemu, pawhiria te mata ki te whakaara ano i te Aratau Keemu.", + "Clipboard Up": "Papa Topenga ki runga", + "CLipboard Down": "Papa Topa ki Raro", + "Clipboard Seamless": "Papa Topenga Kore", + "Prefer Local Cursor": "Me pai ki te Pehu Paetata", + "Translate keyboard shortcuts": "Whakamaorihia nga pokatata papapātuhi", + "Enable WebRTC UDP Transit": "Whakahohea te Tukutuku UDP WebRTC", + "Enable WebP Compression": "Whakahohehia te Kopeke Tukutuku", + "Enable Performance Stats": "Whakahohehia nga Tauanga Mahinga", + "Enable Pointer Lock": "Whakahohe Maukati Tohu", + "IME Input Mode": "Aratau Whakauru IME", + "Show Virtual Keyboard Control": "Whakaatu Mana Papapātuhi Mariko", + "Toggle Control Panel via Keystrokes": "Tahurihia te Paewhiri Mana ma te Patua", + "Render Native Resolution": "Whakaahua Whakatau Maori", + "Keyboard Shortcuts": "Pokatata Papapātuhi", + "Enable KasmVNC Keyboard Shortcuts": "Whakahohehia nga Pokatata Papapātuhi KasmVNC", + "1 - Toggle Control Panel": "1 - Takahuri Paewhiri Mana", + "2 - Toggle Game Pointer Mode": "2 - Takahuri Aratau Aratohu Kēmu", + "3 - Toggle Pointer Lock": "3 - Takahuri Maukati Aratohu", + "Stream Quality": "Kounga Rerema", + "Preset Modes:": "Aratau Tatūkē:", + "Static": "Patika", + "Low": "Paheke", + "Medium": "Waenga", + "High": "Teitei", + "Extreme": "Tino rawa", + "Lossless": "Ngarokore", + "Custom": " Ritenga ", + "Anti-Aliasing:": "Ati-Aliasing:", + "Auto Dynamic": "Hini Aunoa", + "Off": "Wehe", + "On": "Kei", + "Dynamic Quality Min:": "Min Kounga Hihiko:", + "Dynamic Quality Max:": "Mōrahi Kounga Hihiko:", + "Treat Lossless:": "Whakaaro Ngarokore:", + "Frame Rate:": "Rere Tapare:", + "Video JPEG Quality:": "Kounga JPEG Ataata:", + "Video WEBP Quality:": "Kounga WEBP Ataata:", + "Video Area:": "Horahanga Ataata:", + "Video Time:": "Wā Ataata:", + "Video Out Time:": "Wā Whakaputa Ataata:", + "Video Mode Width:": "Aratau Ataata Whānui:", + "Video Mode Height:": "Teitei Aratau Ataata:", + "Documentation": "Tuhinga", + "Drag Viewport": "Toia Tauranga Tirohanga", + "KasmVNC encountered an error:": "I hapa a KasmVNC:" +} \ No newline at end of file diff --git a/app/locale/mk.json b/app/locale/mk.json new file mode 100644 index 0000000..deb356e --- /dev/null +++ b/app/locale/mk.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Се поврзува...", + "Disconnecting...": "Се исклучува...", + "Reconnecting...": "Повторно поврзување...", + "Internal error": "Внатрешна грешка", + "Must set host": "Мора да се постави домаќин", + "Connected (encrypted) to ": "Поврзан (шифриран) со", + "Connected (unencrypted) to ": "Поврзано (нешифрирано) со", + "Something went wrong, connection is closed": "Нешто тргна наопаку, врската е затворена", + "Failed to connect to server": "Не можам да се поврзам на серверот", + "Disconnected": "Исклучено", + "New connection has been rejected with reason: ": "Новата врска е отфрлена со причина:", + "New connection has been rejected": "Новата врска е одбиена", + "Credentials are required": "Потребни се акредитиви", + "Hide/Show the control bar": "Сокриј/Покажи ја контролната лента", + "Drag": "Повлечете", + "Move/Drag Viewport": "Премести/Повлечете го приказот", + "Keyboard": "Тастатура", + "Show Keyboard": "Прикажи тастатура", + "Extra keys": "Дополнителни клучеви", + "Show Extra Keys": "Прикажи дополнителни клучеви", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Премести Ctrl", + "Alt": "Alt", + "Toggle Alt": "Вклучи Alt", + "Toggle Windows": "Премести Windows", + "Windows": "Виндоус", + "Send Tab": "Испрати јазиче", + "Tab": "Таб", + "Esc": "Esc", + "Send Escape": "Испрати бегство", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Испрати Ctrl-Alt-Del", + "Shutdown/Reboot": "Исклучување/рестартирање", + "Shutdown/Reboot...": "Исклучување/рестартирање...", + "Power": "Моќ", + "Shutdown": "Исклучи", + "Reboot": "Рестартирај", + "Reset": "Ресетирање", + "Clipboard": "Табла со исечоци", + "Clear": "Јасно", + "Fullscreen": "Цел екран", + "Settings": "Поставки", + "Shared Mode": "Споделен режим", + "View Only": "Само преглед", + "Clip to Window": "Клип до прозорец", + "Scaling Mode:": "Режим на скалирање:", + "None": "Никој", + "Local Scaling": "Локално скалирање", + "Remote Resizing": "Далечинска промена на големината", + "Advanced": "Напредно", + "Quality:": "Квалитет:", + "Compression level:": "Ниво на компресија:", + "Repeater ID:": "ID на повторувач:", + "WebSocket": "Вебсокет", + "Encrypt": "Шифрирај", + "Host:": "Домаќин:", + "Port:": "Пристаниште:", + "Path:": "Пат:", + "Automatic Reconnect": "Автоматско повторно поврзување", + "Reconnect Delay (ms):": "Одложено повторно поврзување (ms):", + "Show Dot when No Cursor": "Прикажи точка кога нема курсор", + "Logging:": "Сеча:", + "Version:": "Верзија:", + "Disconnect": "Исклучи се", + "Connect": "Поврзи", + "Username:": "Корисничко име:", + "Password:": "Лозинка:", + "Send Credentials": "Испрати ингеренции", + "Cancel": "Откажи", + "Keys": "Клучеви", + "Game Cursor Mode": "Режим на курсорот на играта", + "Press Esc Key to Exit Pointer Lock Mode": "Притиснете го копчето Esc за да излезете од режимот за заклучување на покажувачот", + "Game Mode paused, click on screen to resume Game Mode.": "Режимот на игра е паузиран, кликнете на екранот за да продолжите со режимот на игра.", + "Clipboard Up": "Таблата со исечоци нагоре", + "CLipboard Down": "Клипборд надолу", + "Clipboard Seamless": "Безшевната табла со исечоци", + "Prefer Local Cursor": "Преферирај локален курсор", + "Translate keyboard shortcuts": "Преведи кратенки на тастатурата", + "Enable WebRTC UDP Transit": "Овозможи WebRTC UDP Transit", + "Enable WebP Compression": "Овозможи компресија на WebP", + "Enable Performance Stats": "Овозможи статистика за перформанси", + "Enable Pointer Lock": "Овозможи заклучување на покажувачот", + "IME Input Mode": "Режим за внесување IME", + "Show Virtual Keyboard Control": "Прикажи контрола на виртуелна тастатура", + "Toggle Control Panel via Keystrokes": "Вклучете ја контролната табла преку притискање на копчињата", + "Render Native Resolution": "Изнеси мајчин резолуција", + "Keyboard Shortcuts": "Кратенки на тастатурата", + "Enable KasmVNC Keyboard Shortcuts": "Овозможи кратенки на тастатура KasmVNC", + "1 - Toggle Control Panel": "1 - Вклучи контролен панел", + "2 - Toggle Game Pointer Mode": "2 - Вклучи го режимот на покажувачот на играта", + "3 - Toggle Pointer Lock": "3 - Вклучи заклучување на покажувачот", + "Stream Quality": "Квалитет на пренос", + "Preset Modes:": "Претпоставени режими:", + "Static": "статички", + "Low": "Ниско", + "Medium": "Среден", + "High": "високо", + "Extreme": "Екстремно", + "Lossless": "Без загуба", + "Custom": "Прилагодено", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Автодинамика", + "Off": "Исклучено", + "On": "На", + "Dynamic Quality Min:": "Мин динамички квалитет:", + "Dynamic Quality Max:": "Макс за динамички квалитет:", + "Treat Lossless:": "Третирајте без загуба:", + "Frame Rate:": "Стапка на слики:", + "Video JPEG Quality:": "Квалитет на видео JPEG:", + "Video WEBP Quality:": "Видео WEBP квалитет:", + "Video Area:": "Видео област:", + "Video Time:": "Време за видео:", + "Video Out Time:": "Време на излегување на видеото:", + "Video Mode Width:": "Ширина на видео режим:", + "Video Mode Height:": "Висина на режимот на видео:", + "Documentation": "Документација", + "Drag Viewport": "Повлечете го погледот", + "KasmVNC encountered an error:": "KasmVNC наиде на грешка:" +} \ No newline at end of file diff --git a/app/locale/mk_MK.json b/app/locale/mk_MK.json new file mode 100644 index 0000000..deb356e --- /dev/null +++ b/app/locale/mk_MK.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Се поврзува...", + "Disconnecting...": "Се исклучува...", + "Reconnecting...": "Повторно поврзување...", + "Internal error": "Внатрешна грешка", + "Must set host": "Мора да се постави домаќин", + "Connected (encrypted) to ": "Поврзан (шифриран) со", + "Connected (unencrypted) to ": "Поврзано (нешифрирано) со", + "Something went wrong, connection is closed": "Нешто тргна наопаку, врската е затворена", + "Failed to connect to server": "Не можам да се поврзам на серверот", + "Disconnected": "Исклучено", + "New connection has been rejected with reason: ": "Новата врска е отфрлена со причина:", + "New connection has been rejected": "Новата врска е одбиена", + "Credentials are required": "Потребни се акредитиви", + "Hide/Show the control bar": "Сокриј/Покажи ја контролната лента", + "Drag": "Повлечете", + "Move/Drag Viewport": "Премести/Повлечете го приказот", + "Keyboard": "Тастатура", + "Show Keyboard": "Прикажи тастатура", + "Extra keys": "Дополнителни клучеви", + "Show Extra Keys": "Прикажи дополнителни клучеви", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Премести Ctrl", + "Alt": "Alt", + "Toggle Alt": "Вклучи Alt", + "Toggle Windows": "Премести Windows", + "Windows": "Виндоус", + "Send Tab": "Испрати јазиче", + "Tab": "Таб", + "Esc": "Esc", + "Send Escape": "Испрати бегство", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Испрати Ctrl-Alt-Del", + "Shutdown/Reboot": "Исклучување/рестартирање", + "Shutdown/Reboot...": "Исклучување/рестартирање...", + "Power": "Моќ", + "Shutdown": "Исклучи", + "Reboot": "Рестартирај", + "Reset": "Ресетирање", + "Clipboard": "Табла со исечоци", + "Clear": "Јасно", + "Fullscreen": "Цел екран", + "Settings": "Поставки", + "Shared Mode": "Споделен режим", + "View Only": "Само преглед", + "Clip to Window": "Клип до прозорец", + "Scaling Mode:": "Режим на скалирање:", + "None": "Никој", + "Local Scaling": "Локално скалирање", + "Remote Resizing": "Далечинска промена на големината", + "Advanced": "Напредно", + "Quality:": "Квалитет:", + "Compression level:": "Ниво на компресија:", + "Repeater ID:": "ID на повторувач:", + "WebSocket": "Вебсокет", + "Encrypt": "Шифрирај", + "Host:": "Домаќин:", + "Port:": "Пристаниште:", + "Path:": "Пат:", + "Automatic Reconnect": "Автоматско повторно поврзување", + "Reconnect Delay (ms):": "Одложено повторно поврзување (ms):", + "Show Dot when No Cursor": "Прикажи точка кога нема курсор", + "Logging:": "Сеча:", + "Version:": "Верзија:", + "Disconnect": "Исклучи се", + "Connect": "Поврзи", + "Username:": "Корисничко име:", + "Password:": "Лозинка:", + "Send Credentials": "Испрати ингеренции", + "Cancel": "Откажи", + "Keys": "Клучеви", + "Game Cursor Mode": "Режим на курсорот на играта", + "Press Esc Key to Exit Pointer Lock Mode": "Притиснете го копчето Esc за да излезете од режимот за заклучување на покажувачот", + "Game Mode paused, click on screen to resume Game Mode.": "Режимот на игра е паузиран, кликнете на екранот за да продолжите со режимот на игра.", + "Clipboard Up": "Таблата со исечоци нагоре", + "CLipboard Down": "Клипборд надолу", + "Clipboard Seamless": "Безшевната табла со исечоци", + "Prefer Local Cursor": "Преферирај локален курсор", + "Translate keyboard shortcuts": "Преведи кратенки на тастатурата", + "Enable WebRTC UDP Transit": "Овозможи WebRTC UDP Transit", + "Enable WebP Compression": "Овозможи компресија на WebP", + "Enable Performance Stats": "Овозможи статистика за перформанси", + "Enable Pointer Lock": "Овозможи заклучување на покажувачот", + "IME Input Mode": "Режим за внесување IME", + "Show Virtual Keyboard Control": "Прикажи контрола на виртуелна тастатура", + "Toggle Control Panel via Keystrokes": "Вклучете ја контролната табла преку притискање на копчињата", + "Render Native Resolution": "Изнеси мајчин резолуција", + "Keyboard Shortcuts": "Кратенки на тастатурата", + "Enable KasmVNC Keyboard Shortcuts": "Овозможи кратенки на тастатура KasmVNC", + "1 - Toggle Control Panel": "1 - Вклучи контролен панел", + "2 - Toggle Game Pointer Mode": "2 - Вклучи го режимот на покажувачот на играта", + "3 - Toggle Pointer Lock": "3 - Вклучи заклучување на покажувачот", + "Stream Quality": "Квалитет на пренос", + "Preset Modes:": "Претпоставени режими:", + "Static": "статички", + "Low": "Ниско", + "Medium": "Среден", + "High": "високо", + "Extreme": "Екстремно", + "Lossless": "Без загуба", + "Custom": "Прилагодено", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Автодинамика", + "Off": "Исклучено", + "On": "На", + "Dynamic Quality Min:": "Мин динамички квалитет:", + "Dynamic Quality Max:": "Макс за динамички квалитет:", + "Treat Lossless:": "Третирајте без загуба:", + "Frame Rate:": "Стапка на слики:", + "Video JPEG Quality:": "Квалитет на видео JPEG:", + "Video WEBP Quality:": "Видео WEBP квалитет:", + "Video Area:": "Видео област:", + "Video Time:": "Време за видео:", + "Video Out Time:": "Време на излегување на видеото:", + "Video Mode Width:": "Ширина на видео режим:", + "Video Mode Height:": "Висина на режимот на видео:", + "Documentation": "Документација", + "Drag Viewport": "Повлечете го погледот", + "KasmVNC encountered an error:": "KasmVNC наиде на грешка:" +} \ No newline at end of file diff --git a/app/locale/ml.json b/app/locale/ml.json new file mode 100644 index 0000000..c7c1cc7 --- /dev/null +++ b/app/locale/ml.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "കണക്u200cറ്റുചെയ്യുന്നു...", + "Disconnecting...": "വിച്ഛേദിക്കുന്നു...", + "Reconnecting...": "വീണ്ടും ബന്ധിപ്പിക്കുന്നു...", + "Internal error": "ആന്തരിക പിശക്", + "Must set host": "ഹോസ്റ്റ് സജ്ജീകരിക്കണം", + "Connected (encrypted) to ": "ഇതിലേക്ക് കണക്റ്റുചെയ്u200cതു (എൻക്രിപ്റ്റ് ചെയ്u200cതു)", + "Connected (unencrypted) to ": "ഇതിലേക്ക് ബന്ധിപ്പിച്ചിരിക്കുന്നു (എൻക്രിപ്റ്റ് ചെയ്യാത്തത്)", + "Something went wrong, connection is closed": "എന്തോ കുഴപ്പം സംഭവിച്ചു, കണക്ഷൻ അടച്ചു", + "Failed to connect to server": "സെര്വറുമായി കണക്റ്റ് ചെയ്യാനായില്ല", + "Disconnected": "വിച്ഛേദിച്ചു", + "New connection has been rejected with reason: ": "പുതിയ കണക്ഷൻ കാരണം നിരസിച്ചു:", + "New connection has been rejected": "പുതിയ കണക്ഷൻ നിരസിച്ചു", + "Credentials are required": "ക്രെഡൻഷ്യലുകൾ ആവശ്യമാണ്", + "Hide/Show the control bar": "നിയന്ത്രണ ബാർ മറയ്ക്കുക/കാണിക്കുക", + "Drag": "വലിച്ചിടുക", + "Move/Drag Viewport": "വ്യൂപോർട്ട് നീക്കുക/വലിക്കുക", + "Keyboard": "കീബോർഡ്", + "Show Keyboard": "കീബോർഡ് കാണിക്കുക", + "Extra keys": "അധിക കീകൾ", + "Show Extra Keys": "അധിക കീകൾ കാണിക്കുക", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl മാറ്റുക", + "Alt": "Alt", + "Toggle Alt": "Alt ടോഗിൾ ചെയ്യുക", + "Toggle Windows": "വിൻഡോസ് മാറ്റുക", + "Windows": "വിൻഡോസ്", + "Send Tab": "ടാബ് അയയ്ക്കുക", + "Tab": "ടാബ്", + "Esc": "ഇഎസ്സി", + "Send Escape": "രക്ഷപ്പെടാൻ അയയ്ക്കുക", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del അയയ്ക്കുക", + "Shutdown/Reboot": "ഷട്ട്ഡൗൺ/റീബൂട്ട്", + "Shutdown/Reboot...": "ഷട്ട്ഡൗൺ/റീബൂട്ട്...", + "Power": "ശക്തി", + "Shutdown": "ഷട്ട് ഡൗൺ", + "Reboot": "റീബൂട്ട്", + "Reset": "പുനഃസജ്ജമാക്കുക", + "Clipboard": "ക്ലിപ്പ്ബോർഡ്", + "Clear": "വ്യക്തം", + "Fullscreen": "പൂർണ്ണ സ്ക്രീൻ", + "Settings": "ക്രമീകരണങ്ങൾ", + "Shared Mode": "പങ്കിട്ട മോഡ്", + "View Only": "കാണുക മാത്രം", + "Clip to Window": "ക്ലിപ്പ് ടു വിൻഡോ", + "Scaling Mode:": "സ്കെയിലിംഗ് മോഡ്:", + "None": "ഒന്നുമില്ല", + "Local Scaling": "ലോക്കൽ സ്കെയിലിംഗ്", + "Remote Resizing": "വിദൂര വലുപ്പം മാറ്റൽ", + "Advanced": "വിപുലമായ", + "Quality:": "ഗുണമേന്മയുള്ള:", + "Compression level:": "കംപ്രഷൻ ലെവൽ:", + "Repeater ID:": "റിപ്പീറ്റർ ഐഡി:", + "WebSocket": "വെബ്സോക്കറ്റ്", + "Encrypt": "എൻക്രിപ്റ്റ്", + "Host:": "ഹോസ്റ്റ്:", + "Port:": "തുറമുഖം:", + "Path:": "പാത:", + "Automatic Reconnect": "ഓട്ടോമാറ്റിക് റീകണക്റ്റ്", + "Reconnect Delay (ms):": "വീണ്ടും കണക്u200cറ്റ് ചെയ്യാനുള്ള കാലതാമസം (മി.സെ.):", + "Show Dot when No Cursor": "കഴ്u200cസർ ഇല്ലെങ്കിൽ ഡോട്ട് കാണിക്കുക", + "Logging:": "ലോഗിംഗ്:", + "Version:": "പതിപ്പ്:", + "Disconnect": "വിച്ഛേദിക്കുക", + "Connect": "ബന്ധിപ്പിക്കുക", + "Username:": "ഉപയോക്തൃനാമം:", + "Password:": "Password:", + "Send Credentials": "ക്രെഡൻഷ്യലുകൾ അയയ്ക്കുക", + "Cancel": "റദ്ദാക്കുക", + "Keys": "കീകൾ", + "Game Cursor Mode": "ഗെയിം കഴ്u200cസർ മോഡ്", + "Press Esc Key to Exit Pointer Lock Mode": "പോയിന്റർ ലോക്ക് മോഡിൽ നിന്ന് പുറത്തുകടക്കാൻ Esc കീ അമർത്തുക", + "Game Mode paused, click on screen to resume Game Mode.": "ഗെയിം മോഡ് താൽക്കാലികമായി നിർത്തി, ഗെയിം മോഡ് പുനരാരംഭിക്കാൻ സ്ക്രീനിൽ ക്ലിക്കുചെയ്യുക.", + "Clipboard Up": "ക്ലിപ്പ്ബോർഡ് അപ്പ്", + "CLipboard Down": "ക്ലിപ്പ്ബോർഡ് ഡൗൺ", + "Clipboard Seamless": "ക്ലിപ്പ്ബോർഡ് തടസ്സമില്ലാത്തത്", + "Prefer Local Cursor": "പ്രാദേശിക കഴ്u200cസർ മുൻഗണന നൽകുക", + "Translate keyboard shortcuts": "കീബോർഡ് കുറുക്കുവഴികൾ വിവർത്തനം ചെയ്യുക", + "Enable WebRTC UDP Transit": "WebRTC UDP ട്രാൻസിറ്റ് പ്രവർത്തനക്ഷമമാക്കുക", + "Enable WebP Compression": "WebP കംപ്രഷൻ പ്രവർത്തനക്ഷമമാക്കുക", + "Enable Performance Stats": "പ്രകടന സ്ഥിതിവിവരക്കണക്കുകൾ പ്രവർത്തനക്ഷമമാക്കുക", + "Enable Pointer Lock": "പോയിന്റർ ലോക്ക് പ്രവർത്തനക്ഷമമാക്കുക", + "IME Input Mode": "IME ഇൻപുട്ട് മോഡ്", + "Show Virtual Keyboard Control": "വെർച്വൽ കീബോർഡ് നിയന്ത്രണം കാണിക്കുക", + "Toggle Control Panel via Keystrokes": "കീസ്ട്രോക്കുകൾ വഴി നിയന്ത്രണ പാനൽ മാറ്റുക", + "Render Native Resolution": "റെൻഡർ നേറ്റീവ് റെസല്യൂഷൻ", + "Keyboard Shortcuts": "കീബോർഡ് കുറുക്കുവഴികൾ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC കീബോർഡ് കുറുക്കുവഴികൾ പ്രവർത്തനക്ഷമമാക്കുക", + "1 - Toggle Control Panel": "1 - നിയന്ത്രണ പാനൽ ടോഗിൾ ചെയ്യുക", + "2 - Toggle Game Pointer Mode": "2 - ഗെയിം പോയിന്റർ മോഡ് ടോഗിൾ ചെയ്യുക", + "3 - Toggle Pointer Lock": "3 - ടോഗിൾ പോയിന്റർ ലോക്ക്", + "Stream Quality": "സ്ട്രീം ഗുണനിലവാരം", + "Preset Modes:": "പ്രീസെറ്റ് മോഡുകൾ:", + "Static": "സ്റ്റാറ്റിക്", + "Low": "താഴ്ന്ന", + "Medium": "ഇടത്തരം", + "High": "ഉയർന്ന", + "Extreme": "അങ്ങേയറ്റം", + "Lossless": "നഷ്ടമില്ലാത്തത്", + "Custom": "ഇഷ്u200cടാനുസൃതം", + "Anti-Aliasing:": "ആന്റി അപരനാമം:", + "Auto Dynamic": "ഓട്ടോ ഡൈനാമിക്", + "Off": "ഓഫ്", + "On": "ഓൺ", + "Dynamic Quality Min:": "ഡൈനാമിക് ക്വാളിറ്റി മിനി:", + "Dynamic Quality Max:": "ഡൈനാമിക് ക്വാളിറ്റി മാക്സ്:", + "Treat Lossless:": "നഷ്ടരഹിതമായി പെരുമാറുക:", + "Frame Rate:": "ഫ്രെയിം നിരക്ക്:", + "Video JPEG Quality:": "വീഡിയോ JPEG ഗുണനിലവാരം:", + "Video WEBP Quality:": "വീഡിയോ WEBP നിലവാരം:", + "Video Area:": "വീഡിയോ ഏരിയ:", + "Video Time:": "വീഡിയോ സമയം:", + "Video Out Time:": "വീഡിയോ ഔട്ട് സമയം:", + "Video Mode Width:": "വീഡിയോ മോഡ് വീതി:", + "Video Mode Height:": "വീഡിയോ മോഡ് ഉയരം:", + "Documentation": "പ്രമാണീകരണം", + "Drag Viewport": "വ്യൂപോർട്ട് വലിച്ചിടുക", + "KasmVNC encountered an error:": "KasmVNC ഒരു പിശക് നേരിട്ടു:" +} \ No newline at end of file diff --git a/app/locale/ml_IN.json b/app/locale/ml_IN.json new file mode 100644 index 0000000..c7c1cc7 --- /dev/null +++ b/app/locale/ml_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "കണക്u200cറ്റുചെയ്യുന്നു...", + "Disconnecting...": "വിച്ഛേദിക്കുന്നു...", + "Reconnecting...": "വീണ്ടും ബന്ധിപ്പിക്കുന്നു...", + "Internal error": "ആന്തരിക പിശക്", + "Must set host": "ഹോസ്റ്റ് സജ്ജീകരിക്കണം", + "Connected (encrypted) to ": "ഇതിലേക്ക് കണക്റ്റുചെയ്u200cതു (എൻക്രിപ്റ്റ് ചെയ്u200cതു)", + "Connected (unencrypted) to ": "ഇതിലേക്ക് ബന്ധിപ്പിച്ചിരിക്കുന്നു (എൻക്രിപ്റ്റ് ചെയ്യാത്തത്)", + "Something went wrong, connection is closed": "എന്തോ കുഴപ്പം സംഭവിച്ചു, കണക്ഷൻ അടച്ചു", + "Failed to connect to server": "സെര്വറുമായി കണക്റ്റ് ചെയ്യാനായില്ല", + "Disconnected": "വിച്ഛേദിച്ചു", + "New connection has been rejected with reason: ": "പുതിയ കണക്ഷൻ കാരണം നിരസിച്ചു:", + "New connection has been rejected": "പുതിയ കണക്ഷൻ നിരസിച്ചു", + "Credentials are required": "ക്രെഡൻഷ്യലുകൾ ആവശ്യമാണ്", + "Hide/Show the control bar": "നിയന്ത്രണ ബാർ മറയ്ക്കുക/കാണിക്കുക", + "Drag": "വലിച്ചിടുക", + "Move/Drag Viewport": "വ്യൂപോർട്ട് നീക്കുക/വലിക്കുക", + "Keyboard": "കീബോർഡ്", + "Show Keyboard": "കീബോർഡ് കാണിക്കുക", + "Extra keys": "അധിക കീകൾ", + "Show Extra Keys": "അധിക കീകൾ കാണിക്കുക", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl മാറ്റുക", + "Alt": "Alt", + "Toggle Alt": "Alt ടോഗിൾ ചെയ്യുക", + "Toggle Windows": "വിൻഡോസ് മാറ്റുക", + "Windows": "വിൻഡോസ്", + "Send Tab": "ടാബ് അയയ്ക്കുക", + "Tab": "ടാബ്", + "Esc": "ഇഎസ്സി", + "Send Escape": "രക്ഷപ്പെടാൻ അയയ്ക്കുക", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del അയയ്ക്കുക", + "Shutdown/Reboot": "ഷട്ട്ഡൗൺ/റീബൂട്ട്", + "Shutdown/Reboot...": "ഷട്ട്ഡൗൺ/റീബൂട്ട്...", + "Power": "ശക്തി", + "Shutdown": "ഷട്ട് ഡൗൺ", + "Reboot": "റീബൂട്ട്", + "Reset": "പുനഃസജ്ജമാക്കുക", + "Clipboard": "ക്ലിപ്പ്ബോർഡ്", + "Clear": "വ്യക്തം", + "Fullscreen": "പൂർണ്ണ സ്ക്രീൻ", + "Settings": "ക്രമീകരണങ്ങൾ", + "Shared Mode": "പങ്കിട്ട മോഡ്", + "View Only": "കാണുക മാത്രം", + "Clip to Window": "ക്ലിപ്പ് ടു വിൻഡോ", + "Scaling Mode:": "സ്കെയിലിംഗ് മോഡ്:", + "None": "ഒന്നുമില്ല", + "Local Scaling": "ലോക്കൽ സ്കെയിലിംഗ്", + "Remote Resizing": "വിദൂര വലുപ്പം മാറ്റൽ", + "Advanced": "വിപുലമായ", + "Quality:": "ഗുണമേന്മയുള്ള:", + "Compression level:": "കംപ്രഷൻ ലെവൽ:", + "Repeater ID:": "റിപ്പീറ്റർ ഐഡി:", + "WebSocket": "വെബ്സോക്കറ്റ്", + "Encrypt": "എൻക്രിപ്റ്റ്", + "Host:": "ഹോസ്റ്റ്:", + "Port:": "തുറമുഖം:", + "Path:": "പാത:", + "Automatic Reconnect": "ഓട്ടോമാറ്റിക് റീകണക്റ്റ്", + "Reconnect Delay (ms):": "വീണ്ടും കണക്u200cറ്റ് ചെയ്യാനുള്ള കാലതാമസം (മി.സെ.):", + "Show Dot when No Cursor": "കഴ്u200cസർ ഇല്ലെങ്കിൽ ഡോട്ട് കാണിക്കുക", + "Logging:": "ലോഗിംഗ്:", + "Version:": "പതിപ്പ്:", + "Disconnect": "വിച്ഛേദിക്കുക", + "Connect": "ബന്ധിപ്പിക്കുക", + "Username:": "ഉപയോക്തൃനാമം:", + "Password:": "Password:", + "Send Credentials": "ക്രെഡൻഷ്യലുകൾ അയയ്ക്കുക", + "Cancel": "റദ്ദാക്കുക", + "Keys": "കീകൾ", + "Game Cursor Mode": "ഗെയിം കഴ്u200cസർ മോഡ്", + "Press Esc Key to Exit Pointer Lock Mode": "പോയിന്റർ ലോക്ക് മോഡിൽ നിന്ന് പുറത്തുകടക്കാൻ Esc കീ അമർത്തുക", + "Game Mode paused, click on screen to resume Game Mode.": "ഗെയിം മോഡ് താൽക്കാലികമായി നിർത്തി, ഗെയിം മോഡ് പുനരാരംഭിക്കാൻ സ്ക്രീനിൽ ക്ലിക്കുചെയ്യുക.", + "Clipboard Up": "ക്ലിപ്പ്ബോർഡ് അപ്പ്", + "CLipboard Down": "ക്ലിപ്പ്ബോർഡ് ഡൗൺ", + "Clipboard Seamless": "ക്ലിപ്പ്ബോർഡ് തടസ്സമില്ലാത്തത്", + "Prefer Local Cursor": "പ്രാദേശിക കഴ്u200cസർ മുൻഗണന നൽകുക", + "Translate keyboard shortcuts": "കീബോർഡ് കുറുക്കുവഴികൾ വിവർത്തനം ചെയ്യുക", + "Enable WebRTC UDP Transit": "WebRTC UDP ട്രാൻസിറ്റ് പ്രവർത്തനക്ഷമമാക്കുക", + "Enable WebP Compression": "WebP കംപ്രഷൻ പ്രവർത്തനക്ഷമമാക്കുക", + "Enable Performance Stats": "പ്രകടന സ്ഥിതിവിവരക്കണക്കുകൾ പ്രവർത്തനക്ഷമമാക്കുക", + "Enable Pointer Lock": "പോയിന്റർ ലോക്ക് പ്രവർത്തനക്ഷമമാക്കുക", + "IME Input Mode": "IME ഇൻപുട്ട് മോഡ്", + "Show Virtual Keyboard Control": "വെർച്വൽ കീബോർഡ് നിയന്ത്രണം കാണിക്കുക", + "Toggle Control Panel via Keystrokes": "കീസ്ട്രോക്കുകൾ വഴി നിയന്ത്രണ പാനൽ മാറ്റുക", + "Render Native Resolution": "റെൻഡർ നേറ്റീവ് റെസല്യൂഷൻ", + "Keyboard Shortcuts": "കീബോർഡ് കുറുക്കുവഴികൾ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC കീബോർഡ് കുറുക്കുവഴികൾ പ്രവർത്തനക്ഷമമാക്കുക", + "1 - Toggle Control Panel": "1 - നിയന്ത്രണ പാനൽ ടോഗിൾ ചെയ്യുക", + "2 - Toggle Game Pointer Mode": "2 - ഗെയിം പോയിന്റർ മോഡ് ടോഗിൾ ചെയ്യുക", + "3 - Toggle Pointer Lock": "3 - ടോഗിൾ പോയിന്റർ ലോക്ക്", + "Stream Quality": "സ്ട്രീം ഗുണനിലവാരം", + "Preset Modes:": "പ്രീസെറ്റ് മോഡുകൾ:", + "Static": "സ്റ്റാറ്റിക്", + "Low": "താഴ്ന്ന", + "Medium": "ഇടത്തരം", + "High": "ഉയർന്ന", + "Extreme": "അങ്ങേയറ്റം", + "Lossless": "നഷ്ടമില്ലാത്തത്", + "Custom": "ഇഷ്u200cടാനുസൃതം", + "Anti-Aliasing:": "ആന്റി അപരനാമം:", + "Auto Dynamic": "ഓട്ടോ ഡൈനാമിക്", + "Off": "ഓഫ്", + "On": "ഓൺ", + "Dynamic Quality Min:": "ഡൈനാമിക് ക്വാളിറ്റി മിനി:", + "Dynamic Quality Max:": "ഡൈനാമിക് ക്വാളിറ്റി മാക്സ്:", + "Treat Lossless:": "നഷ്ടരഹിതമായി പെരുമാറുക:", + "Frame Rate:": "ഫ്രെയിം നിരക്ക്:", + "Video JPEG Quality:": "വീഡിയോ JPEG ഗുണനിലവാരം:", + "Video WEBP Quality:": "വീഡിയോ WEBP നിലവാരം:", + "Video Area:": "വീഡിയോ ഏരിയ:", + "Video Time:": "വീഡിയോ സമയം:", + "Video Out Time:": "വീഡിയോ ഔട്ട് സമയം:", + "Video Mode Width:": "വീഡിയോ മോഡ് വീതി:", + "Video Mode Height:": "വീഡിയോ മോഡ് ഉയരം:", + "Documentation": "പ്രമാണീകരണം", + "Drag Viewport": "വ്യൂപോർട്ട് വലിച്ചിടുക", + "KasmVNC encountered an error:": "KasmVNC ഒരു പിശക് നേരിട്ടു:" +} \ No newline at end of file diff --git a/app/locale/mn.json b/app/locale/mn.json new file mode 100644 index 0000000..a12043f --- /dev/null +++ b/app/locale/mn.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Холбож байна...", + "Disconnecting...": "Салгаж байна...", + "Reconnecting...": "Дахин холбогдож байна...", + "Internal error": "Дотоод алдаа", + "Must set host": "Хастыг тохируулах ёстой", + "Connected (encrypted) to ": "Холбогдсон (шифрлэгдсэн)", + "Connected (unencrypted) to ": "Холбогдсон (шифрлэгдээгүй)", + "Something went wrong, connection is closed": "Ямар нэг алдаа гарлаа, холболт хаагдсан", + "Failed to connect to server": "Сервертэй холбогдож чадсангүй", + "Disconnected": "Таслагдсан", + "New connection has been rejected with reason: ": "Шинэ холболтоос татгалзсан шалтгаан нь:", + "New connection has been rejected": "Шинэ холболтоос татгалзсан", + "Credentials are required": "Итгэмжлэх жуух бичиг шаардлагатай", + "Hide/Show the control bar": "Хяналтын мөрийг нуух/ харуулах", + "Drag": "Чирэх", + "Move/Drag Viewport": "Харах талбарыг зөөх/чирэх", + "Keyboard": "Гар", + "Show Keyboard": "Гарыг харуулах", + "Extra keys": "Нэмэлт түлхүүрүүд", + "Show Extra Keys": "Нэмэлт түлхүүрүүдийг харуулах", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl-г асаах/унтраах", + "Alt": "Алт", + "Toggle Alt": "Alt-ыг асаах/унтраах", + "Toggle Windows": "Windows-ыг асаах/унтраах", + "Windows": "Windows", + "Send Tab": "Илгээх таб", + "Tab": "Таб", + "Esc": "Esc", + "Send Escape": "Зутгал илгээх", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del илгээх", + "Shutdown/Reboot": "Унтраах/дахин ачаалах", + "Shutdown/Reboot...": "Унтраах/дахин ачаалах...", + "Power": "Хүч", + "Shutdown": "Унтраах", + "Reboot": "Дахин ачаалах", + "Reset": "Дахин тохируулах", + "Clipboard": "Хүрээний санах ой", + "Clear": "Цэвэр", + "Fullscreen": "Дэлгэц дүүрэн", + "Settings": "Тохиргоо", + "Shared Mode": "Хуваалцсан горим", + "View Only": "Зөвхөн харах", + "Clip to Window": "Цонхонд хавчих", + "Scaling Mode:": "Хамшрах горим:", + "None": "Үгүй", + "Local Scaling": "Орон нутгийн масштаб", + "Remote Resizing": "Алсын хэмжээг өөрчлөх", + "Advanced": "Дэвшилтэт", + "Quality:": "Чанар:", + "Compression level:": "Шахалтын түвшин:", + "Repeater ID:": "Давтагч ID:", + "WebSocket": "WebSocket", + "Encrypt": "Шифрлэх", + "Host:": "Хөтлөгч:", + "Port:": "Порт:", + "Path:": "Зам:", + "Automatic Reconnect": "Автоматаар дахин холбох", + "Reconnect Delay (ms):": "Дахин холболтын саатал (мс):", + "Show Dot when No Cursor": "Курсор байхгүй үед цэгийг харуулах", + "Logging:": "Бүртгэл:", + "Version:": "Хувилбар:", + "Disconnect": "Таслах", + "Connect": "Холбох", + "Username:": "Хэрэглэгчийн нэр:", + "Password:": "Нууц үг:", + "Send Credentials": "Итгэмжлэх жуух бичгээ илгээх", + "Cancel": "Цуцлах", + "Keys": "Түлхүүр", + "Game Cursor Mode": "Тоглоомын курсорын горим", + "Press Esc Key to Exit Pointer Lock Mode": "Заагч түгжих горимоос гарахын тулд Esc товчийг дарна уу", + "Game Mode paused, click on screen to resume Game Mode.": "Тоглоомын горим түр зогссон. Тоглоомын горимыг үргэлжлүүлэхийн тулд дэлгэцэн дээр дарна уу.", + "Clipboard Up": "Цахилгаан санах ой", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Цахилгаан санах ойгүй", + "Prefer Local Cursor": "Орон нутгийн курсорыг илүүд үзэх", + "Translate keyboard shortcuts": "Гарын товчлолыг орчуулах", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit-г идэвхжүүлэх", + "Enable WebP Compression": "WebP шахалтыг идэвхжүүлэх", + "Enable Performance Stats": "Гүйцэтгэлийн статистикийг идэвхжүүлэх", + "Enable Pointer Lock": "Заагч түгжээг идэвхжүүлэх", + "IME Input Mode": "IME оролтын горим", + "Show Virtual Keyboard Control": "Виртуал гарын удирдлагыг харуулах", + "Toggle Control Panel via Keystrokes": "Хяналтын самбарыг товчлуураар солих", + "Render Native Resolution": "Үндсэн нарийвчлалыг харуулах", + "Keyboard Shortcuts": "Гарын товчлол", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC гарын товчлолыг идэвхжүүлэх", + "1 - Toggle Control Panel": "1 - Хяналтын самбарыг асаах/унтраах", + "2 - Toggle Game Pointer Mode": "2 - Тоглоомын заагч горимыг асаах/унтраах", + "3 - Toggle Pointer Lock": "3 - Заагч түгжээг сэлгэх", + "Stream Quality": "Дамжуулалтын чанар", + "Preset Modes:": "Урьдчилан тохируулсан горимууд:", + "Static": "Статик", + "Low": "Бага", + "Medium": "Дунд", + "High": "Өндөр", + "Extreme": "Онцгой", + "Lossless": "Алдагдалгүй", + "Custom": "Захиалгат", + "Anti-Aliasing:": "Эсрэг ялгах:", + "Auto Dynamic": "Авто динамик", + "Off": "Унтраах", + "On": "Асаалттай", + "Dynamic Quality Min:": "Динамик чанарын хамгийн бага:", + "Dynamic Quality Max:": "Динамик чанарын дээд тал нь:", + "Treat Lossless:": "Алдагдалгүй эмчил:", + "Frame Rate:": "Хүрээний хурд:", + "Video JPEG Quality:": "Видео JPEG чанар:", + "Video WEBP Quality:": "Видео WEBP чанар:", + "Video Area:": "Видео хэсэг:", + "Video Time:": "Видео цаг:", + "Video Out Time:": "Видео гарах цаг:", + "Video Mode Width:": "Видео горимын өргөн:", + "Video Mode Height:": "Видео горимын өндөр:", + "Documentation": "Баримт бичиг", + "Drag Viewport": "Харах цонхыг чирэх", + "KasmVNC encountered an error:": "KasmVNC алдаа гарлаа:" +} \ No newline at end of file diff --git a/app/locale/mn_MN.json b/app/locale/mn_MN.json new file mode 100644 index 0000000..a12043f --- /dev/null +++ b/app/locale/mn_MN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Холбож байна...", + "Disconnecting...": "Салгаж байна...", + "Reconnecting...": "Дахин холбогдож байна...", + "Internal error": "Дотоод алдаа", + "Must set host": "Хастыг тохируулах ёстой", + "Connected (encrypted) to ": "Холбогдсон (шифрлэгдсэн)", + "Connected (unencrypted) to ": "Холбогдсон (шифрлэгдээгүй)", + "Something went wrong, connection is closed": "Ямар нэг алдаа гарлаа, холболт хаагдсан", + "Failed to connect to server": "Сервертэй холбогдож чадсангүй", + "Disconnected": "Таслагдсан", + "New connection has been rejected with reason: ": "Шинэ холболтоос татгалзсан шалтгаан нь:", + "New connection has been rejected": "Шинэ холболтоос татгалзсан", + "Credentials are required": "Итгэмжлэх жуух бичиг шаардлагатай", + "Hide/Show the control bar": "Хяналтын мөрийг нуух/ харуулах", + "Drag": "Чирэх", + "Move/Drag Viewport": "Харах талбарыг зөөх/чирэх", + "Keyboard": "Гар", + "Show Keyboard": "Гарыг харуулах", + "Extra keys": "Нэмэлт түлхүүрүүд", + "Show Extra Keys": "Нэмэлт түлхүүрүүдийг харуулах", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl-г асаах/унтраах", + "Alt": "Алт", + "Toggle Alt": "Alt-ыг асаах/унтраах", + "Toggle Windows": "Windows-ыг асаах/унтраах", + "Windows": "Windows", + "Send Tab": "Илгээх таб", + "Tab": "Таб", + "Esc": "Esc", + "Send Escape": "Зутгал илгээх", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del илгээх", + "Shutdown/Reboot": "Унтраах/дахин ачаалах", + "Shutdown/Reboot...": "Унтраах/дахин ачаалах...", + "Power": "Хүч", + "Shutdown": "Унтраах", + "Reboot": "Дахин ачаалах", + "Reset": "Дахин тохируулах", + "Clipboard": "Хүрээний санах ой", + "Clear": "Цэвэр", + "Fullscreen": "Дэлгэц дүүрэн", + "Settings": "Тохиргоо", + "Shared Mode": "Хуваалцсан горим", + "View Only": "Зөвхөн харах", + "Clip to Window": "Цонхонд хавчих", + "Scaling Mode:": "Хамшрах горим:", + "None": "Үгүй", + "Local Scaling": "Орон нутгийн масштаб", + "Remote Resizing": "Алсын хэмжээг өөрчлөх", + "Advanced": "Дэвшилтэт", + "Quality:": "Чанар:", + "Compression level:": "Шахалтын түвшин:", + "Repeater ID:": "Давтагч ID:", + "WebSocket": "WebSocket", + "Encrypt": "Шифрлэх", + "Host:": "Хөтлөгч:", + "Port:": "Порт:", + "Path:": "Зам:", + "Automatic Reconnect": "Автоматаар дахин холбох", + "Reconnect Delay (ms):": "Дахин холболтын саатал (мс):", + "Show Dot when No Cursor": "Курсор байхгүй үед цэгийг харуулах", + "Logging:": "Бүртгэл:", + "Version:": "Хувилбар:", + "Disconnect": "Таслах", + "Connect": "Холбох", + "Username:": "Хэрэглэгчийн нэр:", + "Password:": "Нууц үг:", + "Send Credentials": "Итгэмжлэх жуух бичгээ илгээх", + "Cancel": "Цуцлах", + "Keys": "Түлхүүр", + "Game Cursor Mode": "Тоглоомын курсорын горим", + "Press Esc Key to Exit Pointer Lock Mode": "Заагч түгжих горимоос гарахын тулд Esc товчийг дарна уу", + "Game Mode paused, click on screen to resume Game Mode.": "Тоглоомын горим түр зогссон. Тоглоомын горимыг үргэлжлүүлэхийн тулд дэлгэцэн дээр дарна уу.", + "Clipboard Up": "Цахилгаан санах ой", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Цахилгаан санах ойгүй", + "Prefer Local Cursor": "Орон нутгийн курсорыг илүүд үзэх", + "Translate keyboard shortcuts": "Гарын товчлолыг орчуулах", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit-г идэвхжүүлэх", + "Enable WebP Compression": "WebP шахалтыг идэвхжүүлэх", + "Enable Performance Stats": "Гүйцэтгэлийн статистикийг идэвхжүүлэх", + "Enable Pointer Lock": "Заагч түгжээг идэвхжүүлэх", + "IME Input Mode": "IME оролтын горим", + "Show Virtual Keyboard Control": "Виртуал гарын удирдлагыг харуулах", + "Toggle Control Panel via Keystrokes": "Хяналтын самбарыг товчлуураар солих", + "Render Native Resolution": "Үндсэн нарийвчлалыг харуулах", + "Keyboard Shortcuts": "Гарын товчлол", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC гарын товчлолыг идэвхжүүлэх", + "1 - Toggle Control Panel": "1 - Хяналтын самбарыг асаах/унтраах", + "2 - Toggle Game Pointer Mode": "2 - Тоглоомын заагч горимыг асаах/унтраах", + "3 - Toggle Pointer Lock": "3 - Заагч түгжээг сэлгэх", + "Stream Quality": "Дамжуулалтын чанар", + "Preset Modes:": "Урьдчилан тохируулсан горимууд:", + "Static": "Статик", + "Low": "Бага", + "Medium": "Дунд", + "High": "Өндөр", + "Extreme": "Онцгой", + "Lossless": "Алдагдалгүй", + "Custom": "Захиалгат", + "Anti-Aliasing:": "Эсрэг ялгах:", + "Auto Dynamic": "Авто динамик", + "Off": "Унтраах", + "On": "Асаалттай", + "Dynamic Quality Min:": "Динамик чанарын хамгийн бага:", + "Dynamic Quality Max:": "Динамик чанарын дээд тал нь:", + "Treat Lossless:": "Алдагдалгүй эмчил:", + "Frame Rate:": "Хүрээний хурд:", + "Video JPEG Quality:": "Видео JPEG чанар:", + "Video WEBP Quality:": "Видео WEBP чанар:", + "Video Area:": "Видео хэсэг:", + "Video Time:": "Видео цаг:", + "Video Out Time:": "Видео гарах цаг:", + "Video Mode Width:": "Видео горимын өргөн:", + "Video Mode Height:": "Видео горимын өндөр:", + "Documentation": "Баримт бичиг", + "Drag Viewport": "Харах цонхыг чирэх", + "KasmVNC encountered an error:": "KasmVNC алдаа гарлаа:" +} \ No newline at end of file diff --git a/app/locale/mr.json b/app/locale/mr.json new file mode 100644 index 0000000..6566c11 --- /dev/null +++ b/app/locale/mr.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "कनेक्ट करत आहे...", + "Disconnecting...": "डिस्कनेक्ट करत आहे...", + "Reconnecting...": "पुन्हा कनेक्ट करत आहे...", + "Internal error": "अंतर्गत त्रुटी", + "Must set host": "होस्ट सेट करणे आवश्यक आहे", + "Connected (encrypted) to ": "शी कनेक्ट केलेले (एनक्रिप्ट केलेले) ", + "Connected (unencrypted) to ": "शी कनेक्ट केलेले (एनक्रिप्ट केलेले) ", + "Something went wrong, connection is closed": "काहीतरी चूक झाली, कनेक्शन बंद आहे", + "Failed to connect to server": "सर्व्हरशी जोडण्यास असमर्थ", + "Disconnected": "डिस्कनेक्ट केलेले", + "New connection has been rejected with reason: ": "नवीन कनेक्शन कारणास्तव नाकारले गेले आहे:", + "New connection has been rejected": "नवीन कनेक्शन नाकारले गेले आहे", + "Credentials are required": "प्रमाणपत्रे आवश्यक आहेत", + "Hide/Show the control bar": "नियंत्रण पट्टी लपवा/दाखवा", + "Drag": "ड्रॅग", + "Move/Drag Viewport": "व्ह्यूपोर्ट हलवा/ड्रॅग करा", + "Keyboard": "कीबोर्ड", + "Show Keyboard": "कीबोर्ड दाखवा", + "Extra keys": "अतिरिक्त कळा", + "Show Extra Keys": "अतिरिक्त की दर्शवा", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl टॉगल करा", + "Alt": "Alt", + "Toggle Alt": "Alt टॉगल करा", + "Toggle Windows": "विंडोज टॉगल करा", + "Windows": "विंडोज", + "Send Tab": "टॅब पाठवा", + "Tab": "टॅब", + "Esc": "Esc", + "Send Escape": "पलायन पाठवा", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del पाठवा", + "Shutdown/Reboot": "शटडाउन/रीबूट", + "Shutdown/Reboot...": "शटडाउन/रीबूट...", + "Power": "शक्ती", + "Shutdown": "बंद", + "Reboot": "रीबूट करा", + "Reset": "रीसेट करा", + "Clipboard": "क्लिपबोर्ड", + "Clear": "साफ", + "Fullscreen": "फुलस्क्रीन", + "Settings": "सेटिंग्ज", + "Shared Mode": "सामायिक मोड", + "View Only": "केवळ पहा", + "Clip to Window": "क्लिप टू विंडो", + "Scaling Mode:": "स्केलिंग मोड:", + "None": "काहीही नाही", + "Local Scaling": "स्थानिक स्केलिंग", + "Remote Resizing": "दूरस्थ आकार बदलणे", + "Advanced": "प्रगत", + "Quality:": "गुणवत्ता:", + "Compression level:": "संक्षेप पातळी:", + "Repeater ID:": "रिपीटर आयडी:", + "WebSocket": "वेबसॉकेट", + "Encrypt": "एनक्रिप्ट", + "Host:": "होस्ट:", + "Port:": "पोर्ट:", + "Path:": "पथ:", + "Automatic Reconnect": "स्वयंचलित पुन्हा कनेक्ट करा", + "Reconnect Delay (ms):": "पुन्हा कनेक्ट करा विलंब (ms):", + "Show Dot when No Cursor": "कर्सर नसताना बिंदू दाखवा", + "Logging:": "लॉगिंग:", + "Version:": "आवृत्ती:", + "Disconnect": "डिस्कनेक्ट करा", + "Connect": "कनेक्ट करा", + "Username:": "वापरकर्तानाव:", + "Password:": "पासवर्ड:", + "Send Credentials": "क्रेडेन्शियल पाठवा", + "Cancel": "रद्द करा", + "Keys": "चाव्या", + "Game Cursor Mode": "गेम कर्सर मोड", + "Press Esc Key to Exit Pointer Lock Mode": "पॉइंटर लॉक मोडमधून बाहेर पडण्यासाठी Esc की दाबा", + "Game Mode paused, click on screen to resume Game Mode.": "गेम मोडला विराम दिला, गेम मोड पुन्हा सुरू करण्यासाठी स्क्रीनवर क्लिक करा.", + "Clipboard Up": "क्लिपबोर्ड वर", + "CLipboard Down": "क्लिपबोर्ड खाली", + "Clipboard Seamless": "क्लिपबोर्ड सीमलेस", + "Prefer Local Cursor": "स्थानिक कर्सरला प्राधान्य द्या", + "Translate keyboard shortcuts": "कीबोर्ड शॉर्टकटचे भाषांतर करा", + "Enable WebRTC UDP Transit": "WebRTC UDP ट्रान्झिट सक्षम करा", + "Enable WebP Compression": "वेबपी कॉम्प्रेशन सक्षम करा", + "Enable Performance Stats": "कार्यप्रदर्शन आकडेवारी सक्षम करा", + "Enable Pointer Lock": "पॉइंटर लॉक सक्षम करा", + "IME Input Mode": "IME इनपुट मोड", + "Show Virtual Keyboard Control": "व्हर्च्युअल कीबोर्ड नियंत्रण दर्शवा", + "Toggle Control Panel via Keystrokes": "कीस्ट्रोकद्वारे नियंत्रण पॅनेल टॉगल करा", + "Render Native Resolution": "नेटिव्ह रिझोल्यूशन रेंडर करा", + "Keyboard Shortcuts": "कीबोर्ड शॉर्टकट", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC कीबोर्ड शॉर्टकट सक्षम करा", + "1 - Toggle Control Panel": "1 - नियंत्रण पॅनेल टॉगल करा", + "2 - Toggle Game Pointer Mode": "2 - गेम पॉइंटर मोड टॉगल करा", + "3 - Toggle Pointer Lock": "3 - पॉइंटर लॉक टॉगल करा", + "Stream Quality": "प्रवाह गुणवत्ता", + "Preset Modes:": "प्रीसेट मोड:", + "Static": "स्थिर", + "Low": "कमी", + "Medium": "मध्यम", + "High": "उच्च", + "Extreme": "अत्यंत", + "Lossless": "तोटाहीन", + "Custom": "सानुकूल", + "Anti-Aliasing:": "विरोधी aliasing:", + "Auto Dynamic": "ऑटो डायनॅमिक", + "Off": "बंद", + "On": "चालू", + "Dynamic Quality Min:": "डायनॅमिक गुणवत्ता किमान:", + "Dynamic Quality Max:": "डायनॅमिक गुणवत्ता कमाल:", + "Treat Lossless:": "तोटारहित उपचार करा:", + "Frame Rate:": "फ्रेम दर:", + "Video JPEG Quality:": "व्हिडिओ JPEG गुणवत्ता:", + "Video WEBP Quality:": "व्हिडिओ WEBP गुणवत्ता:", + "Video Area:": "व्हिडिओ क्षेत्र:", + "Video Time:": "व्हिडिओ वेळ:", + "Video Out Time:": "व्हिडिओ संपण्याची वेळ:", + "Video Mode Width:": "व्हिडिओ मोड रुंदी:", + "Video Mode Height:": "व्हिडिओ मोड उंची:", + "Documentation": "दस्तऐवजीकरण", + "Drag Viewport": "व्ह्यूपोर्ट ड्रॅग करा", + "KasmVNC encountered an error:": "KasmVNC मध्ये त्रुटी आली:" +} \ No newline at end of file diff --git a/app/locale/mr_IN.json b/app/locale/mr_IN.json new file mode 100644 index 0000000..6566c11 --- /dev/null +++ b/app/locale/mr_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "कनेक्ट करत आहे...", + "Disconnecting...": "डिस्कनेक्ट करत आहे...", + "Reconnecting...": "पुन्हा कनेक्ट करत आहे...", + "Internal error": "अंतर्गत त्रुटी", + "Must set host": "होस्ट सेट करणे आवश्यक आहे", + "Connected (encrypted) to ": "शी कनेक्ट केलेले (एनक्रिप्ट केलेले) ", + "Connected (unencrypted) to ": "शी कनेक्ट केलेले (एनक्रिप्ट केलेले) ", + "Something went wrong, connection is closed": "काहीतरी चूक झाली, कनेक्शन बंद आहे", + "Failed to connect to server": "सर्व्हरशी जोडण्यास असमर्थ", + "Disconnected": "डिस्कनेक्ट केलेले", + "New connection has been rejected with reason: ": "नवीन कनेक्शन कारणास्तव नाकारले गेले आहे:", + "New connection has been rejected": "नवीन कनेक्शन नाकारले गेले आहे", + "Credentials are required": "प्रमाणपत्रे आवश्यक आहेत", + "Hide/Show the control bar": "नियंत्रण पट्टी लपवा/दाखवा", + "Drag": "ड्रॅग", + "Move/Drag Viewport": "व्ह्यूपोर्ट हलवा/ड्रॅग करा", + "Keyboard": "कीबोर्ड", + "Show Keyboard": "कीबोर्ड दाखवा", + "Extra keys": "अतिरिक्त कळा", + "Show Extra Keys": "अतिरिक्त की दर्शवा", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl टॉगल करा", + "Alt": "Alt", + "Toggle Alt": "Alt टॉगल करा", + "Toggle Windows": "विंडोज टॉगल करा", + "Windows": "विंडोज", + "Send Tab": "टॅब पाठवा", + "Tab": "टॅब", + "Esc": "Esc", + "Send Escape": "पलायन पाठवा", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del पाठवा", + "Shutdown/Reboot": "शटडाउन/रीबूट", + "Shutdown/Reboot...": "शटडाउन/रीबूट...", + "Power": "शक्ती", + "Shutdown": "बंद", + "Reboot": "रीबूट करा", + "Reset": "रीसेट करा", + "Clipboard": "क्लिपबोर्ड", + "Clear": "साफ", + "Fullscreen": "फुलस्क्रीन", + "Settings": "सेटिंग्ज", + "Shared Mode": "सामायिक मोड", + "View Only": "केवळ पहा", + "Clip to Window": "क्लिप टू विंडो", + "Scaling Mode:": "स्केलिंग मोड:", + "None": "काहीही नाही", + "Local Scaling": "स्थानिक स्केलिंग", + "Remote Resizing": "दूरस्थ आकार बदलणे", + "Advanced": "प्रगत", + "Quality:": "गुणवत्ता:", + "Compression level:": "संक्षेप पातळी:", + "Repeater ID:": "रिपीटर आयडी:", + "WebSocket": "वेबसॉकेट", + "Encrypt": "एनक्रिप्ट", + "Host:": "होस्ट:", + "Port:": "पोर्ट:", + "Path:": "पथ:", + "Automatic Reconnect": "स्वयंचलित पुन्हा कनेक्ट करा", + "Reconnect Delay (ms):": "पुन्हा कनेक्ट करा विलंब (ms):", + "Show Dot when No Cursor": "कर्सर नसताना बिंदू दाखवा", + "Logging:": "लॉगिंग:", + "Version:": "आवृत्ती:", + "Disconnect": "डिस्कनेक्ट करा", + "Connect": "कनेक्ट करा", + "Username:": "वापरकर्तानाव:", + "Password:": "पासवर्ड:", + "Send Credentials": "क्रेडेन्शियल पाठवा", + "Cancel": "रद्द करा", + "Keys": "चाव्या", + "Game Cursor Mode": "गेम कर्सर मोड", + "Press Esc Key to Exit Pointer Lock Mode": "पॉइंटर लॉक मोडमधून बाहेर पडण्यासाठी Esc की दाबा", + "Game Mode paused, click on screen to resume Game Mode.": "गेम मोडला विराम दिला, गेम मोड पुन्हा सुरू करण्यासाठी स्क्रीनवर क्लिक करा.", + "Clipboard Up": "क्लिपबोर्ड वर", + "CLipboard Down": "क्लिपबोर्ड खाली", + "Clipboard Seamless": "क्लिपबोर्ड सीमलेस", + "Prefer Local Cursor": "स्थानिक कर्सरला प्राधान्य द्या", + "Translate keyboard shortcuts": "कीबोर्ड शॉर्टकटचे भाषांतर करा", + "Enable WebRTC UDP Transit": "WebRTC UDP ट्रान्झिट सक्षम करा", + "Enable WebP Compression": "वेबपी कॉम्प्रेशन सक्षम करा", + "Enable Performance Stats": "कार्यप्रदर्शन आकडेवारी सक्षम करा", + "Enable Pointer Lock": "पॉइंटर लॉक सक्षम करा", + "IME Input Mode": "IME इनपुट मोड", + "Show Virtual Keyboard Control": "व्हर्च्युअल कीबोर्ड नियंत्रण दर्शवा", + "Toggle Control Panel via Keystrokes": "कीस्ट्रोकद्वारे नियंत्रण पॅनेल टॉगल करा", + "Render Native Resolution": "नेटिव्ह रिझोल्यूशन रेंडर करा", + "Keyboard Shortcuts": "कीबोर्ड शॉर्टकट", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC कीबोर्ड शॉर्टकट सक्षम करा", + "1 - Toggle Control Panel": "1 - नियंत्रण पॅनेल टॉगल करा", + "2 - Toggle Game Pointer Mode": "2 - गेम पॉइंटर मोड टॉगल करा", + "3 - Toggle Pointer Lock": "3 - पॉइंटर लॉक टॉगल करा", + "Stream Quality": "प्रवाह गुणवत्ता", + "Preset Modes:": "प्रीसेट मोड:", + "Static": "स्थिर", + "Low": "कमी", + "Medium": "मध्यम", + "High": "उच्च", + "Extreme": "अत्यंत", + "Lossless": "तोटाहीन", + "Custom": "सानुकूल", + "Anti-Aliasing:": "विरोधी aliasing:", + "Auto Dynamic": "ऑटो डायनॅमिक", + "Off": "बंद", + "On": "चालू", + "Dynamic Quality Min:": "डायनॅमिक गुणवत्ता किमान:", + "Dynamic Quality Max:": "डायनॅमिक गुणवत्ता कमाल:", + "Treat Lossless:": "तोटारहित उपचार करा:", + "Frame Rate:": "फ्रेम दर:", + "Video JPEG Quality:": "व्हिडिओ JPEG गुणवत्ता:", + "Video WEBP Quality:": "व्हिडिओ WEBP गुणवत्ता:", + "Video Area:": "व्हिडिओ क्षेत्र:", + "Video Time:": "व्हिडिओ वेळ:", + "Video Out Time:": "व्हिडिओ संपण्याची वेळ:", + "Video Mode Width:": "व्हिडिओ मोड रुंदी:", + "Video Mode Height:": "व्हिडिओ मोड उंची:", + "Documentation": "दस्तऐवजीकरण", + "Drag Viewport": "व्ह्यूपोर्ट ड्रॅग करा", + "KasmVNC encountered an error:": "KasmVNC मध्ये त्रुटी आली:" +} \ No newline at end of file diff --git a/app/locale/ms.json b/app/locale/ms.json new file mode 100644 index 0000000..a4fcfd2 --- /dev/null +++ b/app/locale/ms.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Menyambung...", + "Disconnecting...": "Memutuskan sambungan...", + "Reconnecting...": "Menyambung semula...", + "Internal error": "Masalah dalaman", + "Must set host": "Mesti tetapkan hos", + "Connected (encrypted) to ": "Disambungkan (disulitkan) ke ", + "Connected (unencrypted) to ": "Disambungkan (tidak disulitkan) ke ", + "Something went wrong, connection is closed": "Sesuatu telah berlaku, sambungan ditutup", + "Failed to connect to server": "Gagal menyambung ke pelayan", + "Disconnected": "Terputus sambungan", + "New connection has been rejected with reason: ": "Sambungan baharu telah ditolak dengan alasan: ", + "New connection has been rejected": "Sambungan baharu telah ditolak", + "Credentials are required": "Tauliah diperlukan", + "Hide/Show the control bar": "Sembunyikan/Tunjukkan bar kawalan", + "Drag": "Seret", + "Move/Drag Viewport": "Gerak/Seret Viewport", + "Keyboard": "Papan kekunci", + "Show Keyboard": "Tunjukkan Papan Kekunci", + "Extra keys": "Kunci tambahan", + "Show Extra Keys": "Tunjukkan Kunci Tambahan", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Togol Ctrl", + "Alt": "Alt", + "Toggle Alt": "Togol Alt", + "Toggle Windows": "Togol Windows", + "Windows": "Windows", + "Send Tab": "Hantar Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Hantar Melarikan Diri", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Hantar Ctrl-Alt-Del", + "Shutdown/Reboot": "Tutup/But Semula", + "Shutdown/Reboot...": "Tutup/But Semula...", + "Power": "Kuasa", + "Shutdown": "Menutup", + "Reboot": "But semula", + "Reset": "Tetapkan semula", + "Clipboard": "Papan keratan", + "Clear": "Jelas", + "Fullscreen": "Skrin penuh", + "Settings": "Tetapan", + "Shared Mode": "Mod Kongsi", + "View Only": "Lihat Sahaja", + "Clip to Window": "Klip ke Tetingkap", + "Scaling Mode:": "Mod Penskalaan:", + "None": "Tiada", + "Local Scaling": "Penskalaan Tempatan", + "Remote Resizing": "Saiz Semula Jauh", + "Advanced": "Maju", + "Quality:": "Kualiti:", + "Compression level:": "Tahap mampatan:", + "Repeater ID:": "ID Pengulang:", + "WebSocket": "WebSocket", + "Encrypt": "Sulitkan", + "Host:": "Hos:", + "Port:": "Pelabuhan:", + "Path:": "Laluan:", + "Automatic Reconnect": "Sambung Semula Automatik", + "Reconnect Delay (ms):": "Sambung Semula Kelewatan (ms):", + "Show Dot when No Cursor": "Tunjukkan Titik apabila Tiada Kursor", + "Logging:": "Membalak:", + "Version:": "Versi:", + "Disconnect": "Putuskan sambungan", + "Connect": "Sambung", + "Username:": "Nama pengguna:", + "Password:": "Kata laluan:", + "Send Credentials": "Hantar Bukti Kelayakan", + "Cancel": "Batalkan", + "Keys": "Kunci", + "Game Cursor Mode": "Mod Kursor Permainan", + "Press Esc Key to Exit Pointer Lock Mode": "Tekan Kekunci Esc untuk Keluar dari Mod Kunci Penunjuk", + "Game Mode paused, click on screen to resume Game Mode.": "Mod Permainan dijeda, klik pada skrin untuk menyambung semula Mod Permainan.", + "Clipboard Up": "Papan Keratan Atas", + "CLipboard Down": "Papan Klip ke Bawah", + "Clipboard Seamless": "Papan Keratan Lancar", + "Prefer Local Cursor": "Pilih Kursor Tempatan", + "Translate keyboard shortcuts": "Terjemah pintasan papan kekunci", + "Enable WebRTC UDP Transit": "Dayakan WebRTC UDP Transit", + "Enable WebP Compression": "Dayakan Pemampatan WebP", + "Enable Performance Stats": "Dayakan Statistik Prestasi", + "Enable Pointer Lock": "Dayakan Kunci Penunjuk", + "IME Input Mode": "Mod Input IME", + "Show Virtual Keyboard Control": "Tunjukkan Kawalan Papan Kekunci Maya", + "Toggle Control Panel via Keystrokes": "Togol Panel Kawalan melalui Ketukan Kekunci", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Pintasan Papan Kekunci", + "Enable KasmVNC Keyboard Shortcuts": "Dayakan Pintasan Papan Kekunci KasmVNC", + "1 - Toggle Control Panel": "1 - Togol Panel Kawalan", + "2 - Toggle Game Pointer Mode": "2 - Togol Mod Penunjuk Permainan", + "3 - Toggle Pointer Lock": "3 - Togol Kunci Penunjuk", + "Stream Quality": "Kualiti Strim", + "Preset Modes:": "Mod Pratetap:", + "Static": "Statik", + "Low": "Rendah", + "Medium": "Sederhana", + "High": "Tinggi", + "Extreme": "Melampau", + "Lossless": "Tidak rugi", + "Custom": "Tersuai", + "Anti-Aliasing:": "Anti-aliasi:", + "Auto Dynamic": "Auto Dinamik", + "Off": "Mati", + "On": "Hidup", + "Dynamic Quality Min:": "Min Kualiti Dinamik:", + "Dynamic Quality Max:": "Maks Kualiti Dinamik:", + "Treat Lossless:": "Rawat Lossless:", + "Frame Rate:": "Kadar bingkai:", + "Video JPEG Quality:": "Kualiti JPEG Video:", + "Video WEBP Quality:": "Kualiti WEBP Video:", + "Video Area:": "Kawasan Video:", + "Video Time:": "Masa Video:", + "Video Out Time:": "Masa Keluar Video:", + "Video Mode Width:": "Lebar Mod Video:", + "Video Mode Height:": "Ketinggian Mod Video:", + "Documentation": "Dokumentasi", + "Drag Viewport": "Seret Viewport", + "KasmVNC encountered an error:": "KasmVNC mengalami ralat:" +} \ No newline at end of file diff --git a/app/locale/ms_MY.json b/app/locale/ms_MY.json new file mode 100644 index 0000000..a4fcfd2 --- /dev/null +++ b/app/locale/ms_MY.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Menyambung...", + "Disconnecting...": "Memutuskan sambungan...", + "Reconnecting...": "Menyambung semula...", + "Internal error": "Masalah dalaman", + "Must set host": "Mesti tetapkan hos", + "Connected (encrypted) to ": "Disambungkan (disulitkan) ke ", + "Connected (unencrypted) to ": "Disambungkan (tidak disulitkan) ke ", + "Something went wrong, connection is closed": "Sesuatu telah berlaku, sambungan ditutup", + "Failed to connect to server": "Gagal menyambung ke pelayan", + "Disconnected": "Terputus sambungan", + "New connection has been rejected with reason: ": "Sambungan baharu telah ditolak dengan alasan: ", + "New connection has been rejected": "Sambungan baharu telah ditolak", + "Credentials are required": "Tauliah diperlukan", + "Hide/Show the control bar": "Sembunyikan/Tunjukkan bar kawalan", + "Drag": "Seret", + "Move/Drag Viewport": "Gerak/Seret Viewport", + "Keyboard": "Papan kekunci", + "Show Keyboard": "Tunjukkan Papan Kekunci", + "Extra keys": "Kunci tambahan", + "Show Extra Keys": "Tunjukkan Kunci Tambahan", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Togol Ctrl", + "Alt": "Alt", + "Toggle Alt": "Togol Alt", + "Toggle Windows": "Togol Windows", + "Windows": "Windows", + "Send Tab": "Hantar Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Hantar Melarikan Diri", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Hantar Ctrl-Alt-Del", + "Shutdown/Reboot": "Tutup/But Semula", + "Shutdown/Reboot...": "Tutup/But Semula...", + "Power": "Kuasa", + "Shutdown": "Menutup", + "Reboot": "But semula", + "Reset": "Tetapkan semula", + "Clipboard": "Papan keratan", + "Clear": "Jelas", + "Fullscreen": "Skrin penuh", + "Settings": "Tetapan", + "Shared Mode": "Mod Kongsi", + "View Only": "Lihat Sahaja", + "Clip to Window": "Klip ke Tetingkap", + "Scaling Mode:": "Mod Penskalaan:", + "None": "Tiada", + "Local Scaling": "Penskalaan Tempatan", + "Remote Resizing": "Saiz Semula Jauh", + "Advanced": "Maju", + "Quality:": "Kualiti:", + "Compression level:": "Tahap mampatan:", + "Repeater ID:": "ID Pengulang:", + "WebSocket": "WebSocket", + "Encrypt": "Sulitkan", + "Host:": "Hos:", + "Port:": "Pelabuhan:", + "Path:": "Laluan:", + "Automatic Reconnect": "Sambung Semula Automatik", + "Reconnect Delay (ms):": "Sambung Semula Kelewatan (ms):", + "Show Dot when No Cursor": "Tunjukkan Titik apabila Tiada Kursor", + "Logging:": "Membalak:", + "Version:": "Versi:", + "Disconnect": "Putuskan sambungan", + "Connect": "Sambung", + "Username:": "Nama pengguna:", + "Password:": "Kata laluan:", + "Send Credentials": "Hantar Bukti Kelayakan", + "Cancel": "Batalkan", + "Keys": "Kunci", + "Game Cursor Mode": "Mod Kursor Permainan", + "Press Esc Key to Exit Pointer Lock Mode": "Tekan Kekunci Esc untuk Keluar dari Mod Kunci Penunjuk", + "Game Mode paused, click on screen to resume Game Mode.": "Mod Permainan dijeda, klik pada skrin untuk menyambung semula Mod Permainan.", + "Clipboard Up": "Papan Keratan Atas", + "CLipboard Down": "Papan Klip ke Bawah", + "Clipboard Seamless": "Papan Keratan Lancar", + "Prefer Local Cursor": "Pilih Kursor Tempatan", + "Translate keyboard shortcuts": "Terjemah pintasan papan kekunci", + "Enable WebRTC UDP Transit": "Dayakan WebRTC UDP Transit", + "Enable WebP Compression": "Dayakan Pemampatan WebP", + "Enable Performance Stats": "Dayakan Statistik Prestasi", + "Enable Pointer Lock": "Dayakan Kunci Penunjuk", + "IME Input Mode": "Mod Input IME", + "Show Virtual Keyboard Control": "Tunjukkan Kawalan Papan Kekunci Maya", + "Toggle Control Panel via Keystrokes": "Togol Panel Kawalan melalui Ketukan Kekunci", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Pintasan Papan Kekunci", + "Enable KasmVNC Keyboard Shortcuts": "Dayakan Pintasan Papan Kekunci KasmVNC", + "1 - Toggle Control Panel": "1 - Togol Panel Kawalan", + "2 - Toggle Game Pointer Mode": "2 - Togol Mod Penunjuk Permainan", + "3 - Toggle Pointer Lock": "3 - Togol Kunci Penunjuk", + "Stream Quality": "Kualiti Strim", + "Preset Modes:": "Mod Pratetap:", + "Static": "Statik", + "Low": "Rendah", + "Medium": "Sederhana", + "High": "Tinggi", + "Extreme": "Melampau", + "Lossless": "Tidak rugi", + "Custom": "Tersuai", + "Anti-Aliasing:": "Anti-aliasi:", + "Auto Dynamic": "Auto Dinamik", + "Off": "Mati", + "On": "Hidup", + "Dynamic Quality Min:": "Min Kualiti Dinamik:", + "Dynamic Quality Max:": "Maks Kualiti Dinamik:", + "Treat Lossless:": "Rawat Lossless:", + "Frame Rate:": "Kadar bingkai:", + "Video JPEG Quality:": "Kualiti JPEG Video:", + "Video WEBP Quality:": "Kualiti WEBP Video:", + "Video Area:": "Kawasan Video:", + "Video Time:": "Masa Video:", + "Video Out Time:": "Masa Keluar Video:", + "Video Mode Width:": "Lebar Mod Video:", + "Video Mode Height:": "Ketinggian Mod Video:", + "Documentation": "Dokumentasi", + "Drag Viewport": "Seret Viewport", + "KasmVNC encountered an error:": "KasmVNC mengalami ralat:" +} \ No newline at end of file diff --git a/app/locale/mt.json b/app/locale/mt.json new file mode 100644 index 0000000..605ab79 --- /dev/null +++ b/app/locale/mt.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Konnessjoni...", + "Disconnecting...": "Skonnettja...", + "Reconnecting...": "Qiegħed mill-ġdid...", + "Internal error": "Żball intern", + "Must set host": "Irid issettja l-ospitant", + "Connected (encrypted) to ": "Konnessi (kodifikat) ma'", + "Connected (unencrypted) to ": "Konnessi (mhux kriptat) ma'", + "Something went wrong, connection is closed": "Xi ħaġa marret ħażin, il-konnessjoni hija magħluqa", + "Failed to connect to server": "Ma rnexxiex tikkonnettja mas-server", + "Disconnected": "Skonnettjat", + "New connection has been rejected with reason: ": "Konnessjoni ġdida ġiet miċħuda bir-raġuni: ", + "New connection has been rejected": "Konnessjoni ġdida ġiet miċħuda", + "Credentials are required": "Kredenzjali huma meħtieġa", + "Hide/Show the control bar": "Aħbi/Uri l-bar tal-kontroll", + "Drag": "Ikaxkar", + "Move/Drag Viewport": "Mexxi/Idreggja l-Viewport", + "Keyboard": "Tastiera", + "Show Keyboard": "Uri Keyboard", + "Extra keys": "Ċwievet żejda", + "Show Extra Keys": "Uri Ċwievet Extra", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Aqleb Ctrl", + "Alt": "Alt", + "Toggle Alt": "Aqleb Alt", + "Toggle Windows": "Aqleb Windows", + "Windows": "Windows", + "Send Tab": "Ibgħat Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Ibgħat Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ibgħat Ctrl-Alt-Del", + "Shutdown/Reboot": "Tfiq/Reboot", + "Shutdown/Reboot...": "Itfi/Reboot...", + "Power": "Qawwa", + "Shutdown": "Għalaq", + "Reboot": "Reboot", + "Reset": "Irrisettja", + "Clipboard": "Clipboard", + "Clear": "Ċara", + "Fullscreen": "Fullscreen", + "Settings": "Settings", + "Shared Mode": "Modalità Kondiviża", + "View Only": "Ara biss", + "Clip to Window": "Klip għat-Tieqa", + "Scaling Mode:": "Modalità ta' Skala:", + "None": "Xejn", + "Local Scaling": "Skalar Lokali", + "Remote Resizing": "Ridimensjonar mill-bogħod", + "Advanced": "Avvanzat", + "Quality:": "Kwalità:", + "Compression level:": "Livell ta' kompressjoni:", + "Repeater ID:": "ID tar-ripetitur:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Ospitanti:", + "Port:": "Port:", + "Path:": "Path:", + "Automatic Reconnect": "Konnettja mill-ġdid awtomatika", + "Reconnect Delay (ms):": "Dawn mill-ġdid (ms):", + "Show Dot when No Cursor": "Uri Dot meta L-ebda Cursor", + "Logging:": "Logging:", + "Version:": "Verżjoni:", + "Disconnect": "Skonnettja", + "Connect": "Ikkonnettja", + "Username:": "Isem tal-Utent:", + "Password:": "Password:", + "Send Credentials": "Ibgħat Kredenzjali", + "Cancel": "Ikkanċella", + "Keys": "Ċwievet", + "Game Cursor Mode": "Modalità tal-Kursur tal-Logħba", + "Press Esc Key to Exit Pointer Lock Mode": "Agħfas Esc Key biex toħroġ mill-Modalità Lock Pointer", + "Game Mode paused, click on screen to resume Game Mode.": "Modalità Logħba waqfa qasira, ikklikkja fuq l-iskrin biex terġa 'tibda Modalità Logħba.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "CLIPboard 'l isfel", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Ippreferi Kursur Lokali", + "Translate keyboard shortcuts": "Ittraduċi shortcuts tat-tastiera", + "Enable WebRTC UDP Transit": "Ippermetti WebRTC UDP Transit", + "Enable WebP Compression": "Ippermetti Kompressjoni WebP", + "Enable Performance Stats": "Ippermetti Stats tal-Prestazzjoni", + "Enable Pointer Lock": "Ippermetti Pointer Lock", + "IME Input Mode": "Modalità ta' Input IME", + "Show Virtual Keyboard Control": "Uri Kontroll tat-Tastiera Virtwali", + "Toggle Control Panel via Keystrokes": "Aqleb il-Panew tal-Kontroll permezz tat-Tasti", + "Render Native Resolution": "Irrendi Riżoluzzjoni Nattiva", + "Keyboard Shortcuts": "Shortcuts tat-Tastiera", + "Enable KasmVNC Keyboard Shortcuts": "Ippermetti KasmVNC Shortcuts tat-Tastiera", + "1 - Toggle Control Panel": "1 - Toggle Control Panel", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Kwalità tan-nixxiegħa", + "Preset Modes:": "Modi ssettjati minn qabel:", + "Static": "Statiku", + "Low": "Baxx", + "Medium": "Medju", + "High": "Għoli", + "Extreme": "Estremi", + "Lossless": "Mingħajr telf", + "Custom": "Custom", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Awtodinamiku", + "Off": "Itfi", + "On": "Fuq", + "Dynamic Quality Min:": "Kwalità Dinamika Min:", + "Dynamic Quality Max:": "Kwalità Dinamika Max:", + "Treat Lossless:": "Itratta Lossless:", + "Frame Rate:": "Frame Rate:", + "Video JPEG Quality:": "Kwalità JPEG tal-vidjo:", + "Video WEBP Quality:": "Kwalità tal-WEBP tal-vidjo:", + "Video Area:": "Żona tal-vidjo:", + "Video Time:": "Ħin tal-vidjo:", + "Video Out Time:": "Ħin tal-Ħruġ tal-Video:", + "Video Mode Width:": "Wsa 'Modalità Video:", + "Video Mode Height:": "Għoli tal-Modalità Video:", + "Documentation": "Dokumentazzjoni", + "Drag Viewport": "Dragg Viewport", + "KasmVNC encountered an error:": "KasmVNC iltaqa' ma' żball:" +} \ No newline at end of file diff --git a/app/locale/mt_MT.json b/app/locale/mt_MT.json new file mode 100644 index 0000000..605ab79 --- /dev/null +++ b/app/locale/mt_MT.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Konnessjoni...", + "Disconnecting...": "Skonnettja...", + "Reconnecting...": "Qiegħed mill-ġdid...", + "Internal error": "Żball intern", + "Must set host": "Irid issettja l-ospitant", + "Connected (encrypted) to ": "Konnessi (kodifikat) ma'", + "Connected (unencrypted) to ": "Konnessi (mhux kriptat) ma'", + "Something went wrong, connection is closed": "Xi ħaġa marret ħażin, il-konnessjoni hija magħluqa", + "Failed to connect to server": "Ma rnexxiex tikkonnettja mas-server", + "Disconnected": "Skonnettjat", + "New connection has been rejected with reason: ": "Konnessjoni ġdida ġiet miċħuda bir-raġuni: ", + "New connection has been rejected": "Konnessjoni ġdida ġiet miċħuda", + "Credentials are required": "Kredenzjali huma meħtieġa", + "Hide/Show the control bar": "Aħbi/Uri l-bar tal-kontroll", + "Drag": "Ikaxkar", + "Move/Drag Viewport": "Mexxi/Idreggja l-Viewport", + "Keyboard": "Tastiera", + "Show Keyboard": "Uri Keyboard", + "Extra keys": "Ċwievet żejda", + "Show Extra Keys": "Uri Ċwievet Extra", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Aqleb Ctrl", + "Alt": "Alt", + "Toggle Alt": "Aqleb Alt", + "Toggle Windows": "Aqleb Windows", + "Windows": "Windows", + "Send Tab": "Ibgħat Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Ibgħat Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ibgħat Ctrl-Alt-Del", + "Shutdown/Reboot": "Tfiq/Reboot", + "Shutdown/Reboot...": "Itfi/Reboot...", + "Power": "Qawwa", + "Shutdown": "Għalaq", + "Reboot": "Reboot", + "Reset": "Irrisettja", + "Clipboard": "Clipboard", + "Clear": "Ċara", + "Fullscreen": "Fullscreen", + "Settings": "Settings", + "Shared Mode": "Modalità Kondiviża", + "View Only": "Ara biss", + "Clip to Window": "Klip għat-Tieqa", + "Scaling Mode:": "Modalità ta' Skala:", + "None": "Xejn", + "Local Scaling": "Skalar Lokali", + "Remote Resizing": "Ridimensjonar mill-bogħod", + "Advanced": "Avvanzat", + "Quality:": "Kwalità:", + "Compression level:": "Livell ta' kompressjoni:", + "Repeater ID:": "ID tar-ripetitur:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Ospitanti:", + "Port:": "Port:", + "Path:": "Path:", + "Automatic Reconnect": "Konnettja mill-ġdid awtomatika", + "Reconnect Delay (ms):": "Dawn mill-ġdid (ms):", + "Show Dot when No Cursor": "Uri Dot meta L-ebda Cursor", + "Logging:": "Logging:", + "Version:": "Verżjoni:", + "Disconnect": "Skonnettja", + "Connect": "Ikkonnettja", + "Username:": "Isem tal-Utent:", + "Password:": "Password:", + "Send Credentials": "Ibgħat Kredenzjali", + "Cancel": "Ikkanċella", + "Keys": "Ċwievet", + "Game Cursor Mode": "Modalità tal-Kursur tal-Logħba", + "Press Esc Key to Exit Pointer Lock Mode": "Agħfas Esc Key biex toħroġ mill-Modalità Lock Pointer", + "Game Mode paused, click on screen to resume Game Mode.": "Modalità Logħba waqfa qasira, ikklikkja fuq l-iskrin biex terġa 'tibda Modalità Logħba.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "CLIPboard 'l isfel", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Ippreferi Kursur Lokali", + "Translate keyboard shortcuts": "Ittraduċi shortcuts tat-tastiera", + "Enable WebRTC UDP Transit": "Ippermetti WebRTC UDP Transit", + "Enable WebP Compression": "Ippermetti Kompressjoni WebP", + "Enable Performance Stats": "Ippermetti Stats tal-Prestazzjoni", + "Enable Pointer Lock": "Ippermetti Pointer Lock", + "IME Input Mode": "Modalità ta' Input IME", + "Show Virtual Keyboard Control": "Uri Kontroll tat-Tastiera Virtwali", + "Toggle Control Panel via Keystrokes": "Aqleb il-Panew tal-Kontroll permezz tat-Tasti", + "Render Native Resolution": "Irrendi Riżoluzzjoni Nattiva", + "Keyboard Shortcuts": "Shortcuts tat-Tastiera", + "Enable KasmVNC Keyboard Shortcuts": "Ippermetti KasmVNC Shortcuts tat-Tastiera", + "1 - Toggle Control Panel": "1 - Toggle Control Panel", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Kwalità tan-nixxiegħa", + "Preset Modes:": "Modi ssettjati minn qabel:", + "Static": "Statiku", + "Low": "Baxx", + "Medium": "Medju", + "High": "Għoli", + "Extreme": "Estremi", + "Lossless": "Mingħajr telf", + "Custom": "Custom", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Awtodinamiku", + "Off": "Itfi", + "On": "Fuq", + "Dynamic Quality Min:": "Kwalità Dinamika Min:", + "Dynamic Quality Max:": "Kwalità Dinamika Max:", + "Treat Lossless:": "Itratta Lossless:", + "Frame Rate:": "Frame Rate:", + "Video JPEG Quality:": "Kwalità JPEG tal-vidjo:", + "Video WEBP Quality:": "Kwalità tal-WEBP tal-vidjo:", + "Video Area:": "Żona tal-vidjo:", + "Video Time:": "Ħin tal-vidjo:", + "Video Out Time:": "Ħin tal-Ħruġ tal-Video:", + "Video Mode Width:": "Wsa 'Modalità Video:", + "Video Mode Height:": "Għoli tal-Modalità Video:", + "Documentation": "Dokumentazzjoni", + "Drag Viewport": "Dragg Viewport", + "KasmVNC encountered an error:": "KasmVNC iltaqa' ma' żball:" +} \ No newline at end of file diff --git a/app/locale/my.json b/app/locale/my.json new file mode 100644 index 0000000..f81d03f --- /dev/null +++ b/app/locale/my.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ချိတ်ဆက်နေသည်...", + "Disconnecting...": "အဆက်ဖြတ်နေသည်...", + "Reconnecting...": "ပြန်လည်ချိတ်ဆက်နေသည်...", + "Internal error": "အတွင်းပိုင်းအမှား", + "Must set host": "အိမ်ရှင်သတ်မှတ်ရမယ်", + "Connected (encrypted) to ": "ချိတ်ဆက်ထားသည် (ကုဒ်ဝှက်ထားသည်)", + "Connected (unencrypted) to ": "ချိတ်ဆက်ထားသည် (စာဝှက်မထားသော)", + "Something went wrong, connection is closed": "တစ်ခုခုမှားနေပြီ၊ ချိတ်ဆက်မှုပိတ်ထား", + "Failed to connect to server": "ဆာဗာသို့ ချိတ်ဆက်၍မရပါ", + "Disconnected": "အဆက်ပြတ်သွားပြီ", + "New connection has been rejected with reason: ": "ချိတ်ဆက်မှုအသစ်ကို အကြောင်းပြချက်ဖြင့် ပယ်ချခဲ့သည်", + "New connection has been rejected": "ချိတ်ဆက်မှုအသစ်ကို ငြင်းပယ်ထားသည်", + "Credentials are required": "အထောက်အထားများ လိုအပ်သည်", + "Hide/Show the control bar": "ထိန်းချုပ်မှုဘားကို ဖျောက်/ပြပါ", + "Drag": "ဆွဲ", + "Move/Drag Viewport": "ရှုခင်းကိုရွှေ့/ဆွဲပါ", + "Keyboard": "ကီးဘုတ်", + "Show Keyboard": "လက်ကွက်ကို ပြပါ", + "Extra keys": "အပိုသော့များ", + "Show Extra Keys": "အပိုသော့များကိုပြပါ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ကိုပြောင်းရန်", + "Alt": "Alt", + "Toggle Alt": "Alt ကို ပြောင်းရန်", + "Toggle Windows": "Windows ကိုပြောင်းရန်", + "Windows": "Windows", + "Send Tab": "တဘ်ပို့ရန်", + "Tab": "တက်ဘ်", + "Esc": "Esc", + "Send Escape": "လွတ်မြောက်အောင် ပို့ပေးပါ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ပို့ပါ", + "Shutdown/Reboot": "ပိတ်/ပြန်ဖွင့်ပါ", + "Shutdown/Reboot...": "ပိတ်/ပြန်ဖွင့်...", + "Power": "ပါဝါ", + "Shutdown": "အပြီးပိတ်လိုက်သည်", + "Reboot": "ပြန်ဖွင့်ပါ", + "Reset": "ပြန်လည်သတ်မှတ်ခြင်း", + "Clipboard": "ကလစ်ဘုတ်", + "Clear": "ရှင်းလင်းသော", + "Fullscreen": "မျက်နှာပြင်အပြည့်", + "Settings": "ဆက်တင်များ", + "Shared Mode": "မျှဝေထားသည့်မုဒ်", + "View Only": "ကြည့်ရန်သာ", + "Clip to Window": "ပြတင်းပေါက်မှ ကလစ်", + "Scaling Mode:": "စကေးမုဒ်-", + "None": "မရှိဘူး", + "Local Scaling": "ဒေသအလိုက် အတိုင်းအတာ", + "Remote Resizing": "အဝေးမှ အရွယ်အစားပြောင်းလဲခြင်း", + "Advanced": "အဆင့်မြင့်", + "Quality:": "အရည်အသွေး:", + "Compression level:": "ချုံ့မှုအဆင့်-", + "Repeater ID:": "ထပ်ယူသူ ID-", + "WebSocket": "ဝဘ်ပေါက်ပေါက်", + "Encrypt": "စာဝှက်ရန်", + "Host:": "အိမ်ရှင်-", + "Port:": "ဆိပ်ကမ်း-", + "Path:": "လမ်း:", + "Automatic Reconnect": "အလိုအလျောက် ပြန်လည်ချိတ်ဆက်ခြင်း", + "Reconnect Delay (ms):": "ပြန်ချိတ်ဆက်ရန်နှောင့်နှေး (ms):", + "Show Dot when No Cursor": "ကာဆာမရှိသည့်အခါ အစက်ပြပါ", + "Logging:": "မှတ်တမ်း-", + "Version:": "ဗားရှင်း-", + "Disconnect": "အဆက်ဖြတ်ရန်", + "Connect": "ချိတ်ဆက်", + "Username:": "အသုံးပြုသူအမည်-", + "Password:": "စကားဝှက်-", + "Send Credentials": "အထောက်အထားများ ပေးပို့ပါ", + "Cancel": "ပယ်ဖျက်", + "Keys": "သော့များ", + "Game Cursor Mode": "ဂိမ်း Cursor မုဒ်", + "Press Esc Key to Exit Pointer Lock Mode": "Pointer Lock Mode မှထွက်ရန် Esc Key ကိုနှိပ်ပါ", + "Game Mode paused, click on screen to resume Game Mode.": "ဂိမ်းမုဒ်ကို ခေတ္တရပ်ထားပြီး၊ ဂိမ်းမုဒ်ကို ပြန်လည်စတင်ရန် မျက်နှာပြင်ပေါ်တွင် နှိပ်ပါ။", + "Clipboard Up": "ကလစ်ဘုတ်ပေါ်", + "CLipboard Down": "ကလစ်ဘုတ်အောက်", + "Clipboard Seamless": "ညှပ်ဘုတ် ချောမွေ့ခြင်း", + "Prefer Local Cursor": "ဒေသခံကာဆာကို ဦးစားပေးပါ", + "Translate keyboard shortcuts": "ဘာသာပြန်ရန် ကီးဘုတ်ဖြတ်လမ်းများ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ကိုဖွင့်ပါ", + "Enable WebP Compression": "WebP Compression ကိုဖွင့်ပါ", + "Enable Performance Stats": "စွမ်းဆောင်ရည်စာရင်းများကိုဖွင့်ပါ", + "Enable Pointer Lock": "ညွှန်ပြလော့ခ်ကိုဖွင့်ပါ", + "IME Input Mode": "IME ထည့်သွင်းမုဒ်", + "Show Virtual Keyboard Control": "လက်ကွက်အတု ထိန်းချုပ်မှုကို ပြပါ", + "Toggle Control Panel via Keystrokes": "Keystrokes မှတဆင့် Control Panel ကိုပြောင်းရန်", + "Render Native Resolution": "ဇာတိဆုံးဖြတ်ချက်ကို တင်ဆက်ခြင်း", + "Keyboard Shortcuts": "ကီးဘုတ်ဖြတ်လမ်းများ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ကီးဘုတ်ဖြတ်လမ်းများကိုဖွင့်ပါ", + "1 - Toggle Control Panel": "1 - Control Panel ကို ပြောင်းရန်", + "2 - Toggle Game Pointer Mode": "2 - Game Pointer Mode ကို ပြောင်းရန်", + "3 - Toggle Pointer Lock": "3 - Pointer Lock ကို ပြောင်းရန်", + "Stream Quality": "ထုတ်လွှင့်မှုအရည်အသွေး", + "Preset Modes:": "ကြိုတင်သတ်မှတ်မုဒ်များ-", + "Static": "ငြိမ်", + "Low": "နိမ့်", + "Medium": "အလယ်အလတ်", + "High": "မြင့်", + "Extreme": "အလွန်အမင်း", + "Lossless": "အရှုံးမရှိ", + "Custom": "စိတ်ကြိုက်", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "အလိုအလျောက် ဒိုင်းနမစ်", + "Off": "ပိတ်", + "On": "ဂ", + "Dynamic Quality Min:": "ဒိုင်နမစ် အရည်အသွေး အနည်းဆုံး-", + "Dynamic Quality Max:": "ဒိုင်နမစ် အရည်အသွေး အများဆုံး-", + "Treat Lossless:": "အရှုံးမရှိအောင် ကုသပါ", + "Frame Rate:": "ဘောင်နှုန်း-", + "Video JPEG Quality:": "ဗီဒီယို JPEG အရည်အသွေး-", + "Video WEBP Quality:": "ဗီဒီယို WEBP အရည်အသွေး-", + "Video Area:": "ဗီဒီယိုဧရိယာ-", + "Video Time:": "ဗီဒီယိုအချိန်-", + "Video Out Time:": "ဗီဒီယိုထွက်ချိန်-", + "Video Mode Width:": "ဗီဒီယိုမုဒ် အကျယ်-", + "Video Mode Height:": "ဗီဒီယိုမုဒ် အမြင့်-", + "Documentation": "စာရွက်စာတမ်း", + "Drag Viewport": "ရှုထောင့်ကို ဆွဲယူပါ", + "KasmVNC encountered an error:": "KasmVNC သည် အမှားအယွင်းတစ်ခု ကြုံတွေ့ခဲ့သည်-" +} \ No newline at end of file diff --git a/app/locale/my_MM.json b/app/locale/my_MM.json new file mode 100644 index 0000000..f81d03f --- /dev/null +++ b/app/locale/my_MM.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ချိတ်ဆက်နေသည်...", + "Disconnecting...": "အဆက်ဖြတ်နေသည်...", + "Reconnecting...": "ပြန်လည်ချိတ်ဆက်နေသည်...", + "Internal error": "အတွင်းပိုင်းအမှား", + "Must set host": "အိမ်ရှင်သတ်မှတ်ရမယ်", + "Connected (encrypted) to ": "ချိတ်ဆက်ထားသည် (ကုဒ်ဝှက်ထားသည်)", + "Connected (unencrypted) to ": "ချိတ်ဆက်ထားသည် (စာဝှက်မထားသော)", + "Something went wrong, connection is closed": "တစ်ခုခုမှားနေပြီ၊ ချိတ်ဆက်မှုပိတ်ထား", + "Failed to connect to server": "ဆာဗာသို့ ချိတ်ဆက်၍မရပါ", + "Disconnected": "အဆက်ပြတ်သွားပြီ", + "New connection has been rejected with reason: ": "ချိတ်ဆက်မှုအသစ်ကို အကြောင်းပြချက်ဖြင့် ပယ်ချခဲ့သည်", + "New connection has been rejected": "ချိတ်ဆက်မှုအသစ်ကို ငြင်းပယ်ထားသည်", + "Credentials are required": "အထောက်အထားများ လိုအပ်သည်", + "Hide/Show the control bar": "ထိန်းချုပ်မှုဘားကို ဖျောက်/ပြပါ", + "Drag": "ဆွဲ", + "Move/Drag Viewport": "ရှုခင်းကိုရွှေ့/ဆွဲပါ", + "Keyboard": "ကီးဘုတ်", + "Show Keyboard": "လက်ကွက်ကို ပြပါ", + "Extra keys": "အပိုသော့များ", + "Show Extra Keys": "အပိုသော့များကိုပြပါ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ကိုပြောင်းရန်", + "Alt": "Alt", + "Toggle Alt": "Alt ကို ပြောင်းရန်", + "Toggle Windows": "Windows ကိုပြောင်းရန်", + "Windows": "Windows", + "Send Tab": "တဘ်ပို့ရန်", + "Tab": "တက်ဘ်", + "Esc": "Esc", + "Send Escape": "လွတ်မြောက်အောင် ပို့ပေးပါ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ပို့ပါ", + "Shutdown/Reboot": "ပိတ်/ပြန်ဖွင့်ပါ", + "Shutdown/Reboot...": "ပိတ်/ပြန်ဖွင့်...", + "Power": "ပါဝါ", + "Shutdown": "အပြီးပိတ်လိုက်သည်", + "Reboot": "ပြန်ဖွင့်ပါ", + "Reset": "ပြန်လည်သတ်မှတ်ခြင်း", + "Clipboard": "ကလစ်ဘုတ်", + "Clear": "ရှင်းလင်းသော", + "Fullscreen": "မျက်နှာပြင်အပြည့်", + "Settings": "ဆက်တင်များ", + "Shared Mode": "မျှဝေထားသည့်မုဒ်", + "View Only": "ကြည့်ရန်သာ", + "Clip to Window": "ပြတင်းပေါက်မှ ကလစ်", + "Scaling Mode:": "စကေးမုဒ်-", + "None": "မရှိဘူး", + "Local Scaling": "ဒေသအလိုက် အတိုင်းအတာ", + "Remote Resizing": "အဝေးမှ အရွယ်အစားပြောင်းလဲခြင်း", + "Advanced": "အဆင့်မြင့်", + "Quality:": "အရည်အသွေး:", + "Compression level:": "ချုံ့မှုအဆင့်-", + "Repeater ID:": "ထပ်ယူသူ ID-", + "WebSocket": "ဝဘ်ပေါက်ပေါက်", + "Encrypt": "စာဝှက်ရန်", + "Host:": "အိမ်ရှင်-", + "Port:": "ဆိပ်ကမ်း-", + "Path:": "လမ်း:", + "Automatic Reconnect": "အလိုအလျောက် ပြန်လည်ချိတ်ဆက်ခြင်း", + "Reconnect Delay (ms):": "ပြန်ချိတ်ဆက်ရန်နှောင့်နှေး (ms):", + "Show Dot when No Cursor": "ကာဆာမရှိသည့်အခါ အစက်ပြပါ", + "Logging:": "မှတ်တမ်း-", + "Version:": "ဗားရှင်း-", + "Disconnect": "အဆက်ဖြတ်ရန်", + "Connect": "ချိတ်ဆက်", + "Username:": "အသုံးပြုသူအမည်-", + "Password:": "စကားဝှက်-", + "Send Credentials": "အထောက်အထားများ ပေးပို့ပါ", + "Cancel": "ပယ်ဖျက်", + "Keys": "သော့များ", + "Game Cursor Mode": "ဂိမ်း Cursor မုဒ်", + "Press Esc Key to Exit Pointer Lock Mode": "Pointer Lock Mode မှထွက်ရန် Esc Key ကိုနှိပ်ပါ", + "Game Mode paused, click on screen to resume Game Mode.": "ဂိမ်းမုဒ်ကို ခေတ္တရပ်ထားပြီး၊ ဂိမ်းမုဒ်ကို ပြန်လည်စတင်ရန် မျက်နှာပြင်ပေါ်တွင် နှိပ်ပါ။", + "Clipboard Up": "ကလစ်ဘုတ်ပေါ်", + "CLipboard Down": "ကလစ်ဘုတ်အောက်", + "Clipboard Seamless": "ညှပ်ဘုတ် ချောမွေ့ခြင်း", + "Prefer Local Cursor": "ဒေသခံကာဆာကို ဦးစားပေးပါ", + "Translate keyboard shortcuts": "ဘာသာပြန်ရန် ကီးဘုတ်ဖြတ်လမ်းများ", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ကိုဖွင့်ပါ", + "Enable WebP Compression": "WebP Compression ကိုဖွင့်ပါ", + "Enable Performance Stats": "စွမ်းဆောင်ရည်စာရင်းများကိုဖွင့်ပါ", + "Enable Pointer Lock": "ညွှန်ပြလော့ခ်ကိုဖွင့်ပါ", + "IME Input Mode": "IME ထည့်သွင်းမုဒ်", + "Show Virtual Keyboard Control": "လက်ကွက်အတု ထိန်းချုပ်မှုကို ပြပါ", + "Toggle Control Panel via Keystrokes": "Keystrokes မှတဆင့် Control Panel ကိုပြောင်းရန်", + "Render Native Resolution": "ဇာတိဆုံးဖြတ်ချက်ကို တင်ဆက်ခြင်း", + "Keyboard Shortcuts": "ကီးဘုတ်ဖြတ်လမ်းများ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ကီးဘုတ်ဖြတ်လမ်းများကိုဖွင့်ပါ", + "1 - Toggle Control Panel": "1 - Control Panel ကို ပြောင်းရန်", + "2 - Toggle Game Pointer Mode": "2 - Game Pointer Mode ကို ပြောင်းရန်", + "3 - Toggle Pointer Lock": "3 - Pointer Lock ကို ပြောင်းရန်", + "Stream Quality": "ထုတ်လွှင့်မှုအရည်အသွေး", + "Preset Modes:": "ကြိုတင်သတ်မှတ်မုဒ်များ-", + "Static": "ငြိမ်", + "Low": "နိမ့်", + "Medium": "အလယ်အလတ်", + "High": "မြင့်", + "Extreme": "အလွန်အမင်း", + "Lossless": "အရှုံးမရှိ", + "Custom": "စိတ်ကြိုက်", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "အလိုအလျောက် ဒိုင်းနမစ်", + "Off": "ပိတ်", + "On": "ဂ", + "Dynamic Quality Min:": "ဒိုင်နမစ် အရည်အသွေး အနည်းဆုံး-", + "Dynamic Quality Max:": "ဒိုင်နမစ် အရည်အသွေး အများဆုံး-", + "Treat Lossless:": "အရှုံးမရှိအောင် ကုသပါ", + "Frame Rate:": "ဘောင်နှုန်း-", + "Video JPEG Quality:": "ဗီဒီယို JPEG အရည်အသွေး-", + "Video WEBP Quality:": "ဗီဒီယို WEBP အရည်အသွေး-", + "Video Area:": "ဗီဒီယိုဧရိယာ-", + "Video Time:": "ဗီဒီယိုအချိန်-", + "Video Out Time:": "ဗီဒီယိုထွက်ချိန်-", + "Video Mode Width:": "ဗီဒီယိုမုဒ် အကျယ်-", + "Video Mode Height:": "ဗီဒီယိုမုဒ် အမြင့်-", + "Documentation": "စာရွက်စာတမ်း", + "Drag Viewport": "ရှုထောင့်ကို ဆွဲယူပါ", + "KasmVNC encountered an error:": "KasmVNC သည် အမှားအယွင်းတစ်ခု ကြုံတွေ့ခဲ့သည်-" +} \ No newline at end of file diff --git a/app/locale/ne.json b/app/locale/ne.json new file mode 100644 index 0000000..3f21298 --- /dev/null +++ b/app/locale/ne.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "जोड्दै...", + "Disconnecting...": "विच्छेद गर्दै...", + "Reconnecting...": "पुन: जडान गर्दै...", + "Internal error": "आन्तरिक त्रुटि", + "Must set host": "होस्ट सेट गर्नुपर्छ", + "Connected (encrypted) to ": "जोडिएको (इन्क्रिप्टेड) मा", + "Connected (unencrypted) to ": "जोडिएको (एन्क्रिप्ट नगरिएको) मा", + "Something went wrong, connection is closed": "केही गडबड भयो, जडान बन्द छ", + "Failed to connect to server": "सर्भर जडान गर्न असफल", + "Disconnected": "विच्छेद भयो", + "New connection has been rejected with reason: ": "नयाँ जडान कारणले अस्वीकार गरिएको छ:", + "New connection has been rejected": "नयाँ जडान अस्वीकार गरिएको छ", + "Credentials are required": "प्रमाणपत्र आवश्यक छ", + "Hide/Show the control bar": "नियन्त्रण पट्टी लुकाउनुहोस्/देखाउनुहोस्", + "Drag": "तान्नुहोस्", + "Move/Drag Viewport": "भ्यूपोर्ट सार्नुहोस्/तान्नुहोस्", + "Keyboard": "कीबोर्ड", + "Show Keyboard": "कीबोर्ड देखाउनुहोस्", + "Extra keys": "अतिरिक्त कुञ्जीहरू", + "Show Extra Keys": "अतिरिक्त कुञ्जीहरू देखाउनुहोस्", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl टगल गर्नुहोस्", + "Alt": "Alt", + "Toggle Alt": "Alt टगल गर्नुहोस्", + "Toggle Windows": "विन्डोज टगल गर्नुहोस्", + "Windows": "विन्डोज", + "Send Tab": "ट्याब पठाउनुहोस्", + "Tab": "ट्याब", + "Esc": "Esc", + "Send Escape": "एस्केप पठाउनुहोस्", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del पठाउनुहोस्", + "Shutdown/Reboot": "शटडाउन/रिबुट", + "Shutdown/Reboot...": "शटडाउन/रिबुट...", + "Power": "शक्ति", + "Shutdown": "बन्द गर", + "Reboot": "रिबुट", + "Reset": "रिसेट गर्नुहोस्", + "Clipboard": "क्लिपबोर्ड", + "Clear": "स्पष्ट", + "Fullscreen": "फुलस्क्रिन", + "Settings": "सेटिङहरू", + "Shared Mode": "साझा मोड", + "View Only": "हेर्नुहोस् मात्र", + "Clip to Window": "सञ्झ्यालमा क्लिप गर्नुहोस्", + "Scaling Mode:": "स्केलिंग मोड:", + "None": "कुनै पनि छैन", + "Local Scaling": "स्थानीय मापन", + "Remote Resizing": "रिमोट रिसाइजिङ", + "Advanced": "उन्नत", + "Quality:": "गुणस्तर:", + "Compression level:": "संकुचन स्तर:", + "Repeater ID:": "रिपीटर ID:", + "WebSocket": "वेबसकेट", + "Encrypt": "इन्क्रिप्ट", + "Host:": "होस्ट:", + "Port:": "पोर्ट:", + "Path:": "मार्ग:", + "Automatic Reconnect": "स्वचालित पुन: जडान", + "Reconnect Delay (ms):": "पुन: जडान ढिलाइ (ms):", + "Show Dot when No Cursor": "कर्सर नभएको बेला डट देखाउनुहोस्", + "Logging:": "लगिङ:", + "Version:": "संस्करण:", + "Disconnect": "विच्छेद गर्नुहोस्", + "Connect": "जडान", + "Username:": "प्रयोगकर्ता नाम:", + "Password:": "पासवर्ड:", + "Send Credentials": "प्रमाणपत्रहरू पठाउनुहोस्", + "Cancel": "रद्द गर्नुहोस्", + "Keys": "कुञ्जीहरू", + "Game Cursor Mode": "खेल कर्सर मोड", + "Press Esc Key to Exit Pointer Lock Mode": "पोइन्टर लक मोडबाट बाहिर निस्कन Esc कुञ्जी थिच्नुहोस्", + "Game Mode paused, click on screen to resume Game Mode.": "खेल मोड पज गरियो, खेल मोड पुन: सुरु गर्न स्क्रिनमा क्लिक गर्नुहोस्।", + "Clipboard Up": "क्लिपबोर्ड माथि", + "CLipboard Down": "क्लिपबोर्ड तल", + "Clipboard Seamless": "क्लिपबोर्ड सिमलेस", + "Prefer Local Cursor": "स्थानीय कर्सरलाई प्राथमिकता दिनुहोस्", + "Translate keyboard shortcuts": "किबोर्ड सर्टकटहरू अनुवाद गर्नुहोस्", + "Enable WebRTC UDP Transit": "WebRTC UDP ट्रान्जिट सक्षम गर्नुहोस्", + "Enable WebP Compression": "WebP कम्प्रेसन सक्षम गर्नुहोस्", + "Enable Performance Stats": "कार्यसम्पादन तथ्याङ्क सक्षम गर्नुहोस्", + "Enable Pointer Lock": "सूचक लक सक्षम गर्नुहोस्", + "IME Input Mode": "IME इनपुट मोड", + "Show Virtual Keyboard Control": "भर्चुअल किबोर्ड नियन्त्रण देखाउनुहोस्", + "Toggle Control Panel via Keystrokes": "कीस्ट्रोक मार्फत नियन्त्रण प्यानल टगल गर्नुहोस्", + "Render Native Resolution": "नेटिभ रिजोल्युसन रेन्डर गर्नुहोस्", + "Keyboard Shortcuts": "कीबोर्ड सर्टकटहरू", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC किबोर्ड सर्टकट सक्षम गर्नुहोस्", + "1 - Toggle Control Panel": "१ - नियन्त्रण प्यानल टगल गर्नुहोस्", + "2 - Toggle Game Pointer Mode": "२ - खेल सूचक मोड टगल गर्नुहोस्", + "3 - Toggle Pointer Lock": "3 - सूचक लक टगल गर्नुहोस्", + "Stream Quality": "स्ट्रिम गुणस्तर", + "Preset Modes:": "प्रिसेट मोडहरू:", + "Static": "स्थिर", + "Low": "कम", + "Medium": "मध्यम", + "High": "उच्च", + "Extreme": "चरम", + "Lossless": "हानिरहित", + "Custom": "अनुकूल", + "Anti-Aliasing:": "एन्टि-एलियासिङ:", + "Auto Dynamic": "अटो डायनामिक", + "Off": "बन्द", + "On": "चालू", + "Dynamic Quality Min:": "गतिशील गुणस्तर न्यूनतम:", + "Dynamic Quality Max:": "गतिशील गुणस्तर अधिकतम:", + "Treat Lossless:": "हानिरहित उपचार गर्नुहोस्:", + "Frame Rate:": "फ्रेम दर:", + "Video JPEG Quality:": "भिडियो JPEG गुणस्तर:", + "Video WEBP Quality:": "भिडियो WEBP गुणस्तर:", + "Video Area:": "भिडियो क्षेत्र:", + "Video Time:": "भिडियो समय:", + "Video Out Time:": "भिडियो आउट समय:", + "Video Mode Width:": "भिडियो मोड चौडाई:", + "Video Mode Height:": "भिडियो मोड उचाइ:", + "Documentation": "कागजात", + "Drag Viewport": "ड्र्याग भ्यूपोर्ट", + "KasmVNC encountered an error:": "KasmVNC ले त्रुटिको सामना गर्यो:" +} \ No newline at end of file diff --git a/app/locale/ne_NP.json b/app/locale/ne_NP.json new file mode 100644 index 0000000..3f21298 --- /dev/null +++ b/app/locale/ne_NP.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "जोड्दै...", + "Disconnecting...": "विच्छेद गर्दै...", + "Reconnecting...": "पुन: जडान गर्दै...", + "Internal error": "आन्तरिक त्रुटि", + "Must set host": "होस्ट सेट गर्नुपर्छ", + "Connected (encrypted) to ": "जोडिएको (इन्क्रिप्टेड) मा", + "Connected (unencrypted) to ": "जोडिएको (एन्क्रिप्ट नगरिएको) मा", + "Something went wrong, connection is closed": "केही गडबड भयो, जडान बन्द छ", + "Failed to connect to server": "सर्भर जडान गर्न असफल", + "Disconnected": "विच्छेद भयो", + "New connection has been rejected with reason: ": "नयाँ जडान कारणले अस्वीकार गरिएको छ:", + "New connection has been rejected": "नयाँ जडान अस्वीकार गरिएको छ", + "Credentials are required": "प्रमाणपत्र आवश्यक छ", + "Hide/Show the control bar": "नियन्त्रण पट्टी लुकाउनुहोस्/देखाउनुहोस्", + "Drag": "तान्नुहोस्", + "Move/Drag Viewport": "भ्यूपोर्ट सार्नुहोस्/तान्नुहोस्", + "Keyboard": "कीबोर्ड", + "Show Keyboard": "कीबोर्ड देखाउनुहोस्", + "Extra keys": "अतिरिक्त कुञ्जीहरू", + "Show Extra Keys": "अतिरिक्त कुञ्जीहरू देखाउनुहोस्", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl टगल गर्नुहोस्", + "Alt": "Alt", + "Toggle Alt": "Alt टगल गर्नुहोस्", + "Toggle Windows": "विन्डोज टगल गर्नुहोस्", + "Windows": "विन्डोज", + "Send Tab": "ट्याब पठाउनुहोस्", + "Tab": "ट्याब", + "Esc": "Esc", + "Send Escape": "एस्केप पठाउनुहोस्", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del पठाउनुहोस्", + "Shutdown/Reboot": "शटडाउन/रिबुट", + "Shutdown/Reboot...": "शटडाउन/रिबुट...", + "Power": "शक्ति", + "Shutdown": "बन्द गर", + "Reboot": "रिबुट", + "Reset": "रिसेट गर्नुहोस्", + "Clipboard": "क्लिपबोर्ड", + "Clear": "स्पष्ट", + "Fullscreen": "फुलस्क्रिन", + "Settings": "सेटिङहरू", + "Shared Mode": "साझा मोड", + "View Only": "हेर्नुहोस् मात्र", + "Clip to Window": "सञ्झ्यालमा क्लिप गर्नुहोस्", + "Scaling Mode:": "स्केलिंग मोड:", + "None": "कुनै पनि छैन", + "Local Scaling": "स्थानीय मापन", + "Remote Resizing": "रिमोट रिसाइजिङ", + "Advanced": "उन्नत", + "Quality:": "गुणस्तर:", + "Compression level:": "संकुचन स्तर:", + "Repeater ID:": "रिपीटर ID:", + "WebSocket": "वेबसकेट", + "Encrypt": "इन्क्रिप्ट", + "Host:": "होस्ट:", + "Port:": "पोर्ट:", + "Path:": "मार्ग:", + "Automatic Reconnect": "स्वचालित पुन: जडान", + "Reconnect Delay (ms):": "पुन: जडान ढिलाइ (ms):", + "Show Dot when No Cursor": "कर्सर नभएको बेला डट देखाउनुहोस्", + "Logging:": "लगिङ:", + "Version:": "संस्करण:", + "Disconnect": "विच्छेद गर्नुहोस्", + "Connect": "जडान", + "Username:": "प्रयोगकर्ता नाम:", + "Password:": "पासवर्ड:", + "Send Credentials": "प्रमाणपत्रहरू पठाउनुहोस्", + "Cancel": "रद्द गर्नुहोस्", + "Keys": "कुञ्जीहरू", + "Game Cursor Mode": "खेल कर्सर मोड", + "Press Esc Key to Exit Pointer Lock Mode": "पोइन्टर लक मोडबाट बाहिर निस्कन Esc कुञ्जी थिच्नुहोस्", + "Game Mode paused, click on screen to resume Game Mode.": "खेल मोड पज गरियो, खेल मोड पुन: सुरु गर्न स्क्रिनमा क्लिक गर्नुहोस्।", + "Clipboard Up": "क्लिपबोर्ड माथि", + "CLipboard Down": "क्लिपबोर्ड तल", + "Clipboard Seamless": "क्लिपबोर्ड सिमलेस", + "Prefer Local Cursor": "स्थानीय कर्सरलाई प्राथमिकता दिनुहोस्", + "Translate keyboard shortcuts": "किबोर्ड सर्टकटहरू अनुवाद गर्नुहोस्", + "Enable WebRTC UDP Transit": "WebRTC UDP ट्रान्जिट सक्षम गर्नुहोस्", + "Enable WebP Compression": "WebP कम्प्रेसन सक्षम गर्नुहोस्", + "Enable Performance Stats": "कार्यसम्पादन तथ्याङ्क सक्षम गर्नुहोस्", + "Enable Pointer Lock": "सूचक लक सक्षम गर्नुहोस्", + "IME Input Mode": "IME इनपुट मोड", + "Show Virtual Keyboard Control": "भर्चुअल किबोर्ड नियन्त्रण देखाउनुहोस्", + "Toggle Control Panel via Keystrokes": "कीस्ट्रोक मार्फत नियन्त्रण प्यानल टगल गर्नुहोस्", + "Render Native Resolution": "नेटिभ रिजोल्युसन रेन्डर गर्नुहोस्", + "Keyboard Shortcuts": "कीबोर्ड सर्टकटहरू", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC किबोर्ड सर्टकट सक्षम गर्नुहोस्", + "1 - Toggle Control Panel": "१ - नियन्त्रण प्यानल टगल गर्नुहोस्", + "2 - Toggle Game Pointer Mode": "२ - खेल सूचक मोड टगल गर्नुहोस्", + "3 - Toggle Pointer Lock": "3 - सूचक लक टगल गर्नुहोस्", + "Stream Quality": "स्ट्रिम गुणस्तर", + "Preset Modes:": "प्रिसेट मोडहरू:", + "Static": "स्थिर", + "Low": "कम", + "Medium": "मध्यम", + "High": "उच्च", + "Extreme": "चरम", + "Lossless": "हानिरहित", + "Custom": "अनुकूल", + "Anti-Aliasing:": "एन्टि-एलियासिङ:", + "Auto Dynamic": "अटो डायनामिक", + "Off": "बन्द", + "On": "चालू", + "Dynamic Quality Min:": "गतिशील गुणस्तर न्यूनतम:", + "Dynamic Quality Max:": "गतिशील गुणस्तर अधिकतम:", + "Treat Lossless:": "हानिरहित उपचार गर्नुहोस्:", + "Frame Rate:": "फ्रेम दर:", + "Video JPEG Quality:": "भिडियो JPEG गुणस्तर:", + "Video WEBP Quality:": "भिडियो WEBP गुणस्तर:", + "Video Area:": "भिडियो क्षेत्र:", + "Video Time:": "भिडियो समय:", + "Video Out Time:": "भिडियो आउट समय:", + "Video Mode Width:": "भिडियो मोड चौडाई:", + "Video Mode Height:": "भिडियो मोड उचाइ:", + "Documentation": "कागजात", + "Drag Viewport": "ड्र्याग भ्यूपोर्ट", + "KasmVNC encountered an error:": "KasmVNC ले त्रुटिको सामना गर्यो:" +} \ No newline at end of file diff --git a/app/locale/nl.json b/app/locale/nl.json new file mode 100644 index 0000000..9a50b25 --- /dev/null +++ b/app/locale/nl.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Verbinden...", + "Disconnecting...": "Verbinding verbreken...", + "Reconnecting...": "Opnieuw verbinding maken...", + "Internal error": "Interne fout", + "Must set host": "Host moeten worden ingesteld", + "Connected (encrypted) to ": "Verbonden (versleuteld) met ", + "Connected (unencrypted) to ": "Verbonden (onversleuteld) met ", + "Something went wrong, connection is closed": "Er iets fout gelopen, verbinding werd verbroken", + "Failed to connect to server": "Verbinding maken met server is mislukt", + "Disconnected": "Verbinding verbroken", + "New connection has been rejected with reason: ": "Nieuwe verbinding is geweigerd omwille van de volgende reden: ", + "New connection has been rejected": "Nieuwe verbinding is geweigerd", + "Password is required": "Wachtwoord is vereist", + "Hide/Show the control bar": "Verberg/Toon de bedieningsbalk", + "Move/Drag Viewport": "Verplaats/Versleep Kijkvenster", + "viewport drag": "kijkvenster slepen", + "Active Mouse Button": "Actieve Muisknop", + "No mousebutton": "Geen muisknop", + "Left mousebutton": "Linker muisknop", + "Middle mousebutton": "Middelste muisknop", + "Right mousebutton": "Rechter muisknop", + "Keyboard": "Toetsenbord", + "Show Keyboard": "Toon Toetsenbord", + "Extra keys": "Extra toetsen", + "Show Extra Keys": "Toon Extra Toetsen", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl omschakelen", + "Alt": "Alt", + "Toggle Alt": "Alt omschakelen", + "Toggle Windows": "Windows omschakelen", + "Windows": "Windows", + "Send Tab": "Tab Sturen", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Escape Sturen", + "Ctrl+Alt+Del": "Ctrl-Alt-Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Sturen", + "Shutdown/Reboot": "Uitschakelen/Herstarten", + "Shutdown/Reboot...": "Uitschakelen/Herstarten...", + "Power": "Systeem", + "Shutdown": "Uitschakelen", + "Reboot": "Herstarten", + "Reset": "Resetten", + "Clipboard": "Klembord", + "Clear": "Wissen", + "Fullscreen": "Volledig Scherm", + "Settings": "Instellingen", + "Shared Mode": "Gedeelde Modus", + "View Only": "Alleen Kijken", + "Clip to Window": "Randen buiten venster afsnijden", + "Scaling Mode:": "Schaalmodus:", + "None": "Geen", + "Local Scaling": "Lokaal Schalen", + "Remote Resizing": "Op Afstand Formaat Wijzigen", + "Advanced": "Geavanceerd", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Versleutelen", + "Host:": "Host:", + "Port:": "Poort:", + "Path:": "Pad:", + "Automatic Reconnect": "Automatisch Opnieuw Verbinden", + "Reconnect Delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):", + "Show Dot when No Cursor": "Geef stip weer indien geen cursor", + "Logging:": "Logmeldingen:", + "Disconnect": "Verbinding verbreken", + "Connect": "Verbinden", + "Password:": "Wachtwoord:", + "Send Password": "Verzend Wachtwoord:", + "Cancel": "Annuleren", + "Credentials are required": "Inloggegevens zijn vereist", + "Drag": "Sleuren", + "Quality:": "Kwaliteit:", + "Compression level:": "Compressieniveau:", + "Version:": "Versie:", + "Username:": "Gebruikersnaam:", + "Send Credentials": "Inloggegevens verzenden", + "Keys": "Sleutels", + "Game Cursor Mode": "Spelcursormodus", + "Press Esc Key to Exit Pointer Lock Mode": "Druk op de Esc-toets om de aanwijzervergrendelingsmodus af te sluiten", + "Game Mode paused, click on screen to resume Game Mode.": "Spelmodus gepauzeerd, klik op het scherm om de spelmodus te hervatten.", + "Clipboard Up": "Klembord omhoog", + "CLipboard Down": "Klembord naar beneden", + "Clipboard Seamless": "Klembord naadloos", + "Prefer Local Cursor": "Geef de voorkeur aan lokale cursor", + "Translate keyboard shortcuts": "Sneltoetsen vertalen", + "Enable WebRTC UDP Transit": "WebRTC UDP-transit inschakelen", + "Enable WebP Compression": "WebP-compressie inschakelen", + "Enable Performance Stats": "Prestatiestatistieken inschakelen", + "Enable Pointer Lock": "Aanwijzervergrendeling inschakelen", + "IME Input Mode": "IME-invoermodus", + "Show Virtual Keyboard Control": "Toon virtuele toetsenbordbediening", + "Toggle Control Panel via Keystrokes": "Toggle Configuratiescherm via toetsaanslagen", + "Render Native Resolution": "Native resolutie weergeven", + "Keyboard Shortcuts": "Toetsenbord sneltoetsen", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-sneltoetsen inschakelen", + "1 - Toggle Control Panel": "1 - Configuratiescherm omschakelen", + "2 - Toggle Game Pointer Mode": "2 - Schakel Game Pointer-modus in", + "3 - Toggle Pointer Lock": "3 - Aanwijzervergrendeling in-/uitschakelen", + "Stream Quality": "Streamkwaliteit", + "Preset Modes:": "Vooraf ingestelde modi:", + "Static": "Statisch", + "Low": "Laag", + "Medium": "Medium", + "High": "Hoog", + "Extreme": "Extreem", + "Lossless": "Verliesloos", + "Custom": "Aangepast", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamisch", + "Off": "Uit", + "On": "Op", + "Dynamic Quality Min:": "Dynamische kwaliteit min:", + "Dynamic Quality Max:": "Dynamische kwaliteit max:", + "Treat Lossless:": "Behandel Lossless:", + "Frame Rate:": "Frame rate:", + "Video JPEG Quality:": "Video JPEG-kwaliteit:", + "Video WEBP Quality:": "Video WEBP-kwaliteit:", + "Video Area:": "Videogebied:", + "Video Time:": "Videotijd:", + "Video Out Time:": "Video uit tijd:", + "Video Mode Width:": "Breedte videomodus:", + "Video Mode Height:": "Hoogte videomodus:", + "Documentation": "Documentatie", + "Drag Viewport": "Sleep Viewport", + "KasmVNC encountered an error:": "KasmVNC heeft een fout aangetroffen:" +} \ No newline at end of file diff --git a/app/locale/nl_AW.json b/app/locale/nl_AW.json new file mode 100644 index 0000000..9a50b25 --- /dev/null +++ b/app/locale/nl_AW.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Verbinden...", + "Disconnecting...": "Verbinding verbreken...", + "Reconnecting...": "Opnieuw verbinding maken...", + "Internal error": "Interne fout", + "Must set host": "Host moeten worden ingesteld", + "Connected (encrypted) to ": "Verbonden (versleuteld) met ", + "Connected (unencrypted) to ": "Verbonden (onversleuteld) met ", + "Something went wrong, connection is closed": "Er iets fout gelopen, verbinding werd verbroken", + "Failed to connect to server": "Verbinding maken met server is mislukt", + "Disconnected": "Verbinding verbroken", + "New connection has been rejected with reason: ": "Nieuwe verbinding is geweigerd omwille van de volgende reden: ", + "New connection has been rejected": "Nieuwe verbinding is geweigerd", + "Password is required": "Wachtwoord is vereist", + "Hide/Show the control bar": "Verberg/Toon de bedieningsbalk", + "Move/Drag Viewport": "Verplaats/Versleep Kijkvenster", + "viewport drag": "kijkvenster slepen", + "Active Mouse Button": "Actieve Muisknop", + "No mousebutton": "Geen muisknop", + "Left mousebutton": "Linker muisknop", + "Middle mousebutton": "Middelste muisknop", + "Right mousebutton": "Rechter muisknop", + "Keyboard": "Toetsenbord", + "Show Keyboard": "Toon Toetsenbord", + "Extra keys": "Extra toetsen", + "Show Extra Keys": "Toon Extra Toetsen", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl omschakelen", + "Alt": "Alt", + "Toggle Alt": "Alt omschakelen", + "Toggle Windows": "Windows omschakelen", + "Windows": "Windows", + "Send Tab": "Tab Sturen", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Escape Sturen", + "Ctrl+Alt+Del": "Ctrl-Alt-Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Sturen", + "Shutdown/Reboot": "Uitschakelen/Herstarten", + "Shutdown/Reboot...": "Uitschakelen/Herstarten...", + "Power": "Systeem", + "Shutdown": "Uitschakelen", + "Reboot": "Herstarten", + "Reset": "Resetten", + "Clipboard": "Klembord", + "Clear": "Wissen", + "Fullscreen": "Volledig Scherm", + "Settings": "Instellingen", + "Shared Mode": "Gedeelde Modus", + "View Only": "Alleen Kijken", + "Clip to Window": "Randen buiten venster afsnijden", + "Scaling Mode:": "Schaalmodus:", + "None": "Geen", + "Local Scaling": "Lokaal Schalen", + "Remote Resizing": "Op Afstand Formaat Wijzigen", + "Advanced": "Geavanceerd", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Versleutelen", + "Host:": "Host:", + "Port:": "Poort:", + "Path:": "Pad:", + "Automatic Reconnect": "Automatisch Opnieuw Verbinden", + "Reconnect Delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):", + "Show Dot when No Cursor": "Geef stip weer indien geen cursor", + "Logging:": "Logmeldingen:", + "Disconnect": "Verbinding verbreken", + "Connect": "Verbinden", + "Password:": "Wachtwoord:", + "Send Password": "Verzend Wachtwoord:", + "Cancel": "Annuleren", + "Credentials are required": "Inloggegevens zijn vereist", + "Drag": "Sleuren", + "Quality:": "Kwaliteit:", + "Compression level:": "Compressieniveau:", + "Version:": "Versie:", + "Username:": "Gebruikersnaam:", + "Send Credentials": "Inloggegevens verzenden", + "Keys": "Sleutels", + "Game Cursor Mode": "Spelcursormodus", + "Press Esc Key to Exit Pointer Lock Mode": "Druk op de Esc-toets om de aanwijzervergrendelingsmodus af te sluiten", + "Game Mode paused, click on screen to resume Game Mode.": "Spelmodus gepauzeerd, klik op het scherm om de spelmodus te hervatten.", + "Clipboard Up": "Klembord omhoog", + "CLipboard Down": "Klembord naar beneden", + "Clipboard Seamless": "Klembord naadloos", + "Prefer Local Cursor": "Geef de voorkeur aan lokale cursor", + "Translate keyboard shortcuts": "Sneltoetsen vertalen", + "Enable WebRTC UDP Transit": "WebRTC UDP-transit inschakelen", + "Enable WebP Compression": "WebP-compressie inschakelen", + "Enable Performance Stats": "Prestatiestatistieken inschakelen", + "Enable Pointer Lock": "Aanwijzervergrendeling inschakelen", + "IME Input Mode": "IME-invoermodus", + "Show Virtual Keyboard Control": "Toon virtuele toetsenbordbediening", + "Toggle Control Panel via Keystrokes": "Toggle Configuratiescherm via toetsaanslagen", + "Render Native Resolution": "Native resolutie weergeven", + "Keyboard Shortcuts": "Toetsenbord sneltoetsen", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-sneltoetsen inschakelen", + "1 - Toggle Control Panel": "1 - Configuratiescherm omschakelen", + "2 - Toggle Game Pointer Mode": "2 - Schakel Game Pointer-modus in", + "3 - Toggle Pointer Lock": "3 - Aanwijzervergrendeling in-/uitschakelen", + "Stream Quality": "Streamkwaliteit", + "Preset Modes:": "Vooraf ingestelde modi:", + "Static": "Statisch", + "Low": "Laag", + "Medium": "Medium", + "High": "Hoog", + "Extreme": "Extreem", + "Lossless": "Verliesloos", + "Custom": "Aangepast", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamisch", + "Off": "Uit", + "On": "Op", + "Dynamic Quality Min:": "Dynamische kwaliteit min:", + "Dynamic Quality Max:": "Dynamische kwaliteit max:", + "Treat Lossless:": "Behandel Lossless:", + "Frame Rate:": "Frame rate:", + "Video JPEG Quality:": "Video JPEG-kwaliteit:", + "Video WEBP Quality:": "Video WEBP-kwaliteit:", + "Video Area:": "Videogebied:", + "Video Time:": "Videotijd:", + "Video Out Time:": "Video uit tijd:", + "Video Mode Width:": "Breedte videomodus:", + "Video Mode Height:": "Hoogte videomodus:", + "Documentation": "Documentatie", + "Drag Viewport": "Sleep Viewport", + "KasmVNC encountered an error:": "KasmVNC heeft een fout aangetroffen:" +} \ No newline at end of file diff --git a/app/locale/nl_BE.json b/app/locale/nl_BE.json new file mode 100644 index 0000000..9a50b25 --- /dev/null +++ b/app/locale/nl_BE.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Verbinden...", + "Disconnecting...": "Verbinding verbreken...", + "Reconnecting...": "Opnieuw verbinding maken...", + "Internal error": "Interne fout", + "Must set host": "Host moeten worden ingesteld", + "Connected (encrypted) to ": "Verbonden (versleuteld) met ", + "Connected (unencrypted) to ": "Verbonden (onversleuteld) met ", + "Something went wrong, connection is closed": "Er iets fout gelopen, verbinding werd verbroken", + "Failed to connect to server": "Verbinding maken met server is mislukt", + "Disconnected": "Verbinding verbroken", + "New connection has been rejected with reason: ": "Nieuwe verbinding is geweigerd omwille van de volgende reden: ", + "New connection has been rejected": "Nieuwe verbinding is geweigerd", + "Password is required": "Wachtwoord is vereist", + "Hide/Show the control bar": "Verberg/Toon de bedieningsbalk", + "Move/Drag Viewport": "Verplaats/Versleep Kijkvenster", + "viewport drag": "kijkvenster slepen", + "Active Mouse Button": "Actieve Muisknop", + "No mousebutton": "Geen muisknop", + "Left mousebutton": "Linker muisknop", + "Middle mousebutton": "Middelste muisknop", + "Right mousebutton": "Rechter muisknop", + "Keyboard": "Toetsenbord", + "Show Keyboard": "Toon Toetsenbord", + "Extra keys": "Extra toetsen", + "Show Extra Keys": "Toon Extra Toetsen", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl omschakelen", + "Alt": "Alt", + "Toggle Alt": "Alt omschakelen", + "Toggle Windows": "Windows omschakelen", + "Windows": "Windows", + "Send Tab": "Tab Sturen", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Escape Sturen", + "Ctrl+Alt+Del": "Ctrl-Alt-Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Sturen", + "Shutdown/Reboot": "Uitschakelen/Herstarten", + "Shutdown/Reboot...": "Uitschakelen/Herstarten...", + "Power": "Systeem", + "Shutdown": "Uitschakelen", + "Reboot": "Herstarten", + "Reset": "Resetten", + "Clipboard": "Klembord", + "Clear": "Wissen", + "Fullscreen": "Volledig Scherm", + "Settings": "Instellingen", + "Shared Mode": "Gedeelde Modus", + "View Only": "Alleen Kijken", + "Clip to Window": "Randen buiten venster afsnijden", + "Scaling Mode:": "Schaalmodus:", + "None": "Geen", + "Local Scaling": "Lokaal Schalen", + "Remote Resizing": "Op Afstand Formaat Wijzigen", + "Advanced": "Geavanceerd", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Versleutelen", + "Host:": "Host:", + "Port:": "Poort:", + "Path:": "Pad:", + "Automatic Reconnect": "Automatisch Opnieuw Verbinden", + "Reconnect Delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):", + "Show Dot when No Cursor": "Geef stip weer indien geen cursor", + "Logging:": "Logmeldingen:", + "Disconnect": "Verbinding verbreken", + "Connect": "Verbinden", + "Password:": "Wachtwoord:", + "Send Password": "Verzend Wachtwoord:", + "Cancel": "Annuleren", + "Credentials are required": "Inloggegevens zijn vereist", + "Drag": "Sleuren", + "Quality:": "Kwaliteit:", + "Compression level:": "Compressieniveau:", + "Version:": "Versie:", + "Username:": "Gebruikersnaam:", + "Send Credentials": "Inloggegevens verzenden", + "Keys": "Sleutels", + "Game Cursor Mode": "Spelcursormodus", + "Press Esc Key to Exit Pointer Lock Mode": "Druk op de Esc-toets om de aanwijzervergrendelingsmodus af te sluiten", + "Game Mode paused, click on screen to resume Game Mode.": "Spelmodus gepauzeerd, klik op het scherm om de spelmodus te hervatten.", + "Clipboard Up": "Klembord omhoog", + "CLipboard Down": "Klembord naar beneden", + "Clipboard Seamless": "Klembord naadloos", + "Prefer Local Cursor": "Geef de voorkeur aan lokale cursor", + "Translate keyboard shortcuts": "Sneltoetsen vertalen", + "Enable WebRTC UDP Transit": "WebRTC UDP-transit inschakelen", + "Enable WebP Compression": "WebP-compressie inschakelen", + "Enable Performance Stats": "Prestatiestatistieken inschakelen", + "Enable Pointer Lock": "Aanwijzervergrendeling inschakelen", + "IME Input Mode": "IME-invoermodus", + "Show Virtual Keyboard Control": "Toon virtuele toetsenbordbediening", + "Toggle Control Panel via Keystrokes": "Toggle Configuratiescherm via toetsaanslagen", + "Render Native Resolution": "Native resolutie weergeven", + "Keyboard Shortcuts": "Toetsenbord sneltoetsen", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-sneltoetsen inschakelen", + "1 - Toggle Control Panel": "1 - Configuratiescherm omschakelen", + "2 - Toggle Game Pointer Mode": "2 - Schakel Game Pointer-modus in", + "3 - Toggle Pointer Lock": "3 - Aanwijzervergrendeling in-/uitschakelen", + "Stream Quality": "Streamkwaliteit", + "Preset Modes:": "Vooraf ingestelde modi:", + "Static": "Statisch", + "Low": "Laag", + "Medium": "Medium", + "High": "Hoog", + "Extreme": "Extreem", + "Lossless": "Verliesloos", + "Custom": "Aangepast", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamisch", + "Off": "Uit", + "On": "Op", + "Dynamic Quality Min:": "Dynamische kwaliteit min:", + "Dynamic Quality Max:": "Dynamische kwaliteit max:", + "Treat Lossless:": "Behandel Lossless:", + "Frame Rate:": "Frame rate:", + "Video JPEG Quality:": "Video JPEG-kwaliteit:", + "Video WEBP Quality:": "Video WEBP-kwaliteit:", + "Video Area:": "Videogebied:", + "Video Time:": "Videotijd:", + "Video Out Time:": "Video uit tijd:", + "Video Mode Width:": "Breedte videomodus:", + "Video Mode Height:": "Hoogte videomodus:", + "Documentation": "Documentatie", + "Drag Viewport": "Sleep Viewport", + "KasmVNC encountered an error:": "KasmVNC heeft een fout aangetroffen:" +} \ No newline at end of file diff --git a/app/locale/nl_NL.json b/app/locale/nl_NL.json new file mode 100644 index 0000000..9a50b25 --- /dev/null +++ b/app/locale/nl_NL.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Verbinden...", + "Disconnecting...": "Verbinding verbreken...", + "Reconnecting...": "Opnieuw verbinding maken...", + "Internal error": "Interne fout", + "Must set host": "Host moeten worden ingesteld", + "Connected (encrypted) to ": "Verbonden (versleuteld) met ", + "Connected (unencrypted) to ": "Verbonden (onversleuteld) met ", + "Something went wrong, connection is closed": "Er iets fout gelopen, verbinding werd verbroken", + "Failed to connect to server": "Verbinding maken met server is mislukt", + "Disconnected": "Verbinding verbroken", + "New connection has been rejected with reason: ": "Nieuwe verbinding is geweigerd omwille van de volgende reden: ", + "New connection has been rejected": "Nieuwe verbinding is geweigerd", + "Password is required": "Wachtwoord is vereist", + "Hide/Show the control bar": "Verberg/Toon de bedieningsbalk", + "Move/Drag Viewport": "Verplaats/Versleep Kijkvenster", + "viewport drag": "kijkvenster slepen", + "Active Mouse Button": "Actieve Muisknop", + "No mousebutton": "Geen muisknop", + "Left mousebutton": "Linker muisknop", + "Middle mousebutton": "Middelste muisknop", + "Right mousebutton": "Rechter muisknop", + "Keyboard": "Toetsenbord", + "Show Keyboard": "Toon Toetsenbord", + "Extra keys": "Extra toetsen", + "Show Extra Keys": "Toon Extra Toetsen", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl omschakelen", + "Alt": "Alt", + "Toggle Alt": "Alt omschakelen", + "Toggle Windows": "Windows omschakelen", + "Windows": "Windows", + "Send Tab": "Tab Sturen", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Escape Sturen", + "Ctrl+Alt+Del": "Ctrl-Alt-Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Sturen", + "Shutdown/Reboot": "Uitschakelen/Herstarten", + "Shutdown/Reboot...": "Uitschakelen/Herstarten...", + "Power": "Systeem", + "Shutdown": "Uitschakelen", + "Reboot": "Herstarten", + "Reset": "Resetten", + "Clipboard": "Klembord", + "Clear": "Wissen", + "Fullscreen": "Volledig Scherm", + "Settings": "Instellingen", + "Shared Mode": "Gedeelde Modus", + "View Only": "Alleen Kijken", + "Clip to Window": "Randen buiten venster afsnijden", + "Scaling Mode:": "Schaalmodus:", + "None": "Geen", + "Local Scaling": "Lokaal Schalen", + "Remote Resizing": "Op Afstand Formaat Wijzigen", + "Advanced": "Geavanceerd", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Versleutelen", + "Host:": "Host:", + "Port:": "Poort:", + "Path:": "Pad:", + "Automatic Reconnect": "Automatisch Opnieuw Verbinden", + "Reconnect Delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):", + "Show Dot when No Cursor": "Geef stip weer indien geen cursor", + "Logging:": "Logmeldingen:", + "Disconnect": "Verbinding verbreken", + "Connect": "Verbinden", + "Password:": "Wachtwoord:", + "Send Password": "Verzend Wachtwoord:", + "Cancel": "Annuleren", + "Credentials are required": "Inloggegevens zijn vereist", + "Drag": "Sleuren", + "Quality:": "Kwaliteit:", + "Compression level:": "Compressieniveau:", + "Version:": "Versie:", + "Username:": "Gebruikersnaam:", + "Send Credentials": "Inloggegevens verzenden", + "Keys": "Sleutels", + "Game Cursor Mode": "Spelcursormodus", + "Press Esc Key to Exit Pointer Lock Mode": "Druk op de Esc-toets om de aanwijzervergrendelingsmodus af te sluiten", + "Game Mode paused, click on screen to resume Game Mode.": "Spelmodus gepauzeerd, klik op het scherm om de spelmodus te hervatten.", + "Clipboard Up": "Klembord omhoog", + "CLipboard Down": "Klembord naar beneden", + "Clipboard Seamless": "Klembord naadloos", + "Prefer Local Cursor": "Geef de voorkeur aan lokale cursor", + "Translate keyboard shortcuts": "Sneltoetsen vertalen", + "Enable WebRTC UDP Transit": "WebRTC UDP-transit inschakelen", + "Enable WebP Compression": "WebP-compressie inschakelen", + "Enable Performance Stats": "Prestatiestatistieken inschakelen", + "Enable Pointer Lock": "Aanwijzervergrendeling inschakelen", + "IME Input Mode": "IME-invoermodus", + "Show Virtual Keyboard Control": "Toon virtuele toetsenbordbediening", + "Toggle Control Panel via Keystrokes": "Toggle Configuratiescherm via toetsaanslagen", + "Render Native Resolution": "Native resolutie weergeven", + "Keyboard Shortcuts": "Toetsenbord sneltoetsen", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC-sneltoetsen inschakelen", + "1 - Toggle Control Panel": "1 - Configuratiescherm omschakelen", + "2 - Toggle Game Pointer Mode": "2 - Schakel Game Pointer-modus in", + "3 - Toggle Pointer Lock": "3 - Aanwijzervergrendeling in-/uitschakelen", + "Stream Quality": "Streamkwaliteit", + "Preset Modes:": "Vooraf ingestelde modi:", + "Static": "Statisch", + "Low": "Laag", + "Medium": "Medium", + "High": "Hoog", + "Extreme": "Extreem", + "Lossless": "Verliesloos", + "Custom": "Aangepast", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamisch", + "Off": "Uit", + "On": "Op", + "Dynamic Quality Min:": "Dynamische kwaliteit min:", + "Dynamic Quality Max:": "Dynamische kwaliteit max:", + "Treat Lossless:": "Behandel Lossless:", + "Frame Rate:": "Frame rate:", + "Video JPEG Quality:": "Video JPEG-kwaliteit:", + "Video WEBP Quality:": "Video WEBP-kwaliteit:", + "Video Area:": "Videogebied:", + "Video Time:": "Videotijd:", + "Video Out Time:": "Video uit tijd:", + "Video Mode Width:": "Breedte videomodus:", + "Video Mode Height:": "Hoogte videomodus:", + "Documentation": "Documentatie", + "Drag Viewport": "Sleep Viewport", + "KasmVNC encountered an error:": "KasmVNC heeft een fout aangetroffen:" +} \ No newline at end of file diff --git a/app/locale/pa.json b/app/locale/pa.json new file mode 100644 index 0000000..5228758 --- /dev/null +++ b/app/locale/pa.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...", + "Disconnecting...": "ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...", + "Reconnecting...": "ਮੁੜ ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...", + "Internal error": "ਅੰਦਰੂਨੀ ਗਲਤੀ", + "Must set host": "ਹੋਸਟ ਸੈੱਟ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ", + "Connected (encrypted) to ": "ਨਾਲ ਜੁੜਿਆ (ਏਨਕ੍ਰਿਪਟਡ)", + "Connected (unencrypted) to ": "ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ (ਅਨ-ਇਨਕ੍ਰਿਪਟਡ)", + "Something went wrong, connection is closed": "ਕੁਝ ਗਲਤ ਹੋ ਗਿਆ, ਕੁਨੈਕਸ਼ਨ ਬੰਦ ਹੈ", + "Failed to connect to server": "ਸਰਵਰ ਨਾਲ ਜੁੜਨ ਵਿੱਚ ਅਸਫਲ", + "Disconnected": "ਡਿਸਕਨੈਕਟ", + "New connection has been rejected with reason: ": "ਨਵਾਂ ਕੁਨੈਕਸ਼ਨ ਕਾਰਨ ਕਰਕੇ ਰੱਦ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ:", + "New connection has been rejected": "ਨਵਾਂ ਕੁਨੈਕਸ਼ਨ ਅਸਵੀਕਾਰ ਕੀਤਾ ਗਿਆ ਹੈ", + "Credentials are required": "ਪ੍ਰਮਾਣ ਪੱਤਰ ਲੋੜੀਂਦੇ ਹਨ", + "Hide/Show the control bar": "ਕੰਟਰੋਲ ਬਾਰ ਨੂੰ ਲੁਕਾਓ/ਵੇਖੋ", + "Drag": "ਖਿੱਚੋ", + "Move/Drag Viewport": "ਮੂਵ/ਡਰੈਗ ਵਿਊਪੋਰਟ", + "Keyboard": "ਕੀਬੋਰਡ", + "Show Keyboard": "ਕੀਬੋਰਡ ਦਿਖਾਓ", + "Extra keys": "ਵਾਧੂ ਕੁੰਜੀਆਂ", + "Show Extra Keys": "ਵਾਧੂ ਕੁੰਜੀਆਂ ਦਿਖਾਓ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ਟੌਗਲ ਕਰੋ", + "Alt": "Alt", + "Toggle Alt": "Alt ਟੌਗਲ ਕਰੋ", + "Toggle Windows": "ਵਿੰਡੋਜ਼ ਟੌਗਲ ਕਰੋ", + "Windows": "ਵਿੰਡੋਜ਼", + "Send Tab": "ਟੈਬ ਭੇਜੋ", + "Tab": "ਟੈਬ", + "Esc": "Esc", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ਭੇਜੋ", + "Shutdown/Reboot": "ਬੰਦ ਕਰੋ/ਰੀਬੂਟ ਕਰੋ", + "Shutdown/Reboot...": "ਬੰਦ ਕਰੋ/ਰੀਬੂਟ ਕਰੋ...", + "Power": "ਤਾਕਤ", + "Shutdown": "ਸ਼ਟ ਡਾਉਨ", + "Reboot": "ਮੁੜ - ਚਾਲੂ", + "Reset": "ਰੀਸੈੱਟ", + "Clipboard": "ਕਲਿੱਪਬੋਰਡ", + "Clear": "ਸਾਫ਼", + "Fullscreen": "ਪੂਰਾ ਸਕਰੀਨ", + "Settings": "ਸੈਟਿੰਗਾਂ", + "Shared Mode": "ਸਾਂਝਾ ਮੋਡ", + "View Only": "ਸਿਰਫ਼ ਵੇਖੋ", + "Clip to Window": "ਵਿੰਡੋ ਲਈ ਕਲਿੱਪ", + "Scaling Mode:": "ਸਕੇਲਿੰਗ ਮੋਡ:", + "None": "ਕੋਈ ਨਹੀਂ", + "Local Scaling": "ਸਥਾਨਕ ਸਕੇਲਿੰਗ", + "Remote Resizing": "ਰਿਮੋਟ ਰੀਸਾਈਜ਼ਿੰਗ", + "Advanced": "ਐਡਵਾਂਸਡ", + "Quality:": "ਗੁਣਵੱਤਾ:", + "Compression level:": "ਸੰਕੁਚਨ ਪੱਧਰ:", + "Repeater ID:": "ਰਿਪੀਟਰ ID:", + "WebSocket": "ਵੈੱਬਸਾਕੇਟ", + "Encrypt": "ਇਨਕ੍ਰਿਪਟ", + "Host:": "ਮੇਜ਼ਬਾਨ:", + "Port:": "ਪੋਰਟ:", + "Path:": "ਮਾਰਗ:", + "Automatic Reconnect": "ਆਟੋਮੈਟਿਕ ਰੀਕਨੈਕਟ", + "Reconnect Delay (ms):": "ਦੇਰੀ (ms) ਨੂੰ ਮੁੜ ਕਨੈਕਟ ਕਰੋ:", + "Show Dot when No Cursor": "ਕਰਸਰ ਨਾ ਹੋਣ 'ਤੇ ਬਿੰਦੀ ਦਿਖਾਓ", + "Logging:": "ਲੌਗਿੰਗ:", + "Version:": "ਵਰਜਨ:", + "Disconnect": "ਡਿਸਕਨੈਕਟ ਕਰੋ", + "Connect": "ਕਨੈਕਟ ਕਰੋ", + "Username:": "ਉਪਭੋਗਤਾ ਨਾਮ:", + "Password:": "ਪਾਸਵਰਡ:", + "Send Credentials": "ਪ੍ਰਮਾਣ ਪੱਤਰ ਭੇਜੋ", + "Cancel": "ਰੱਦ ਕਰੋ", + "Keys": "ਕੁੰਜੀ", + "Game Cursor Mode": "ਗੇਮ ਕਰਸਰ ਮੋਡ", + "Press Esc Key to Exit Pointer Lock Mode": "ਪੁਆਇੰਟਰ ਲੌਕ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਣ ਲਈ Esc ਕੁੰਜੀ ਦਬਾਓ", + "Game Mode paused, click on screen to resume Game Mode.": "ਗੇਮ ਮੋਡ ਰੋਕਿਆ ਗਿਆ, ਗੇਮ ਮੋਡ ਨੂੰ ਮੁੜ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਸਕ੍ਰੀਨ 'ਤੇ ਕਲਿੱਕ ਕਰੋ।", + "Clipboard Up": "ਕਲਿੱਪਬੋਰਡ ਅੱਪ", + "CLipboard Down": "ਕਲਿੱਪਬੋਰਡ ਹੇਠਾਂ", + "Clipboard Seamless": "ਕਲਿੱਪਬੋਰਡ ਸਹਿਜ", + "Prefer Local Cursor": "ਸਥਾਨਕ ਕਰਸਰ ਨੂੰ ਤਰਜੀਹ ਦਿਓ", + "Translate keyboard shortcuts": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਦਾ ਅਨੁਵਾਦ ਕਰੋ", + "Enable WebRTC UDP Transit": "WebRTC UDP ਟ੍ਰਾਂਜ਼ਿਟ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ", + "Enable WebP Compression": "WebP ਕੰਪਰੈਸ਼ਨ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ", + "Enable Performance Stats": "ਪ੍ਰਦਰਸ਼ਨ ਅੰਕੜਿਆਂ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ", + "Enable Pointer Lock": "ਪੁਆਇੰਟਰ ਲਾਕ ਚਾਲੂ ਕਰੋ", + "IME Input Mode": "IME ਇਨਪੁਟ ਮੋਡ", + "Show Virtual Keyboard Control": "ਵਰਚੁਅਲ ਕੀਬੋਰਡ ਕੰਟਰੋਲ ਦਿਖਾਓ", + "Toggle Control Panel via Keystrokes": "ਕੀਸਟ੍ਰੋਕ ਦੁਆਰਾ ਕੰਟਰੋਲ ਪੈਨਲ ਨੂੰ ਟੌਗਲ ਕਰੋ", + "Render Native Resolution": "ਨੇਟਿਵ ਰੈਜ਼ੋਲਿਊਸ਼ਨ ਰੈਂਡਰ ਕਰੋ", + "Keyboard Shortcuts": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਯੋਗ ਕਰੋ", + "1 - Toggle Control Panel": "1 - ਕੰਟਰੋਲ ਪੈਨਲ ਟੌਗਲ ਕਰੋ", + "2 - Toggle Game Pointer Mode": "2 - ਗੇਮ ਪੁਆਇੰਟਰ ਮੋਡ ਨੂੰ ਟੌਗਲ ਕਰੋ", + "3 - Toggle Pointer Lock": "3 - ਪੁਆਇੰਟਰ ਲਾਕ ਟੌਗਲ ਕਰੋ", + "Stream Quality": "ਸਟ੍ਰੀਮ ਗੁਣਵੱਤਾ", + "Preset Modes:": "ਪ੍ਰੀਸੈੱਟ ਮੋਡ:", + "Static": "ਸਥਿਰ", + "Low": "ਘੱਟ", + "Medium": "ਮਾਧਿਅਮ", + "High": "ਉੱਚਾ", + "Extreme": "ਅਤਿ", + "Lossless": "ਨੁਕਸਾਨ ਰਹਿਤ", + "Custom": "ਪ੍ਰਥਾ", + "Anti-Aliasing:": "ਵਿਰੋਧੀ ਲਾਇਸਿੰਸ:", + "Auto Dynamic": "ਆਟੋ ਡਾਇਨਾਮਿਕ", + "Off": "ਬੰਦ", + "On": "ਚਾਲੂ", + "Dynamic Quality Min:": "ਡਾਇਨਾਮਿਕ ਕੁਆਲਿਟੀ ਮਿਨ:", + "Dynamic Quality Max:": "ਗਤੀਸ਼ੀਲ ਗੁਣਵੱਤਾ ਅਧਿਕਤਮ:", + "Treat Lossless:": "ਨੁਕਸਾਨ ਰਹਿਤ ਇਲਾਜ ਕਰੋ:", + "Frame Rate:": "ਫਰੇਮ ਦੀ ਦਰ:", + "Video JPEG Quality:": "ਵੀਡੀਓ JPEG ਗੁਣਵੱਤਾ:", + "Video WEBP Quality:": "ਵੀਡੀਓ WEBP ਗੁਣਵੱਤਾ:", + "Video Area:": "ਵੀਡੀਓ ਖੇਤਰ:", + "Video Time:": "ਵੀਡੀਓ ਸਮਾਂ:", + "Video Out Time:": "ਵੀਡੀਓ ਖਤਮ ਹੋਣ ਦਾ ਸਮਾਂ:", + "Video Mode Width:": "ਵੀਡੀਓ ਮੋਡ ਚੌੜਾਈ:", + "Video Mode Height:": "ਵੀਡੀਓ ਮੋਡ ਉਚਾਈ:", + "Documentation": "ਦਸਤਾਵੇਜ਼", + "Drag Viewport": "ਡਰੈਗ ਵਿਊਪੋਰਟ", + "KasmVNC encountered an error:": "KasmVNC ਨੇ ਇੱਕ ਗਲਤੀ ਦਾ ਸਾਹਮਣਾ ਕੀਤਾ:" +} \ No newline at end of file diff --git a/app/locale/pa_IN.json b/app/locale/pa_IN.json new file mode 100644 index 0000000..5228758 --- /dev/null +++ b/app/locale/pa_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...", + "Disconnecting...": "ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...", + "Reconnecting...": "ਮੁੜ ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...", + "Internal error": "ਅੰਦਰੂਨੀ ਗਲਤੀ", + "Must set host": "ਹੋਸਟ ਸੈੱਟ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ", + "Connected (encrypted) to ": "ਨਾਲ ਜੁੜਿਆ (ਏਨਕ੍ਰਿਪਟਡ)", + "Connected (unencrypted) to ": "ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ (ਅਨ-ਇਨਕ੍ਰਿਪਟਡ)", + "Something went wrong, connection is closed": "ਕੁਝ ਗਲਤ ਹੋ ਗਿਆ, ਕੁਨੈਕਸ਼ਨ ਬੰਦ ਹੈ", + "Failed to connect to server": "ਸਰਵਰ ਨਾਲ ਜੁੜਨ ਵਿੱਚ ਅਸਫਲ", + "Disconnected": "ਡਿਸਕਨੈਕਟ", + "New connection has been rejected with reason: ": "ਨਵਾਂ ਕੁਨੈਕਸ਼ਨ ਕਾਰਨ ਕਰਕੇ ਰੱਦ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ:", + "New connection has been rejected": "ਨਵਾਂ ਕੁਨੈਕਸ਼ਨ ਅਸਵੀਕਾਰ ਕੀਤਾ ਗਿਆ ਹੈ", + "Credentials are required": "ਪ੍ਰਮਾਣ ਪੱਤਰ ਲੋੜੀਂਦੇ ਹਨ", + "Hide/Show the control bar": "ਕੰਟਰੋਲ ਬਾਰ ਨੂੰ ਲੁਕਾਓ/ਵੇਖੋ", + "Drag": "ਖਿੱਚੋ", + "Move/Drag Viewport": "ਮੂਵ/ਡਰੈਗ ਵਿਊਪੋਰਟ", + "Keyboard": "ਕੀਬੋਰਡ", + "Show Keyboard": "ਕੀਬੋਰਡ ਦਿਖਾਓ", + "Extra keys": "ਵਾਧੂ ਕੁੰਜੀਆਂ", + "Show Extra Keys": "ਵਾਧੂ ਕੁੰਜੀਆਂ ਦਿਖਾਓ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ਟੌਗਲ ਕਰੋ", + "Alt": "Alt", + "Toggle Alt": "Alt ਟੌਗਲ ਕਰੋ", + "Toggle Windows": "ਵਿੰਡੋਜ਼ ਟੌਗਲ ਕਰੋ", + "Windows": "ਵਿੰਡੋਜ਼", + "Send Tab": "ਟੈਬ ਭੇਜੋ", + "Tab": "ਟੈਬ", + "Esc": "Esc", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ਭੇਜੋ", + "Shutdown/Reboot": "ਬੰਦ ਕਰੋ/ਰੀਬੂਟ ਕਰੋ", + "Shutdown/Reboot...": "ਬੰਦ ਕਰੋ/ਰੀਬੂਟ ਕਰੋ...", + "Power": "ਤਾਕਤ", + "Shutdown": "ਸ਼ਟ ਡਾਉਨ", + "Reboot": "ਮੁੜ - ਚਾਲੂ", + "Reset": "ਰੀਸੈੱਟ", + "Clipboard": "ਕਲਿੱਪਬੋਰਡ", + "Clear": "ਸਾਫ਼", + "Fullscreen": "ਪੂਰਾ ਸਕਰੀਨ", + "Settings": "ਸੈਟਿੰਗਾਂ", + "Shared Mode": "ਸਾਂਝਾ ਮੋਡ", + "View Only": "ਸਿਰਫ਼ ਵੇਖੋ", + "Clip to Window": "ਵਿੰਡੋ ਲਈ ਕਲਿੱਪ", + "Scaling Mode:": "ਸਕੇਲਿੰਗ ਮੋਡ:", + "None": "ਕੋਈ ਨਹੀਂ", + "Local Scaling": "ਸਥਾਨਕ ਸਕੇਲਿੰਗ", + "Remote Resizing": "ਰਿਮੋਟ ਰੀਸਾਈਜ਼ਿੰਗ", + "Advanced": "ਐਡਵਾਂਸਡ", + "Quality:": "ਗੁਣਵੱਤਾ:", + "Compression level:": "ਸੰਕੁਚਨ ਪੱਧਰ:", + "Repeater ID:": "ਰਿਪੀਟਰ ID:", + "WebSocket": "ਵੈੱਬਸਾਕੇਟ", + "Encrypt": "ਇਨਕ੍ਰਿਪਟ", + "Host:": "ਮੇਜ਼ਬਾਨ:", + "Port:": "ਪੋਰਟ:", + "Path:": "ਮਾਰਗ:", + "Automatic Reconnect": "ਆਟੋਮੈਟਿਕ ਰੀਕਨੈਕਟ", + "Reconnect Delay (ms):": "ਦੇਰੀ (ms) ਨੂੰ ਮੁੜ ਕਨੈਕਟ ਕਰੋ:", + "Show Dot when No Cursor": "ਕਰਸਰ ਨਾ ਹੋਣ 'ਤੇ ਬਿੰਦੀ ਦਿਖਾਓ", + "Logging:": "ਲੌਗਿੰਗ:", + "Version:": "ਵਰਜਨ:", + "Disconnect": "ਡਿਸਕਨੈਕਟ ਕਰੋ", + "Connect": "ਕਨੈਕਟ ਕਰੋ", + "Username:": "ਉਪਭੋਗਤਾ ਨਾਮ:", + "Password:": "ਪਾਸਵਰਡ:", + "Send Credentials": "ਪ੍ਰਮਾਣ ਪੱਤਰ ਭੇਜੋ", + "Cancel": "ਰੱਦ ਕਰੋ", + "Keys": "ਕੁੰਜੀ", + "Game Cursor Mode": "ਗੇਮ ਕਰਸਰ ਮੋਡ", + "Press Esc Key to Exit Pointer Lock Mode": "ਪੁਆਇੰਟਰ ਲੌਕ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਣ ਲਈ Esc ਕੁੰਜੀ ਦਬਾਓ", + "Game Mode paused, click on screen to resume Game Mode.": "ਗੇਮ ਮੋਡ ਰੋਕਿਆ ਗਿਆ, ਗੇਮ ਮੋਡ ਨੂੰ ਮੁੜ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਸਕ੍ਰੀਨ 'ਤੇ ਕਲਿੱਕ ਕਰੋ।", + "Clipboard Up": "ਕਲਿੱਪਬੋਰਡ ਅੱਪ", + "CLipboard Down": "ਕਲਿੱਪਬੋਰਡ ਹੇਠਾਂ", + "Clipboard Seamless": "ਕਲਿੱਪਬੋਰਡ ਸਹਿਜ", + "Prefer Local Cursor": "ਸਥਾਨਕ ਕਰਸਰ ਨੂੰ ਤਰਜੀਹ ਦਿਓ", + "Translate keyboard shortcuts": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਦਾ ਅਨੁਵਾਦ ਕਰੋ", + "Enable WebRTC UDP Transit": "WebRTC UDP ਟ੍ਰਾਂਜ਼ਿਟ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ", + "Enable WebP Compression": "WebP ਕੰਪਰੈਸ਼ਨ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ", + "Enable Performance Stats": "ਪ੍ਰਦਰਸ਼ਨ ਅੰਕੜਿਆਂ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ", + "Enable Pointer Lock": "ਪੁਆਇੰਟਰ ਲਾਕ ਚਾਲੂ ਕਰੋ", + "IME Input Mode": "IME ਇਨਪੁਟ ਮੋਡ", + "Show Virtual Keyboard Control": "ਵਰਚੁਅਲ ਕੀਬੋਰਡ ਕੰਟਰੋਲ ਦਿਖਾਓ", + "Toggle Control Panel via Keystrokes": "ਕੀਸਟ੍ਰੋਕ ਦੁਆਰਾ ਕੰਟਰੋਲ ਪੈਨਲ ਨੂੰ ਟੌਗਲ ਕਰੋ", + "Render Native Resolution": "ਨੇਟਿਵ ਰੈਜ਼ੋਲਿਊਸ਼ਨ ਰੈਂਡਰ ਕਰੋ", + "Keyboard Shortcuts": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਯੋਗ ਕਰੋ", + "1 - Toggle Control Panel": "1 - ਕੰਟਰੋਲ ਪੈਨਲ ਟੌਗਲ ਕਰੋ", + "2 - Toggle Game Pointer Mode": "2 - ਗੇਮ ਪੁਆਇੰਟਰ ਮੋਡ ਨੂੰ ਟੌਗਲ ਕਰੋ", + "3 - Toggle Pointer Lock": "3 - ਪੁਆਇੰਟਰ ਲਾਕ ਟੌਗਲ ਕਰੋ", + "Stream Quality": "ਸਟ੍ਰੀਮ ਗੁਣਵੱਤਾ", + "Preset Modes:": "ਪ੍ਰੀਸੈੱਟ ਮੋਡ:", + "Static": "ਸਥਿਰ", + "Low": "ਘੱਟ", + "Medium": "ਮਾਧਿਅਮ", + "High": "ਉੱਚਾ", + "Extreme": "ਅਤਿ", + "Lossless": "ਨੁਕਸਾਨ ਰਹਿਤ", + "Custom": "ਪ੍ਰਥਾ", + "Anti-Aliasing:": "ਵਿਰੋਧੀ ਲਾਇਸਿੰਸ:", + "Auto Dynamic": "ਆਟੋ ਡਾਇਨਾਮਿਕ", + "Off": "ਬੰਦ", + "On": "ਚਾਲੂ", + "Dynamic Quality Min:": "ਡਾਇਨਾਮਿਕ ਕੁਆਲਿਟੀ ਮਿਨ:", + "Dynamic Quality Max:": "ਗਤੀਸ਼ੀਲ ਗੁਣਵੱਤਾ ਅਧਿਕਤਮ:", + "Treat Lossless:": "ਨੁਕਸਾਨ ਰਹਿਤ ਇਲਾਜ ਕਰੋ:", + "Frame Rate:": "ਫਰੇਮ ਦੀ ਦਰ:", + "Video JPEG Quality:": "ਵੀਡੀਓ JPEG ਗੁਣਵੱਤਾ:", + "Video WEBP Quality:": "ਵੀਡੀਓ WEBP ਗੁਣਵੱਤਾ:", + "Video Area:": "ਵੀਡੀਓ ਖੇਤਰ:", + "Video Time:": "ਵੀਡੀਓ ਸਮਾਂ:", + "Video Out Time:": "ਵੀਡੀਓ ਖਤਮ ਹੋਣ ਦਾ ਸਮਾਂ:", + "Video Mode Width:": "ਵੀਡੀਓ ਮੋਡ ਚੌੜਾਈ:", + "Video Mode Height:": "ਵੀਡੀਓ ਮੋਡ ਉਚਾਈ:", + "Documentation": "ਦਸਤਾਵੇਜ਼", + "Drag Viewport": "ਡਰੈਗ ਵਿਊਪੋਰਟ", + "KasmVNC encountered an error:": "KasmVNC ਨੇ ਇੱਕ ਗਲਤੀ ਦਾ ਸਾਹਮਣਾ ਕੀਤਾ:" +} \ No newline at end of file diff --git a/app/locale/pa_PK.json b/app/locale/pa_PK.json new file mode 100644 index 0000000..5228758 --- /dev/null +++ b/app/locale/pa_PK.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...", + "Disconnecting...": "ਡਿਸਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...", + "Reconnecting...": "ਮੁੜ ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...", + "Internal error": "ਅੰਦਰੂਨੀ ਗਲਤੀ", + "Must set host": "ਹੋਸਟ ਸੈੱਟ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ", + "Connected (encrypted) to ": "ਨਾਲ ਜੁੜਿਆ (ਏਨਕ੍ਰਿਪਟਡ)", + "Connected (unencrypted) to ": "ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ (ਅਨ-ਇਨਕ੍ਰਿਪਟਡ)", + "Something went wrong, connection is closed": "ਕੁਝ ਗਲਤ ਹੋ ਗਿਆ, ਕੁਨੈਕਸ਼ਨ ਬੰਦ ਹੈ", + "Failed to connect to server": "ਸਰਵਰ ਨਾਲ ਜੁੜਨ ਵਿੱਚ ਅਸਫਲ", + "Disconnected": "ਡਿਸਕਨੈਕਟ", + "New connection has been rejected with reason: ": "ਨਵਾਂ ਕੁਨੈਕਸ਼ਨ ਕਾਰਨ ਕਰਕੇ ਰੱਦ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ:", + "New connection has been rejected": "ਨਵਾਂ ਕੁਨੈਕਸ਼ਨ ਅਸਵੀਕਾਰ ਕੀਤਾ ਗਿਆ ਹੈ", + "Credentials are required": "ਪ੍ਰਮਾਣ ਪੱਤਰ ਲੋੜੀਂਦੇ ਹਨ", + "Hide/Show the control bar": "ਕੰਟਰੋਲ ਬਾਰ ਨੂੰ ਲੁਕਾਓ/ਵੇਖੋ", + "Drag": "ਖਿੱਚੋ", + "Move/Drag Viewport": "ਮੂਵ/ਡਰੈਗ ਵਿਊਪੋਰਟ", + "Keyboard": "ਕੀਬੋਰਡ", + "Show Keyboard": "ਕੀਬੋਰਡ ਦਿਖਾਓ", + "Extra keys": "ਵਾਧੂ ਕੁੰਜੀਆਂ", + "Show Extra Keys": "ਵਾਧੂ ਕੁੰਜੀਆਂ ਦਿਖਾਓ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ਟੌਗਲ ਕਰੋ", + "Alt": "Alt", + "Toggle Alt": "Alt ਟੌਗਲ ਕਰੋ", + "Toggle Windows": "ਵਿੰਡੋਜ਼ ਟੌਗਲ ਕਰੋ", + "Windows": "ਵਿੰਡੋਜ਼", + "Send Tab": "ਟੈਬ ਭੇਜੋ", + "Tab": "ਟੈਬ", + "Esc": "Esc", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ਭੇਜੋ", + "Shutdown/Reboot": "ਬੰਦ ਕਰੋ/ਰੀਬੂਟ ਕਰੋ", + "Shutdown/Reboot...": "ਬੰਦ ਕਰੋ/ਰੀਬੂਟ ਕਰੋ...", + "Power": "ਤਾਕਤ", + "Shutdown": "ਸ਼ਟ ਡਾਉਨ", + "Reboot": "ਮੁੜ - ਚਾਲੂ", + "Reset": "ਰੀਸੈੱਟ", + "Clipboard": "ਕਲਿੱਪਬੋਰਡ", + "Clear": "ਸਾਫ਼", + "Fullscreen": "ਪੂਰਾ ਸਕਰੀਨ", + "Settings": "ਸੈਟਿੰਗਾਂ", + "Shared Mode": "ਸਾਂਝਾ ਮੋਡ", + "View Only": "ਸਿਰਫ਼ ਵੇਖੋ", + "Clip to Window": "ਵਿੰਡੋ ਲਈ ਕਲਿੱਪ", + "Scaling Mode:": "ਸਕੇਲਿੰਗ ਮੋਡ:", + "None": "ਕੋਈ ਨਹੀਂ", + "Local Scaling": "ਸਥਾਨਕ ਸਕੇਲਿੰਗ", + "Remote Resizing": "ਰਿਮੋਟ ਰੀਸਾਈਜ਼ਿੰਗ", + "Advanced": "ਐਡਵਾਂਸਡ", + "Quality:": "ਗੁਣਵੱਤਾ:", + "Compression level:": "ਸੰਕੁਚਨ ਪੱਧਰ:", + "Repeater ID:": "ਰਿਪੀਟਰ ID:", + "WebSocket": "ਵੈੱਬਸਾਕੇਟ", + "Encrypt": "ਇਨਕ੍ਰਿਪਟ", + "Host:": "ਮੇਜ਼ਬਾਨ:", + "Port:": "ਪੋਰਟ:", + "Path:": "ਮਾਰਗ:", + "Automatic Reconnect": "ਆਟੋਮੈਟਿਕ ਰੀਕਨੈਕਟ", + "Reconnect Delay (ms):": "ਦੇਰੀ (ms) ਨੂੰ ਮੁੜ ਕਨੈਕਟ ਕਰੋ:", + "Show Dot when No Cursor": "ਕਰਸਰ ਨਾ ਹੋਣ 'ਤੇ ਬਿੰਦੀ ਦਿਖਾਓ", + "Logging:": "ਲੌਗਿੰਗ:", + "Version:": "ਵਰਜਨ:", + "Disconnect": "ਡਿਸਕਨੈਕਟ ਕਰੋ", + "Connect": "ਕਨੈਕਟ ਕਰੋ", + "Username:": "ਉਪਭੋਗਤਾ ਨਾਮ:", + "Password:": "ਪਾਸਵਰਡ:", + "Send Credentials": "ਪ੍ਰਮਾਣ ਪੱਤਰ ਭੇਜੋ", + "Cancel": "ਰੱਦ ਕਰੋ", + "Keys": "ਕੁੰਜੀ", + "Game Cursor Mode": "ਗੇਮ ਕਰਸਰ ਮੋਡ", + "Press Esc Key to Exit Pointer Lock Mode": "ਪੁਆਇੰਟਰ ਲੌਕ ਮੋਡ ਤੋਂ ਬਾਹਰ ਜਾਣ ਲਈ Esc ਕੁੰਜੀ ਦਬਾਓ", + "Game Mode paused, click on screen to resume Game Mode.": "ਗੇਮ ਮੋਡ ਰੋਕਿਆ ਗਿਆ, ਗੇਮ ਮੋਡ ਨੂੰ ਮੁੜ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਸਕ੍ਰੀਨ 'ਤੇ ਕਲਿੱਕ ਕਰੋ।", + "Clipboard Up": "ਕਲਿੱਪਬੋਰਡ ਅੱਪ", + "CLipboard Down": "ਕਲਿੱਪਬੋਰਡ ਹੇਠਾਂ", + "Clipboard Seamless": "ਕਲਿੱਪਬੋਰਡ ਸਹਿਜ", + "Prefer Local Cursor": "ਸਥਾਨਕ ਕਰਸਰ ਨੂੰ ਤਰਜੀਹ ਦਿਓ", + "Translate keyboard shortcuts": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਦਾ ਅਨੁਵਾਦ ਕਰੋ", + "Enable WebRTC UDP Transit": "WebRTC UDP ਟ੍ਰਾਂਜ਼ਿਟ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ", + "Enable WebP Compression": "WebP ਕੰਪਰੈਸ਼ਨ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ", + "Enable Performance Stats": "ਪ੍ਰਦਰਸ਼ਨ ਅੰਕੜਿਆਂ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ", + "Enable Pointer Lock": "ਪੁਆਇੰਟਰ ਲਾਕ ਚਾਲੂ ਕਰੋ", + "IME Input Mode": "IME ਇਨਪੁਟ ਮੋਡ", + "Show Virtual Keyboard Control": "ਵਰਚੁਅਲ ਕੀਬੋਰਡ ਕੰਟਰੋਲ ਦਿਖਾਓ", + "Toggle Control Panel via Keystrokes": "ਕੀਸਟ੍ਰੋਕ ਦੁਆਰਾ ਕੰਟਰੋਲ ਪੈਨਲ ਨੂੰ ਟੌਗਲ ਕਰੋ", + "Render Native Resolution": "ਨੇਟਿਵ ਰੈਜ਼ੋਲਿਊਸ਼ਨ ਰੈਂਡਰ ਕਰੋ", + "Keyboard Shortcuts": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਯੋਗ ਕਰੋ", + "1 - Toggle Control Panel": "1 - ਕੰਟਰੋਲ ਪੈਨਲ ਟੌਗਲ ਕਰੋ", + "2 - Toggle Game Pointer Mode": "2 - ਗੇਮ ਪੁਆਇੰਟਰ ਮੋਡ ਨੂੰ ਟੌਗਲ ਕਰੋ", + "3 - Toggle Pointer Lock": "3 - ਪੁਆਇੰਟਰ ਲਾਕ ਟੌਗਲ ਕਰੋ", + "Stream Quality": "ਸਟ੍ਰੀਮ ਗੁਣਵੱਤਾ", + "Preset Modes:": "ਪ੍ਰੀਸੈੱਟ ਮੋਡ:", + "Static": "ਸਥਿਰ", + "Low": "ਘੱਟ", + "Medium": "ਮਾਧਿਅਮ", + "High": "ਉੱਚਾ", + "Extreme": "ਅਤਿ", + "Lossless": "ਨੁਕਸਾਨ ਰਹਿਤ", + "Custom": "ਪ੍ਰਥਾ", + "Anti-Aliasing:": "ਵਿਰੋਧੀ ਲਾਇਸਿੰਸ:", + "Auto Dynamic": "ਆਟੋ ਡਾਇਨਾਮਿਕ", + "Off": "ਬੰਦ", + "On": "ਚਾਲੂ", + "Dynamic Quality Min:": "ਡਾਇਨਾਮਿਕ ਕੁਆਲਿਟੀ ਮਿਨ:", + "Dynamic Quality Max:": "ਗਤੀਸ਼ੀਲ ਗੁਣਵੱਤਾ ਅਧਿਕਤਮ:", + "Treat Lossless:": "ਨੁਕਸਾਨ ਰਹਿਤ ਇਲਾਜ ਕਰੋ:", + "Frame Rate:": "ਫਰੇਮ ਦੀ ਦਰ:", + "Video JPEG Quality:": "ਵੀਡੀਓ JPEG ਗੁਣਵੱਤਾ:", + "Video WEBP Quality:": "ਵੀਡੀਓ WEBP ਗੁਣਵੱਤਾ:", + "Video Area:": "ਵੀਡੀਓ ਖੇਤਰ:", + "Video Time:": "ਵੀਡੀਓ ਸਮਾਂ:", + "Video Out Time:": "ਵੀਡੀਓ ਖਤਮ ਹੋਣ ਦਾ ਸਮਾਂ:", + "Video Mode Width:": "ਵੀਡੀਓ ਮੋਡ ਚੌੜਾਈ:", + "Video Mode Height:": "ਵੀਡੀਓ ਮੋਡ ਉਚਾਈ:", + "Documentation": "ਦਸਤਾਵੇਜ਼", + "Drag Viewport": "ਡਰੈਗ ਵਿਊਪੋਰਟ", + "KasmVNC encountered an error:": "KasmVNC ਨੇ ਇੱਕ ਗਲਤੀ ਦਾ ਸਾਹਮਣਾ ਕੀਤਾ:" +} \ No newline at end of file diff --git a/app/locale/pl.json b/app/locale/pl.json new file mode 100644 index 0000000..7a1b0e1 --- /dev/null +++ b/app/locale/pl.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Łączenie...", + "Disconnecting...": "Rozłączanie...", + "Reconnecting...": "Łączenie...", + "Internal error": "Błąd wewnętrzny", + "Must set host": "Host i port są wymagane", + "Connected (encrypted) to ": "Połączenie (szyfrowane) z ", + "Connected (unencrypted) to ": "Połączenie (nieszyfrowane) z ", + "Something went wrong, connection is closed": "Coś poszło źle, połączenie zostało zamknięte", + "Disconnected": "Rozłączony", + "New connection has been rejected with reason: ": "Nowe połączenie zostało odrzucone z powodu: ", + "New connection has been rejected": "Nowe połączenie zostało odrzucone", + "Password is required": "Hasło jest wymagane", + "Hide/Show the control bar": "Pokaż/Ukryj pasek ustawień", + "Move/Drag Viewport": "Ruszaj/Przeciągaj Viewport", + "viewport drag": "przeciągnij viewport", + "Active Mouse Button": "Aktywny Przycisk Myszy", + "No mousebutton": "Brak przycisku myszy", + "Left mousebutton": "Lewy przycisk myszy", + "Middle mousebutton": "Środkowy przycisk myszy", + "Right mousebutton": "Prawy przycisk myszy", + "Keyboard": "Klawiatura", + "Show Keyboard": "Pokaż klawiaturę", + "Extra keys": "Przyciski dodatkowe", + "Show Extra Keys": "Pokaż przyciski dodatkowe", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Przełącz Ctrl", + "Alt": "Alt", + "Toggle Alt": "Przełącz Alt", + "Send Tab": "Wyślij Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Wyślij Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Wyślij Ctrl-Alt-Del", + "Shutdown/Reboot": "Wyłącz/Uruchom ponownie", + "Shutdown/Reboot...": "Wyłącz/Uruchom ponownie...", + "Power": "Włączony", + "Shutdown": "Wyłącz", + "Reboot": "Uruchom ponownie", + "Reset": "Resetuj", + "Clipboard": "Schowek", + "Clear": "Wyczyść", + "Fullscreen": "Pełny ekran", + "Settings": "Ustawienia", + "Shared Mode": "Tryb Współdzielenia", + "View Only": "Tylko Podgląd", + "Clip to Window": "Przytnij do Okna", + "Scaling Mode:": "Tryb Skalowania:", + "None": "Brak", + "Local Scaling": "Skalowanie lokalne", + "Remote Resizing": "Skalowanie zdalne", + "Advanced": "Zaawansowane", + "Repeater ID:": "ID Repeatera:", + "WebSocket": "WebSocket", + "Encrypt": "Szyfrowanie", + "Host:": "Host:", + "Port:": "Port:", + "Path:": "Ścieżka:", + "Automatic Reconnect": "Automatycznie wznawiaj połączenie", + "Reconnect Delay (ms):": "Opóźnienie wznawiania (ms):", + "Logging:": "Poziom logowania:", + "Disconnect": "Rozłącz", + "Connect": "Połącz", + "Password:": "Hasło:", + "Cancel": "Anuluj", + "Canvas not supported.": "Element Canvas nie jest wspierany.", + "Failed to connect to server": "Błąd połączenia z serwerem", + "Credentials are required": "Wymagane są poświadczenia", + "Drag": "Ciągnąć", + "Toggle Windows": "Przełącz okna", + "Windows": "Okna", + "Quality:": "Jakość:", + "Compression level:": "Poziom kompresji:", + "Show Dot when No Cursor": "Pokaż kropkę, gdy nie ma kursora", + "Version:": "Wersja:", + "Username:": "Nazwa użytkownika:", + "Send Credentials": "Wyślij dane uwierzytelniające", + "Keys": "Klucze", + "Game Cursor Mode": "Tryb kursora gry", + "Press Esc Key to Exit Pointer Lock Mode": "Naciśnij klawisz Esc, aby wyjść z trybu blokady wskaźnika", + "Game Mode paused, click on screen to resume Game Mode.": "Tryb gry został wstrzymany, kliknij ekran, aby wznowić tryb gry.", + "Clipboard Up": "Schowek w górę", + "CLipboard Down": "Schowek w dół", + "Clipboard Seamless": "Schowek bez szwu", + "Prefer Local Cursor": "Preferuj lokalny kursor", + "Translate keyboard shortcuts": "Przetłumacz skróty klawiaturowe", + "Enable WebRTC UDP Transit": "Włącz tranzyt WebRTC UDP", + "Enable WebP Compression": "Włącz kompresję WebP", + "Enable Performance Stats": "Włącz statystyki wydajności", + "Enable Pointer Lock": "Włącz blokadę wskaźnika", + "IME Input Mode": "Tryb wprowadzania edytora IME", + "Show Virtual Keyboard Control": "Pokaż sterowanie klawiaturą wirtualną", + "Toggle Control Panel via Keystrokes": "Przełącz panel sterowania za pomocą naciśnięć klawiszy", + "Render Native Resolution": "Renderuj rozdzielczość natywną", + "Keyboard Shortcuts": "Skróty klawiszowe", + "Enable KasmVNC Keyboard Shortcuts": "Włącz skróty klawiaturowe KasmVNC", + "1 - Toggle Control Panel": "1 - Przełącz panel sterowania", + "2 - Toggle Game Pointer Mode": "2 - Przełącz tryb wskaźnika gry", + "3 - Toggle Pointer Lock": "3 - Przełącz blokadę wskaźnika", + "Stream Quality": "Jakość strumienia", + "Preset Modes:": "Tryby ustawień wstępnych:", + "Static": "Statyczny", + "Low": "Niski", + "Medium": "Średni", + "High": "Wysoki", + "Extreme": "Skrajny", + "Lossless": "Bezstratny", + "Custom": "Zwyczaj", + "Anti-Aliasing:": "Wygładzanie krawędzi:", + "Auto Dynamic": "Autodynamiczny", + "Off": "Wyłączony", + "On": "NA", + "Dynamic Quality Min:": "Minimalna jakość dynamiczna:", + "Dynamic Quality Max:": "Dynamiczna jakość maks.:", + "Treat Lossless:": "Lecz bezstratnie:", + "Frame Rate:": "Częstotliwość wyświetlania klatek:", + "Video JPEG Quality:": "Jakość wideo JPEG:", + "Video WEBP Quality:": "Jakość wideo WEBP:", + "Video Area:": "Obszar wideo:", + "Video Time:": "Czas wideo:", + "Video Out Time:": "Czas wyjścia wideo:", + "Video Mode Width:": "Szerokość trybu wideo:", + "Video Mode Height:": "Wysokość trybu wideo:", + "Documentation": "Dokumentacja", + "Drag Viewport": "Przeciągnij rzutnię", + "KasmVNC encountered an error:": "KasmVNC napotkał błąd:" +} \ No newline at end of file diff --git a/app/locale/pl_PL.json b/app/locale/pl_PL.json new file mode 100644 index 0000000..7a1b0e1 --- /dev/null +++ b/app/locale/pl_PL.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Łączenie...", + "Disconnecting...": "Rozłączanie...", + "Reconnecting...": "Łączenie...", + "Internal error": "Błąd wewnętrzny", + "Must set host": "Host i port są wymagane", + "Connected (encrypted) to ": "Połączenie (szyfrowane) z ", + "Connected (unencrypted) to ": "Połączenie (nieszyfrowane) z ", + "Something went wrong, connection is closed": "Coś poszło źle, połączenie zostało zamknięte", + "Disconnected": "Rozłączony", + "New connection has been rejected with reason: ": "Nowe połączenie zostało odrzucone z powodu: ", + "New connection has been rejected": "Nowe połączenie zostało odrzucone", + "Password is required": "Hasło jest wymagane", + "Hide/Show the control bar": "Pokaż/Ukryj pasek ustawień", + "Move/Drag Viewport": "Ruszaj/Przeciągaj Viewport", + "viewport drag": "przeciągnij viewport", + "Active Mouse Button": "Aktywny Przycisk Myszy", + "No mousebutton": "Brak przycisku myszy", + "Left mousebutton": "Lewy przycisk myszy", + "Middle mousebutton": "Środkowy przycisk myszy", + "Right mousebutton": "Prawy przycisk myszy", + "Keyboard": "Klawiatura", + "Show Keyboard": "Pokaż klawiaturę", + "Extra keys": "Przyciski dodatkowe", + "Show Extra Keys": "Pokaż przyciski dodatkowe", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Przełącz Ctrl", + "Alt": "Alt", + "Toggle Alt": "Przełącz Alt", + "Send Tab": "Wyślij Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Wyślij Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Wyślij Ctrl-Alt-Del", + "Shutdown/Reboot": "Wyłącz/Uruchom ponownie", + "Shutdown/Reboot...": "Wyłącz/Uruchom ponownie...", + "Power": "Włączony", + "Shutdown": "Wyłącz", + "Reboot": "Uruchom ponownie", + "Reset": "Resetuj", + "Clipboard": "Schowek", + "Clear": "Wyczyść", + "Fullscreen": "Pełny ekran", + "Settings": "Ustawienia", + "Shared Mode": "Tryb Współdzielenia", + "View Only": "Tylko Podgląd", + "Clip to Window": "Przytnij do Okna", + "Scaling Mode:": "Tryb Skalowania:", + "None": "Brak", + "Local Scaling": "Skalowanie lokalne", + "Remote Resizing": "Skalowanie zdalne", + "Advanced": "Zaawansowane", + "Repeater ID:": "ID Repeatera:", + "WebSocket": "WebSocket", + "Encrypt": "Szyfrowanie", + "Host:": "Host:", + "Port:": "Port:", + "Path:": "Ścieżka:", + "Automatic Reconnect": "Automatycznie wznawiaj połączenie", + "Reconnect Delay (ms):": "Opóźnienie wznawiania (ms):", + "Logging:": "Poziom logowania:", + "Disconnect": "Rozłącz", + "Connect": "Połącz", + "Password:": "Hasło:", + "Cancel": "Anuluj", + "Canvas not supported.": "Element Canvas nie jest wspierany.", + "Failed to connect to server": "Błąd połączenia z serwerem", + "Credentials are required": "Wymagane są poświadczenia", + "Drag": "Ciągnąć", + "Toggle Windows": "Przełącz okna", + "Windows": "Okna", + "Quality:": "Jakość:", + "Compression level:": "Poziom kompresji:", + "Show Dot when No Cursor": "Pokaż kropkę, gdy nie ma kursora", + "Version:": "Wersja:", + "Username:": "Nazwa użytkownika:", + "Send Credentials": "Wyślij dane uwierzytelniające", + "Keys": "Klucze", + "Game Cursor Mode": "Tryb kursora gry", + "Press Esc Key to Exit Pointer Lock Mode": "Naciśnij klawisz Esc, aby wyjść z trybu blokady wskaźnika", + "Game Mode paused, click on screen to resume Game Mode.": "Tryb gry został wstrzymany, kliknij ekran, aby wznowić tryb gry.", + "Clipboard Up": "Schowek w górę", + "CLipboard Down": "Schowek w dół", + "Clipboard Seamless": "Schowek bez szwu", + "Prefer Local Cursor": "Preferuj lokalny kursor", + "Translate keyboard shortcuts": "Przetłumacz skróty klawiaturowe", + "Enable WebRTC UDP Transit": "Włącz tranzyt WebRTC UDP", + "Enable WebP Compression": "Włącz kompresję WebP", + "Enable Performance Stats": "Włącz statystyki wydajności", + "Enable Pointer Lock": "Włącz blokadę wskaźnika", + "IME Input Mode": "Tryb wprowadzania edytora IME", + "Show Virtual Keyboard Control": "Pokaż sterowanie klawiaturą wirtualną", + "Toggle Control Panel via Keystrokes": "Przełącz panel sterowania za pomocą naciśnięć klawiszy", + "Render Native Resolution": "Renderuj rozdzielczość natywną", + "Keyboard Shortcuts": "Skróty klawiszowe", + "Enable KasmVNC Keyboard Shortcuts": "Włącz skróty klawiaturowe KasmVNC", + "1 - Toggle Control Panel": "1 - Przełącz panel sterowania", + "2 - Toggle Game Pointer Mode": "2 - Przełącz tryb wskaźnika gry", + "3 - Toggle Pointer Lock": "3 - Przełącz blokadę wskaźnika", + "Stream Quality": "Jakość strumienia", + "Preset Modes:": "Tryby ustawień wstępnych:", + "Static": "Statyczny", + "Low": "Niski", + "Medium": "Średni", + "High": "Wysoki", + "Extreme": "Skrajny", + "Lossless": "Bezstratny", + "Custom": "Zwyczaj", + "Anti-Aliasing:": "Wygładzanie krawędzi:", + "Auto Dynamic": "Autodynamiczny", + "Off": "Wyłączony", + "On": "NA", + "Dynamic Quality Min:": "Minimalna jakość dynamiczna:", + "Dynamic Quality Max:": "Dynamiczna jakość maks.:", + "Treat Lossless:": "Lecz bezstratnie:", + "Frame Rate:": "Częstotliwość wyświetlania klatek:", + "Video JPEG Quality:": "Jakość wideo JPEG:", + "Video WEBP Quality:": "Jakość wideo WEBP:", + "Video Area:": "Obszar wideo:", + "Video Time:": "Czas wideo:", + "Video Out Time:": "Czas wyjścia wideo:", + "Video Mode Width:": "Szerokość trybu wideo:", + "Video Mode Height:": "Wysokość trybu wideo:", + "Documentation": "Dokumentacja", + "Drag Viewport": "Przeciągnij rzutnię", + "KasmVNC encountered an error:": "KasmVNC napotkał błąd:" +} \ No newline at end of file diff --git a/app/locale/ps.json b/app/locale/ps.json new file mode 100644 index 0000000..ddfdbc6 --- /dev/null +++ b/app/locale/ps.json @@ -0,0 +1,120 @@ +{ + "Connecting...": " ﻝﻮﻠښﻧ ", + "Disconnecting...": " ﻝﻮﮐ ﻊﻄﻘﻨﻣ", + "Reconnecting...": " ﻝﻮﻠښﻧ ﺎﯿﺑ", + "Internal error": "ﻪﻨﺗﻭﺮﯧﺗ ﻲﻠﺧﺍﺩ", + "Must set host": "ﺉړﮐ ﻢﯿﻈﻨﺗ ﻪﺑﺭﻮﮐ ﺪﯾﺎﺑ", + "Connected (encrypted) to ": "(ﯼﻮﺷ ډﻮﮐ) ﯼﻮﺷ ﻞﺻﻭ ﻩﺮﺳ", + "Connected (unencrypted) to ": "(ﯼﻮﺷ ډﻮﮐ ﻪﻧ) ﯼﻮﺷ ﻞﺻﻭ ﻩﺮﺳ", + "Something went wrong, connection is closed": "ﯤﻮﺷ ﻝړﺗ ﻪﮑﯾړﺍ ،ﻱﻮﺷ ﻂﻠﻏ ﻪڅ ﻮﯾ", + "Failed to connect to server": "ﯽﻠﻏﺍﺭ ﯥﺗﺎﭘ ﯥﮐ ﻮﻟﻮﻠښﻧ ﻪﭘ ﻩﺮﺳ ﺭﻭﺮﺳ ﺩ", + "Disconnected": "ﯼﻮﺷ ﻞﺤﻨﻣ", + "New connection has been rejected with reason: ": "ﯼﺩ ﯼﻮﺷ ﺩﺭ ﻩﺮﺳ ﻞﯿﻟﺩ ﺩ ﻁﺎﺒﺗﺭﺍ ﯼﻮﻧ", + "New connection has been rejected": "ﯼﻮﺷ ﺩﺭ ﻁﺎﺒﺗﺭﺍ ﯼﻮﻧ", + "Credentials are required": "ﻩﺩ ﺎﯿﺗړﺍ ﻭﺩﺎﻨﺳﺍ ﺩ", + "Hide/Show the control bar": "ﺉړﮐ ﻩﺭﺎﮑښ / ﺉړﮐ ټﭘ ﺭﺎﺑ ﻝﻭﺮټﻨﮐ ﺩ", + "Drag": "ﺶﺸﮐ", + "Move/Drag Viewport": "ګﯾﺭډ / ﺖﮐﺮﺣ ټﺭﻮﭘﻮﯿﻟ", + "Keyboard": "ډﺭﻮﺒﯿﮐ", + "Show Keyboard": "ﺖﺳﺎﯾﺎښﻭ ډﺭﻮﺒﯿﮐ", + "Extra keys": "ﻲﻠﯿﮐ ﻲﻓﺎﺿﺍ", + "Show Extra Keys": "ﺖﺳﺎﯾﺎښﻭ ﻲﻠﯿﮐ ﻲﻓﺎﺿﺍ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ﺉړﮐ ﻝﺪﺑ", + "Alt": "Alt", + "Toggle Alt": "Alt ﺉړﮐ ﻝﺪﺑ", + "Toggle Windows": "ﺉړﮐ ﻞﮕټ ﺯﻭډﻨﯾﻭ", + "Windows": "ﺯﻭډﻨﯾﻭ", + "Send Tab": "ﺉږﯧﻟﻭ ﺐټ", + "Tab": "ﺐټ", + "Esc": "Esc", + "Send Escape": "ﺉږﯧﻟﻭ ﯥﺘښﯧﺗ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﺉږﯧﻟﻭ", + "Shutdown/Reboot": "ټﻮﺒﯾﺭ / ﺪﻨﺑ", + "Shutdown/Reboot...": " ټﻮﺒﯾﺭ / ﺪﻨﺑ", + "Power": "ﮎﺍﻮځ", + "Shutdown": "u200du200du200dﻝﻭﺪﻨﺑ", + "Reboot": "ټﻮﺒﯾﺭ", + "Reset": "ﺉړﮐ ﻢﯿﻈﻨﺗ ﺎﯿﺑ", + "Clipboard": "ډﺭﻮﺑ ﭗﯿﻠﮐ", + "Clear": "ﮎﺎﭘ", + "Fullscreen": "ﻪﺤﻔﺻ ﻪﻠﻤﮑﻣ", + "Settings": "ﺕﺎﺒﯿﺗﺮﺗ", + "Shared Mode": "ﺖﻟﺎﺣ ﮏﯾﺮﺷ", + "View Only": "ﻝﺪﯿﻟ ﯤﺯﺍﻮﯾ", + "Clip to Window": "ﮏﯿﻠﮐ ﻪﺗ ۍﮐړﮐ", + "Scaling Mode:": "ﺖﻟﺎﺣ ﻮﻟﻮﮐ ﻩﺯﺍﺪﻧﺍ ﺩ", + "None": "ﻪﻧ څﯿﻫ", + "Local Scaling": "ﻝﻮﮐ ﻩﺯﺍﺪﻧﺍ ﺰﯾﺍ ﻪﻤﯿﺳ", + "Remote Resizing": "ﻝﻮﮐ ﻩﺯﺍﺪﻧﺍ ټﻮﻤﯾﺭ ﺩ", + "Advanced": "ﯽﻠﻠﺘﺨﻣﺮﭘ", + "Quality:": "ﺖﯿﻔﯿﮐ", + "Compression level:": "ﻪﭽﮐ ﻦﺸﯾﺮﭙﻤﮐ ﺩ", + "Repeater ID:": "ID ﻱﺭﺍﺮﮑﺗ ﺩ", + "WebSocket": "ټﮐﺎﺳ ﺐﯾﻭ", + "Encrypt": "ﻝﻮﮐ ډﻮﮐ", + "Host:": "ﻪﺑﺭﻮﮐ", + "Port:": "ټﺭﻮﭘ", + "Path:": "ﻩﺭﻻ", + "Automatic Reconnect": "ﻝﻮﻠښﻧ ﻝﻭډ ﮏﻴﺗﺎﻣﻮﺗﺍ ﻪﭘ", + "Reconnect Delay (ms):": "(ms) ﻝﻮﻠښﻧ ﺎﯿﺑ ډﻨځ", + "Show Dot when No Cursor": "ﺉړﮐ ﻩﺭﺎﮑښ ﻪﻄﻘﻧ ﻱﻭ ﻪﻧ ﺮﺳﺮﮐ ﯥﭼ ﻪﻠﮐ", + "Logging:": "ﻞﺗﻮﻨﻧ", + "Version:": "ﻪﺨﺴﻧ", + "Disconnect": "ﻝﻮﮐ ﯤﺮﭘ ﯥﺑ", + "Connect": "ﻞﺻﻭ", + "Username:": "ﻡﻮﻧ ﻥﺭﺎﮐ", + "Password:": "ﺰﻣﺭ", + "Send Credentials": "ﻝږﯿﻟ ﻭﺩﺎﻨﺳﺍ ﺩ", + "Cancel": "ﻝﻮﮐ ﻪﺨﺴﻓ", + "Keys": "ﻲﻠﯿﮐ", + "Game Cursor Mode": "ﺖﻟﺎﺣ ﺮﺳﺮﮐ ﯥﺑﻮﻟ ﺩ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺉړﮐﺭﻭ ﺭﺎﺸﻓ ﻲﻠﯿﮐ Esc ﺩ ﻩﺭﺎﭙﻟ ﻮﻠﺗﻭ ﻪﺨڅ ﺖﻟﺎﺣ ﮎﻻ ﺮټﻨﺋﺍﻮﭘ ﺩ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺉړﮐﻭ ﮏﯿﻠﮐ ﯤﺪﻧﺎﺑ ﻦﯾﺮﮑﺳ ﻪﭘ ﻩﺭﺎﭙﻟ ﻮﻟﻮﻠﯿﭘ ﺎﯿﺑ ﺖﻟﺎﺣ ﯥﺑﻮﻟ ﺩ ،ﻮﺷ ﻝﻭﺭﺩﻭ ﺖﻟﺎﺣ ﯥﺑﻮﻟ ﺩ", + "Clipboard Up": "ﻪﺗﺭﻮﭘ ډﺭﻮﺑ ﭗﯿﻠﮐ", + "CLipboard Down": "ﻪﺘﮑښ ډﺭﻮﺑ ﭗﯿﻠﮐ", + "Clipboard Seamless": "ﻪﻤﯿﺳ ﯥﺑ ډﺭﻮﺑ ﭗﯿﻠﮐ", + "Prefer Local Cursor": "ﺉړﮐ ﻩﺭﻮﻏ ﺮﺳﺮﮐ ﺰﯾﺍ ﻪﻤﯿﺳ", + "Translate keyboard shortcuts": "ﺉړﺎﺑﮊﻭ ﻮﻧﻮټﮐ ټﺭﺎﺷ ډﺭﻮﺒﯿﮐ ﺩ", + "Enable WebRTC UDP Transit": "WebRTC UDP ﺉړﮐ ﻝﺎﻌﻓ ﺩږﯿﻟ", + "Enable WebP Compression": "WebP ﺉړﮐ ﻝﺎﻌﻓ ﻦﺸﯾﺮﭙﻤﮐ", + "Enable Performance Stats": "ﺉړﮐ ﻝﺎﻌﻓ ﯥﯾﺎﺼﺣﺍ ﺖﯿﻟﺎﻌﻓ ﺩ", + "Enable Pointer Lock": "ﺉړﮐ ﻝﺎﻌﻓ ﮎﻻ ﺮټﻨﺋﺍﻮﭘ ﺩ", + "IME Input Mode": "IME ﺖﻟﺎﺣ ټﭘ ﻥﺍ", + "Show Virtual Keyboard Control": "ﺖﺳﺎﯾﺎښﻭ ﻝﻭﺮټﻨﮐ ډﺭﻮﺒﯿﮐ ﯼﺯﺎﺠﻣ ﺩ", + "Toggle Control Panel via Keystrokes": "ﺉړﮐ ﻝﺪﺑ ﻞﻨﯿﭘ ﻝﻭﺮټﻨﮐ ﺩ ﯤﺭﻻ ﻪﻟ ﮎﻭﺮټﺴﯿﮐ ﺩ", + "Render Native Resolution": "ﻝﻮﮐ ﯤﺪﻧﺍړﻭ ﻞﺣ ﻲﻠﺻﺍ ﺩ", + "Keyboard Shortcuts": "ﻪﻧﻮټﮐ ټﺭﺎﺷ ډﺭﻮﺑ ﯽﮐ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺉړﮐ ﻝﺎﻌﻓ ﻪﻧﻮټﮐ ټﺭﺎﺷ ډﺭﻮﺑ ﯽﮐ", + "1 - Toggle Control Panel": "ﺉړﮐ ﻝﺪﺑ ﻞﻨﯿﭘ ﻝﻭﺮټﻨﮐ ﺩ - 1", + "2 - Toggle Game Pointer Mode": "ﺉړﮐ ﻝﺪﺑ ﺖﻟﺎﺣ ﺮټﻨﯾﻮﭘ ﯥﺑﻮﻟ ﺩ - 2", + "3 - Toggle Pointer Lock": "ﺉړﮐ ﻝﺪﺑ ﮎﻻ ﺮټﻨﺋﺍﻮﭘ ﺩ - 3", + "Stream Quality": "ﺖﯿﻔﯿﮐ ﻥﺎﯾﺮﺟ ﺩ", + "Preset Modes:": "ﯥﻘﯾﺮﻃ ۍﻨﯿﮑﺨﻣ", + "Static": "ﺪﻣﺎﺟ", + "Low": "ټﻴټ", + "Medium": "ﯽﻨځﻨﻣ", + "High": "ړﻮﻟ", + "Extreme": "ﺖﺨﺳ", + "Lossless": "ﻥﺍﻭﺎﺗ ﯥﺑ", + "Custom": "ﺐﻠﻄﻣ", + "Anti-Aliasing:": "ﺪﺿ ﻮﻟﻮﮐ ﺱﺎﯿﻟﺍ ﺩ", + "Auto Dynamic": "ﮎﺮﺤﺘﻣ ﻮټﺁ", + "Off": "ﺪﻨﺑ", + "On": "ﺮﭘ", + "Dynamic Quality Min:": "ﻖﯿﻗﺩ ﺖﯿﻔﯿﮐ ﮎﺮﺤﺘﻣ", + "Dynamic Quality Max:": "ﻲﻤﻈﻋﺍ ﺖﯿﻔﯿﮐ ﮎﺮﺤﺘﻣ", + "Treat Lossless:": "ﺉړﮐﻭ ﻪﻨﻠﻣﺭﺩ ﻩﺭﺮﺿ ﯥﺑ", + "Frame Rate:": "ﺥﺮﻧ ټﺎﮐﻮﭼ ﺩ", + "Video JPEG Quality:": "ﺖﯿﻔﯿﮐ JPEG ﻮﯾډﯾﻭ ﺩ", + "Video WEBP Quality:": "ﺖﯿﻔﯿﮐ ﭗﺒﯾﻭ ﻮﯾډﯾﻭ ﺩ", + "Video Area:": "ﻪﺣﺎﺳ ﻮﯾډﯾﻭ ﺩ", + "Video Time:": "ﺖﺧﻭ ﻮﯾډﯾﻭ ﺩ", + "Video Out Time:": "ﺖﺧﻭ ﻮﻟﻮﻤﺘﺧ ﻮﯾډﯾﻭ ﺩ", + "Video Mode Width:": "ﺽﺮﻋ ﺖﻟﺎﺣ ﻮﯾډﯾﻭ ﺩ", + "Video Mode Height:": "ﯽﻟﺍﻭړﻮﻟ ﺖﻟﺎﺣ ﻮﯾډﯾﻭ ﺩ", + "Documentation": "ﺩﺎﻨﺳﺍ", + "Drag Viewport": "ګﯾﺭډ ﺪﯿﻟ ﺪﯿﻟ ﺩ", + "KasmVNC encountered an error:": "KasmVNC ﻮﺷ ﺦﻣ ﻩﺮﺳ ﯥﻨﺗﻭﺮﯧﺗ ﯤﻮﯾ ﺩ:" +} \ No newline at end of file diff --git a/app/locale/ps_AF.json b/app/locale/ps_AF.json new file mode 100644 index 0000000..ddfdbc6 --- /dev/null +++ b/app/locale/ps_AF.json @@ -0,0 +1,120 @@ +{ + "Connecting...": " ﻝﻮﻠښﻧ ", + "Disconnecting...": " ﻝﻮﮐ ﻊﻄﻘﻨﻣ", + "Reconnecting...": " ﻝﻮﻠښﻧ ﺎﯿﺑ", + "Internal error": "ﻪﻨﺗﻭﺮﯧﺗ ﻲﻠﺧﺍﺩ", + "Must set host": "ﺉړﮐ ﻢﯿﻈﻨﺗ ﻪﺑﺭﻮﮐ ﺪﯾﺎﺑ", + "Connected (encrypted) to ": "(ﯼﻮﺷ ډﻮﮐ) ﯼﻮﺷ ﻞﺻﻭ ﻩﺮﺳ", + "Connected (unencrypted) to ": "(ﯼﻮﺷ ډﻮﮐ ﻪﻧ) ﯼﻮﺷ ﻞﺻﻭ ﻩﺮﺳ", + "Something went wrong, connection is closed": "ﯤﻮﺷ ﻝړﺗ ﻪﮑﯾړﺍ ،ﻱﻮﺷ ﻂﻠﻏ ﻪڅ ﻮﯾ", + "Failed to connect to server": "ﯽﻠﻏﺍﺭ ﯥﺗﺎﭘ ﯥﮐ ﻮﻟﻮﻠښﻧ ﻪﭘ ﻩﺮﺳ ﺭﻭﺮﺳ ﺩ", + "Disconnected": "ﯼﻮﺷ ﻞﺤﻨﻣ", + "New connection has been rejected with reason: ": "ﯼﺩ ﯼﻮﺷ ﺩﺭ ﻩﺮﺳ ﻞﯿﻟﺩ ﺩ ﻁﺎﺒﺗﺭﺍ ﯼﻮﻧ", + "New connection has been rejected": "ﯼﻮﺷ ﺩﺭ ﻁﺎﺒﺗﺭﺍ ﯼﻮﻧ", + "Credentials are required": "ﻩﺩ ﺎﯿﺗړﺍ ﻭﺩﺎﻨﺳﺍ ﺩ", + "Hide/Show the control bar": "ﺉړﮐ ﻩﺭﺎﮑښ / ﺉړﮐ ټﭘ ﺭﺎﺑ ﻝﻭﺮټﻨﮐ ﺩ", + "Drag": "ﺶﺸﮐ", + "Move/Drag Viewport": "ګﯾﺭډ / ﺖﮐﺮﺣ ټﺭﻮﭘﻮﯿﻟ", + "Keyboard": "ډﺭﻮﺒﯿﮐ", + "Show Keyboard": "ﺖﺳﺎﯾﺎښﻭ ډﺭﻮﺒﯿﮐ", + "Extra keys": "ﻲﻠﯿﮐ ﻲﻓﺎﺿﺍ", + "Show Extra Keys": "ﺖﺳﺎﯾﺎښﻭ ﻲﻠﯿﮐ ﻲﻓﺎﺿﺍ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ﺉړﮐ ﻝﺪﺑ", + "Alt": "Alt", + "Toggle Alt": "Alt ﺉړﮐ ﻝﺪﺑ", + "Toggle Windows": "ﺉړﮐ ﻞﮕټ ﺯﻭډﻨﯾﻭ", + "Windows": "ﺯﻭډﻨﯾﻭ", + "Send Tab": "ﺉږﯧﻟﻭ ﺐټ", + "Tab": "ﺐټ", + "Esc": "Esc", + "Send Escape": "ﺉږﯧﻟﻭ ﯥﺘښﯧﺗ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﺉږﯧﻟﻭ", + "Shutdown/Reboot": "ټﻮﺒﯾﺭ / ﺪﻨﺑ", + "Shutdown/Reboot...": " ټﻮﺒﯾﺭ / ﺪﻨﺑ", + "Power": "ﮎﺍﻮځ", + "Shutdown": "u200du200du200dﻝﻭﺪﻨﺑ", + "Reboot": "ټﻮﺒﯾﺭ", + "Reset": "ﺉړﮐ ﻢﯿﻈﻨﺗ ﺎﯿﺑ", + "Clipboard": "ډﺭﻮﺑ ﭗﯿﻠﮐ", + "Clear": "ﮎﺎﭘ", + "Fullscreen": "ﻪﺤﻔﺻ ﻪﻠﻤﮑﻣ", + "Settings": "ﺕﺎﺒﯿﺗﺮﺗ", + "Shared Mode": "ﺖﻟﺎﺣ ﮏﯾﺮﺷ", + "View Only": "ﻝﺪﯿﻟ ﯤﺯﺍﻮﯾ", + "Clip to Window": "ﮏﯿﻠﮐ ﻪﺗ ۍﮐړﮐ", + "Scaling Mode:": "ﺖﻟﺎﺣ ﻮﻟﻮﮐ ﻩﺯﺍﺪﻧﺍ ﺩ", + "None": "ﻪﻧ څﯿﻫ", + "Local Scaling": "ﻝﻮﮐ ﻩﺯﺍﺪﻧﺍ ﺰﯾﺍ ﻪﻤﯿﺳ", + "Remote Resizing": "ﻝﻮﮐ ﻩﺯﺍﺪﻧﺍ ټﻮﻤﯾﺭ ﺩ", + "Advanced": "ﯽﻠﻠﺘﺨﻣﺮﭘ", + "Quality:": "ﺖﯿﻔﯿﮐ", + "Compression level:": "ﻪﭽﮐ ﻦﺸﯾﺮﭙﻤﮐ ﺩ", + "Repeater ID:": "ID ﻱﺭﺍﺮﮑﺗ ﺩ", + "WebSocket": "ټﮐﺎﺳ ﺐﯾﻭ", + "Encrypt": "ﻝﻮﮐ ډﻮﮐ", + "Host:": "ﻪﺑﺭﻮﮐ", + "Port:": "ټﺭﻮﭘ", + "Path:": "ﻩﺭﻻ", + "Automatic Reconnect": "ﻝﻮﻠښﻧ ﻝﻭډ ﮏﻴﺗﺎﻣﻮﺗﺍ ﻪﭘ", + "Reconnect Delay (ms):": "(ms) ﻝﻮﻠښﻧ ﺎﯿﺑ ډﻨځ", + "Show Dot when No Cursor": "ﺉړﮐ ﻩﺭﺎﮑښ ﻪﻄﻘﻧ ﻱﻭ ﻪﻧ ﺮﺳﺮﮐ ﯥﭼ ﻪﻠﮐ", + "Logging:": "ﻞﺗﻮﻨﻧ", + "Version:": "ﻪﺨﺴﻧ", + "Disconnect": "ﻝﻮﮐ ﯤﺮﭘ ﯥﺑ", + "Connect": "ﻞﺻﻭ", + "Username:": "ﻡﻮﻧ ﻥﺭﺎﮐ", + "Password:": "ﺰﻣﺭ", + "Send Credentials": "ﻝږﯿﻟ ﻭﺩﺎﻨﺳﺍ ﺩ", + "Cancel": "ﻝﻮﮐ ﻪﺨﺴﻓ", + "Keys": "ﻲﻠﯿﮐ", + "Game Cursor Mode": "ﺖﻟﺎﺣ ﺮﺳﺮﮐ ﯥﺑﻮﻟ ﺩ", + "Press Esc Key to Exit Pointer Lock Mode": "ﺉړﮐﺭﻭ ﺭﺎﺸﻓ ﻲﻠﯿﮐ Esc ﺩ ﻩﺭﺎﭙﻟ ﻮﻠﺗﻭ ﻪﺨڅ ﺖﻟﺎﺣ ﮎﻻ ﺮټﻨﺋﺍﻮﭘ ﺩ", + "Game Mode paused, click on screen to resume Game Mode.": "ﺉړﮐﻭ ﮏﯿﻠﮐ ﯤﺪﻧﺎﺑ ﻦﯾﺮﮑﺳ ﻪﭘ ﻩﺭﺎﭙﻟ ﻮﻟﻮﻠﯿﭘ ﺎﯿﺑ ﺖﻟﺎﺣ ﯥﺑﻮﻟ ﺩ ،ﻮﺷ ﻝﻭﺭﺩﻭ ﺖﻟﺎﺣ ﯥﺑﻮﻟ ﺩ", + "Clipboard Up": "ﻪﺗﺭﻮﭘ ډﺭﻮﺑ ﭗﯿﻠﮐ", + "CLipboard Down": "ﻪﺘﮑښ ډﺭﻮﺑ ﭗﯿﻠﮐ", + "Clipboard Seamless": "ﻪﻤﯿﺳ ﯥﺑ ډﺭﻮﺑ ﭗﯿﻠﮐ", + "Prefer Local Cursor": "ﺉړﮐ ﻩﺭﻮﻏ ﺮﺳﺮﮐ ﺰﯾﺍ ﻪﻤﯿﺳ", + "Translate keyboard shortcuts": "ﺉړﺎﺑﮊﻭ ﻮﻧﻮټﮐ ټﺭﺎﺷ ډﺭﻮﺒﯿﮐ ﺩ", + "Enable WebRTC UDP Transit": "WebRTC UDP ﺉړﮐ ﻝﺎﻌﻓ ﺩږﯿﻟ", + "Enable WebP Compression": "WebP ﺉړﮐ ﻝﺎﻌﻓ ﻦﺸﯾﺮﭙﻤﮐ", + "Enable Performance Stats": "ﺉړﮐ ﻝﺎﻌﻓ ﯥﯾﺎﺼﺣﺍ ﺖﯿﻟﺎﻌﻓ ﺩ", + "Enable Pointer Lock": "ﺉړﮐ ﻝﺎﻌﻓ ﮎﻻ ﺮټﻨﺋﺍﻮﭘ ﺩ", + "IME Input Mode": "IME ﺖﻟﺎﺣ ټﭘ ﻥﺍ", + "Show Virtual Keyboard Control": "ﺖﺳﺎﯾﺎښﻭ ﻝﻭﺮټﻨﮐ ډﺭﻮﺒﯿﮐ ﯼﺯﺎﺠﻣ ﺩ", + "Toggle Control Panel via Keystrokes": "ﺉړﮐ ﻝﺪﺑ ﻞﻨﯿﭘ ﻝﻭﺮټﻨﮐ ﺩ ﯤﺭﻻ ﻪﻟ ﮎﻭﺮټﺴﯿﮐ ﺩ", + "Render Native Resolution": "ﻝﻮﮐ ﯤﺪﻧﺍړﻭ ﻞﺣ ﻲﻠﺻﺍ ﺩ", + "Keyboard Shortcuts": "ﻪﻧﻮټﮐ ټﺭﺎﺷ ډﺭﻮﺑ ﯽﮐ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﺉړﮐ ﻝﺎﻌﻓ ﻪﻧﻮټﮐ ټﺭﺎﺷ ډﺭﻮﺑ ﯽﮐ", + "1 - Toggle Control Panel": "ﺉړﮐ ﻝﺪﺑ ﻞﻨﯿﭘ ﻝﻭﺮټﻨﮐ ﺩ - 1", + "2 - Toggle Game Pointer Mode": "ﺉړﮐ ﻝﺪﺑ ﺖﻟﺎﺣ ﺮټﻨﯾﻮﭘ ﯥﺑﻮﻟ ﺩ - 2", + "3 - Toggle Pointer Lock": "ﺉړﮐ ﻝﺪﺑ ﮎﻻ ﺮټﻨﺋﺍﻮﭘ ﺩ - 3", + "Stream Quality": "ﺖﯿﻔﯿﮐ ﻥﺎﯾﺮﺟ ﺩ", + "Preset Modes:": "ﯥﻘﯾﺮﻃ ۍﻨﯿﮑﺨﻣ", + "Static": "ﺪﻣﺎﺟ", + "Low": "ټﻴټ", + "Medium": "ﯽﻨځﻨﻣ", + "High": "ړﻮﻟ", + "Extreme": "ﺖﺨﺳ", + "Lossless": "ﻥﺍﻭﺎﺗ ﯥﺑ", + "Custom": "ﺐﻠﻄﻣ", + "Anti-Aliasing:": "ﺪﺿ ﻮﻟﻮﮐ ﺱﺎﯿﻟﺍ ﺩ", + "Auto Dynamic": "ﮎﺮﺤﺘﻣ ﻮټﺁ", + "Off": "ﺪﻨﺑ", + "On": "ﺮﭘ", + "Dynamic Quality Min:": "ﻖﯿﻗﺩ ﺖﯿﻔﯿﮐ ﮎﺮﺤﺘﻣ", + "Dynamic Quality Max:": "ﻲﻤﻈﻋﺍ ﺖﯿﻔﯿﮐ ﮎﺮﺤﺘﻣ", + "Treat Lossless:": "ﺉړﮐﻭ ﻪﻨﻠﻣﺭﺩ ﻩﺭﺮﺿ ﯥﺑ", + "Frame Rate:": "ﺥﺮﻧ ټﺎﮐﻮﭼ ﺩ", + "Video JPEG Quality:": "ﺖﯿﻔﯿﮐ JPEG ﻮﯾډﯾﻭ ﺩ", + "Video WEBP Quality:": "ﺖﯿﻔﯿﮐ ﭗﺒﯾﻭ ﻮﯾډﯾﻭ ﺩ", + "Video Area:": "ﻪﺣﺎﺳ ﻮﯾډﯾﻭ ﺩ", + "Video Time:": "ﺖﺧﻭ ﻮﯾډﯾﻭ ﺩ", + "Video Out Time:": "ﺖﺧﻭ ﻮﻟﻮﻤﺘﺧ ﻮﯾډﯾﻭ ﺩ", + "Video Mode Width:": "ﺽﺮﻋ ﺖﻟﺎﺣ ﻮﯾډﯾﻭ ﺩ", + "Video Mode Height:": "ﯽﻟﺍﻭړﻮﻟ ﺖﻟﺎﺣ ﻮﯾډﯾﻭ ﺩ", + "Documentation": "ﺩﺎﻨﺳﺍ", + "Drag Viewport": "ګﯾﺭډ ﺪﯿﻟ ﺪﯿﻟ ﺩ", + "KasmVNC encountered an error:": "KasmVNC ﻮﺷ ﺦﻣ ﻩﺮﺳ ﯥﻨﺗﻭﺮﯧﺗ ﯤﻮﯾ ﺩ:" +} \ No newline at end of file diff --git a/app/locale/pt.json b/app/locale/pt.json new file mode 100644 index 0000000..bd153df --- /dev/null +++ b/app/locale/pt.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Conectando...", + "Disconnecting...": "Desconectando...", + "Reconnecting...": "Reconectando...", + "Internal error": "Erro interno", + "Must set host": "É necessário definir o host", + "Connected (encrypted) to ": "Conectado (com criptografia) a ", + "Connected (unencrypted) to ": "Conectado (sem criptografia) a ", + "Something went wrong, connection is closed": "Algo deu errado. A conexão foi encerrada.", + "Failed to connect to server": "Falha ao conectar-se ao servidor", + "Disconnected": "Desconectado", + "New connection has been rejected with reason: ": "A nova conexão foi rejeitada pelo motivo: ", + "New connection has been rejected": "A nova conexão foi rejeitada", + "Credentials are required": "Credenciais são obrigatórias", + "Hide/Show the control bar": "Esconder/mostrar a barra de controles", + "Drag": "Arrastar", + "Move/Drag Viewport": "Mover/arrastar a janela", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionais", + "Show Extra Keys": "Mostar teclas adicionais", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pressionar/soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pressionar/soltar Alt", + "Toggle Windows": "Pressionar/soltar Windows", + "Windows": "Windows", + "Send Tab": "Enviar Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Enviar Esc", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl-Alt-Del", + "Shutdown/Reboot": "Desligar/reiniciar", + "Shutdown/Reboot...": "Desligar/reiniciar...", + "Power": "Ligar", + "Shutdown": "Desligar", + "Reboot": "Reiniciar", + "Reset": "Reiniciar (forçado)", + "Clipboard": "Área de transferência", + "Clear": "Limpar", + "Fullscreen": "Tela cheia", + "Settings": "Configurações", + "Shared Mode": "Modo compartilhado", + "View Only": "Apenas visualizar", + "Clip to Window": "Recortar à janela", + "Scaling Mode:": "Modo de dimensionamento:", + "None": "Nenhum", + "Local Scaling": "Local", + "Remote Resizing": "Remoto", + "Advanced": "Avançado", + "Quality:": "Qualidade:", + "Compression level:": "Nível de compressão:", + "Repeater ID:": "ID do repetidor:", + "WebSocket": "WebSocket", + "Encrypt": "Criptografar", + "Host:": "Host:", + "Port:": "Porta:", + "Path:": "Caminho:", + "Automatic Reconnect": "Reconexão automática", + "Reconnect Delay (ms):": "Atraso da reconexão (ms)", + "Show Dot when No Cursor": "Mostrar ponto quando não há cursor", + "Logging:": "Registros:", + "Version:": "Versão:", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Username:": "Nome de usuário:", + "Password:": "Senha:", + "Send Credentials": "Enviar credenciais", + "Cancel": "Cancelar", + "Keys": "Chaves", + "Game Cursor Mode": "Modo cursor do jogo", + "Press Esc Key to Exit Pointer Lock Mode": "Pressione a tecla Esc para sair do modo de bloqueio do ponteiro", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de jogo pausado, clique na tela para retomar o modo de jogo.", + "Clipboard Up": "Área de transferência para cima", + "CLipboard Down": "Área de transferência para baixo", + "Clipboard Seamless": "Área de transferência perfeita", + "Prefer Local Cursor": "Preferir Cursor Local", + "Translate keyboard shortcuts": "Traduzir atalhos de teclado", + "Enable WebRTC UDP Transit": "Ativar trânsito UDP WebRTC", + "Enable WebP Compression": "Ativar compactação WebP", + "Enable Performance Stats": "Ativar estatísticas de desempenho", + "Enable Pointer Lock": "Ativar bloqueio do ponteiro", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar controle de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar painel de controle por meio de teclas", + "Render Native Resolution": "Renderizar resolução nativa", + "Keyboard Shortcuts": "Atalhos do teclado", + "Enable KasmVNC Keyboard Shortcuts": "Ativar atalhos de teclado KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar painel de controle", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de ponteiro de jogo", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueio do ponteiro", + "Stream Quality": "Qualidade da Transmissão", + "Preset Modes:": "Modos predefinidos:", + "Static": "Estático", + "Low": "Baixo", + "Medium": "Médio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "Sem perdas", + "Custom": "Personalizado", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dinâmico", + "Off": "Desligado", + "On": "Sobre", + "Dynamic Quality Min:": "Qualidade dinâmica mínima:", + "Dynamic Quality Max:": "Qualidade dinâmica máxima:", + "Treat Lossless:": "Trate sem perdas:", + "Frame Rate:": "Taxa de quadros:", + "Video JPEG Quality:": "Qualidade JPEG de vídeo:", + "Video WEBP Quality:": "Qualidade WEBP de vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tempo do vídeo:", + "Video Out Time:": "Tempo de saída do vídeo:", + "Video Mode Width:": "Largura do modo de vídeo:", + "Video Mode Height:": "Altura do modo de vídeo:", + "Documentation": "Documentação", + "Drag Viewport": "Arrastar janela de visualização", + "KasmVNC encountered an error:": "KasmVNC encontrou um erro:" +} \ No newline at end of file diff --git a/app/locale/pt_BR.json b/app/locale/pt_BR.json new file mode 100644 index 0000000..bd153df --- /dev/null +++ b/app/locale/pt_BR.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Conectando...", + "Disconnecting...": "Desconectando...", + "Reconnecting...": "Reconectando...", + "Internal error": "Erro interno", + "Must set host": "É necessário definir o host", + "Connected (encrypted) to ": "Conectado (com criptografia) a ", + "Connected (unencrypted) to ": "Conectado (sem criptografia) a ", + "Something went wrong, connection is closed": "Algo deu errado. A conexão foi encerrada.", + "Failed to connect to server": "Falha ao conectar-se ao servidor", + "Disconnected": "Desconectado", + "New connection has been rejected with reason: ": "A nova conexão foi rejeitada pelo motivo: ", + "New connection has been rejected": "A nova conexão foi rejeitada", + "Credentials are required": "Credenciais são obrigatórias", + "Hide/Show the control bar": "Esconder/mostrar a barra de controles", + "Drag": "Arrastar", + "Move/Drag Viewport": "Mover/arrastar a janela", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionais", + "Show Extra Keys": "Mostar teclas adicionais", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pressionar/soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pressionar/soltar Alt", + "Toggle Windows": "Pressionar/soltar Windows", + "Windows": "Windows", + "Send Tab": "Enviar Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Enviar Esc", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl-Alt-Del", + "Shutdown/Reboot": "Desligar/reiniciar", + "Shutdown/Reboot...": "Desligar/reiniciar...", + "Power": "Ligar", + "Shutdown": "Desligar", + "Reboot": "Reiniciar", + "Reset": "Reiniciar (forçado)", + "Clipboard": "Área de transferência", + "Clear": "Limpar", + "Fullscreen": "Tela cheia", + "Settings": "Configurações", + "Shared Mode": "Modo compartilhado", + "View Only": "Apenas visualizar", + "Clip to Window": "Recortar à janela", + "Scaling Mode:": "Modo de dimensionamento:", + "None": "Nenhum", + "Local Scaling": "Local", + "Remote Resizing": "Remoto", + "Advanced": "Avançado", + "Quality:": "Qualidade:", + "Compression level:": "Nível de compressão:", + "Repeater ID:": "ID do repetidor:", + "WebSocket": "WebSocket", + "Encrypt": "Criptografar", + "Host:": "Host:", + "Port:": "Porta:", + "Path:": "Caminho:", + "Automatic Reconnect": "Reconexão automática", + "Reconnect Delay (ms):": "Atraso da reconexão (ms)", + "Show Dot when No Cursor": "Mostrar ponto quando não há cursor", + "Logging:": "Registros:", + "Version:": "Versão:", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Username:": "Nome de usuário:", + "Password:": "Senha:", + "Send Credentials": "Enviar credenciais", + "Cancel": "Cancelar", + "Keys": "Chaves", + "Game Cursor Mode": "Modo cursor do jogo", + "Press Esc Key to Exit Pointer Lock Mode": "Pressione a tecla Esc para sair do modo de bloqueio do ponteiro", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de jogo pausado, clique na tela para retomar o modo de jogo.", + "Clipboard Up": "Área de transferência para cima", + "CLipboard Down": "Área de transferência para baixo", + "Clipboard Seamless": "Área de transferência perfeita", + "Prefer Local Cursor": "Preferir Cursor Local", + "Translate keyboard shortcuts": "Traduzir atalhos de teclado", + "Enable WebRTC UDP Transit": "Ativar trânsito UDP WebRTC", + "Enable WebP Compression": "Ativar compactação WebP", + "Enable Performance Stats": "Ativar estatísticas de desempenho", + "Enable Pointer Lock": "Ativar bloqueio do ponteiro", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar controle de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar painel de controle por meio de teclas", + "Render Native Resolution": "Renderizar resolução nativa", + "Keyboard Shortcuts": "Atalhos do teclado", + "Enable KasmVNC Keyboard Shortcuts": "Ativar atalhos de teclado KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar painel de controle", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de ponteiro de jogo", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueio do ponteiro", + "Stream Quality": "Qualidade da Transmissão", + "Preset Modes:": "Modos predefinidos:", + "Static": "Estático", + "Low": "Baixo", + "Medium": "Médio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "Sem perdas", + "Custom": "Personalizado", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dinâmico", + "Off": "Desligado", + "On": "Sobre", + "Dynamic Quality Min:": "Qualidade dinâmica mínima:", + "Dynamic Quality Max:": "Qualidade dinâmica máxima:", + "Treat Lossless:": "Trate sem perdas:", + "Frame Rate:": "Taxa de quadros:", + "Video JPEG Quality:": "Qualidade JPEG de vídeo:", + "Video WEBP Quality:": "Qualidade WEBP de vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tempo do vídeo:", + "Video Out Time:": "Tempo de saída do vídeo:", + "Video Mode Width:": "Largura do modo de vídeo:", + "Video Mode Height:": "Altura do modo de vídeo:", + "Documentation": "Documentação", + "Drag Viewport": "Arrastar janela de visualização", + "KasmVNC encountered an error:": "KasmVNC encontrou um erro:" +} \ No newline at end of file diff --git a/app/locale/pt_PT.json b/app/locale/pt_PT.json new file mode 100644 index 0000000..bd153df --- /dev/null +++ b/app/locale/pt_PT.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Conectando...", + "Disconnecting...": "Desconectando...", + "Reconnecting...": "Reconectando...", + "Internal error": "Erro interno", + "Must set host": "É necessário definir o host", + "Connected (encrypted) to ": "Conectado (com criptografia) a ", + "Connected (unencrypted) to ": "Conectado (sem criptografia) a ", + "Something went wrong, connection is closed": "Algo deu errado. A conexão foi encerrada.", + "Failed to connect to server": "Falha ao conectar-se ao servidor", + "Disconnected": "Desconectado", + "New connection has been rejected with reason: ": "A nova conexão foi rejeitada pelo motivo: ", + "New connection has been rejected": "A nova conexão foi rejeitada", + "Credentials are required": "Credenciais são obrigatórias", + "Hide/Show the control bar": "Esconder/mostrar a barra de controles", + "Drag": "Arrastar", + "Move/Drag Viewport": "Mover/arrastar a janela", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionais", + "Show Extra Keys": "Mostar teclas adicionais", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pressionar/soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pressionar/soltar Alt", + "Toggle Windows": "Pressionar/soltar Windows", + "Windows": "Windows", + "Send Tab": "Enviar Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Enviar Esc", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl-Alt-Del", + "Shutdown/Reboot": "Desligar/reiniciar", + "Shutdown/Reboot...": "Desligar/reiniciar...", + "Power": "Ligar", + "Shutdown": "Desligar", + "Reboot": "Reiniciar", + "Reset": "Reiniciar (forçado)", + "Clipboard": "Área de transferência", + "Clear": "Limpar", + "Fullscreen": "Tela cheia", + "Settings": "Configurações", + "Shared Mode": "Modo compartilhado", + "View Only": "Apenas visualizar", + "Clip to Window": "Recortar à janela", + "Scaling Mode:": "Modo de dimensionamento:", + "None": "Nenhum", + "Local Scaling": "Local", + "Remote Resizing": "Remoto", + "Advanced": "Avançado", + "Quality:": "Qualidade:", + "Compression level:": "Nível de compressão:", + "Repeater ID:": "ID do repetidor:", + "WebSocket": "WebSocket", + "Encrypt": "Criptografar", + "Host:": "Host:", + "Port:": "Porta:", + "Path:": "Caminho:", + "Automatic Reconnect": "Reconexão automática", + "Reconnect Delay (ms):": "Atraso da reconexão (ms)", + "Show Dot when No Cursor": "Mostrar ponto quando não há cursor", + "Logging:": "Registros:", + "Version:": "Versão:", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Username:": "Nome de usuário:", + "Password:": "Senha:", + "Send Credentials": "Enviar credenciais", + "Cancel": "Cancelar", + "Keys": "Chaves", + "Game Cursor Mode": "Modo cursor do jogo", + "Press Esc Key to Exit Pointer Lock Mode": "Pressione a tecla Esc para sair do modo de bloqueio do ponteiro", + "Game Mode paused, click on screen to resume Game Mode.": "Modo de jogo pausado, clique na tela para retomar o modo de jogo.", + "Clipboard Up": "Área de transferência para cima", + "CLipboard Down": "Área de transferência para baixo", + "Clipboard Seamless": "Área de transferência perfeita", + "Prefer Local Cursor": "Preferir Cursor Local", + "Translate keyboard shortcuts": "Traduzir atalhos de teclado", + "Enable WebRTC UDP Transit": "Ativar trânsito UDP WebRTC", + "Enable WebP Compression": "Ativar compactação WebP", + "Enable Performance Stats": "Ativar estatísticas de desempenho", + "Enable Pointer Lock": "Ativar bloqueio do ponteiro", + "IME Input Mode": "Modo de entrada IME", + "Show Virtual Keyboard Control": "Mostrar controle de teclado virtual", + "Toggle Control Panel via Keystrokes": "Alternar painel de controle por meio de teclas", + "Render Native Resolution": "Renderizar resolução nativa", + "Keyboard Shortcuts": "Atalhos do teclado", + "Enable KasmVNC Keyboard Shortcuts": "Ativar atalhos de teclado KasmVNC", + "1 - Toggle Control Panel": "1 - Alternar painel de controle", + "2 - Toggle Game Pointer Mode": "2 - Alternar modo de ponteiro de jogo", + "3 - Toggle Pointer Lock": "3 - Alternar bloqueio do ponteiro", + "Stream Quality": "Qualidade da Transmissão", + "Preset Modes:": "Modos predefinidos:", + "Static": "Estático", + "Low": "Baixo", + "Medium": "Médio", + "High": "Alto", + "Extreme": "Extremo", + "Lossless": "Sem perdas", + "Custom": "Personalizado", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dinâmico", + "Off": "Desligado", + "On": "Sobre", + "Dynamic Quality Min:": "Qualidade dinâmica mínima:", + "Dynamic Quality Max:": "Qualidade dinâmica máxima:", + "Treat Lossless:": "Trate sem perdas:", + "Frame Rate:": "Taxa de quadros:", + "Video JPEG Quality:": "Qualidade JPEG de vídeo:", + "Video WEBP Quality:": "Qualidade WEBP de vídeo:", + "Video Area:": "Área de vídeo:", + "Video Time:": "Tempo do vídeo:", + "Video Out Time:": "Tempo de saída do vídeo:", + "Video Mode Width:": "Largura do modo de vídeo:", + "Video Mode Height:": "Altura do modo de vídeo:", + "Documentation": "Documentação", + "Drag Viewport": "Arrastar janela de visualização", + "KasmVNC encountered an error:": "KasmVNC encontrou um erro:" +} \ No newline at end of file diff --git a/app/locale/ro.json b/app/locale/ro.json new file mode 100644 index 0000000..0ffb05a --- /dev/null +++ b/app/locale/ro.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Se conectează...", + "Disconnecting...": "Se deconectează...", + "Reconnecting...": "Reconectare...", + "Internal error": "Eroare internă", + "Must set host": "Trebuie să setați gazda", + "Connected (encrypted) to ": "Conectat (criptat) la ", + "Connected (unencrypted) to ": "Conectat (necriptat) la ", + "Something went wrong, connection is closed": "Ceva a mers prost, conexiunea este închisă", + "Failed to connect to server": "Conectare eșuată la server", + "Disconnected": "Deconectat", + "New connection has been rejected with reason: ": "Noua conexiune a fost respinsă cu motiv: ", + "New connection has been rejected": "Noua conexiune a fost respinsă", + "Credentials are required": "Sunt necesare acreditări", + "Hide/Show the control bar": "Ascunde/Afișează bara de control", + "Drag": "Trage", + "Move/Drag Viewport": "Mutați/Trageți fereastra de vizualizare", + "Keyboard": "Tastatură", + "Show Keyboard": "Afișează tastatura", + "Extra keys": "Chei suplimentare", + "Show Extra Keys": "Afișați cheile suplimentare", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Comută Ctrl", + "Alt": "Alt", + "Toggle Alt": "Comută Alt", + "Toggle Windows": "Comută Windows", + "Windows": "Windows", + "Send Tab": "Trimite fila", + "Tab": "Fila", + "Esc": "Esc", + "Send Escape": "Trimite evadare", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Trimite Ctrl-Alt-Del", + "Shutdown/Reboot": "Oprire/Repornire", + "Shutdown/Reboot...": "Oprire/Repornire...", + "Power": "Putere", + "Shutdown": "Închide", + "Reboot": "Reporniți", + "Reset": "Resetare", + "Clipboard": "Clipboard", + "Clear": "Clar", + "Fullscreen": "Ecran complet", + "Settings": "Setări", + "Shared Mode": "Mod partajat", + "View Only": "Doar vizualizare", + "Clip to Window": "Clip la fereastră", + "Scaling Mode:": "Modul de scalare:", + "None": "Nici unul", + "Local Scaling": "Scalarea locală", + "Remote Resizing": "Redimensionare la distanță", + "Advanced": "Avansat", + "Quality:": "Calitate:", + "Compression level:": "Nivel de compresie:", + "Repeater ID:": "ID repetitor:", + "WebSocket": "WebSocket", + "Encrypt": "criptare", + "Host:": "Gazdă:", + "Port:": "Port:", + "Path:": "Cale:", + "Automatic Reconnect": "Reconectare automată", + "Reconnect Delay (ms):": "Întârziere reconectare (ms):", + "Show Dot when No Cursor": "Afișați punctul când nu există cursor", + "Logging:": "Logare:", + "Version:": "Versiune:", + "Disconnect": "Deconectat", + "Connect": "Conectați", + "Username:": "Nume de utilizator:", + "Password:": "Parola:", + "Send Credentials": "Trimiteți acreditări", + "Cancel": "Anulare", + "Keys": "Chei", + "Game Cursor Mode": "Modul cursor de joc", + "Press Esc Key to Exit Pointer Lock Mode": "Apăsați tasta Esc pentru a ieși din modul de blocare a indicatorului", + "Game Mode paused, click on screen to resume Game Mode.": "Modul de joc a fost întrerupt, faceți clic pe ecran pentru a relua modul de joc.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard fără sudură", + "Prefer Local Cursor": "Preferați cursorul local", + "Translate keyboard shortcuts": "Traduceți comenzile rapide de la tastatură", + "Enable WebRTC UDP Transit": "Activați tranzitul WebRTC UDP", + "Enable WebP Compression": "Activați compresia WebP", + "Enable Performance Stats": "Activați statisticile de performanță", + "Enable Pointer Lock": "Activați blocarea pointerului", + "IME Input Mode": "Mod de intrare IME", + "Show Virtual Keyboard Control": "Afișați controlul tastaturii virtuale", + "Toggle Control Panel via Keystrokes": "Comutați panoul de control prin apăsări de taste", + "Render Native Resolution": "Redare rezoluție nativă", + "Keyboard Shortcuts": "Comenzi rapide de la tastatură", + "Enable KasmVNC Keyboard Shortcuts": "Activați comenzile rapide de la tastatură KasmVNC", + "1 - Toggle Control Panel": "1 - Comutați panoul de control", + "2 - Toggle Game Pointer Mode": "2 - Comutați modul indicator de joc", + "3 - Toggle Pointer Lock": "3 - Comutați blocarea indicatorului", + "Stream Quality": "Calitatea fluxului", + "Preset Modes:": "Moduri presetate:", + "Static": "Static", + "Low": "Scăzut", + "Medium": "Mediu", + "High": "Înalt", + "Extreme": "Extrem", + "Lossless": "Fara pierderi", + "Custom": "Personalizat", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Autodinamic", + "Off": "Oprit", + "On": "Pe", + "Dynamic Quality Min:": "Calitate dinamică min:", + "Dynamic Quality Max:": "Calitate dinamică maximă:", + "Treat Lossless:": "Tratați fără pierderi:", + "Frame Rate:": "Rata de cadre:", + "Video JPEG Quality:": "Calitate JPEG video:", + "Video WEBP Quality:": "Calitate WEBP video:", + "Video Area:": "Zona video:", + "Video Time:": "Timp video:", + "Video Out Time:": "Timp de ieșire video:", + "Video Mode Width:": "Lățimea modului video:", + "Video Mode Height:": "Înălțimea modului video:", + "Documentation": "Documentație", + "Drag Viewport": "Trasați fereastra de vizualizare", + "KasmVNC encountered an error:": "KasmVNC a întâmpinat o eroare:" +} \ No newline at end of file diff --git a/app/locale/ro_RO.json b/app/locale/ro_RO.json new file mode 100644 index 0000000..0ffb05a --- /dev/null +++ b/app/locale/ro_RO.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Se conectează...", + "Disconnecting...": "Se deconectează...", + "Reconnecting...": "Reconectare...", + "Internal error": "Eroare internă", + "Must set host": "Trebuie să setați gazda", + "Connected (encrypted) to ": "Conectat (criptat) la ", + "Connected (unencrypted) to ": "Conectat (necriptat) la ", + "Something went wrong, connection is closed": "Ceva a mers prost, conexiunea este închisă", + "Failed to connect to server": "Conectare eșuată la server", + "Disconnected": "Deconectat", + "New connection has been rejected with reason: ": "Noua conexiune a fost respinsă cu motiv: ", + "New connection has been rejected": "Noua conexiune a fost respinsă", + "Credentials are required": "Sunt necesare acreditări", + "Hide/Show the control bar": "Ascunde/Afișează bara de control", + "Drag": "Trage", + "Move/Drag Viewport": "Mutați/Trageți fereastra de vizualizare", + "Keyboard": "Tastatură", + "Show Keyboard": "Afișează tastatura", + "Extra keys": "Chei suplimentare", + "Show Extra Keys": "Afișați cheile suplimentare", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Comută Ctrl", + "Alt": "Alt", + "Toggle Alt": "Comută Alt", + "Toggle Windows": "Comută Windows", + "Windows": "Windows", + "Send Tab": "Trimite fila", + "Tab": "Fila", + "Esc": "Esc", + "Send Escape": "Trimite evadare", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Trimite Ctrl-Alt-Del", + "Shutdown/Reboot": "Oprire/Repornire", + "Shutdown/Reboot...": "Oprire/Repornire...", + "Power": "Putere", + "Shutdown": "Închide", + "Reboot": "Reporniți", + "Reset": "Resetare", + "Clipboard": "Clipboard", + "Clear": "Clar", + "Fullscreen": "Ecran complet", + "Settings": "Setări", + "Shared Mode": "Mod partajat", + "View Only": "Doar vizualizare", + "Clip to Window": "Clip la fereastră", + "Scaling Mode:": "Modul de scalare:", + "None": "Nici unul", + "Local Scaling": "Scalarea locală", + "Remote Resizing": "Redimensionare la distanță", + "Advanced": "Avansat", + "Quality:": "Calitate:", + "Compression level:": "Nivel de compresie:", + "Repeater ID:": "ID repetitor:", + "WebSocket": "WebSocket", + "Encrypt": "criptare", + "Host:": "Gazdă:", + "Port:": "Port:", + "Path:": "Cale:", + "Automatic Reconnect": "Reconectare automată", + "Reconnect Delay (ms):": "Întârziere reconectare (ms):", + "Show Dot when No Cursor": "Afișați punctul când nu există cursor", + "Logging:": "Logare:", + "Version:": "Versiune:", + "Disconnect": "Deconectat", + "Connect": "Conectați", + "Username:": "Nume de utilizator:", + "Password:": "Parola:", + "Send Credentials": "Trimiteți acreditări", + "Cancel": "Anulare", + "Keys": "Chei", + "Game Cursor Mode": "Modul cursor de joc", + "Press Esc Key to Exit Pointer Lock Mode": "Apăsați tasta Esc pentru a ieși din modul de blocare a indicatorului", + "Game Mode paused, click on screen to resume Game Mode.": "Modul de joc a fost întrerupt, faceți clic pe ecran pentru a relua modul de joc.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard fără sudură", + "Prefer Local Cursor": "Preferați cursorul local", + "Translate keyboard shortcuts": "Traduceți comenzile rapide de la tastatură", + "Enable WebRTC UDP Transit": "Activați tranzitul WebRTC UDP", + "Enable WebP Compression": "Activați compresia WebP", + "Enable Performance Stats": "Activați statisticile de performanță", + "Enable Pointer Lock": "Activați blocarea pointerului", + "IME Input Mode": "Mod de intrare IME", + "Show Virtual Keyboard Control": "Afișați controlul tastaturii virtuale", + "Toggle Control Panel via Keystrokes": "Comutați panoul de control prin apăsări de taste", + "Render Native Resolution": "Redare rezoluție nativă", + "Keyboard Shortcuts": "Comenzi rapide de la tastatură", + "Enable KasmVNC Keyboard Shortcuts": "Activați comenzile rapide de la tastatură KasmVNC", + "1 - Toggle Control Panel": "1 - Comutați panoul de control", + "2 - Toggle Game Pointer Mode": "2 - Comutați modul indicator de joc", + "3 - Toggle Pointer Lock": "3 - Comutați blocarea indicatorului", + "Stream Quality": "Calitatea fluxului", + "Preset Modes:": "Moduri presetate:", + "Static": "Static", + "Low": "Scăzut", + "Medium": "Mediu", + "High": "Înalt", + "Extreme": "Extrem", + "Lossless": "Fara pierderi", + "Custom": "Personalizat", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Autodinamic", + "Off": "Oprit", + "On": "Pe", + "Dynamic Quality Min:": "Calitate dinamică min:", + "Dynamic Quality Max:": "Calitate dinamică maximă:", + "Treat Lossless:": "Tratați fără pierderi:", + "Frame Rate:": "Rata de cadre:", + "Video JPEG Quality:": "Calitate JPEG video:", + "Video WEBP Quality:": "Calitate WEBP video:", + "Video Area:": "Zona video:", + "Video Time:": "Timp video:", + "Video Out Time:": "Timp de ieșire video:", + "Video Mode Width:": "Lățimea modului video:", + "Video Mode Height:": "Înălțimea modului video:", + "Documentation": "Documentație", + "Drag Viewport": "Trasați fereastra de vizualizare", + "KasmVNC encountered an error:": "KasmVNC a întâmpinat o eroare:" +} \ No newline at end of file diff --git a/app/locale/ru.json b/app/locale/ru.json new file mode 100644 index 0000000..9f86b01 --- /dev/null +++ b/app/locale/ru.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Подключение...", + "Disconnecting...": "Отключение...", + "Reconnecting...": "Переподключение...", + "Internal error": "Внутренняя ошибка", + "Must set host": "Задайте имя сервера или IP", + "Connected (encrypted) to ": "Подключено (с шифрованием) к ", + "Connected (unencrypted) to ": "Подключено (без шифрования) к ", + "Something went wrong, connection is closed": "Что-то пошло не так, подключение разорвано", + "Failed to connect to server": "Ошибка подключения к серверу", + "Disconnected": "Отключено", + "New connection has been rejected with reason: ": "Подключиться не удалось: ", + "New connection has been rejected": "Подключиться не удалось", + "Password is required": "Требуется пароль", + "Hide/Show the control bar": "Скрыть/Показать контрольную панель", + "Move/Drag Viewport": "Переместить окно", + "viewport drag": "Переместить окно", + "Active Mouse Button": "Активировать кнопки мыши", + "No mousebutton": "Отключить кнопки мыши", + "Left mousebutton": "Левая кнопка мыши", + "Middle mousebutton": "Средняя кнопка мыши", + "Right mousebutton": "Правая кнопка мыши", + "Keyboard": "Клавиатура", + "Show Keyboard": "Показать клавиатуру", + "Extra keys": "Доп. кнопки", + "Show Extra Keys": "Показать дополнительные кнопки", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Передать нажатие Ctrl", + "Alt": "Alt", + "Toggle Alt": "Передать нажатие Alt", + "Toggle Windows": "Переключение вкладок", + "Windows": "Вкладка", + "Send Tab": "Передать нажатие Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Передать нажатие Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Передать нажатие Ctrl-Alt-Del", + "Shutdown/Reboot": "Выключить/Перезагрузить", + "Shutdown/Reboot...": "Выключить/Перезагрузить...", + "Power": "Питание", + "Shutdown": "Выключить", + "Reboot": "Перезагрузить", + "Reset": "Сброс", + "Clipboard": "Буфер обмена", + "Clear": "Очистить", + "Fullscreen": "Во весь экран", + "Settings": "Настройки", + "Shared Mode": "Общий режим", + "View Only": "Просмотр", + "Clip to Window": "В окно", + "Scaling Mode:": "Масштаб:", + "None": "Нет", + "Local Scaling": "Локльный масштаб", + "Remote Resizing": "Удаленный масштаб", + "Advanced": "Дополнительно", + "Repeater ID:": "Идентификатор ID:", + "WebSocket": "WebSocket", + "Encrypt": "Шифрование", + "Host:": "Сервер:", + "Port:": "Порт:", + "Path:": "Путь:", + "Automatic Reconnect": "Автоматическое переподключение", + "Reconnect Delay (ms):": "Задержка переподключения (мс):", + "Show Dot when No Cursor": "Показать точку вместо курсора", + "Logging:": "Лог:", + "Disconnect": "Отключение", + "Connect": "Подключение", + "Password:": "Пароль:", + "Send Password": "Пароль: ", + "Cancel": "Выход", + "Credentials are required": "Требуются учетные данные", + "Drag": "Тащить", + "Quality:": "Качество:", + "Compression level:": "Уровень сжатия:", + "Version:": "Версия:", + "Username:": "Имя пользователя:", + "Send Credentials": "Отправить учетные данные", + "Keys": "Ключи", + "Game Cursor Mode": "Режим игрового курсора", + "Press Esc Key to Exit Pointer Lock Mode": "Нажмите клавишу Esc, чтобы выйти из режима блокировки указателя", + "Game Mode paused, click on screen to resume Game Mode.": "Игровой режим приостановлен, нажмите на экран, чтобы возобновить игровой режим.", + "Clipboard Up": "Буфер обмена вверх", + "CLipboard Down": "Буфер обмена вниз", + "Clipboard Seamless": "Буфер обмена бесшовный", + "Prefer Local Cursor": "Предпочитать локальный курсор", + "Translate keyboard shortcuts": "Перевести сочетания клавиш", + "Enable WebRTC UDP Transit": "Включить UDP-транзит WebRTC", + "Enable WebP Compression": "Включить сжатие WebP", + "Enable Performance Stats": "Включить статистику производительности", + "Enable Pointer Lock": "Включить блокировку указателя", + "IME Input Mode": "Режим ввода IME", + "Show Virtual Keyboard Control": "Показать управление виртуальной клавиатурой", + "Toggle Control Panel via Keystrokes": "Переключить панель управления с помощью клавиш", + "Render Native Resolution": "Визуализировать исходное разрешение", + "Keyboard Shortcuts": "Горячие клавиши", + "Enable KasmVNC Keyboard Shortcuts": "Включить сочетания клавиш KasmVNC", + "1 - Toggle Control Panel": "1 - Переключить панель управления", + "2 - Toggle Game Pointer Mode": "2 - Переключить режим указателя игры", + "3 - Toggle Pointer Lock": "3 — Переключить блокировку указателя", + "Stream Quality": "Качество трансляции", + "Preset Modes:": "Предустановленные режимы:", + "Static": "Статический", + "Low": "Низкий", + "Medium": "Середина", + "High": "Высокий", + "Extreme": "Экстрим", + "Lossless": "Без потерь", + "Custom": "Обычай", + "Anti-Aliasing:": "Сглаживание:", + "Auto Dynamic": "Автодинамический", + "Off": "Выключенный", + "On": "На", + "Dynamic Quality Min:": "Динамическое качество Мин:", + "Dynamic Quality Max:": "Динамическое качество макс.:", + "Treat Lossless:": "Лечить без потерь:", + "Frame Rate:": "Частота кадров:", + "Video JPEG Quality:": "Качество видео в формате JPEG:", + "Video WEBP Quality:": "Качество видео WEBP:", + "Video Area:": "Область видео:", + "Video Time:": "Время видео:", + "Video Out Time:": "Время выхода видео:", + "Video Mode Width:": "Ширина видеорежима:", + "Video Mode Height:": "Высота режима видео:", + "Documentation": "Документация", + "Drag Viewport": "Перетаскивание видового экрана", + "KasmVNC encountered an error:": "KasmVNC обнаружил ошибку:" +} \ No newline at end of file diff --git a/app/locale/ru_RU.json b/app/locale/ru_RU.json new file mode 100644 index 0000000..9f86b01 --- /dev/null +++ b/app/locale/ru_RU.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Подключение...", + "Disconnecting...": "Отключение...", + "Reconnecting...": "Переподключение...", + "Internal error": "Внутренняя ошибка", + "Must set host": "Задайте имя сервера или IP", + "Connected (encrypted) to ": "Подключено (с шифрованием) к ", + "Connected (unencrypted) to ": "Подключено (без шифрования) к ", + "Something went wrong, connection is closed": "Что-то пошло не так, подключение разорвано", + "Failed to connect to server": "Ошибка подключения к серверу", + "Disconnected": "Отключено", + "New connection has been rejected with reason: ": "Подключиться не удалось: ", + "New connection has been rejected": "Подключиться не удалось", + "Password is required": "Требуется пароль", + "Hide/Show the control bar": "Скрыть/Показать контрольную панель", + "Move/Drag Viewport": "Переместить окно", + "viewport drag": "Переместить окно", + "Active Mouse Button": "Активировать кнопки мыши", + "No mousebutton": "Отключить кнопки мыши", + "Left mousebutton": "Левая кнопка мыши", + "Middle mousebutton": "Средняя кнопка мыши", + "Right mousebutton": "Правая кнопка мыши", + "Keyboard": "Клавиатура", + "Show Keyboard": "Показать клавиатуру", + "Extra keys": "Доп. кнопки", + "Show Extra Keys": "Показать дополнительные кнопки", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Передать нажатие Ctrl", + "Alt": "Alt", + "Toggle Alt": "Передать нажатие Alt", + "Toggle Windows": "Переключение вкладок", + "Windows": "Вкладка", + "Send Tab": "Передать нажатие Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Передать нажатие Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Передать нажатие Ctrl-Alt-Del", + "Shutdown/Reboot": "Выключить/Перезагрузить", + "Shutdown/Reboot...": "Выключить/Перезагрузить...", + "Power": "Питание", + "Shutdown": "Выключить", + "Reboot": "Перезагрузить", + "Reset": "Сброс", + "Clipboard": "Буфер обмена", + "Clear": "Очистить", + "Fullscreen": "Во весь экран", + "Settings": "Настройки", + "Shared Mode": "Общий режим", + "View Only": "Просмотр", + "Clip to Window": "В окно", + "Scaling Mode:": "Масштаб:", + "None": "Нет", + "Local Scaling": "Локльный масштаб", + "Remote Resizing": "Удаленный масштаб", + "Advanced": "Дополнительно", + "Repeater ID:": "Идентификатор ID:", + "WebSocket": "WebSocket", + "Encrypt": "Шифрование", + "Host:": "Сервер:", + "Port:": "Порт:", + "Path:": "Путь:", + "Automatic Reconnect": "Автоматическое переподключение", + "Reconnect Delay (ms):": "Задержка переподключения (мс):", + "Show Dot when No Cursor": "Показать точку вместо курсора", + "Logging:": "Лог:", + "Disconnect": "Отключение", + "Connect": "Подключение", + "Password:": "Пароль:", + "Send Password": "Пароль: ", + "Cancel": "Выход", + "Credentials are required": "Требуются учетные данные", + "Drag": "Тащить", + "Quality:": "Качество:", + "Compression level:": "Уровень сжатия:", + "Version:": "Версия:", + "Username:": "Имя пользователя:", + "Send Credentials": "Отправить учетные данные", + "Keys": "Ключи", + "Game Cursor Mode": "Режим игрового курсора", + "Press Esc Key to Exit Pointer Lock Mode": "Нажмите клавишу Esc, чтобы выйти из режима блокировки указателя", + "Game Mode paused, click on screen to resume Game Mode.": "Игровой режим приостановлен, нажмите на экран, чтобы возобновить игровой режим.", + "Clipboard Up": "Буфер обмена вверх", + "CLipboard Down": "Буфер обмена вниз", + "Clipboard Seamless": "Буфер обмена бесшовный", + "Prefer Local Cursor": "Предпочитать локальный курсор", + "Translate keyboard shortcuts": "Перевести сочетания клавиш", + "Enable WebRTC UDP Transit": "Включить UDP-транзит WebRTC", + "Enable WebP Compression": "Включить сжатие WebP", + "Enable Performance Stats": "Включить статистику производительности", + "Enable Pointer Lock": "Включить блокировку указателя", + "IME Input Mode": "Режим ввода IME", + "Show Virtual Keyboard Control": "Показать управление виртуальной клавиатурой", + "Toggle Control Panel via Keystrokes": "Переключить панель управления с помощью клавиш", + "Render Native Resolution": "Визуализировать исходное разрешение", + "Keyboard Shortcuts": "Горячие клавиши", + "Enable KasmVNC Keyboard Shortcuts": "Включить сочетания клавиш KasmVNC", + "1 - Toggle Control Panel": "1 - Переключить панель управления", + "2 - Toggle Game Pointer Mode": "2 - Переключить режим указателя игры", + "3 - Toggle Pointer Lock": "3 — Переключить блокировку указателя", + "Stream Quality": "Качество трансляции", + "Preset Modes:": "Предустановленные режимы:", + "Static": "Статический", + "Low": "Низкий", + "Medium": "Середина", + "High": "Высокий", + "Extreme": "Экстрим", + "Lossless": "Без потерь", + "Custom": "Обычай", + "Anti-Aliasing:": "Сглаживание:", + "Auto Dynamic": "Автодинамический", + "Off": "Выключенный", + "On": "На", + "Dynamic Quality Min:": "Динамическое качество Мин:", + "Dynamic Quality Max:": "Динамическое качество макс.:", + "Treat Lossless:": "Лечить без потерь:", + "Frame Rate:": "Частота кадров:", + "Video JPEG Quality:": "Качество видео в формате JPEG:", + "Video WEBP Quality:": "Качество видео WEBP:", + "Video Area:": "Область видео:", + "Video Time:": "Время видео:", + "Video Out Time:": "Время выхода видео:", + "Video Mode Width:": "Ширина видеорежима:", + "Video Mode Height:": "Высота режима видео:", + "Documentation": "Документация", + "Drag Viewport": "Перетаскивание видового экрана", + "KasmVNC encountered an error:": "KasmVNC обнаружил ошибку:" +} \ No newline at end of file diff --git a/app/locale/ru_UA.json b/app/locale/ru_UA.json new file mode 100644 index 0000000..9f86b01 --- /dev/null +++ b/app/locale/ru_UA.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Подключение...", + "Disconnecting...": "Отключение...", + "Reconnecting...": "Переподключение...", + "Internal error": "Внутренняя ошибка", + "Must set host": "Задайте имя сервера или IP", + "Connected (encrypted) to ": "Подключено (с шифрованием) к ", + "Connected (unencrypted) to ": "Подключено (без шифрования) к ", + "Something went wrong, connection is closed": "Что-то пошло не так, подключение разорвано", + "Failed to connect to server": "Ошибка подключения к серверу", + "Disconnected": "Отключено", + "New connection has been rejected with reason: ": "Подключиться не удалось: ", + "New connection has been rejected": "Подключиться не удалось", + "Password is required": "Требуется пароль", + "Hide/Show the control bar": "Скрыть/Показать контрольную панель", + "Move/Drag Viewport": "Переместить окно", + "viewport drag": "Переместить окно", + "Active Mouse Button": "Активировать кнопки мыши", + "No mousebutton": "Отключить кнопки мыши", + "Left mousebutton": "Левая кнопка мыши", + "Middle mousebutton": "Средняя кнопка мыши", + "Right mousebutton": "Правая кнопка мыши", + "Keyboard": "Клавиатура", + "Show Keyboard": "Показать клавиатуру", + "Extra keys": "Доп. кнопки", + "Show Extra Keys": "Показать дополнительные кнопки", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Передать нажатие Ctrl", + "Alt": "Alt", + "Toggle Alt": "Передать нажатие Alt", + "Toggle Windows": "Переключение вкладок", + "Windows": "Вкладка", + "Send Tab": "Передать нажатие Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Передать нажатие Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Передать нажатие Ctrl-Alt-Del", + "Shutdown/Reboot": "Выключить/Перезагрузить", + "Shutdown/Reboot...": "Выключить/Перезагрузить...", + "Power": "Питание", + "Shutdown": "Выключить", + "Reboot": "Перезагрузить", + "Reset": "Сброс", + "Clipboard": "Буфер обмена", + "Clear": "Очистить", + "Fullscreen": "Во весь экран", + "Settings": "Настройки", + "Shared Mode": "Общий режим", + "View Only": "Просмотр", + "Clip to Window": "В окно", + "Scaling Mode:": "Масштаб:", + "None": "Нет", + "Local Scaling": "Локльный масштаб", + "Remote Resizing": "Удаленный масштаб", + "Advanced": "Дополнительно", + "Repeater ID:": "Идентификатор ID:", + "WebSocket": "WebSocket", + "Encrypt": "Шифрование", + "Host:": "Сервер:", + "Port:": "Порт:", + "Path:": "Путь:", + "Automatic Reconnect": "Автоматическое переподключение", + "Reconnect Delay (ms):": "Задержка переподключения (мс):", + "Show Dot when No Cursor": "Показать точку вместо курсора", + "Logging:": "Лог:", + "Disconnect": "Отключение", + "Connect": "Подключение", + "Password:": "Пароль:", + "Send Password": "Пароль: ", + "Cancel": "Выход", + "Credentials are required": "Требуются учетные данные", + "Drag": "Тащить", + "Quality:": "Качество:", + "Compression level:": "Уровень сжатия:", + "Version:": "Версия:", + "Username:": "Имя пользователя:", + "Send Credentials": "Отправить учетные данные", + "Keys": "Ключи", + "Game Cursor Mode": "Режим игрового курсора", + "Press Esc Key to Exit Pointer Lock Mode": "Нажмите клавишу Esc, чтобы выйти из режима блокировки указателя", + "Game Mode paused, click on screen to resume Game Mode.": "Игровой режим приостановлен, нажмите на экран, чтобы возобновить игровой режим.", + "Clipboard Up": "Буфер обмена вверх", + "CLipboard Down": "Буфер обмена вниз", + "Clipboard Seamless": "Буфер обмена бесшовный", + "Prefer Local Cursor": "Предпочитать локальный курсор", + "Translate keyboard shortcuts": "Перевести сочетания клавиш", + "Enable WebRTC UDP Transit": "Включить UDP-транзит WebRTC", + "Enable WebP Compression": "Включить сжатие WebP", + "Enable Performance Stats": "Включить статистику производительности", + "Enable Pointer Lock": "Включить блокировку указателя", + "IME Input Mode": "Режим ввода IME", + "Show Virtual Keyboard Control": "Показать управление виртуальной клавиатурой", + "Toggle Control Panel via Keystrokes": "Переключить панель управления с помощью клавиш", + "Render Native Resolution": "Визуализировать исходное разрешение", + "Keyboard Shortcuts": "Горячие клавиши", + "Enable KasmVNC Keyboard Shortcuts": "Включить сочетания клавиш KasmVNC", + "1 - Toggle Control Panel": "1 - Переключить панель управления", + "2 - Toggle Game Pointer Mode": "2 - Переключить режим указателя игры", + "3 - Toggle Pointer Lock": "3 — Переключить блокировку указателя", + "Stream Quality": "Качество трансляции", + "Preset Modes:": "Предустановленные режимы:", + "Static": "Статический", + "Low": "Низкий", + "Medium": "Середина", + "High": "Высокий", + "Extreme": "Экстрим", + "Lossless": "Без потерь", + "Custom": "Обычай", + "Anti-Aliasing:": "Сглаживание:", + "Auto Dynamic": "Автодинамический", + "Off": "Выключенный", + "On": "На", + "Dynamic Quality Min:": "Динамическое качество Мин:", + "Dynamic Quality Max:": "Динамическое качество макс.:", + "Treat Lossless:": "Лечить без потерь:", + "Frame Rate:": "Частота кадров:", + "Video JPEG Quality:": "Качество видео в формате JPEG:", + "Video WEBP Quality:": "Качество видео WEBP:", + "Video Area:": "Область видео:", + "Video Time:": "Время видео:", + "Video Out Time:": "Время выхода видео:", + "Video Mode Width:": "Ширина видеорежима:", + "Video Mode Height:": "Высота режима видео:", + "Documentation": "Документация", + "Drag Viewport": "Перетаскивание видового экрана", + "KasmVNC encountered an error:": "KasmVNC обнаружил ошибку:" +} \ No newline at end of file diff --git a/app/locale/sd.json b/app/locale/sd.json new file mode 100644 index 0000000..b45614c --- /dev/null +++ b/app/locale/sd.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻱﺪﻨﻳﮃﻨﮘ", + "Disconnecting...": " ﻲﻫﺁ ﻮﻴﻫﺭ ﻲﭤ ﻊﻄﻘﻨﻣ", + "Reconnecting...": " ﻲﻫﺁ ﻮﻴﻫﺭ ﻱﮃﻨﮘ ﺮﻬﻴﭔ", + "Internal error": "ﻲﻄﻠﻏ ﻲﻧﻭﺭﺪﻧﺍ", + "Must set host": "ﻲﺟﺮﻬﮔ ﮠﺮڪ ﺭﺮﻘﻣ ﻥﺎﺑﺰﻴﻣ", + "Connected (encrypted) to ": "ﻥﺎﺳ (ﻞﻴﭤ ٽﭘﺮڪﻧﺍ) ڪﻠﺴﻨﻣ", + "Connected (unencrypted) to ": "ﻥﺎﺳ (ﻞﻳﮃﻨﮘ ﮠﺍ) ﻞﻳﮃﻨﮘ", + "Something went wrong, connection is closed": "ﻲﻫﺁ ﺪﻨﺑ ﻦﺸڪﻴﻨڪ ،ﻮﻳﻭ ﻲﭤ ﻂﻠﻏ ﻪﻬﺠڪ", + "Failed to connect to server": "ﻮﻴﭤ ﻡﺎڪﺎﻧ ۾ ﮠﮃﻨﮘ ﻥﺎﺳ ﺭﻭﺮﺳ", + "Disconnected": "ﻊﻄﻘﻨﻣ", + "New connection has been rejected with reason: ": "ﻲﻫﺁ ﻮﻳﻭ ﻮﻴڪ ﺩﺭ ﺐﺒﺳ ﻦﺸڪﻴﻨڪ ﻦﻴﺌﻧ", + "New connection has been rejected": "ﻲﻫﺁ ﻮﻳﻭ ﻮﻴڪ ﺩﺭ ﻦﺸڪﻴﻨڪ ﻥﻮﺌﻧ", + "Credentials are required": "ﻲﻫﺁ ﺕﺭﻭﺮﺿ ﻲﺟ ﻦﭤﺎﺳ", + "Hide/Show the control bar": "ﺭﺎﺑ ﻝﻭﺮٽﻨڪ ﻮﻳﺭﺎﮑﻳڏ / ﻮﻳﺎڪﻟ", + "Drag": "ﻮﻳڏﮀ", + "Move/Drag Viewport": "ٽﺭﻮﭘ ﻮﺌﻳڏ ﻮﻴڪﮀ / ﻞﻘﺘﻨﻣ", + "Keyboard": "ڊﺭﻮﺑ ﻲڪ", + "Show Keyboard": "ﻮﻳﺭﺎﮑﻳڏ ڊﺭﻮﺑ ﻲڪ", + "Extra keys": "ﻥﻮﻴﺑﺎﭼ ﻲﻓﺎﺿﺍ", + "Show Extra Keys": "ﻮﻳﺭﺎﮑﻳڏ ﻥﻮﻴﺑﺎﭼ ﻲﻓﺎﺿﺍ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ﻞﮕٽ", + "Alt": "Alt", + "Toggle Alt": "Alt ﻞﮕٽ", + "Toggle Windows": "ﻮﻳﺮڪ ﻞﮔﻮٽ ﻲﮐ ﺯﻭڊﻧﻭ", + "Windows": "ﺯﻭڊﻧﻭ", + "Send Tab": "ﻮﻴﻠڪﻮﻣ ﺐﻴٽ", + "Tab": "ﺐﻴٽ", + "Esc": "Esc", + "Send Escape": "ﻮﻴﻠڪﻮﻣ ﺭﺍﺮﻓ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻮﻴﻠڪﻮﻣ", + "Shutdown/Reboot": "ٽﻮﺒﻳﺭ / ﺪﻨﺑ", + "Shutdown/Reboot...": " ٽﻮﺒﻳﺭ / ﺪﻨﺑ", + "Power": "ﺖﻗﺎﻃ", + "Shutdown": "ﻮﻳﺮڪ ﺪﻨﺑ", + "Reboot": "ٽﻮﺒﻳﺭ", + "Reset": "ﻮﻳﺮڪ ٽﻴﺳ ﺮﻬﻴﭔ", + "Clipboard": "ڊﺭﻮﺑ ﭗﻠڪ", + "Clear": "ﻑﺎﺻ", + "Fullscreen": "ﻦﻳﺮڪﺳﺍ ﻞﻤڪﻣ", + "Settings": "ﻥﻮﮕﻨٽﻴﺳ", + "Shared Mode": "ڊﻮﻣ ﻞﻴﭤ ﺮﺌﻴﺷ", + "View Only": "ﻮﺳڏ ﻑﺮﺻ", + "Clip to Window": "ﭗﻠڪ ﻦﻬﻧﺍڏ ﻭڊﻧﻭ", + "Scaling Mode:": "ڊﻮﻣ ﮓﻨﻠﻴڪﺳﺍ", + "None": "ﻪﻧ ﻪﺑ ﻮڪ", + "Local Scaling": "ﮓﻨﻠﻴڪﺳﺍ ﻲﻣﺎﻘﻣ", + "Remote Resizing": "ﮓﻧﺰﻴﺋﺎﺴﻳﺭ ٽﻮﻤﻳﺭ", + "Advanced": "ﻪﺘﻓﺎﻳ ﻲﻗﺮﺗ", + "Quality:": "ﺭﺎﻴﻌﻣ", + "Compression level:": "ﺢﻄﺳ ﻦﺸﻳﺮﭙﻤﮐ", + "Repeater ID:": "ID ﺮٽﻴﭙﻳﺭ", + "WebSocket": "ٽﮐﺎﺳ ﺐﻳﻭ", + "Encrypt": "ٽﭘﺮڪﻧﺍ", + "Host:": "ﻥﺎﺑﺰﻴﻣ", + "Port:": "ٽﺭﻮﭘ", + "Path:": "ﻮﺘﺳﺭ", + "Automatic Reconnect": "ﻮﻳﮃﻨﮘ ﺮﻬﻴﭔ ﺭﺎڪﺩﻮﺧ", + "Reconnect Delay (ms):": "(ms) ﺮﻳﺩ ﻮﻳﮃﻨﮘ ﺮﻬﻴﭔ", + "Show Dot when No Cursor": "ﻮﻳﺭﺎﮑﻳڏ ٽڊ ﻲﮬﺁ ﻪﻧ ﺮﺴڪ ﻦﮬڏﺟ", + "Logging:": "ﮓﻨﮔﻻ", + "Version:": "ﺦﺴﻧ", + "Disconnect": "ﻮﻳﮃﻨﮘ", + "Connect": "ﻮﻳﮃﻨﮘ", + "Username:": "ﻮﻟﺎﻧ ﻮﺟ ڙﺪﻨڪ ﻝﺎﻤﻌﺘﺳﺍ", + "Password:": "ڊﺭﻮﺳﺎﭘ", + "Send Credentials": "ﻮﻴﻠڪﻮﻣ ﭗﮢﺎﭹﺳ", + "Cancel": "ﺥﻮﺴﻨﻣ", + "Keys": "ﻲﭔﺎﭼ", + "Game Cursor Mode": "ڊﻮﻣ ﺮﺳﺮڪ ﺪﻧﺍﺭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﻮﻳﺎﭔﺩ ﻲﮐ ﻲﺌﻴڪ Esc ءِﻻ ﮠﺮڪﻧ ﻥﺎﻣ ڊﻮﻣ ڪﻻ ﺮٽﻨﺋﺎﭘ", + "Game Mode paused, click on screen to resume Game Mode.": "ﻮﻳﺮڪ ڪﻠڪ ﻲﺗ ﻦﻳﺮڪﺳﺍ ءﻻ ﮠﺮڪ ﻉﻭﺮﺷ ﺮﻬﻴﭔ ﻲﮐ ڊﻮﻣ ﺪﻧﺍﺭ ،ﻮﻳﻭ ﻮﻴڪﻭﺭ ڊﻮﻣ ﺪﻧﺍﺭ", + "Clipboard Up": "ﻲﭥﻣ ڊﺭﻮﺑ ﭗﻠڪ", + "CLipboard Down": "ﭟﻴﻫ ڊﺭﻮﺑ ﭗﻠڪ", + "Clipboard Seamless": "ﺪﺤﻴﺑ ڊﺭﻮﺑ ﭗﻠڪ", + "Prefer Local Cursor": "ﻮﻳڏ ﺢﻴﺟﺮﺗ ﻲﮐ ﺮﺴڪ ﻲﻣﺎﻘﻣ", + "Translate keyboard shortcuts": "ﻮﻳﺮڪ ﻮﻤﺟﺮﺗ ﻮﺟ ﺲٽڪ ٽﺭﺎﺷ ڊﺭﻮﺑ ﻲڪ", + "Enable WebRTC UDP Transit": "WebRTC UDP ﻮﻳﺮڪ ﻝﺎﻌﻓ ﻲﮐ ٽﺰﻧﺍﺮٽ", + "Enable WebP Compression": "WebP ﻮﻳﺮڪ ﻝﺎﻌﻓ ﻲﮐ ﻦﺸﻳﺮﭙﻤﮐ", + "Enable Performance Stats": "ﻮﻳﺮڪ ﻝﺎﻌﻓ ﻲﮐ ﻥﺮﮐﺍ ﻦﮕﻧﺍ ﻲﺟ ﻲﮔﺩﺮڪﺭﺎڪ", + "Enable Pointer Lock": "ﻮﻳﺮڪ ﻝﺎﻌﻓ ﻲﮐ ﮎﻻ ﺮٽﻨﺋﺍﻮﭘ", + "IME Input Mode": "IME ڊﻮﻣ ٽﭘ ﻥﺍ", + "Show Virtual Keyboard Control": "ﻮﻳﺭﺎﮑﻳڏ ﻝﻭﺮٽﻨڪ ڊﺭﻮﺑ ﻲڪ ﻞﺋﻮﭼﺭﻭ", + "Toggle Control Panel via Keystrokes": "ﻮﻳﺮڪ ﻞﮔﻮٽ ﻲﮐ ﻞﻨﻴﭘ ﻝﻭﺮٽﻨڪ ﻲﻌﻳﺭﺫ ڪﻭﺮٽﺳﺍ ﻲڪ", + "Render Native Resolution": "ﻮﻳﺮڪ ﺶﻴﭘ ﺩﺍﺩﺭﺍﺮﻗ ﻲﻣﺎﻘﻣ", + "Keyboard Shortcuts": "ﺲٽڪ ٽﺭﺎﺷ ڊﺭﻮﺑ ﻲڪ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﻮﻳﺮڪ ﻝﺎﻌﻓ ﻲﮐ ﺲٽڪ ٽﺭﺎﺷ ڊﺭﻮﺑ ﻲڪ", + "1 - Toggle Control Panel": "ﻮﻳﺮڪ ﻞﮔﻮٽ ﻲﮐ ﻞﻨﻴﭘ ﻝﻭﺮٽﻨڪ - 1", + "2 - Toggle Game Pointer Mode": "ڊﻮﻣ ﺮٽﻨﺋﺍﻮﭘ ﻢﻴﮔ ﻞﮔﻮٽ - 2", + "3 - Toggle Pointer Lock": "ڪﻻ ﺮٽﻨﺋﺍﻮﭘ ﻞﮔﻮٽ - 3", + "Stream Quality": "ﺭﺎﻴﻌﻣ ﻢﻳﺮٽﺳﺍ", + "Preset Modes:": "ﺱڊﻮﻣ ﻲﮢﻮﮘﺍ", + "Static": "ﺪﻣﺎﺟ", + "Low": "ٽﻬﮔ", + "Medium": "ﻲﻟﻮﭼﻭ", + "High": "ﺪﻨﻠﺑ", + "Extreme": "ﻲﺋﺎﻬﺘﻧﺍ", + "Lossless": "ﻥﺎﺼﻘﻧ ﻲﺑ", + "Custom": "ﻲﺿﺮﻣ", + "Anti-Aliasing:": "Aliasing ﻒﻟﺎﺨﻣ:", + "Auto Dynamic": "ڪﺮﺤﺘﻣ ﺭﺎڪﺩﻮﺧ", + "Off": "ﺪﻨﺑ", + "On": "ﻲﺗ", + "Dynamic Quality Min:": "ٽﻨﻣ ﺭﺎﻴﻌﻣ ڪﺮﺤﺘﻣ", + "Dynamic Quality Max:": "ﮄﻭ ۾ ﮄﻭ ﺭﺎﻴﻌﻣ ڪﺮﺤﺘﻣ", + "Treat Lossless:": "ﻮﻳﺮڪ ﺝﻼﻋ ﻮﺟ ﻥﺎﺼﻘﻧ ﻲﺑ", + "Frame Rate:": "ﺡﺮﺷ ﻲﺟ ﻢﻳﺮﻓ", + "Video JPEG Quality:": "ﺭﺎﻴﻌﻣ JPEG ﻮﻳڊﻳﻭ", + "Video WEBP Quality:": "ﺭﺎﻴﻌﻣ WEBP ﻮﻳڊﻳﻭ", + "Video Area:": "ﺎﻳﺮﻳﺍ ﻮﻳڊﻭ", + "Video Time:": "ﺖﻗﻭ ﻮﻳڊﻭ", + "Video Out Time:": "ﺖﻗﻭ ﻮﺟ ﮡﻴﭤ ﻢﺘﺧ ﻮﻳڊﻭ", + "Video Mode Width:": "ﺮڪﻳﻭ ڊﻮﻣ ﻮﻳڊﻭ", + "Video Mode Height:": "ﻲﺋﺎﭽﻧﻭﺍ ڊﻮﻣ ﻮﻳڊﻭ", + "Documentation": "ﺰﻳﻭﺎﺘﺳﺩ", + "Drag Viewport": "ٽﺭﻮﭘ ﻮﺌﻳڏ ﻮﻳڏﮀ", + "KasmVNC encountered an error:": "KasmVNC ﻮﻴڪ ﻦﻬﻨﻣ ﻥﺎﺳ ﻲﻄﻠﻏ ڪﻫ:" +} \ No newline at end of file diff --git a/app/locale/sd_IN.json b/app/locale/sd_IN.json new file mode 100644 index 0000000..b45614c --- /dev/null +++ b/app/locale/sd_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﻱﺪﻨﻳﮃﻨﮘ", + "Disconnecting...": " ﻲﻫﺁ ﻮﻴﻫﺭ ﻲﭤ ﻊﻄﻘﻨﻣ", + "Reconnecting...": " ﻲﻫﺁ ﻮﻴﻫﺭ ﻱﮃﻨﮘ ﺮﻬﻴﭔ", + "Internal error": "ﻲﻄﻠﻏ ﻲﻧﻭﺭﺪﻧﺍ", + "Must set host": "ﻲﺟﺮﻬﮔ ﮠﺮڪ ﺭﺮﻘﻣ ﻥﺎﺑﺰﻴﻣ", + "Connected (encrypted) to ": "ﻥﺎﺳ (ﻞﻴﭤ ٽﭘﺮڪﻧﺍ) ڪﻠﺴﻨﻣ", + "Connected (unencrypted) to ": "ﻥﺎﺳ (ﻞﻳﮃﻨﮘ ﮠﺍ) ﻞﻳﮃﻨﮘ", + "Something went wrong, connection is closed": "ﻲﻫﺁ ﺪﻨﺑ ﻦﺸڪﻴﻨڪ ،ﻮﻳﻭ ﻲﭤ ﻂﻠﻏ ﻪﻬﺠڪ", + "Failed to connect to server": "ﻮﻴﭤ ﻡﺎڪﺎﻧ ۾ ﮠﮃﻨﮘ ﻥﺎﺳ ﺭﻭﺮﺳ", + "Disconnected": "ﻊﻄﻘﻨﻣ", + "New connection has been rejected with reason: ": "ﻲﻫﺁ ﻮﻳﻭ ﻮﻴڪ ﺩﺭ ﺐﺒﺳ ﻦﺸڪﻴﻨڪ ﻦﻴﺌﻧ", + "New connection has been rejected": "ﻲﻫﺁ ﻮﻳﻭ ﻮﻴڪ ﺩﺭ ﻦﺸڪﻴﻨڪ ﻥﻮﺌﻧ", + "Credentials are required": "ﻲﻫﺁ ﺕﺭﻭﺮﺿ ﻲﺟ ﻦﭤﺎﺳ", + "Hide/Show the control bar": "ﺭﺎﺑ ﻝﻭﺮٽﻨڪ ﻮﻳﺭﺎﮑﻳڏ / ﻮﻳﺎڪﻟ", + "Drag": "ﻮﻳڏﮀ", + "Move/Drag Viewport": "ٽﺭﻮﭘ ﻮﺌﻳڏ ﻮﻴڪﮀ / ﻞﻘﺘﻨﻣ", + "Keyboard": "ڊﺭﻮﺑ ﻲڪ", + "Show Keyboard": "ﻮﻳﺭﺎﮑﻳڏ ڊﺭﻮﺑ ﻲڪ", + "Extra keys": "ﻥﻮﻴﺑﺎﭼ ﻲﻓﺎﺿﺍ", + "Show Extra Keys": "ﻮﻳﺭﺎﮑﻳڏ ﻥﻮﻴﺑﺎﭼ ﻲﻓﺎﺿﺍ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ﻞﮕٽ", + "Alt": "Alt", + "Toggle Alt": "Alt ﻞﮕٽ", + "Toggle Windows": "ﻮﻳﺮڪ ﻞﮔﻮٽ ﻲﮐ ﺯﻭڊﻧﻭ", + "Windows": "ﺯﻭڊﻧﻭ", + "Send Tab": "ﻮﻴﻠڪﻮﻣ ﺐﻴٽ", + "Tab": "ﺐﻴٽ", + "Esc": "Esc", + "Send Escape": "ﻮﻴﻠڪﻮﻣ ﺭﺍﺮﻓ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﻮﻴﻠڪﻮﻣ", + "Shutdown/Reboot": "ٽﻮﺒﻳﺭ / ﺪﻨﺑ", + "Shutdown/Reboot...": " ٽﻮﺒﻳﺭ / ﺪﻨﺑ", + "Power": "ﺖﻗﺎﻃ", + "Shutdown": "ﻮﻳﺮڪ ﺪﻨﺑ", + "Reboot": "ٽﻮﺒﻳﺭ", + "Reset": "ﻮﻳﺮڪ ٽﻴﺳ ﺮﻬﻴﭔ", + "Clipboard": "ڊﺭﻮﺑ ﭗﻠڪ", + "Clear": "ﻑﺎﺻ", + "Fullscreen": "ﻦﻳﺮڪﺳﺍ ﻞﻤڪﻣ", + "Settings": "ﻥﻮﮕﻨٽﻴﺳ", + "Shared Mode": "ڊﻮﻣ ﻞﻴﭤ ﺮﺌﻴﺷ", + "View Only": "ﻮﺳڏ ﻑﺮﺻ", + "Clip to Window": "ﭗﻠڪ ﻦﻬﻧﺍڏ ﻭڊﻧﻭ", + "Scaling Mode:": "ڊﻮﻣ ﮓﻨﻠﻴڪﺳﺍ", + "None": "ﻪﻧ ﻪﺑ ﻮڪ", + "Local Scaling": "ﮓﻨﻠﻴڪﺳﺍ ﻲﻣﺎﻘﻣ", + "Remote Resizing": "ﮓﻧﺰﻴﺋﺎﺴﻳﺭ ٽﻮﻤﻳﺭ", + "Advanced": "ﻪﺘﻓﺎﻳ ﻲﻗﺮﺗ", + "Quality:": "ﺭﺎﻴﻌﻣ", + "Compression level:": "ﺢﻄﺳ ﻦﺸﻳﺮﭙﻤﮐ", + "Repeater ID:": "ID ﺮٽﻴﭙﻳﺭ", + "WebSocket": "ٽﮐﺎﺳ ﺐﻳﻭ", + "Encrypt": "ٽﭘﺮڪﻧﺍ", + "Host:": "ﻥﺎﺑﺰﻴﻣ", + "Port:": "ٽﺭﻮﭘ", + "Path:": "ﻮﺘﺳﺭ", + "Automatic Reconnect": "ﻮﻳﮃﻨﮘ ﺮﻬﻴﭔ ﺭﺎڪﺩﻮﺧ", + "Reconnect Delay (ms):": "(ms) ﺮﻳﺩ ﻮﻳﮃﻨﮘ ﺮﻬﻴﭔ", + "Show Dot when No Cursor": "ﻮﻳﺭﺎﮑﻳڏ ٽڊ ﻲﮬﺁ ﻪﻧ ﺮﺴڪ ﻦﮬڏﺟ", + "Logging:": "ﮓﻨﮔﻻ", + "Version:": "ﺦﺴﻧ", + "Disconnect": "ﻮﻳﮃﻨﮘ", + "Connect": "ﻮﻳﮃﻨﮘ", + "Username:": "ﻮﻟﺎﻧ ﻮﺟ ڙﺪﻨڪ ﻝﺎﻤﻌﺘﺳﺍ", + "Password:": "ڊﺭﻮﺳﺎﭘ", + "Send Credentials": "ﻮﻴﻠڪﻮﻣ ﭗﮢﺎﭹﺳ", + "Cancel": "ﺥﻮﺴﻨﻣ", + "Keys": "ﻲﭔﺎﭼ", + "Game Cursor Mode": "ڊﻮﻣ ﺮﺳﺮڪ ﺪﻧﺍﺭ", + "Press Esc Key to Exit Pointer Lock Mode": "ﻮﻳﺎﭔﺩ ﻲﮐ ﻲﺌﻴڪ Esc ءِﻻ ﮠﺮڪﻧ ﻥﺎﻣ ڊﻮﻣ ڪﻻ ﺮٽﻨﺋﺎﭘ", + "Game Mode paused, click on screen to resume Game Mode.": "ﻮﻳﺮڪ ڪﻠڪ ﻲﺗ ﻦﻳﺮڪﺳﺍ ءﻻ ﮠﺮڪ ﻉﻭﺮﺷ ﺮﻬﻴﭔ ﻲﮐ ڊﻮﻣ ﺪﻧﺍﺭ ،ﻮﻳﻭ ﻮﻴڪﻭﺭ ڊﻮﻣ ﺪﻧﺍﺭ", + "Clipboard Up": "ﻲﭥﻣ ڊﺭﻮﺑ ﭗﻠڪ", + "CLipboard Down": "ﭟﻴﻫ ڊﺭﻮﺑ ﭗﻠڪ", + "Clipboard Seamless": "ﺪﺤﻴﺑ ڊﺭﻮﺑ ﭗﻠڪ", + "Prefer Local Cursor": "ﻮﻳڏ ﺢﻴﺟﺮﺗ ﻲﮐ ﺮﺴڪ ﻲﻣﺎﻘﻣ", + "Translate keyboard shortcuts": "ﻮﻳﺮڪ ﻮﻤﺟﺮﺗ ﻮﺟ ﺲٽڪ ٽﺭﺎﺷ ڊﺭﻮﺑ ﻲڪ", + "Enable WebRTC UDP Transit": "WebRTC UDP ﻮﻳﺮڪ ﻝﺎﻌﻓ ﻲﮐ ٽﺰﻧﺍﺮٽ", + "Enable WebP Compression": "WebP ﻮﻳﺮڪ ﻝﺎﻌﻓ ﻲﮐ ﻦﺸﻳﺮﭙﻤﮐ", + "Enable Performance Stats": "ﻮﻳﺮڪ ﻝﺎﻌﻓ ﻲﮐ ﻥﺮﮐﺍ ﻦﮕﻧﺍ ﻲﺟ ﻲﮔﺩﺮڪﺭﺎڪ", + "Enable Pointer Lock": "ﻮﻳﺮڪ ﻝﺎﻌﻓ ﻲﮐ ﮎﻻ ﺮٽﻨﺋﺍﻮﭘ", + "IME Input Mode": "IME ڊﻮﻣ ٽﭘ ﻥﺍ", + "Show Virtual Keyboard Control": "ﻮﻳﺭﺎﮑﻳڏ ﻝﻭﺮٽﻨڪ ڊﺭﻮﺑ ﻲڪ ﻞﺋﻮﭼﺭﻭ", + "Toggle Control Panel via Keystrokes": "ﻮﻳﺮڪ ﻞﮔﻮٽ ﻲﮐ ﻞﻨﻴﭘ ﻝﻭﺮٽﻨڪ ﻲﻌﻳﺭﺫ ڪﻭﺮٽﺳﺍ ﻲڪ", + "Render Native Resolution": "ﻮﻳﺮڪ ﺶﻴﭘ ﺩﺍﺩﺭﺍﺮﻗ ﻲﻣﺎﻘﻣ", + "Keyboard Shortcuts": "ﺲٽڪ ٽﺭﺎﺷ ڊﺭﻮﺑ ﻲڪ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﻮﻳﺮڪ ﻝﺎﻌﻓ ﻲﮐ ﺲٽڪ ٽﺭﺎﺷ ڊﺭﻮﺑ ﻲڪ", + "1 - Toggle Control Panel": "ﻮﻳﺮڪ ﻞﮔﻮٽ ﻲﮐ ﻞﻨﻴﭘ ﻝﻭﺮٽﻨڪ - 1", + "2 - Toggle Game Pointer Mode": "ڊﻮﻣ ﺮٽﻨﺋﺍﻮﭘ ﻢﻴﮔ ﻞﮔﻮٽ - 2", + "3 - Toggle Pointer Lock": "ڪﻻ ﺮٽﻨﺋﺍﻮﭘ ﻞﮔﻮٽ - 3", + "Stream Quality": "ﺭﺎﻴﻌﻣ ﻢﻳﺮٽﺳﺍ", + "Preset Modes:": "ﺱڊﻮﻣ ﻲﮢﻮﮘﺍ", + "Static": "ﺪﻣﺎﺟ", + "Low": "ٽﻬﮔ", + "Medium": "ﻲﻟﻮﭼﻭ", + "High": "ﺪﻨﻠﺑ", + "Extreme": "ﻲﺋﺎﻬﺘﻧﺍ", + "Lossless": "ﻥﺎﺼﻘﻧ ﻲﺑ", + "Custom": "ﻲﺿﺮﻣ", + "Anti-Aliasing:": "Aliasing ﻒﻟﺎﺨﻣ:", + "Auto Dynamic": "ڪﺮﺤﺘﻣ ﺭﺎڪﺩﻮﺧ", + "Off": "ﺪﻨﺑ", + "On": "ﻲﺗ", + "Dynamic Quality Min:": "ٽﻨﻣ ﺭﺎﻴﻌﻣ ڪﺮﺤﺘﻣ", + "Dynamic Quality Max:": "ﮄﻭ ۾ ﮄﻭ ﺭﺎﻴﻌﻣ ڪﺮﺤﺘﻣ", + "Treat Lossless:": "ﻮﻳﺮڪ ﺝﻼﻋ ﻮﺟ ﻥﺎﺼﻘﻧ ﻲﺑ", + "Frame Rate:": "ﺡﺮﺷ ﻲﺟ ﻢﻳﺮﻓ", + "Video JPEG Quality:": "ﺭﺎﻴﻌﻣ JPEG ﻮﻳڊﻳﻭ", + "Video WEBP Quality:": "ﺭﺎﻴﻌﻣ WEBP ﻮﻳڊﻳﻭ", + "Video Area:": "ﺎﻳﺮﻳﺍ ﻮﻳڊﻭ", + "Video Time:": "ﺖﻗﻭ ﻮﻳڊﻭ", + "Video Out Time:": "ﺖﻗﻭ ﻮﺟ ﮡﻴﭤ ﻢﺘﺧ ﻮﻳڊﻭ", + "Video Mode Width:": "ﺮڪﻳﻭ ڊﻮﻣ ﻮﻳڊﻭ", + "Video Mode Height:": "ﻲﺋﺎﭽﻧﻭﺍ ڊﻮﻣ ﻮﻳڊﻭ", + "Documentation": "ﺰﻳﻭﺎﺘﺳﺩ", + "Drag Viewport": "ٽﺭﻮﭘ ﻮﺌﻳڏ ﻮﻳڏﮀ", + "KasmVNC encountered an error:": "KasmVNC ﻮﻴڪ ﻦﻬﻨﻣ ﻥﺎﺳ ﻲﻄﻠﻏ ڪﻫ:" +} \ No newline at end of file diff --git a/app/locale/si.json b/app/locale/si.json new file mode 100644 index 0000000..d149e14 --- /dev/null +++ b/app/locale/si.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "සම්බන්ධ වෙමින්...", + "Disconnecting...": "විසන්ධි කරමින්...", + "Reconnecting...": "නැවත සම්බන්ධ වෙමින්...", + "Internal error": "අභ්u200dයන්තර දෝෂය", + "Must set host": "ධාරකය සැකසිය යුතුය", + "Connected (encrypted) to ": "සම්බන්ධිත (සංකේතනය) වෙත", + "Connected (unencrypted) to ": "සම්බන්ධිත (සංකේතනය නොකළ)", + "Something went wrong, connection is closed": "යමක් වැරදී ඇත, සම්බන්ධතාවය වසා ඇත", + "Failed to connect to server": "සේවාදායකයට සම්බන්ධ වීමට අපොහොසත් විය", + "Disconnected": "විසන්ධි විය", + "New connection has been rejected with reason: ": "නව සම්බන්ධතාවය හේතු සහිතව ප්u200dරතික්ෂේප කර ඇත:", + "New connection has been rejected": "නව සම්බන්ධතාවය ප්u200dරතික්ෂේප කර ඇත", + "Credentials are required": "ඇත්තපත්u200dර අවශ්u200dයයි", + "Hide/Show the control bar": "පාලක තීරුව සඟවන්න/පෙන්වන්න", + "Drag": "අදින්න", + "Move/Drag Viewport": "වීව්පෝට් ගෙනයන්න/අදින්න", + "Keyboard": "යතුරු පුවරුව", + "Show Keyboard": "යතුරු පුවරුව පෙන්වන්න", + "Extra keys": "අමතර යතුරු", + "Show Extra Keys": "අමතර යතුරු පෙන්වන්න", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ටොගල් කරන්න", + "Alt": "Alt", + "Toggle Alt": "Alt ටොගල් කරන්න", + "Toggle Windows": "වින්ඩෝස් ටොගල් කරන්න", + "Windows": "වින්ඩෝස්", + "Send Tab": "යවන්න ටැබ්", + "Tab": "ටැබ්", + "Esc": "පිට වීම", + "Send Escape": "පලා යාම යවන්න", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del යවන්න", + "Shutdown/Reboot": "වසා දැමීම / නැවත ආරම්භ කිරීම", + "Shutdown/Reboot...": "වසා දැමීම / නැවත ආරම්භ කිරීම...", + "Power": "බලය", + "Shutdown": "වසා දමන්න", + "Reboot": "නැවත ආරම්භ කරන්න", + "Reset": "නැවත පිහිටුවන්න", + "Clipboard": "ක්ලිප්බෝඩ්", + "Clear": "පැහැදිලිව", + "Fullscreen": "පුන් තිරය", + "Settings": "සැකසුම්", + "Shared Mode": "බෙදාගත් මාදිලිය", + "View Only": "බලන්න පමණයි", + "Clip to Window": "කවුළුව වෙත ක්ලිප් කරන්න", + "Scaling Mode:": "පරිමාණ මාදිලිය:", + "None": "කිසිවක් නැත", + "Local Scaling": "දේශීය පරිමාණය", + "Remote Resizing": "දුරස්ථ ප්u200dරමාණය වෙනස් කිරීම", + "Advanced": "උසස්", + "Quality:": "ගුණාත්මක:", + "Compression level:": "සම්පීඩන මට්ටම:", + "Repeater ID:": "පුනරාවර්තන හැඳුනුම්පත:", + "WebSocket": "වෙබ්සොකට්", + "Encrypt": "සංකේතනය කරන්න", + "Host:": "සත්කාරක:", + "Port:": "වරාය:", + "Path:": "මාර්ගය:", + "Automatic Reconnect": "ස්වයංක්u200dරීය නැවත සම්බන්ධ කිරීම", + "Reconnect Delay (ms):": "ප්u200dරමාදය නැවත සම්බන්ධ කරන්න (ms):", + "Show Dot when No Cursor": "කර්සරය නොමැති විට තිත පෙන්වන්න", + "Logging:": "ලොග් කිරීම:", + "Version:": "පිටපත:", + "Disconnect": "විසන්ධි කරන්න", + "Connect": "සම්බන්ධ කරන්න", + "Username:": "පරිශීලක නාමය:", + "Password:": "මුරපදය:", + "Send Credentials": "ඇත්තපත්u200dර යවන්න", + "Cancel": "අවලංගු කරන්න", + "Keys": "යතුරු", + "Game Cursor Mode": "ගේම් කර්සර මාදිලිය", + "Press Esc Key to Exit Pointer Lock Mode": "Pointer Lock Mode එකෙන් පිටවීමට Esc යතුර ඔබන්න", + "Game Mode paused, click on screen to resume Game Mode.": "ක්u200dරීඩා ප්u200dරකාරය විරාම කරන ලදී, ක්u200dරීඩා ප්u200dරකාරය නැවත ආරම්භ කිරීමට තිරය මත ක්ලික් කරන්න.", + "Clipboard Up": "ක්ලිප්බෝඩ් ඉහළට", + "CLipboard Down": "ක්ලිප්බෝඩ් පහලට", + "Clipboard Seamless": "ක්ලිප්බෝඩ් බාධාවකින් තොරව", + "Prefer Local Cursor": "දේශීය කර්සරය කැමති", + "Translate keyboard shortcuts": "යතුරු පුවරු කෙටිමං පරිවර්තනය කරන්න", + "Enable WebRTC UDP Transit": "WebRTC UDP සංක්u200dරමණය සබල කරන්න", + "Enable WebP Compression": "WebP සම්පීඩනය සබල කරන්න", + "Enable Performance Stats": "කාර්ය සාධන සංඛ්යාලේඛන සබල කරන්න", + "Enable Pointer Lock": "පොයින්ටර් අගුල සබල කරන්න", + "IME Input Mode": "IME ආදාන මාදිලිය", + "Show Virtual Keyboard Control": "අතථ්u200dය යතුරුපුවරු පාලනය පෙන්වන්න", + "Toggle Control Panel via Keystrokes": "යතුරු පහර හරහා පාලන පැනලය ටොගල් කරන්න", + "Render Native Resolution": "දේශීය විභේදනය ඉදිරිපත් කරන්න", + "Keyboard Shortcuts": "යතුරුපුවරු කෙටිමං", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC යතුරුපුවරු කෙටිමං සබල කරන්න", + "1 - Toggle Control Panel": "1 - පාලක පැනලය ටොගල් කරන්න", + "2 - Toggle Game Pointer Mode": "2 - ටොගල් ගේම් පොයින්ටර් මාදිලිය", + "3 - Toggle Pointer Lock": "3 - ටොගල් පොයින්ටර් ලොක්", + "Stream Quality": "ප්රවාහයේ ගුණාත්මකභාවය", + "Preset Modes:": "පෙරසැකසුම් මාදිලි:", + "Static": "ස්ථිතික", + "Low": "අඩු", + "Medium": "මධ්යම", + "High": "අධි", + "Extreme": "අතිශයින්", + "Lossless": "පාඩු නැති", + "Custom": "අභිරුචි", + "Anti-Aliasing:": "විරෝධී අන්වර්ථකරණය:", + "Auto Dynamic": "ස්වයං ගතික", + "Off": "අක්රිය", + "On": "මත", + "Dynamic Quality Min:": "ගතික තත්ත්ව අවම:", + "Dynamic Quality Max:": "ගතික තත්ත්ව උපරිම:", + "Treat Lossless:": "අහිමියෙන් සලකන්න:", + "Frame Rate:": "රාමු අනුපාතය:", + "Video JPEG Quality:": "වීඩියෝ JPEG ගුණාත්මකභාවය:", + "Video WEBP Quality:": "වීඩියෝ WEBP ගුණාත්මකභාවය:", + "Video Area:": "වීඩියෝ ප්රදේශය:", + "Video Time:": "වීඩියෝ වේලාව:", + "Video Out Time:": "වීඩියෝ අවසන් වන වේලාව:", + "Video Mode Width:": "වීඩියෝ මාදිලියේ පළල:", + "Video Mode Height:": "වීඩියෝ මාදිලියේ උස:", + "Documentation": "ලේඛන", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "KasmVNC දෝෂයක් ඇති විය:" +} \ No newline at end of file diff --git a/app/locale/si_LK.json b/app/locale/si_LK.json new file mode 100644 index 0000000..d149e14 --- /dev/null +++ b/app/locale/si_LK.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "සම්බන්ධ වෙමින්...", + "Disconnecting...": "විසන්ධි කරමින්...", + "Reconnecting...": "නැවත සම්බන්ධ වෙමින්...", + "Internal error": "අභ්u200dයන්තර දෝෂය", + "Must set host": "ධාරකය සැකසිය යුතුය", + "Connected (encrypted) to ": "සම්බන්ධිත (සංකේතනය) වෙත", + "Connected (unencrypted) to ": "සම්බන්ධිත (සංකේතනය නොකළ)", + "Something went wrong, connection is closed": "යමක් වැරදී ඇත, සම්බන්ධතාවය වසා ඇත", + "Failed to connect to server": "සේවාදායකයට සම්බන්ධ වීමට අපොහොසත් විය", + "Disconnected": "විසන්ධි විය", + "New connection has been rejected with reason: ": "නව සම්බන්ධතාවය හේතු සහිතව ප්u200dරතික්ෂේප කර ඇත:", + "New connection has been rejected": "නව සම්බන්ධතාවය ප්u200dරතික්ෂේප කර ඇත", + "Credentials are required": "ඇත්තපත්u200dර අවශ්u200dයයි", + "Hide/Show the control bar": "පාලක තීරුව සඟවන්න/පෙන්වන්න", + "Drag": "අදින්න", + "Move/Drag Viewport": "වීව්පෝට් ගෙනයන්න/අදින්න", + "Keyboard": "යතුරු පුවරුව", + "Show Keyboard": "යතුරු පුවරුව පෙන්වන්න", + "Extra keys": "අමතර යතුරු", + "Show Extra Keys": "අමතර යතුරු පෙන්වන්න", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ටොගල් කරන්න", + "Alt": "Alt", + "Toggle Alt": "Alt ටොගල් කරන්න", + "Toggle Windows": "වින්ඩෝස් ටොගල් කරන්න", + "Windows": "වින්ඩෝස්", + "Send Tab": "යවන්න ටැබ්", + "Tab": "ටැබ්", + "Esc": "පිට වීම", + "Send Escape": "පලා යාම යවන්න", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del යවන්න", + "Shutdown/Reboot": "වසා දැමීම / නැවත ආරම්භ කිරීම", + "Shutdown/Reboot...": "වසා දැමීම / නැවත ආරම්භ කිරීම...", + "Power": "බලය", + "Shutdown": "වසා දමන්න", + "Reboot": "නැවත ආරම්භ කරන්න", + "Reset": "නැවත පිහිටුවන්න", + "Clipboard": "ක්ලිප්බෝඩ්", + "Clear": "පැහැදිලිව", + "Fullscreen": "පුන් තිරය", + "Settings": "සැකසුම්", + "Shared Mode": "බෙදාගත් මාදිලිය", + "View Only": "බලන්න පමණයි", + "Clip to Window": "කවුළුව වෙත ක්ලිප් කරන්න", + "Scaling Mode:": "පරිමාණ මාදිලිය:", + "None": "කිසිවක් නැත", + "Local Scaling": "දේශීය පරිමාණය", + "Remote Resizing": "දුරස්ථ ප්u200dරමාණය වෙනස් කිරීම", + "Advanced": "උසස්", + "Quality:": "ගුණාත්මක:", + "Compression level:": "සම්පීඩන මට්ටම:", + "Repeater ID:": "පුනරාවර්තන හැඳුනුම්පත:", + "WebSocket": "වෙබ්සොකට්", + "Encrypt": "සංකේතනය කරන්න", + "Host:": "සත්කාරක:", + "Port:": "වරාය:", + "Path:": "මාර්ගය:", + "Automatic Reconnect": "ස්වයංක්u200dරීය නැවත සම්බන්ධ කිරීම", + "Reconnect Delay (ms):": "ප්u200dරමාදය නැවත සම්බන්ධ කරන්න (ms):", + "Show Dot when No Cursor": "කර්සරය නොමැති විට තිත පෙන්වන්න", + "Logging:": "ලොග් කිරීම:", + "Version:": "පිටපත:", + "Disconnect": "විසන්ධි කරන්න", + "Connect": "සම්බන්ධ කරන්න", + "Username:": "පරිශීලක නාමය:", + "Password:": "මුරපදය:", + "Send Credentials": "ඇත්තපත්u200dර යවන්න", + "Cancel": "අවලංගු කරන්න", + "Keys": "යතුරු", + "Game Cursor Mode": "ගේම් කර්සර මාදිලිය", + "Press Esc Key to Exit Pointer Lock Mode": "Pointer Lock Mode එකෙන් පිටවීමට Esc යතුර ඔබන්න", + "Game Mode paused, click on screen to resume Game Mode.": "ක්u200dරීඩා ප්u200dරකාරය විරාම කරන ලදී, ක්u200dරීඩා ප්u200dරකාරය නැවත ආරම්භ කිරීමට තිරය මත ක්ලික් කරන්න.", + "Clipboard Up": "ක්ලිප්බෝඩ් ඉහළට", + "CLipboard Down": "ක්ලිප්බෝඩ් පහලට", + "Clipboard Seamless": "ක්ලිප්බෝඩ් බාධාවකින් තොරව", + "Prefer Local Cursor": "දේශීය කර්සරය කැමති", + "Translate keyboard shortcuts": "යතුරු පුවරු කෙටිමං පරිවර්තනය කරන්න", + "Enable WebRTC UDP Transit": "WebRTC UDP සංක්u200dරමණය සබල කරන්න", + "Enable WebP Compression": "WebP සම්පීඩනය සබල කරන්න", + "Enable Performance Stats": "කාර්ය සාධන සංඛ්යාලේඛන සබල කරන්න", + "Enable Pointer Lock": "පොයින්ටර් අගුල සබල කරන්න", + "IME Input Mode": "IME ආදාන මාදිලිය", + "Show Virtual Keyboard Control": "අතථ්u200dය යතුරුපුවරු පාලනය පෙන්වන්න", + "Toggle Control Panel via Keystrokes": "යතුරු පහර හරහා පාලන පැනලය ටොගල් කරන්න", + "Render Native Resolution": "දේශීය විභේදනය ඉදිරිපත් කරන්න", + "Keyboard Shortcuts": "යතුරුපුවරු කෙටිමං", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC යතුරුපුවරු කෙටිමං සබල කරන්න", + "1 - Toggle Control Panel": "1 - පාලක පැනලය ටොගල් කරන්න", + "2 - Toggle Game Pointer Mode": "2 - ටොගල් ගේම් පොයින්ටර් මාදිලිය", + "3 - Toggle Pointer Lock": "3 - ටොගල් පොයින්ටර් ලොක්", + "Stream Quality": "ප්රවාහයේ ගුණාත්මකභාවය", + "Preset Modes:": "පෙරසැකසුම් මාදිලි:", + "Static": "ස්ථිතික", + "Low": "අඩු", + "Medium": "මධ්යම", + "High": "අධි", + "Extreme": "අතිශයින්", + "Lossless": "පාඩු නැති", + "Custom": "අභිරුචි", + "Anti-Aliasing:": "විරෝධී අන්වර්ථකරණය:", + "Auto Dynamic": "ස්වයං ගතික", + "Off": "අක්රිය", + "On": "මත", + "Dynamic Quality Min:": "ගතික තත්ත්ව අවම:", + "Dynamic Quality Max:": "ගතික තත්ත්ව උපරිම:", + "Treat Lossless:": "අහිමියෙන් සලකන්න:", + "Frame Rate:": "රාමු අනුපාතය:", + "Video JPEG Quality:": "වීඩියෝ JPEG ගුණාත්මකභාවය:", + "Video WEBP Quality:": "වීඩියෝ WEBP ගුණාත්මකභාවය:", + "Video Area:": "වීඩියෝ ප්රදේශය:", + "Video Time:": "වීඩියෝ වේලාව:", + "Video Out Time:": "වීඩියෝ අවසන් වන වේලාව:", + "Video Mode Width:": "වීඩියෝ මාදිලියේ පළල:", + "Video Mode Height:": "වීඩියෝ මාදිලියේ උස:", + "Documentation": "ලේඛන", + "Drag Viewport": "Drag Viewport", + "KasmVNC encountered an error:": "KasmVNC දෝෂයක් ඇති විය:" +} \ No newline at end of file diff --git a/app/locale/sk.json b/app/locale/sk.json new file mode 100644 index 0000000..4638821 --- /dev/null +++ b/app/locale/sk.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Pripája sa...", + "Disconnecting...": "Odpája sa...", + "Reconnecting...": "Opätovné pripojenie...", + "Internal error": "Vnútorná chyba", + "Must set host": "Musíte nastaviť hostiteľa", + "Connected (encrypted) to ": "Pripojené (šifrované) k ", + "Connected (unencrypted) to ": "Pripojené (nešifrované) k ", + "Something went wrong, connection is closed": "Vyskytol sa problém, pripojenie je zatvorené", + "Failed to connect to server": "Nepodarilo sa pripojiť k serveru", + "Disconnected": "Odpojené", + "New connection has been rejected with reason: ": "Nové pripojenie bolo odmietnuté s dôvodom: ", + "New connection has been rejected": "Nové pripojenie bolo odmietnuté", + "Credentials are required": "Vyžadujú sa poverenia", + "Hide/Show the control bar": "Skryť/Zobraziť ovládací panel", + "Drag": "Pretiahnuť", + "Move/Drag Viewport": "Presunúť/pretiahnuť výrez", + "Keyboard": "klávesnica", + "Show Keyboard": "Zobraziť klávesnicu", + "Extra keys": "Extra kľúče", + "Show Extra Keys": "Zobraziť ďalšie kľúče", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Prepnúť Ctrl", + "Alt": "Alt", + "Toggle Alt": "Prepnúť Alt", + "Toggle Windows": "Prepnúť Windows", + "Windows": "Windows", + "Send Tab": "Odoslať kartu", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Poslať únik", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Odoslať Ctrl-Alt-Del", + "Shutdown/Reboot": "Vypnutie/Reštart", + "Shutdown/Reboot...": "Vypnúť/Reštartovať...", + "Power": "Moc", + "Shutdown": "Vypnúť", + "Reboot": "Reštartovať", + "Reset": "Obnoviť", + "Clipboard": "schránka", + "Clear": "Jasný", + "Fullscreen": "Celá obrazovka", + "Settings": "Nastavenie", + "Shared Mode": "Zdieľaný režim", + "View Only": "Len prezerať", + "Clip to Window": "Klip do okna", + "Scaling Mode:": "Režim škálovania:", + "None": "žiadny", + "Local Scaling": "Miestne škálovanie", + "Remote Resizing": "Vzdialená zmena veľkosti", + "Advanced": "Pokročilé", + "Quality:": "Kvalita:", + "Compression level:": "Úroveň kompresie:", + "Repeater ID:": "ID opakovača:", + "WebSocket": "WebSocket", + "Encrypt": "šifrovať", + "Host:": "Hostiteľ:", + "Port:": "Port:", + "Path:": "Cesta:", + "Automatic Reconnect": "Automatické opätovné pripojenie", + "Reconnect Delay (ms):": "Oneskorenie opätovného pripojenia (ms):", + "Show Dot when No Cursor": "Zobraziť bodku, keď nie je žiadny kurzor", + "Logging:": "Prihlasovanie:", + "Version:": "Verzia:", + "Disconnect": "Odpojiť", + "Connect": "Pripojiť", + "Username:": "Používateľské meno:", + "Password:": "Heslo:", + "Send Credentials": "Odoslať poverenia", + "Cancel": "Zrušiť", + "Keys": "kľúče", + "Game Cursor Mode": "Režim herného kurzora", + "Press Esc Key to Exit Pointer Lock Mode": "Stlačením klávesu Esc ukončíte režim uzamknutia ukazovateľa", + "Game Mode paused, click on screen to resume Game Mode.": "Herný režim pozastavený, kliknutím na obrazovku obnovíte herný režim.", + "Clipboard Up": "Schránka hore", + "CLipboard Down": "Schránka dole", + "Clipboard Seamless": "Bezšvová schránka", + "Prefer Local Cursor": "Uprednostniť miestny kurzor", + "Translate keyboard shortcuts": "Preložiť klávesové skratky", + "Enable WebRTC UDP Transit": "Povoliť WebRTC UDP Transit", + "Enable WebP Compression": "Povoliť kompresiu WebP", + "Enable Performance Stats": "Povoliť štatistiky výkonnosti", + "Enable Pointer Lock": "Povoliť uzamknutie ukazovateľa", + "IME Input Mode": "Režim vstupu IME", + "Show Virtual Keyboard Control": "Zobraziť ovládanie virtuálnej klávesnice", + "Toggle Control Panel via Keystrokes": "Prepínanie ovládacieho panela pomocou klávesov", + "Render Native Resolution": "Vykresliť natívne rozlíšenie", + "Keyboard Shortcuts": "Klávesové skratky", + "Enable KasmVNC Keyboard Shortcuts": "Povoliť klávesové skratky KasmVNC", + "1 - Toggle Control Panel": "1 - Prepnúť ovládací panel", + "2 - Toggle Game Pointer Mode": "2 - Prepnúť režim ukazovateľa hry", + "3 - Toggle Pointer Lock": "3 - Prepnúť zámok ukazovateľa", + "Stream Quality": "Kvalita streamu", + "Preset Modes:": "Prednastavené režimy:", + "Static": "statický", + "Low": "nízka", + "Medium": "stredne", + "High": "vysoké", + "Extreme": "extrémne", + "Lossless": "bezstratový", + "Custom": "Vlastné", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "vypnuté", + "On": "zapnuté", + "Dynamic Quality Min:": "Minimálna dynamická kvalita:", + "Dynamic Quality Max:": "Maximálna dynamická kvalita:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Snímok za sekundu:", + "Video JPEG Quality:": "Kvalita videa JPEG:", + "Video WEBP Quality:": "Video WEBP kvalita:", + "Video Area:": "Oblasť videa:", + "Video Time:": "Čas videa:", + "Video Out Time:": "Čas výstupu videa:", + "Video Mode Width:": "Šírka režimu videa:", + "Video Mode Height:": "Výška režimu videa:", + "Documentation": "dokumentácia", + "Drag Viewport": "Pretiahnuť výrez", + "KasmVNC encountered an error:": "KasmVNC narazil na chybu:" +} \ No newline at end of file diff --git a/app/locale/sk_SK.json b/app/locale/sk_SK.json new file mode 100644 index 0000000..4638821 --- /dev/null +++ b/app/locale/sk_SK.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Pripája sa...", + "Disconnecting...": "Odpája sa...", + "Reconnecting...": "Opätovné pripojenie...", + "Internal error": "Vnútorná chyba", + "Must set host": "Musíte nastaviť hostiteľa", + "Connected (encrypted) to ": "Pripojené (šifrované) k ", + "Connected (unencrypted) to ": "Pripojené (nešifrované) k ", + "Something went wrong, connection is closed": "Vyskytol sa problém, pripojenie je zatvorené", + "Failed to connect to server": "Nepodarilo sa pripojiť k serveru", + "Disconnected": "Odpojené", + "New connection has been rejected with reason: ": "Nové pripojenie bolo odmietnuté s dôvodom: ", + "New connection has been rejected": "Nové pripojenie bolo odmietnuté", + "Credentials are required": "Vyžadujú sa poverenia", + "Hide/Show the control bar": "Skryť/Zobraziť ovládací panel", + "Drag": "Pretiahnuť", + "Move/Drag Viewport": "Presunúť/pretiahnuť výrez", + "Keyboard": "klávesnica", + "Show Keyboard": "Zobraziť klávesnicu", + "Extra keys": "Extra kľúče", + "Show Extra Keys": "Zobraziť ďalšie kľúče", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Prepnúť Ctrl", + "Alt": "Alt", + "Toggle Alt": "Prepnúť Alt", + "Toggle Windows": "Prepnúť Windows", + "Windows": "Windows", + "Send Tab": "Odoslať kartu", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Poslať únik", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Odoslať Ctrl-Alt-Del", + "Shutdown/Reboot": "Vypnutie/Reštart", + "Shutdown/Reboot...": "Vypnúť/Reštartovať...", + "Power": "Moc", + "Shutdown": "Vypnúť", + "Reboot": "Reštartovať", + "Reset": "Obnoviť", + "Clipboard": "schránka", + "Clear": "Jasný", + "Fullscreen": "Celá obrazovka", + "Settings": "Nastavenie", + "Shared Mode": "Zdieľaný režim", + "View Only": "Len prezerať", + "Clip to Window": "Klip do okna", + "Scaling Mode:": "Režim škálovania:", + "None": "žiadny", + "Local Scaling": "Miestne škálovanie", + "Remote Resizing": "Vzdialená zmena veľkosti", + "Advanced": "Pokročilé", + "Quality:": "Kvalita:", + "Compression level:": "Úroveň kompresie:", + "Repeater ID:": "ID opakovača:", + "WebSocket": "WebSocket", + "Encrypt": "šifrovať", + "Host:": "Hostiteľ:", + "Port:": "Port:", + "Path:": "Cesta:", + "Automatic Reconnect": "Automatické opätovné pripojenie", + "Reconnect Delay (ms):": "Oneskorenie opätovného pripojenia (ms):", + "Show Dot when No Cursor": "Zobraziť bodku, keď nie je žiadny kurzor", + "Logging:": "Prihlasovanie:", + "Version:": "Verzia:", + "Disconnect": "Odpojiť", + "Connect": "Pripojiť", + "Username:": "Používateľské meno:", + "Password:": "Heslo:", + "Send Credentials": "Odoslať poverenia", + "Cancel": "Zrušiť", + "Keys": "kľúče", + "Game Cursor Mode": "Režim herného kurzora", + "Press Esc Key to Exit Pointer Lock Mode": "Stlačením klávesu Esc ukončíte režim uzamknutia ukazovateľa", + "Game Mode paused, click on screen to resume Game Mode.": "Herný režim pozastavený, kliknutím na obrazovku obnovíte herný režim.", + "Clipboard Up": "Schránka hore", + "CLipboard Down": "Schránka dole", + "Clipboard Seamless": "Bezšvová schránka", + "Prefer Local Cursor": "Uprednostniť miestny kurzor", + "Translate keyboard shortcuts": "Preložiť klávesové skratky", + "Enable WebRTC UDP Transit": "Povoliť WebRTC UDP Transit", + "Enable WebP Compression": "Povoliť kompresiu WebP", + "Enable Performance Stats": "Povoliť štatistiky výkonnosti", + "Enable Pointer Lock": "Povoliť uzamknutie ukazovateľa", + "IME Input Mode": "Režim vstupu IME", + "Show Virtual Keyboard Control": "Zobraziť ovládanie virtuálnej klávesnice", + "Toggle Control Panel via Keystrokes": "Prepínanie ovládacieho panela pomocou klávesov", + "Render Native Resolution": "Vykresliť natívne rozlíšenie", + "Keyboard Shortcuts": "Klávesové skratky", + "Enable KasmVNC Keyboard Shortcuts": "Povoliť klávesové skratky KasmVNC", + "1 - Toggle Control Panel": "1 - Prepnúť ovládací panel", + "2 - Toggle Game Pointer Mode": "2 - Prepnúť režim ukazovateľa hry", + "3 - Toggle Pointer Lock": "3 - Prepnúť zámok ukazovateľa", + "Stream Quality": "Kvalita streamu", + "Preset Modes:": "Prednastavené režimy:", + "Static": "statický", + "Low": "nízka", + "Medium": "stredne", + "High": "vysoké", + "Extreme": "extrémne", + "Lossless": "bezstratový", + "Custom": "Vlastné", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "vypnuté", + "On": "zapnuté", + "Dynamic Quality Min:": "Minimálna dynamická kvalita:", + "Dynamic Quality Max:": "Maximálna dynamická kvalita:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Snímok za sekundu:", + "Video JPEG Quality:": "Kvalita videa JPEG:", + "Video WEBP Quality:": "Video WEBP kvalita:", + "Video Area:": "Oblasť videa:", + "Video Time:": "Čas videa:", + "Video Out Time:": "Čas výstupu videa:", + "Video Mode Width:": "Šírka režimu videa:", + "Video Mode Height:": "Výška režimu videa:", + "Documentation": "dokumentácia", + "Drag Viewport": "Pretiahnuť výrez", + "KasmVNC encountered an error:": "KasmVNC narazil na chybu:" +} \ No newline at end of file diff --git a/app/locale/sl.json b/app/locale/sl.json new file mode 100644 index 0000000..4514fa1 --- /dev/null +++ b/app/locale/sl.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Povezovanje ...", + "Disconnecting...": "Prekinitev povezave ...", + "Reconnecting...": "Ponovna povezava ...", + "Internal error": "Notranja napaka", + "Must set host": "Moram nastaviti gostitelja", + "Connected (encrypted) to ": "Povezan (šifriran) z ", + "Connected (unencrypted) to ": "Povezan (nešifriran) z ", + "Something went wrong, connection is closed": "Nekaj je šlo narobe, povezava je prekinjena", + "Failed to connect to server": "Povezava s strežnikom ni uspela", + "Disconnected": "Odklopljen", + "New connection has been rejected with reason: ": "Nova povezava je bila zavrnjena z razlogom: ", + "New connection has been rejected": "Nova povezava je bila zavrnjena", + "Credentials are required": "Potrebne so poverilnice", + "Hide/Show the control bar": "Skrij/prikaži nadzorno vrstico", + "Drag": "povleci", + "Move/Drag Viewport": "Premakni/povleci vidno polje", + "Keyboard": "Tipkovnica", + "Show Keyboard": "Pokaži tipkovnico", + "Extra keys": "Dodatni ključi", + "Show Extra Keys": "Pokaži dodatne tipke", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Preklopi Ctrl", + "Alt": "Alt", + "Toggle Alt": "Preklopi Alt", + "Toggle Windows": "Preklopi Windows", + "Windows": "Windows", + "Send Tab": "Pošlji zavihek", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Pošlji Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Pošlji Ctrl-Alt-Del", + "Shutdown/Reboot": "Izklop/ponovni zagon", + "Shutdown/Reboot...": "Zaustavitev/ponovni zagon ...", + "Power": "Moč", + "Shutdown": "Ugasniti", + "Reboot": "Ponovni zagon", + "Reset": "Ponastaviti", + "Clipboard": "Odložišče", + "Clear": "Počisti", + "Fullscreen": "Celozaslonski način", + "Settings": "Nastavitve", + "Shared Mode": "Način v skupni rabi", + "View Only": "Samo ogled", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Način skaliranja:", + "None": "brez", + "Local Scaling": "Lokalno skaliranje", + "Remote Resizing": "Oddaljeno spreminjanje velikosti", + "Advanced": "Napredno", + "Quality:": "Kakovost:", + "Compression level:": "Raven stiskanja:", + "Repeater ID:": "ID repetitorja:", + "WebSocket": "WebSocket", + "Encrypt": "Šifriraj", + "Host:": "Gostitelj:", + "Port:": "Pristanišče:", + "Path:": "Pot:", + "Automatic Reconnect": "Samodejna ponovna povezava", + "Reconnect Delay (ms):": "Zakasnitev ponovne povezave (ms):", + "Show Dot when No Cursor": "Prikaži piko, ko ni kazalca", + "Logging:": "Beleženje:", + "Version:": "Različica:", + "Disconnect": "Prekini povezavo", + "Connect": "poveži", + "Username:": "Uporabniško ime:", + "Password:": "Geslo:", + "Send Credentials": "Pošlji poverilnice", + "Cancel": "Prekliči", + "Keys": "Ključi", + "Game Cursor Mode": "Način igralnega kazalca", + "Press Esc Key to Exit Pointer Lock Mode": "Pritisnite tipko Esc za izhod iz načina zaklepanja kazalca", + "Game Mode paused, click on screen to resume Game Mode.": "Game Mode pauseed, click on screen to continue Game Mode.", + "Clipboard Up": "Odložišče gor", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Brezšivno odložišče", + "Prefer Local Cursor": "Raje uporabljaj lokalni kazalec", + "Translate keyboard shortcuts": "Prevedi bližnjice na tipkovnici", + "Enable WebRTC UDP Transit": "Omogoči WebRTC UDP Transit", + "Enable WebP Compression": "Omogoči stiskanje WebP", + "Enable Performance Stats": "Omogoči statistiko uspešnosti", + "Enable Pointer Lock": "Omogoči zaklepanje kazalca", + "IME Input Mode": "Način vnosa IME", + "Show Virtual Keyboard Control": "Pokaži nadzor virtualne tipkovnice", + "Toggle Control Panel via Keystrokes": "Preklopi nadzorno ploščo s tipkami", + "Render Native Resolution": "Upodobitev izvorne ločljivosti", + "Keyboard Shortcuts": "Bližnjice na tipkovnici", + "Enable KasmVNC Keyboard Shortcuts": "Omogoči bližnjice na tipkovnici KasmVNC", + "1 - Toggle Control Panel": "1 - Preklop nadzorne plošče", + "2 - Toggle Game Pointer Mode": "2 - Preklop načina kazalca igre", + "3 - Toggle Pointer Lock": "3 - Preklop zaklepanja kazalca", + "Stream Quality": "Kakovost toka", + "Preset Modes:": "Prednastavljeni načini:", + "Static": "Statično", + "Low": "nizko", + "Medium": "srednje", + "High": "visoko", + "Extreme": "Ekstremno", + "Lossless": "brez izgub", + "Custom": "Po meri", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Samodejno dinamično", + "Off": "izklopljen", + "On": "Vklopljeno", + "Dynamic Quality Min:": "Minimalna dinamična kakovost:", + "Dynamic Quality Max:": "Najvišja dinamična kakovost:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Hitrost sličic:", + "Video JPEG Quality:": "Kakovost videa JPEG:", + "Video WEBP Quality:": "Kakovost videa WEBP:", + "Video Area:": "Območje videa:", + "Video Time:": "Čas videa:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Širina video načina:", + "Video Mode Height:": "Višina video načina:", + "Documentation": "Dokumentacija", + "Drag Viewport": "Povlecite vidno polje", + "KasmVNC encountered an error:": "KasmVNC je naletel na napako:" +} \ No newline at end of file diff --git a/app/locale/sl_SI.json b/app/locale/sl_SI.json new file mode 100644 index 0000000..4514fa1 --- /dev/null +++ b/app/locale/sl_SI.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Povezovanje ...", + "Disconnecting...": "Prekinitev povezave ...", + "Reconnecting...": "Ponovna povezava ...", + "Internal error": "Notranja napaka", + "Must set host": "Moram nastaviti gostitelja", + "Connected (encrypted) to ": "Povezan (šifriran) z ", + "Connected (unencrypted) to ": "Povezan (nešifriran) z ", + "Something went wrong, connection is closed": "Nekaj je šlo narobe, povezava je prekinjena", + "Failed to connect to server": "Povezava s strežnikom ni uspela", + "Disconnected": "Odklopljen", + "New connection has been rejected with reason: ": "Nova povezava je bila zavrnjena z razlogom: ", + "New connection has been rejected": "Nova povezava je bila zavrnjena", + "Credentials are required": "Potrebne so poverilnice", + "Hide/Show the control bar": "Skrij/prikaži nadzorno vrstico", + "Drag": "povleci", + "Move/Drag Viewport": "Premakni/povleci vidno polje", + "Keyboard": "Tipkovnica", + "Show Keyboard": "Pokaži tipkovnico", + "Extra keys": "Dodatni ključi", + "Show Extra Keys": "Pokaži dodatne tipke", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Preklopi Ctrl", + "Alt": "Alt", + "Toggle Alt": "Preklopi Alt", + "Toggle Windows": "Preklopi Windows", + "Windows": "Windows", + "Send Tab": "Pošlji zavihek", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Pošlji Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Pošlji Ctrl-Alt-Del", + "Shutdown/Reboot": "Izklop/ponovni zagon", + "Shutdown/Reboot...": "Zaustavitev/ponovni zagon ...", + "Power": "Moč", + "Shutdown": "Ugasniti", + "Reboot": "Ponovni zagon", + "Reset": "Ponastaviti", + "Clipboard": "Odložišče", + "Clear": "Počisti", + "Fullscreen": "Celozaslonski način", + "Settings": "Nastavitve", + "Shared Mode": "Način v skupni rabi", + "View Only": "Samo ogled", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Način skaliranja:", + "None": "brez", + "Local Scaling": "Lokalno skaliranje", + "Remote Resizing": "Oddaljeno spreminjanje velikosti", + "Advanced": "Napredno", + "Quality:": "Kakovost:", + "Compression level:": "Raven stiskanja:", + "Repeater ID:": "ID repetitorja:", + "WebSocket": "WebSocket", + "Encrypt": "Šifriraj", + "Host:": "Gostitelj:", + "Port:": "Pristanišče:", + "Path:": "Pot:", + "Automatic Reconnect": "Samodejna ponovna povezava", + "Reconnect Delay (ms):": "Zakasnitev ponovne povezave (ms):", + "Show Dot when No Cursor": "Prikaži piko, ko ni kazalca", + "Logging:": "Beleženje:", + "Version:": "Različica:", + "Disconnect": "Prekini povezavo", + "Connect": "poveži", + "Username:": "Uporabniško ime:", + "Password:": "Geslo:", + "Send Credentials": "Pošlji poverilnice", + "Cancel": "Prekliči", + "Keys": "Ključi", + "Game Cursor Mode": "Način igralnega kazalca", + "Press Esc Key to Exit Pointer Lock Mode": "Pritisnite tipko Esc za izhod iz načina zaklepanja kazalca", + "Game Mode paused, click on screen to resume Game Mode.": "Game Mode pauseed, click on screen to continue Game Mode.", + "Clipboard Up": "Odložišče gor", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Brezšivno odložišče", + "Prefer Local Cursor": "Raje uporabljaj lokalni kazalec", + "Translate keyboard shortcuts": "Prevedi bližnjice na tipkovnici", + "Enable WebRTC UDP Transit": "Omogoči WebRTC UDP Transit", + "Enable WebP Compression": "Omogoči stiskanje WebP", + "Enable Performance Stats": "Omogoči statistiko uspešnosti", + "Enable Pointer Lock": "Omogoči zaklepanje kazalca", + "IME Input Mode": "Način vnosa IME", + "Show Virtual Keyboard Control": "Pokaži nadzor virtualne tipkovnice", + "Toggle Control Panel via Keystrokes": "Preklopi nadzorno ploščo s tipkami", + "Render Native Resolution": "Upodobitev izvorne ločljivosti", + "Keyboard Shortcuts": "Bližnjice na tipkovnici", + "Enable KasmVNC Keyboard Shortcuts": "Omogoči bližnjice na tipkovnici KasmVNC", + "1 - Toggle Control Panel": "1 - Preklop nadzorne plošče", + "2 - Toggle Game Pointer Mode": "2 - Preklop načina kazalca igre", + "3 - Toggle Pointer Lock": "3 - Preklop zaklepanja kazalca", + "Stream Quality": "Kakovost toka", + "Preset Modes:": "Prednastavljeni načini:", + "Static": "Statično", + "Low": "nizko", + "Medium": "srednje", + "High": "visoko", + "Extreme": "Ekstremno", + "Lossless": "brez izgub", + "Custom": "Po meri", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Samodejno dinamično", + "Off": "izklopljen", + "On": "Vklopljeno", + "Dynamic Quality Min:": "Minimalna dinamična kakovost:", + "Dynamic Quality Max:": "Najvišja dinamična kakovost:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Hitrost sličic:", + "Video JPEG Quality:": "Kakovost videa JPEG:", + "Video WEBP Quality:": "Kakovost videa WEBP:", + "Video Area:": "Območje videa:", + "Video Time:": "Čas videa:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Širina video načina:", + "Video Mode Height:": "Višina video načina:", + "Documentation": "Dokumentacija", + "Drag Viewport": "Povlecite vidno polje", + "KasmVNC encountered an error:": "KasmVNC je naletel na napako:" +} \ No newline at end of file diff --git a/app/locale/so.json b/app/locale/so.json new file mode 100644 index 0000000..f089b61 --- /dev/null +++ b/app/locale/so.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "isku xidhka...", + "Disconnecting...": "Xiriirka gooya...", + "Reconnecting...": "Dib u xidhidhinta...", + "Internal error": "khalad gudaha ah", + "Must set host": "Waa in la dejiyaa martigeliyaha", + "Connected (encrypted) to ": "Waxa lagu xidhay ( sir ah) ", + "Connected (unencrypted) to ": "Ku xidhan (aan qarsoodi ahayn)", + "Something went wrong, connection is closed": "Waxbaa khaldamay, xidhiidhku waa xidhan yahay", + "Failed to connect to server": "Waa lagu guul daraystay in lagu xidho serfarka", + "Disconnected": "Go'ay", + "New connection has been rejected with reason: ": "Xiriirka cusub waxaa lagu diiday sabab:", + "New connection has been rejected": "Xiriirka cusub waa la diiday", + "Credentials are required": "Waxyaabaha aqoonsiga ayaa loo baahan yahay", + "Hide/Show the control bar": "Qari/muuji barta kontoroolka", + "Drag": "Jiid", + "Move/Drag Viewport": "Dhaqdhaqaaq / Jiid Daawashada", + "Keyboard": "Keyboard", + "Show Keyboard": "muuji kiiboodhka", + "Extra keys": "furayaal dheeri ah", + "Show Extra Keys": "muuji furayaal dheeri ah", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Beddel Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Daaqadaha", + "Send Tab": "Dir Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Dir baxso", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "U dir Ctrl-Alt-Del", + "Shutdown/Reboot": "Xiritaanka/dib u kabashada", + "Shutdown/Reboot...": " Xir/Dib u kici...", + "Power": "Awood", + "Shutdown": "Bakhtii", + "Reboot": "dib u kici", + "Reset": "Dib u habeyn", + "Clipboard": "Klipboard", + "Clear": "Nadiifi", + "Fullscreen": "shaashadda buuxda", + "Settings": "Settings", + "Shared Mode": "Qaabka la wadaago", + "View Only": "Kaliya arag", + "Clip to Window": "Ku duub daaqadda", + "Scaling Mode:": "Qaabka cabbirka:", + "None": "Maya", + "Local Scaling": "Qiimaynta Deegaanka", + "Remote Resizing": "Qiimaynta fog", + "Advanced": "Hore", + "Quality:": "Tayada:", + "Compression level:": "Heerka cadaadiska:", + "Repeater ID:": "Aqoonsiga soo noqnoqda:", + "WebSocket": "WebSocket", + "Encrypt": "Sirta", + "Host:": "Martigeliyaha:", + "Port:": "Dekedda:", + "Path:": "Wadada:", + "Automatic Reconnect": "Dib u xidhid toos ah", + "Reconnect Delay (ms):": "Dib u xidhid dib u dhac (ms):", + "Show Dot when No Cursor": "Show dhibic marka aanay Cursor jirin", + "Logging:": "Goynta:", + "Version:": "Nooca:", + "Disconnect": "Xiriirka ka saar", + "Connect": "isku xidh", + "Username:": "Username:", + "Password:": "Password:", + "Send Credentials": "Soo dir warqadaha aqoonsiga", + "Cancel": "Bejis", + "Keys": "Furayaasha", + "Game Cursor Mode": "Qaabka Cursorka Ciyaarta", + "Press Esc Key to Exit Pointer Lock Mode": "Riix furaha Esc si aad uga baxdo Habka Qufulka Tilmaamaha", + "Game Mode paused, click on screen to resume Game Mode.": "Qaabka ciyaarta waa la hakiyay, guji shaashadda si aad dib ugu bilowdo Habka Ciyaarta.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard-ka bilaa-xun", + "Prefer Local Cursor": "Doorbi Cursor Local", + "Translate keyboard shortcuts": "Turjun furayaasha kiiboodhka", + "Enable WebRTC UDP Transit": "Dari WebRTC UDP Gaadiidka", + "Enable WebP Compression": "Dari isku-buufinta WebP", + "Enable Performance Stats": "Kor u yeel Tirakoobka Waxqabadka", + "Enable Pointer Lock": "Dari qufulka tilmaanta", + "IME Input Mode": "Qaabka galitaanka IME", + "Show Virtual Keyboard Control": "muuji xakamaynta kiiboodhka Virtual", + "Toggle Control Panel via Keystrokes": "Ku beddel kontoroolka furaha", + "Render Native Resolution": "Samee Qaraarka Dhaladka", + "Keyboard Shortcuts": "Keyboodhka Gaaban", + "Enable KasmVNC Keyboard Shortcuts": "Kor-geli KasmVNC Kiiboodhka Gaaban", + "1 - Toggle Control Panel": "1 - Beddel kontoroolka", + "2 - Toggle Game Pointer Mode": "2 - Beddel Habka Tilmaamaha Ciyaarta", + "3 - Toggle Pointer Lock": "3 - Beddel Qufulka Tilmaamaha", + "Stream Quality": "Tayada socodka", + "Preset Modes:": "Qaababka hore loo dhigay:", + "Static": "Static", + "Low": "hooseeya", + "Medium": " Dhexdhexaad ", + "High": "sare", + "Extreme": "aad u daran", + "Lossless": " khasaare la'aan ", + "Custom": "Custom", + "Anti-Aliasing:": "Ka-hortagga aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Dam", + "On": "Daran", + "Dynamic Quality Min:": "Tayada firfircoon Min:", + "Dynamic Quality Max:": "Tayada firfircoonida ugu badan:", + "Treat Lossless:": "La dawee Khasaare La'aan:", + "Frame Rate:": "Heerka jir:", + "Video JPEG Quality:": "Video JPEG Tayada:", + "Video WEBP Quality:": "Video WEBP Tayada:", + "Video Area:": "Aagga Muuqaalka:", + "Video Time:": "Waqtiga Fiidiyowga:", + "Video Out Time:": "Waqtiga Fiidiyaha:", + "Video Mode Width:": "Balac ahaan Qaabka Fiidiyowga:", + "Video Mode Height:": "Habka Fiidiyowga Dhererka:", + "Documentation": "Documentation", + "Drag Viewport": "Deegaanka Jiid", + "KasmVNC encountered an error:": "KasmVNC waxay la kulantay cilad:" +} \ No newline at end of file diff --git a/app/locale/so_DJ.json b/app/locale/so_DJ.json new file mode 100644 index 0000000..f089b61 --- /dev/null +++ b/app/locale/so_DJ.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "isku xidhka...", + "Disconnecting...": "Xiriirka gooya...", + "Reconnecting...": "Dib u xidhidhinta...", + "Internal error": "khalad gudaha ah", + "Must set host": "Waa in la dejiyaa martigeliyaha", + "Connected (encrypted) to ": "Waxa lagu xidhay ( sir ah) ", + "Connected (unencrypted) to ": "Ku xidhan (aan qarsoodi ahayn)", + "Something went wrong, connection is closed": "Waxbaa khaldamay, xidhiidhku waa xidhan yahay", + "Failed to connect to server": "Waa lagu guul daraystay in lagu xidho serfarka", + "Disconnected": "Go'ay", + "New connection has been rejected with reason: ": "Xiriirka cusub waxaa lagu diiday sabab:", + "New connection has been rejected": "Xiriirka cusub waa la diiday", + "Credentials are required": "Waxyaabaha aqoonsiga ayaa loo baahan yahay", + "Hide/Show the control bar": "Qari/muuji barta kontoroolka", + "Drag": "Jiid", + "Move/Drag Viewport": "Dhaqdhaqaaq / Jiid Daawashada", + "Keyboard": "Keyboard", + "Show Keyboard": "muuji kiiboodhka", + "Extra keys": "furayaal dheeri ah", + "Show Extra Keys": "muuji furayaal dheeri ah", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Beddel Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Daaqadaha", + "Send Tab": "Dir Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Dir baxso", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "U dir Ctrl-Alt-Del", + "Shutdown/Reboot": "Xiritaanka/dib u kabashada", + "Shutdown/Reboot...": " Xir/Dib u kici...", + "Power": "Awood", + "Shutdown": "Bakhtii", + "Reboot": "dib u kici", + "Reset": "Dib u habeyn", + "Clipboard": "Klipboard", + "Clear": "Nadiifi", + "Fullscreen": "shaashadda buuxda", + "Settings": "Settings", + "Shared Mode": "Qaabka la wadaago", + "View Only": "Kaliya arag", + "Clip to Window": "Ku duub daaqadda", + "Scaling Mode:": "Qaabka cabbirka:", + "None": "Maya", + "Local Scaling": "Qiimaynta Deegaanka", + "Remote Resizing": "Qiimaynta fog", + "Advanced": "Hore", + "Quality:": "Tayada:", + "Compression level:": "Heerka cadaadiska:", + "Repeater ID:": "Aqoonsiga soo noqnoqda:", + "WebSocket": "WebSocket", + "Encrypt": "Sirta", + "Host:": "Martigeliyaha:", + "Port:": "Dekedda:", + "Path:": "Wadada:", + "Automatic Reconnect": "Dib u xidhid toos ah", + "Reconnect Delay (ms):": "Dib u xidhid dib u dhac (ms):", + "Show Dot when No Cursor": "Show dhibic marka aanay Cursor jirin", + "Logging:": "Goynta:", + "Version:": "Nooca:", + "Disconnect": "Xiriirka ka saar", + "Connect": "isku xidh", + "Username:": "Username:", + "Password:": "Password:", + "Send Credentials": "Soo dir warqadaha aqoonsiga", + "Cancel": "Bejis", + "Keys": "Furayaasha", + "Game Cursor Mode": "Qaabka Cursorka Ciyaarta", + "Press Esc Key to Exit Pointer Lock Mode": "Riix furaha Esc si aad uga baxdo Habka Qufulka Tilmaamaha", + "Game Mode paused, click on screen to resume Game Mode.": "Qaabka ciyaarta waa la hakiyay, guji shaashadda si aad dib ugu bilowdo Habka Ciyaarta.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard-ka bilaa-xun", + "Prefer Local Cursor": "Doorbi Cursor Local", + "Translate keyboard shortcuts": "Turjun furayaasha kiiboodhka", + "Enable WebRTC UDP Transit": "Dari WebRTC UDP Gaadiidka", + "Enable WebP Compression": "Dari isku-buufinta WebP", + "Enable Performance Stats": "Kor u yeel Tirakoobka Waxqabadka", + "Enable Pointer Lock": "Dari qufulka tilmaanta", + "IME Input Mode": "Qaabka galitaanka IME", + "Show Virtual Keyboard Control": "muuji xakamaynta kiiboodhka Virtual", + "Toggle Control Panel via Keystrokes": "Ku beddel kontoroolka furaha", + "Render Native Resolution": "Samee Qaraarka Dhaladka", + "Keyboard Shortcuts": "Keyboodhka Gaaban", + "Enable KasmVNC Keyboard Shortcuts": "Kor-geli KasmVNC Kiiboodhka Gaaban", + "1 - Toggle Control Panel": "1 - Beddel kontoroolka", + "2 - Toggle Game Pointer Mode": "2 - Beddel Habka Tilmaamaha Ciyaarta", + "3 - Toggle Pointer Lock": "3 - Beddel Qufulka Tilmaamaha", + "Stream Quality": "Tayada socodka", + "Preset Modes:": "Qaababka hore loo dhigay:", + "Static": "Static", + "Low": "hooseeya", + "Medium": " Dhexdhexaad ", + "High": "sare", + "Extreme": "aad u daran", + "Lossless": " khasaare la'aan ", + "Custom": "Custom", + "Anti-Aliasing:": "Ka-hortagga aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Dam", + "On": "Daran", + "Dynamic Quality Min:": "Tayada firfircoon Min:", + "Dynamic Quality Max:": "Tayada firfircoonida ugu badan:", + "Treat Lossless:": "La dawee Khasaare La'aan:", + "Frame Rate:": "Heerka jir:", + "Video JPEG Quality:": "Video JPEG Tayada:", + "Video WEBP Quality:": "Video WEBP Tayada:", + "Video Area:": "Aagga Muuqaalka:", + "Video Time:": "Waqtiga Fiidiyowga:", + "Video Out Time:": "Waqtiga Fiidiyaha:", + "Video Mode Width:": "Balac ahaan Qaabka Fiidiyowga:", + "Video Mode Height:": "Habka Fiidiyowga Dhererka:", + "Documentation": "Documentation", + "Drag Viewport": "Deegaanka Jiid", + "KasmVNC encountered an error:": "KasmVNC waxay la kulantay cilad:" +} \ No newline at end of file diff --git a/app/locale/so_ET.json b/app/locale/so_ET.json new file mode 100644 index 0000000..f089b61 --- /dev/null +++ b/app/locale/so_ET.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "isku xidhka...", + "Disconnecting...": "Xiriirka gooya...", + "Reconnecting...": "Dib u xidhidhinta...", + "Internal error": "khalad gudaha ah", + "Must set host": "Waa in la dejiyaa martigeliyaha", + "Connected (encrypted) to ": "Waxa lagu xidhay ( sir ah) ", + "Connected (unencrypted) to ": "Ku xidhan (aan qarsoodi ahayn)", + "Something went wrong, connection is closed": "Waxbaa khaldamay, xidhiidhku waa xidhan yahay", + "Failed to connect to server": "Waa lagu guul daraystay in lagu xidho serfarka", + "Disconnected": "Go'ay", + "New connection has been rejected with reason: ": "Xiriirka cusub waxaa lagu diiday sabab:", + "New connection has been rejected": "Xiriirka cusub waa la diiday", + "Credentials are required": "Waxyaabaha aqoonsiga ayaa loo baahan yahay", + "Hide/Show the control bar": "Qari/muuji barta kontoroolka", + "Drag": "Jiid", + "Move/Drag Viewport": "Dhaqdhaqaaq / Jiid Daawashada", + "Keyboard": "Keyboard", + "Show Keyboard": "muuji kiiboodhka", + "Extra keys": "furayaal dheeri ah", + "Show Extra Keys": "muuji furayaal dheeri ah", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Beddel Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Daaqadaha", + "Send Tab": "Dir Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Dir baxso", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "U dir Ctrl-Alt-Del", + "Shutdown/Reboot": "Xiritaanka/dib u kabashada", + "Shutdown/Reboot...": " Xir/Dib u kici...", + "Power": "Awood", + "Shutdown": "Bakhtii", + "Reboot": "dib u kici", + "Reset": "Dib u habeyn", + "Clipboard": "Klipboard", + "Clear": "Nadiifi", + "Fullscreen": "shaashadda buuxda", + "Settings": "Settings", + "Shared Mode": "Qaabka la wadaago", + "View Only": "Kaliya arag", + "Clip to Window": "Ku duub daaqadda", + "Scaling Mode:": "Qaabka cabbirka:", + "None": "Maya", + "Local Scaling": "Qiimaynta Deegaanka", + "Remote Resizing": "Qiimaynta fog", + "Advanced": "Hore", + "Quality:": "Tayada:", + "Compression level:": "Heerka cadaadiska:", + "Repeater ID:": "Aqoonsiga soo noqnoqda:", + "WebSocket": "WebSocket", + "Encrypt": "Sirta", + "Host:": "Martigeliyaha:", + "Port:": "Dekedda:", + "Path:": "Wadada:", + "Automatic Reconnect": "Dib u xidhid toos ah", + "Reconnect Delay (ms):": "Dib u xidhid dib u dhac (ms):", + "Show Dot when No Cursor": "Show dhibic marka aanay Cursor jirin", + "Logging:": "Goynta:", + "Version:": "Nooca:", + "Disconnect": "Xiriirka ka saar", + "Connect": "isku xidh", + "Username:": "Username:", + "Password:": "Password:", + "Send Credentials": "Soo dir warqadaha aqoonsiga", + "Cancel": "Bejis", + "Keys": "Furayaasha", + "Game Cursor Mode": "Qaabka Cursorka Ciyaarta", + "Press Esc Key to Exit Pointer Lock Mode": "Riix furaha Esc si aad uga baxdo Habka Qufulka Tilmaamaha", + "Game Mode paused, click on screen to resume Game Mode.": "Qaabka ciyaarta waa la hakiyay, guji shaashadda si aad dib ugu bilowdo Habka Ciyaarta.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard-ka bilaa-xun", + "Prefer Local Cursor": "Doorbi Cursor Local", + "Translate keyboard shortcuts": "Turjun furayaasha kiiboodhka", + "Enable WebRTC UDP Transit": "Dari WebRTC UDP Gaadiidka", + "Enable WebP Compression": "Dari isku-buufinta WebP", + "Enable Performance Stats": "Kor u yeel Tirakoobka Waxqabadka", + "Enable Pointer Lock": "Dari qufulka tilmaanta", + "IME Input Mode": "Qaabka galitaanka IME", + "Show Virtual Keyboard Control": "muuji xakamaynta kiiboodhka Virtual", + "Toggle Control Panel via Keystrokes": "Ku beddel kontoroolka furaha", + "Render Native Resolution": "Samee Qaraarka Dhaladka", + "Keyboard Shortcuts": "Keyboodhka Gaaban", + "Enable KasmVNC Keyboard Shortcuts": "Kor-geli KasmVNC Kiiboodhka Gaaban", + "1 - Toggle Control Panel": "1 - Beddel kontoroolka", + "2 - Toggle Game Pointer Mode": "2 - Beddel Habka Tilmaamaha Ciyaarta", + "3 - Toggle Pointer Lock": "3 - Beddel Qufulka Tilmaamaha", + "Stream Quality": "Tayada socodka", + "Preset Modes:": "Qaababka hore loo dhigay:", + "Static": "Static", + "Low": "hooseeya", + "Medium": " Dhexdhexaad ", + "High": "sare", + "Extreme": "aad u daran", + "Lossless": " khasaare la'aan ", + "Custom": "Custom", + "Anti-Aliasing:": "Ka-hortagga aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Dam", + "On": "Daran", + "Dynamic Quality Min:": "Tayada firfircoon Min:", + "Dynamic Quality Max:": "Tayada firfircoonida ugu badan:", + "Treat Lossless:": "La dawee Khasaare La'aan:", + "Frame Rate:": "Heerka jir:", + "Video JPEG Quality:": "Video JPEG Tayada:", + "Video WEBP Quality:": "Video WEBP Tayada:", + "Video Area:": "Aagga Muuqaalka:", + "Video Time:": "Waqtiga Fiidiyowga:", + "Video Out Time:": "Waqtiga Fiidiyaha:", + "Video Mode Width:": "Balac ahaan Qaabka Fiidiyowga:", + "Video Mode Height:": "Habka Fiidiyowga Dhererka:", + "Documentation": "Documentation", + "Drag Viewport": "Deegaanka Jiid", + "KasmVNC encountered an error:": "KasmVNC waxay la kulantay cilad:" +} \ No newline at end of file diff --git a/app/locale/so_KE.json b/app/locale/so_KE.json new file mode 100644 index 0000000..f089b61 --- /dev/null +++ b/app/locale/so_KE.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "isku xidhka...", + "Disconnecting...": "Xiriirka gooya...", + "Reconnecting...": "Dib u xidhidhinta...", + "Internal error": "khalad gudaha ah", + "Must set host": "Waa in la dejiyaa martigeliyaha", + "Connected (encrypted) to ": "Waxa lagu xidhay ( sir ah) ", + "Connected (unencrypted) to ": "Ku xidhan (aan qarsoodi ahayn)", + "Something went wrong, connection is closed": "Waxbaa khaldamay, xidhiidhku waa xidhan yahay", + "Failed to connect to server": "Waa lagu guul daraystay in lagu xidho serfarka", + "Disconnected": "Go'ay", + "New connection has been rejected with reason: ": "Xiriirka cusub waxaa lagu diiday sabab:", + "New connection has been rejected": "Xiriirka cusub waa la diiday", + "Credentials are required": "Waxyaabaha aqoonsiga ayaa loo baahan yahay", + "Hide/Show the control bar": "Qari/muuji barta kontoroolka", + "Drag": "Jiid", + "Move/Drag Viewport": "Dhaqdhaqaaq / Jiid Daawashada", + "Keyboard": "Keyboard", + "Show Keyboard": "muuji kiiboodhka", + "Extra keys": "furayaal dheeri ah", + "Show Extra Keys": "muuji furayaal dheeri ah", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Beddel Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Daaqadaha", + "Send Tab": "Dir Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Dir baxso", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "U dir Ctrl-Alt-Del", + "Shutdown/Reboot": "Xiritaanka/dib u kabashada", + "Shutdown/Reboot...": " Xir/Dib u kici...", + "Power": "Awood", + "Shutdown": "Bakhtii", + "Reboot": "dib u kici", + "Reset": "Dib u habeyn", + "Clipboard": "Klipboard", + "Clear": "Nadiifi", + "Fullscreen": "shaashadda buuxda", + "Settings": "Settings", + "Shared Mode": "Qaabka la wadaago", + "View Only": "Kaliya arag", + "Clip to Window": "Ku duub daaqadda", + "Scaling Mode:": "Qaabka cabbirka:", + "None": "Maya", + "Local Scaling": "Qiimaynta Deegaanka", + "Remote Resizing": "Qiimaynta fog", + "Advanced": "Hore", + "Quality:": "Tayada:", + "Compression level:": "Heerka cadaadiska:", + "Repeater ID:": "Aqoonsiga soo noqnoqda:", + "WebSocket": "WebSocket", + "Encrypt": "Sirta", + "Host:": "Martigeliyaha:", + "Port:": "Dekedda:", + "Path:": "Wadada:", + "Automatic Reconnect": "Dib u xidhid toos ah", + "Reconnect Delay (ms):": "Dib u xidhid dib u dhac (ms):", + "Show Dot when No Cursor": "Show dhibic marka aanay Cursor jirin", + "Logging:": "Goynta:", + "Version:": "Nooca:", + "Disconnect": "Xiriirka ka saar", + "Connect": "isku xidh", + "Username:": "Username:", + "Password:": "Password:", + "Send Credentials": "Soo dir warqadaha aqoonsiga", + "Cancel": "Bejis", + "Keys": "Furayaasha", + "Game Cursor Mode": "Qaabka Cursorka Ciyaarta", + "Press Esc Key to Exit Pointer Lock Mode": "Riix furaha Esc si aad uga baxdo Habka Qufulka Tilmaamaha", + "Game Mode paused, click on screen to resume Game Mode.": "Qaabka ciyaarta waa la hakiyay, guji shaashadda si aad dib ugu bilowdo Habka Ciyaarta.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard-ka bilaa-xun", + "Prefer Local Cursor": "Doorbi Cursor Local", + "Translate keyboard shortcuts": "Turjun furayaasha kiiboodhka", + "Enable WebRTC UDP Transit": "Dari WebRTC UDP Gaadiidka", + "Enable WebP Compression": "Dari isku-buufinta WebP", + "Enable Performance Stats": "Kor u yeel Tirakoobka Waxqabadka", + "Enable Pointer Lock": "Dari qufulka tilmaanta", + "IME Input Mode": "Qaabka galitaanka IME", + "Show Virtual Keyboard Control": "muuji xakamaynta kiiboodhka Virtual", + "Toggle Control Panel via Keystrokes": "Ku beddel kontoroolka furaha", + "Render Native Resolution": "Samee Qaraarka Dhaladka", + "Keyboard Shortcuts": "Keyboodhka Gaaban", + "Enable KasmVNC Keyboard Shortcuts": "Kor-geli KasmVNC Kiiboodhka Gaaban", + "1 - Toggle Control Panel": "1 - Beddel kontoroolka", + "2 - Toggle Game Pointer Mode": "2 - Beddel Habka Tilmaamaha Ciyaarta", + "3 - Toggle Pointer Lock": "3 - Beddel Qufulka Tilmaamaha", + "Stream Quality": "Tayada socodka", + "Preset Modes:": "Qaababka hore loo dhigay:", + "Static": "Static", + "Low": "hooseeya", + "Medium": " Dhexdhexaad ", + "High": "sare", + "Extreme": "aad u daran", + "Lossless": " khasaare la'aan ", + "Custom": "Custom", + "Anti-Aliasing:": "Ka-hortagga aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Dam", + "On": "Daran", + "Dynamic Quality Min:": "Tayada firfircoon Min:", + "Dynamic Quality Max:": "Tayada firfircoonida ugu badan:", + "Treat Lossless:": "La dawee Khasaare La'aan:", + "Frame Rate:": "Heerka jir:", + "Video JPEG Quality:": "Video JPEG Tayada:", + "Video WEBP Quality:": "Video WEBP Tayada:", + "Video Area:": "Aagga Muuqaalka:", + "Video Time:": "Waqtiga Fiidiyowga:", + "Video Out Time:": "Waqtiga Fiidiyaha:", + "Video Mode Width:": "Balac ahaan Qaabka Fiidiyowga:", + "Video Mode Height:": "Habka Fiidiyowga Dhererka:", + "Documentation": "Documentation", + "Drag Viewport": "Deegaanka Jiid", + "KasmVNC encountered an error:": "KasmVNC waxay la kulantay cilad:" +} \ No newline at end of file diff --git a/app/locale/so_SO.json b/app/locale/so_SO.json new file mode 100644 index 0000000..f089b61 --- /dev/null +++ b/app/locale/so_SO.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "isku xidhka...", + "Disconnecting...": "Xiriirka gooya...", + "Reconnecting...": "Dib u xidhidhinta...", + "Internal error": "khalad gudaha ah", + "Must set host": "Waa in la dejiyaa martigeliyaha", + "Connected (encrypted) to ": "Waxa lagu xidhay ( sir ah) ", + "Connected (unencrypted) to ": "Ku xidhan (aan qarsoodi ahayn)", + "Something went wrong, connection is closed": "Waxbaa khaldamay, xidhiidhku waa xidhan yahay", + "Failed to connect to server": "Waa lagu guul daraystay in lagu xidho serfarka", + "Disconnected": "Go'ay", + "New connection has been rejected with reason: ": "Xiriirka cusub waxaa lagu diiday sabab:", + "New connection has been rejected": "Xiriirka cusub waa la diiday", + "Credentials are required": "Waxyaabaha aqoonsiga ayaa loo baahan yahay", + "Hide/Show the control bar": "Qari/muuji barta kontoroolka", + "Drag": "Jiid", + "Move/Drag Viewport": "Dhaqdhaqaaq / Jiid Daawashada", + "Keyboard": "Keyboard", + "Show Keyboard": "muuji kiiboodhka", + "Extra keys": "furayaal dheeri ah", + "Show Extra Keys": "muuji furayaal dheeri ah", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Beddel Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Toggle Windows", + "Windows": "Daaqadaha", + "Send Tab": "Dir Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Dir baxso", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "U dir Ctrl-Alt-Del", + "Shutdown/Reboot": "Xiritaanka/dib u kabashada", + "Shutdown/Reboot...": " Xir/Dib u kici...", + "Power": "Awood", + "Shutdown": "Bakhtii", + "Reboot": "dib u kici", + "Reset": "Dib u habeyn", + "Clipboard": "Klipboard", + "Clear": "Nadiifi", + "Fullscreen": "shaashadda buuxda", + "Settings": "Settings", + "Shared Mode": "Qaabka la wadaago", + "View Only": "Kaliya arag", + "Clip to Window": "Ku duub daaqadda", + "Scaling Mode:": "Qaabka cabbirka:", + "None": "Maya", + "Local Scaling": "Qiimaynta Deegaanka", + "Remote Resizing": "Qiimaynta fog", + "Advanced": "Hore", + "Quality:": "Tayada:", + "Compression level:": "Heerka cadaadiska:", + "Repeater ID:": "Aqoonsiga soo noqnoqda:", + "WebSocket": "WebSocket", + "Encrypt": "Sirta", + "Host:": "Martigeliyaha:", + "Port:": "Dekedda:", + "Path:": "Wadada:", + "Automatic Reconnect": "Dib u xidhid toos ah", + "Reconnect Delay (ms):": "Dib u xidhid dib u dhac (ms):", + "Show Dot when No Cursor": "Show dhibic marka aanay Cursor jirin", + "Logging:": "Goynta:", + "Version:": "Nooca:", + "Disconnect": "Xiriirka ka saar", + "Connect": "isku xidh", + "Username:": "Username:", + "Password:": "Password:", + "Send Credentials": "Soo dir warqadaha aqoonsiga", + "Cancel": "Bejis", + "Keys": "Furayaasha", + "Game Cursor Mode": "Qaabka Cursorka Ciyaarta", + "Press Esc Key to Exit Pointer Lock Mode": "Riix furaha Esc si aad uga baxdo Habka Qufulka Tilmaamaha", + "Game Mode paused, click on screen to resume Game Mode.": "Qaabka ciyaarta waa la hakiyay, guji shaashadda si aad dib ugu bilowdo Habka Ciyaarta.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard-ka bilaa-xun", + "Prefer Local Cursor": "Doorbi Cursor Local", + "Translate keyboard shortcuts": "Turjun furayaasha kiiboodhka", + "Enable WebRTC UDP Transit": "Dari WebRTC UDP Gaadiidka", + "Enable WebP Compression": "Dari isku-buufinta WebP", + "Enable Performance Stats": "Kor u yeel Tirakoobka Waxqabadka", + "Enable Pointer Lock": "Dari qufulka tilmaanta", + "IME Input Mode": "Qaabka galitaanka IME", + "Show Virtual Keyboard Control": "muuji xakamaynta kiiboodhka Virtual", + "Toggle Control Panel via Keystrokes": "Ku beddel kontoroolka furaha", + "Render Native Resolution": "Samee Qaraarka Dhaladka", + "Keyboard Shortcuts": "Keyboodhka Gaaban", + "Enable KasmVNC Keyboard Shortcuts": "Kor-geli KasmVNC Kiiboodhka Gaaban", + "1 - Toggle Control Panel": "1 - Beddel kontoroolka", + "2 - Toggle Game Pointer Mode": "2 - Beddel Habka Tilmaamaha Ciyaarta", + "3 - Toggle Pointer Lock": "3 - Beddel Qufulka Tilmaamaha", + "Stream Quality": "Tayada socodka", + "Preset Modes:": "Qaababka hore loo dhigay:", + "Static": "Static", + "Low": "hooseeya", + "Medium": " Dhexdhexaad ", + "High": "sare", + "Extreme": "aad u daran", + "Lossless": " khasaare la'aan ", + "Custom": "Custom", + "Anti-Aliasing:": "Ka-hortagga aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Dam", + "On": "Daran", + "Dynamic Quality Min:": "Tayada firfircoon Min:", + "Dynamic Quality Max:": "Tayada firfircoonida ugu badan:", + "Treat Lossless:": "La dawee Khasaare La'aan:", + "Frame Rate:": "Heerka jir:", + "Video JPEG Quality:": "Video JPEG Tayada:", + "Video WEBP Quality:": "Video WEBP Tayada:", + "Video Area:": "Aagga Muuqaalka:", + "Video Time:": "Waqtiga Fiidiyowga:", + "Video Out Time:": "Waqtiga Fiidiyaha:", + "Video Mode Width:": "Balac ahaan Qaabka Fiidiyowga:", + "Video Mode Height:": "Habka Fiidiyowga Dhererka:", + "Documentation": "Documentation", + "Drag Viewport": "Deegaanka Jiid", + "KasmVNC encountered an error:": "KasmVNC waxay la kulantay cilad:" +} \ No newline at end of file diff --git a/app/locale/sq.json b/app/locale/sq.json new file mode 100644 index 0000000..69551a3 --- /dev/null +++ b/app/locale/sq.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Po lidhet...", + "Disconnecting...": "Po shkëputet...", + "Reconnecting...": "Rilidhja...", + "Internal error": "Gabim i brendshëm", + "Must set host": "Duhet të vendoset pritësi", + "Connected (encrypted) to ": "I lidhur (i koduar) me", + "Connected (unencrypted) to ": "I lidhur (i pakriptuar) me ", + "Something went wrong, connection is closed": "Diçka shkoi keq, lidhja u mbyll", + "Failed to connect to server": "Dështoi për t'u lidhur me serverin", + "Disconnected": "E shkëputur", + "New connection has been rejected with reason: ": "Lidhja e re është refuzuar me arsye:", + "New connection has been rejected": "Lidhja e re është refuzuar", + "Credentials are required": "Duhen kredenciale", + "Hide/Show the control bar": "Fshihe/Shfaq shiritin e kontrollit", + "Drag": "Zvarrit", + "Move/Drag Viewport": "Lëviz/Zvarrit portën e shikimit", + "Keyboard": "Tastiera", + "Show Keyboard": "Shfaq tastierën", + "Extra keys": "Çelësat shtesë", + "Show Extra Keys": "Trego çelësat shtesë", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ndrysho Ctrl", + "Alt": "Alt", + "Toggle Alt": "Ndrysho Alt", + "Toggle Windows": "Ndrysho Windows", + "Windows": "Windows", + "Send Tab": "Dërgo skedën", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Dërgo arratisje", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Dërgo Ctrl-Alt-Del", + "Shutdown/Reboot": "Fikja / Rindezja", + "Shutdown/Reboot...": "Fikja/rinisja...", + "Power": "fuqi", + "Shutdown": "Fike", + "Reboot": "Rinisni", + "Reset": "Rivendos", + "Clipboard": "Clipboard", + "Clear": "Qartë", + "Fullscreen": "Ekran i plotë", + "Settings": "Cilësimet", + "Shared Mode": "Modaliteti i përbashkët", + "View Only": "Vetëm shikim", + "Clip to Window": "Klip në dritare", + "Scaling Mode:": "Modaliteti i shkallëzimit:", + "None": "Asnje", + "Local Scaling": "Shkallëzimi lokal", + "Remote Resizing": "Ndryshimi i madhësisë në distancë", + "Advanced": "E avancuar", + "Quality:": "Cilësia:", + "Compression level:": "Niveli i kompresimit:", + "Repeater ID:": "ID-ja e përsëritësit:", + "WebSocket": "WebSocket", + "Encrypt": "Enkripto", + "Host:": "Mikpritës:", + "Port:": "Port:", + "Path:": "Rrugë:", + "Automatic Reconnect": "Rilidhja automatike", + "Reconnect Delay (ms):": "Vonesë e rilidhjes (ms):", + "Show Dot when No Cursor": "Trego pikën kur nuk ka kursor", + "Logging:": "Regjistrimi:", + "Version:": "Version:", + "Disconnect": "Shkëputje", + "Connect": "Lidhu", + "Username:": "Emri i përdoruesit:", + "Password:": "Fjalëkalimi:", + "Send Credentials": "Dërgo kredencialet", + "Cancel": "Anulo", + "Keys": "Çelësat", + "Game Cursor Mode": "Modaliteti i kursorit të lojës", + "Press Esc Key to Exit Pointer Lock Mode": "Shtypni tastin Esc për të dalë nga modaliteti i kyçjes së treguesit", + "Game Mode paused, click on screen to resume Game Mode.": "Modaliteti i lojës u ndërpre, klikoni në ekran për të rifilluar modalitetin e lojës.", + "Clipboard Up": "Klipboard lart", + "CLipboard Down": "Clipboard poshtë", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Preferoj kursorin lokal", + "Translate keyboard shortcuts": "Përkthe shkurtoret e tastierës", + "Enable WebRTC UDP Transit": "Aktivizo WebRTC UDP Transit", + "Enable WebP Compression": "Aktivizo kompresimin e WebP", + "Enable Performance Stats": "Aktivizo statistikat e performancës", + "Enable Pointer Lock": "Aktivizo kyçjen e treguesit", + "IME Input Mode": "Modaliteti i hyrjes IME", + "Show Virtual Keyboard Control": "Trego kontrollin e tastierës virtuale", + "Toggle Control Panel via Keystrokes": "Ndrysho panelin e kontrollit nëpërmjet goditjeve të tasteve", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Shkurtoret e tastierës", + "Enable KasmVNC Keyboard Shortcuts": "Aktivizo shkurtoret e tastierës KasmVNC", + "1 - Toggle Control Panel": "1 - Ndrysho panelin e kontrollit", + "2 - Toggle Game Pointer Mode": "2 - Ndrysho modalitetin e treguesit të lojës", + "3 - Toggle Pointer Lock": "3 - Ndrysho kyçjen e treguesit", + "Stream Quality": "Cilësia e transmetimit", + "Preset Modes:": "Modalitetet e paracaktuara:", + "Static": "Statike", + "Low": "I ulët", + "Medium": "e mesme", + "High": "i lartë", + "Extreme": "Ekstreme", + "Lossless": "Pa humbje", + "Custom": "Me porosi", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Fikur", + "On": "On", + "Dynamic Quality Min:": "Minimi i cilësisë dinamike:", + "Dynamic Quality Max:": "Maksimi i cilësisë dinamike:", + "Treat Lossless:": "Trajtoni pa humbje:", + "Frame Rate:": "Shkalla e kornizës:", + "Video JPEG Quality:": "Cilësia e videos JPEG:", + "Video WEBP Quality:": "Cilësia e videos WEBP:", + "Video Area:": "Zona e videos:", + "Video Time:": "Koha e videos:", + "Video Out Time:": "Koha e daljes së videos:", + "Video Mode Width:": "Gjerësia e modalitetit të videos:", + "Video Mode Height:": "Lartësia e modalitetit të videos:", + "Documentation": "Dokumentacioni", + "Drag Viewport": "Zvarrit portin e shikimit", + "KasmVNC encountered an error:": "KasmVNC hasi në një gabim:" +} \ No newline at end of file diff --git a/app/locale/sq_AL.json b/app/locale/sq_AL.json new file mode 100644 index 0000000..69551a3 --- /dev/null +++ b/app/locale/sq_AL.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Po lidhet...", + "Disconnecting...": "Po shkëputet...", + "Reconnecting...": "Rilidhja...", + "Internal error": "Gabim i brendshëm", + "Must set host": "Duhet të vendoset pritësi", + "Connected (encrypted) to ": "I lidhur (i koduar) me", + "Connected (unencrypted) to ": "I lidhur (i pakriptuar) me ", + "Something went wrong, connection is closed": "Diçka shkoi keq, lidhja u mbyll", + "Failed to connect to server": "Dështoi për t'u lidhur me serverin", + "Disconnected": "E shkëputur", + "New connection has been rejected with reason: ": "Lidhja e re është refuzuar me arsye:", + "New connection has been rejected": "Lidhja e re është refuzuar", + "Credentials are required": "Duhen kredenciale", + "Hide/Show the control bar": "Fshihe/Shfaq shiritin e kontrollit", + "Drag": "Zvarrit", + "Move/Drag Viewport": "Lëviz/Zvarrit portën e shikimit", + "Keyboard": "Tastiera", + "Show Keyboard": "Shfaq tastierën", + "Extra keys": "Çelësat shtesë", + "Show Extra Keys": "Trego çelësat shtesë", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ndrysho Ctrl", + "Alt": "Alt", + "Toggle Alt": "Ndrysho Alt", + "Toggle Windows": "Ndrysho Windows", + "Windows": "Windows", + "Send Tab": "Dërgo skedën", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Dërgo arratisje", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Dërgo Ctrl-Alt-Del", + "Shutdown/Reboot": "Fikja / Rindezja", + "Shutdown/Reboot...": "Fikja/rinisja...", + "Power": "fuqi", + "Shutdown": "Fike", + "Reboot": "Rinisni", + "Reset": "Rivendos", + "Clipboard": "Clipboard", + "Clear": "Qartë", + "Fullscreen": "Ekran i plotë", + "Settings": "Cilësimet", + "Shared Mode": "Modaliteti i përbashkët", + "View Only": "Vetëm shikim", + "Clip to Window": "Klip në dritare", + "Scaling Mode:": "Modaliteti i shkallëzimit:", + "None": "Asnje", + "Local Scaling": "Shkallëzimi lokal", + "Remote Resizing": "Ndryshimi i madhësisë në distancë", + "Advanced": "E avancuar", + "Quality:": "Cilësia:", + "Compression level:": "Niveli i kompresimit:", + "Repeater ID:": "ID-ja e përsëritësit:", + "WebSocket": "WebSocket", + "Encrypt": "Enkripto", + "Host:": "Mikpritës:", + "Port:": "Port:", + "Path:": "Rrugë:", + "Automatic Reconnect": "Rilidhja automatike", + "Reconnect Delay (ms):": "Vonesë e rilidhjes (ms):", + "Show Dot when No Cursor": "Trego pikën kur nuk ka kursor", + "Logging:": "Regjistrimi:", + "Version:": "Version:", + "Disconnect": "Shkëputje", + "Connect": "Lidhu", + "Username:": "Emri i përdoruesit:", + "Password:": "Fjalëkalimi:", + "Send Credentials": "Dërgo kredencialet", + "Cancel": "Anulo", + "Keys": "Çelësat", + "Game Cursor Mode": "Modaliteti i kursorit të lojës", + "Press Esc Key to Exit Pointer Lock Mode": "Shtypni tastin Esc për të dalë nga modaliteti i kyçjes së treguesit", + "Game Mode paused, click on screen to resume Game Mode.": "Modaliteti i lojës u ndërpre, klikoni në ekran për të rifilluar modalitetin e lojës.", + "Clipboard Up": "Klipboard lart", + "CLipboard Down": "Clipboard poshtë", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Preferoj kursorin lokal", + "Translate keyboard shortcuts": "Përkthe shkurtoret e tastierës", + "Enable WebRTC UDP Transit": "Aktivizo WebRTC UDP Transit", + "Enable WebP Compression": "Aktivizo kompresimin e WebP", + "Enable Performance Stats": "Aktivizo statistikat e performancës", + "Enable Pointer Lock": "Aktivizo kyçjen e treguesit", + "IME Input Mode": "Modaliteti i hyrjes IME", + "Show Virtual Keyboard Control": "Trego kontrollin e tastierës virtuale", + "Toggle Control Panel via Keystrokes": "Ndrysho panelin e kontrollit nëpërmjet goditjeve të tasteve", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Shkurtoret e tastierës", + "Enable KasmVNC Keyboard Shortcuts": "Aktivizo shkurtoret e tastierës KasmVNC", + "1 - Toggle Control Panel": "1 - Ndrysho panelin e kontrollit", + "2 - Toggle Game Pointer Mode": "2 - Ndrysho modalitetin e treguesit të lojës", + "3 - Toggle Pointer Lock": "3 - Ndrysho kyçjen e treguesit", + "Stream Quality": "Cilësia e transmetimit", + "Preset Modes:": "Modalitetet e paracaktuara:", + "Static": "Statike", + "Low": "I ulët", + "Medium": "e mesme", + "High": "i lartë", + "Extreme": "Ekstreme", + "Lossless": "Pa humbje", + "Custom": "Me porosi", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Fikur", + "On": "On", + "Dynamic Quality Min:": "Minimi i cilësisë dinamike:", + "Dynamic Quality Max:": "Maksimi i cilësisë dinamike:", + "Treat Lossless:": "Trajtoni pa humbje:", + "Frame Rate:": "Shkalla e kornizës:", + "Video JPEG Quality:": "Cilësia e videos JPEG:", + "Video WEBP Quality:": "Cilësia e videos WEBP:", + "Video Area:": "Zona e videos:", + "Video Time:": "Koha e videos:", + "Video Out Time:": "Koha e daljes së videos:", + "Video Mode Width:": "Gjerësia e modalitetit të videos:", + "Video Mode Height:": "Lartësia e modalitetit të videos:", + "Documentation": "Dokumentacioni", + "Drag Viewport": "Zvarrit portin e shikimit", + "KasmVNC encountered an error:": "KasmVNC hasi në një gabim:" +} \ No newline at end of file diff --git a/app/locale/sq_MK.json b/app/locale/sq_MK.json new file mode 100644 index 0000000..69551a3 --- /dev/null +++ b/app/locale/sq_MK.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Po lidhet...", + "Disconnecting...": "Po shkëputet...", + "Reconnecting...": "Rilidhja...", + "Internal error": "Gabim i brendshëm", + "Must set host": "Duhet të vendoset pritësi", + "Connected (encrypted) to ": "I lidhur (i koduar) me", + "Connected (unencrypted) to ": "I lidhur (i pakriptuar) me ", + "Something went wrong, connection is closed": "Diçka shkoi keq, lidhja u mbyll", + "Failed to connect to server": "Dështoi për t'u lidhur me serverin", + "Disconnected": "E shkëputur", + "New connection has been rejected with reason: ": "Lidhja e re është refuzuar me arsye:", + "New connection has been rejected": "Lidhja e re është refuzuar", + "Credentials are required": "Duhen kredenciale", + "Hide/Show the control bar": "Fshihe/Shfaq shiritin e kontrollit", + "Drag": "Zvarrit", + "Move/Drag Viewport": "Lëviz/Zvarrit portën e shikimit", + "Keyboard": "Tastiera", + "Show Keyboard": "Shfaq tastierën", + "Extra keys": "Çelësat shtesë", + "Show Extra Keys": "Trego çelësat shtesë", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ndrysho Ctrl", + "Alt": "Alt", + "Toggle Alt": "Ndrysho Alt", + "Toggle Windows": "Ndrysho Windows", + "Windows": "Windows", + "Send Tab": "Dërgo skedën", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Dërgo arratisje", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Dërgo Ctrl-Alt-Del", + "Shutdown/Reboot": "Fikja / Rindezja", + "Shutdown/Reboot...": "Fikja/rinisja...", + "Power": "fuqi", + "Shutdown": "Fike", + "Reboot": "Rinisni", + "Reset": "Rivendos", + "Clipboard": "Clipboard", + "Clear": "Qartë", + "Fullscreen": "Ekran i plotë", + "Settings": "Cilësimet", + "Shared Mode": "Modaliteti i përbashkët", + "View Only": "Vetëm shikim", + "Clip to Window": "Klip në dritare", + "Scaling Mode:": "Modaliteti i shkallëzimit:", + "None": "Asnje", + "Local Scaling": "Shkallëzimi lokal", + "Remote Resizing": "Ndryshimi i madhësisë në distancë", + "Advanced": "E avancuar", + "Quality:": "Cilësia:", + "Compression level:": "Niveli i kompresimit:", + "Repeater ID:": "ID-ja e përsëritësit:", + "WebSocket": "WebSocket", + "Encrypt": "Enkripto", + "Host:": "Mikpritës:", + "Port:": "Port:", + "Path:": "Rrugë:", + "Automatic Reconnect": "Rilidhja automatike", + "Reconnect Delay (ms):": "Vonesë e rilidhjes (ms):", + "Show Dot when No Cursor": "Trego pikën kur nuk ka kursor", + "Logging:": "Regjistrimi:", + "Version:": "Version:", + "Disconnect": "Shkëputje", + "Connect": "Lidhu", + "Username:": "Emri i përdoruesit:", + "Password:": "Fjalëkalimi:", + "Send Credentials": "Dërgo kredencialet", + "Cancel": "Anulo", + "Keys": "Çelësat", + "Game Cursor Mode": "Modaliteti i kursorit të lojës", + "Press Esc Key to Exit Pointer Lock Mode": "Shtypni tastin Esc për të dalë nga modaliteti i kyçjes së treguesit", + "Game Mode paused, click on screen to resume Game Mode.": "Modaliteti i lojës u ndërpre, klikoni në ekran për të rifilluar modalitetin e lojës.", + "Clipboard Up": "Klipboard lart", + "CLipboard Down": "Clipboard poshtë", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Preferoj kursorin lokal", + "Translate keyboard shortcuts": "Përkthe shkurtoret e tastierës", + "Enable WebRTC UDP Transit": "Aktivizo WebRTC UDP Transit", + "Enable WebP Compression": "Aktivizo kompresimin e WebP", + "Enable Performance Stats": "Aktivizo statistikat e performancës", + "Enable Pointer Lock": "Aktivizo kyçjen e treguesit", + "IME Input Mode": "Modaliteti i hyrjes IME", + "Show Virtual Keyboard Control": "Trego kontrollin e tastierës virtuale", + "Toggle Control Panel via Keystrokes": "Ndrysho panelin e kontrollit nëpërmjet goditjeve të tasteve", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Shkurtoret e tastierës", + "Enable KasmVNC Keyboard Shortcuts": "Aktivizo shkurtoret e tastierës KasmVNC", + "1 - Toggle Control Panel": "1 - Ndrysho panelin e kontrollit", + "2 - Toggle Game Pointer Mode": "2 - Ndrysho modalitetin e treguesit të lojës", + "3 - Toggle Pointer Lock": "3 - Ndrysho kyçjen e treguesit", + "Stream Quality": "Cilësia e transmetimit", + "Preset Modes:": "Modalitetet e paracaktuara:", + "Static": "Statike", + "Low": "I ulët", + "Medium": "e mesme", + "High": "i lartë", + "Extreme": "Ekstreme", + "Lossless": "Pa humbje", + "Custom": "Me porosi", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Fikur", + "On": "On", + "Dynamic Quality Min:": "Minimi i cilësisë dinamike:", + "Dynamic Quality Max:": "Maksimi i cilësisë dinamike:", + "Treat Lossless:": "Trajtoni pa humbje:", + "Frame Rate:": "Shkalla e kornizës:", + "Video JPEG Quality:": "Cilësia e videos JPEG:", + "Video WEBP Quality:": "Cilësia e videos WEBP:", + "Video Area:": "Zona e videos:", + "Video Time:": "Koha e videos:", + "Video Out Time:": "Koha e daljes së videos:", + "Video Mode Width:": "Gjerësia e modalitetit të videos:", + "Video Mode Height:": "Lartësia e modalitetit të videos:", + "Documentation": "Dokumentacioni", + "Drag Viewport": "Zvarrit portin e shikimit", + "KasmVNC encountered an error:": "KasmVNC hasi në një gabim:" +} \ No newline at end of file diff --git a/app/locale/st.json b/app/locale/st.json new file mode 100644 index 0000000..69abad7 --- /dev/null +++ b/app/locale/st.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "E kopanya ...", + "Disconnecting...": "Ho khaola...", + "Reconnecting...": "E kopanya hape...", + "Internal error": "Phoso ea ka hare", + "Must set host": "E tlameha ho seta moamoheli", + "Connected (encrypted) to ": "E hokahane (e patiloe) ho ", + "Connected (unencrypted) to ": "E kopantsoe (e sa ngolisoa) ho ", + "Something went wrong, connection is closed": "Ho na le phoso, khokahano e koetsoe", + "Failed to connect to server": "E hlolehile ho hokela ho seva", + "Disconnected": "E khaotsoe", + "New connection has been rejected with reason: ": "Khokahano e ncha e hanngoe ka lebaka: ", + "New connection has been rejected": "Khokahano e ncha e hanngoe", + "Credentials are required": "Boitsebiso boa hlokahala", + "Hide/Show the control bar": "Pata / Bontša sebaka sa taolo", + "Drag": "Hula", + "Move/Drag Viewport": "Sutha/Hula Viewport", + "Keyboard": "Keyboard", + "Show Keyboard": "Bontša Keyboard", + "Extra keys": "Linotlolo tse ling", + "Show Extra Keys": "Show Extra Keys", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Fetola Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Fetola Windows", + "Windows": "Windows", + "Send Tab": "Romela Tab", + "Tab": "Taba", + "Esc": "Esc", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Romela Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "Matla", + "Shutdown": "Koala", + "Reboot": "Qala bocha", + "Reset": "Reset", + "Clipboard": "Clipboard", + "Clear": "Ho hlakile", + "Fullscreen": "Skrine se felletseng", + "Settings": "Litlhophiso", + "Shared Mode": "Mokhoa o arolelanoeng", + "View Only": "Sheba Feela", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Scaling Mode:", + "None": "Ha ho letho", + "Local Scaling": "Local Scaling", + "Remote Resizing": "Remote Resize", + "Advanced": "E tsoetseng pele", + "Quality:": "Boleng:", + "Compression level:": "Boemo ba compression:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Moamoheli:", + "Port:": "Port:", + "Path:": "Tsela:", + "Automatic Reconnect": "Hokela hape ka othomathiki", + "Reconnect Delay (ms):": "Hokahanya Teeho hape (ms):", + "Show Dot when No Cursor": "Show Dot when No Cursor", + "Logging:": "Ho rema lifate:", + "Version:": "Version:", + "Disconnect": "Haola", + "Connect": "Hokela", + "Username:": "Lebitso la mosebelisi:", + "Password:": "Password:", + "Send Credentials": "Romela Litlhaloso", + "Cancel": "Hlakola", + "Keys": "Linotlolo", + "Game Cursor Mode": "Game Cursor Mode", + "Press Esc Key to Exit Pointer Lock Mode": "Tobetsa Esc Key ho Tsoa Mokhoa oa Lock ea Pointer", + "Game Mode paused, click on screen to resume Game Mode.": "Game Mode e emisitsoe, tobetsa skrineng ho qala Mokhoa oa Papali hape.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard e sa tsitsang", + "Prefer Local Cursor": "Rata Cursor ea Lehae", + "Translate keyboard shortcuts": "Fetolela likhutšoane tsa keyboard", + "Enable WebRTC UDP Transit": "Lumella WebRTC UDP Transit", + "Enable WebP Compression": "Enable WebP Compression", + "Enable Performance Stats": "Enable Performance Stats", + "Enable Pointer Lock": "Enable Pointer Lock", + "IME Input Mode": "IME Mokhoa oa ho Kenya", + "Show Virtual Keyboard Control": "Show Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "Toggle Control Panel ka Keystrokes", + "Render Native Resolution": "Fana ka Qeto ea Naha", + "Keyboard Shortcuts": "Likhaoletso tsa Keyboard", + "Enable KasmVNC Keyboard Shortcuts": "Lumella likhutšoane tsa keyboard ea KasmVNC", + "1 - Toggle Control Panel": "1 - Toggle Control Panel", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Boleng ba Phallo", + "Preset Modes:": "Mefuta e setang esale pele:", + "Static": "Static", + "Low": "tlase", + "Medium": "Bohareng", + "High": "Holimo", + "Extreme": "E feteletseng", + "Lossless": "Tahlehelo", + "Custom": "Tloaelo", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Tima", + "On": "Bula", + "Dynamic Quality Min:": "Dynamic Quality Min:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Tšoara U se Nang tahlehelo:", + "Frame Rate:": "Sekhahla sa Frame:", + "Video JPEG Quality:": "Boleng ba JPEG ea Video:", + "Video WEBP Quality:": "Boleng ba Video WEBP:", + "Video Area:": "Sebaka sa Video:", + "Video Time:": "Nako ea Video:", + "Video Out Time:": "Nako ea ho Fella ha Video:", + "Video Mode Width:": "Bophara ba Mokhoa oa Video:", + "Video Mode Height:": "Boemo ba Mokhoa oa Video:", + "Documentation": "Litokomane", + "Drag Viewport": "Hula Viewport", + "KasmVNC encountered an error:": "KasmVNC e fumane phoso:" +} \ No newline at end of file diff --git a/app/locale/st_ZA.json b/app/locale/st_ZA.json new file mode 100644 index 0000000..69abad7 --- /dev/null +++ b/app/locale/st_ZA.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "E kopanya ...", + "Disconnecting...": "Ho khaola...", + "Reconnecting...": "E kopanya hape...", + "Internal error": "Phoso ea ka hare", + "Must set host": "E tlameha ho seta moamoheli", + "Connected (encrypted) to ": "E hokahane (e patiloe) ho ", + "Connected (unencrypted) to ": "E kopantsoe (e sa ngolisoa) ho ", + "Something went wrong, connection is closed": "Ho na le phoso, khokahano e koetsoe", + "Failed to connect to server": "E hlolehile ho hokela ho seva", + "Disconnected": "E khaotsoe", + "New connection has been rejected with reason: ": "Khokahano e ncha e hanngoe ka lebaka: ", + "New connection has been rejected": "Khokahano e ncha e hanngoe", + "Credentials are required": "Boitsebiso boa hlokahala", + "Hide/Show the control bar": "Pata / Bontša sebaka sa taolo", + "Drag": "Hula", + "Move/Drag Viewport": "Sutha/Hula Viewport", + "Keyboard": "Keyboard", + "Show Keyboard": "Bontša Keyboard", + "Extra keys": "Linotlolo tse ling", + "Show Extra Keys": "Show Extra Keys", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Fetola Ctrl", + "Alt": "Alt", + "Toggle Alt": "Toggle Alt", + "Toggle Windows": "Fetola Windows", + "Windows": "Windows", + "Send Tab": "Romela Tab", + "Tab": "Taba", + "Esc": "Esc", + "Send Escape": "Send Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Romela Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Shutdown/Reboot...", + "Power": "Matla", + "Shutdown": "Koala", + "Reboot": "Qala bocha", + "Reset": "Reset", + "Clipboard": "Clipboard", + "Clear": "Ho hlakile", + "Fullscreen": "Skrine se felletseng", + "Settings": "Litlhophiso", + "Shared Mode": "Mokhoa o arolelanoeng", + "View Only": "Sheba Feela", + "Clip to Window": "Clip to Window", + "Scaling Mode:": "Scaling Mode:", + "None": "Ha ho letho", + "Local Scaling": "Local Scaling", + "Remote Resizing": "Remote Resize", + "Advanced": "E tsoetseng pele", + "Quality:": "Boleng:", + "Compression level:": "Boemo ba compression:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "Encrypt", + "Host:": "Moamoheli:", + "Port:": "Port:", + "Path:": "Tsela:", + "Automatic Reconnect": "Hokela hape ka othomathiki", + "Reconnect Delay (ms):": "Hokahanya Teeho hape (ms):", + "Show Dot when No Cursor": "Show Dot when No Cursor", + "Logging:": "Ho rema lifate:", + "Version:": "Version:", + "Disconnect": "Haola", + "Connect": "Hokela", + "Username:": "Lebitso la mosebelisi:", + "Password:": "Password:", + "Send Credentials": "Romela Litlhaloso", + "Cancel": "Hlakola", + "Keys": "Linotlolo", + "Game Cursor Mode": "Game Cursor Mode", + "Press Esc Key to Exit Pointer Lock Mode": "Tobetsa Esc Key ho Tsoa Mokhoa oa Lock ea Pointer", + "Game Mode paused, click on screen to resume Game Mode.": "Game Mode e emisitsoe, tobetsa skrineng ho qala Mokhoa oa Papali hape.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Clipboard e sa tsitsang", + "Prefer Local Cursor": "Rata Cursor ea Lehae", + "Translate keyboard shortcuts": "Fetolela likhutšoane tsa keyboard", + "Enable WebRTC UDP Transit": "Lumella WebRTC UDP Transit", + "Enable WebP Compression": "Enable WebP Compression", + "Enable Performance Stats": "Enable Performance Stats", + "Enable Pointer Lock": "Enable Pointer Lock", + "IME Input Mode": "IME Mokhoa oa ho Kenya", + "Show Virtual Keyboard Control": "Show Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "Toggle Control Panel ka Keystrokes", + "Render Native Resolution": "Fana ka Qeto ea Naha", + "Keyboard Shortcuts": "Likhaoletso tsa Keyboard", + "Enable KasmVNC Keyboard Shortcuts": "Lumella likhutšoane tsa keyboard ea KasmVNC", + "1 - Toggle Control Panel": "1 - Toggle Control Panel", + "2 - Toggle Game Pointer Mode": "2 - Toggle Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Boleng ba Phallo", + "Preset Modes:": "Mefuta e setang esale pele:", + "Static": "Static", + "Low": "tlase", + "Medium": "Bohareng", + "High": "Holimo", + "Extreme": "E feteletseng", + "Lossless": "Tahlehelo", + "Custom": "Tloaelo", + "Anti-Aliasing:": "Anti-Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Tima", + "On": "Bula", + "Dynamic Quality Min:": "Dynamic Quality Min:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Tšoara U se Nang tahlehelo:", + "Frame Rate:": "Sekhahla sa Frame:", + "Video JPEG Quality:": "Boleng ba JPEG ea Video:", + "Video WEBP Quality:": "Boleng ba Video WEBP:", + "Video Area:": "Sebaka sa Video:", + "Video Time:": "Nako ea Video:", + "Video Out Time:": "Nako ea ho Fella ha Video:", + "Video Mode Width:": "Bophara ba Mokhoa oa Video:", + "Video Mode Height:": "Boemo ba Mokhoa oa Video:", + "Documentation": "Litokomane", + "Drag Viewport": "Hula Viewport", + "KasmVNC encountered an error:": "KasmVNC e fumane phoso:" +} \ No newline at end of file diff --git a/app/locale/sv.json b/app/locale/sv.json new file mode 100644 index 0000000..c061818 --- /dev/null +++ b/app/locale/sv.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ansluter...", + "Disconnecting...": "Kopplar ner...", + "Reconnecting...": "Återansluter...", + "Internal error": "Internt fel", + "Must set host": "Du måste specifiera en värd", + "Connected (encrypted) to ": "Ansluten (krypterat) till ", + "Connected (unencrypted) to ": "Ansluten (okrypterat) till ", + "Something went wrong, connection is closed": "Något gick fel, anslutningen avslutades", + "Failed to connect to server": "Misslyckades att ansluta till servern", + "Disconnected": "Frånkopplad", + "New connection has been rejected with reason: ": "Ny anslutning har blivit nekad med följande skäl: ", + "New connection has been rejected": "Ny anslutning har blivit nekad", + "Credentials are required": "Användaruppgifter krävs", + "Hide/Show the control bar": "Göm/Visa kontrollbaren", + "Drag": "Dra", + "Move/Drag Viewport": "Flytta/Dra Vyn", + "Keyboard": "Tangentbord", + "Show Keyboard": "Visa Tangentbord", + "Extra keys": "Extraknappar", + "Show Extra Keys": "Visa Extraknappar", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Växla Ctrl", + "Alt": "Alt", + "Toggle Alt": "Växla Alt", + "Toggle Windows": "Växla Windows", + "Windows": "Windows", + "Send Tab": "Skicka Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Skicka Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Skicka Ctrl-Alt-Del", + "Shutdown/Reboot": "Stäng av/Boota om", + "Shutdown/Reboot...": "Stäng av/Boota om...", + "Power": "Ström", + "Shutdown": "Stäng av", + "Reboot": "Boota om", + "Reset": "Återställ", + "Clipboard": "Urklipp", + "Clear": "Rensa", + "Fullscreen": "Fullskärm", + "Settings": "Inställningar", + "Shared Mode": "Delat Läge", + "View Only": "Endast Visning", + "Clip to Window": "Begränsa till Fönster", + "Scaling Mode:": "Skalningsläge:", + "None": "Ingen", + "Local Scaling": "Lokal Skalning", + "Remote Resizing": "Ändra Storlek", + "Advanced": "Avancerat", + "Quality:": "Kvalitet:", + "Compression level:": "Kompressionsnivå:", + "Repeater ID:": "Repeater-ID:", + "WebSocket": "WebSocket", + "Encrypt": "Kryptera", + "Host:": "Värd:", + "Port:": "Port:", + "Path:": "Sökväg:", + "Automatic Reconnect": "Automatisk Återanslutning", + "Reconnect Delay (ms):": "Fördröjning (ms):", + "Show Dot when No Cursor": "Visa prick när ingen muspekare finns", + "Logging:": "Loggning:", + "Version:": "Version:", + "Disconnect": "Koppla från", + "Connect": "Anslut", + "Username:": "Användarnamn:", + "Password:": "Lösenord:", + "Send Credentials": "Skicka Användaruppgifter", + "Cancel": "Avbryt", + "Keys": "Nycklar", + "Game Cursor Mode": "Spelmarkörläge", + "Press Esc Key to Exit Pointer Lock Mode": "Tryck på Esc-tangenten för att avsluta pekarlåsläget", + "Game Mode paused, click on screen to resume Game Mode.": "Spelläge pausat, klicka på skärmen för att återuppta spelläge.", + "Clipboard Up": "Urklipp upp", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Urklipp Seamless", + "Prefer Local Cursor": "Föredrar lokal markör", + "Translate keyboard shortcuts": "Översätt kortkommandon", + "Enable WebRTC UDP Transit": "Aktivera WebRTC UDP Transit", + "Enable WebP Compression": "Aktivera WebP-komprimering", + "Enable Performance Stats": "Aktivera prestationsstatistik", + "Enable Pointer Lock": "Aktivera peklås", + "IME Input Mode": "IME Input Mode", + "Show Virtual Keyboard Control": "Visa virtuell tangentbordskontroll", + "Toggle Control Panel via Keystrokes": "Växla kontrollpanelen via tangenttryckningar", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Tangentbordsgenvägar", + "Enable KasmVNC Keyboard Shortcuts": "Aktivera KasmVNC tangentbordsgenvägar", + "1 - Toggle Control Panel": "1 - Växla kontrollpanelen", + "2 - Toggle Game Pointer Mode": "2 - Växla spelpekarläge", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Strömkvalitet", + "Preset Modes:": "Förinställda lägen:", + "Static": "Statisk", + "Low": "Låg", + "Medium": "Medium", + "High": "Hög", + "Extreme": "Extrem", + "Lossless": "Förlust mindre", + "Custom": "Beställnings", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Av", + "On": "På", + "Dynamic Quality Min:": "Dynamisk kvalitet min:", + "Dynamic Quality Max:": "Dynamisk kvalitet Max:", + "Treat Lossless:": "Behandla Lossless:", + "Frame Rate:": "Bildfrekvens:", + "Video JPEG Quality:": "Video JPEG-kvalitet:", + "Video WEBP Quality:": "Video WEBP Quality:", + "Video Area:": "Videoområde:", + "Video Time:": "Videotid:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Videolägesbredd:", + "Video Mode Height:": "Videolägeshöjd:", + "Documentation": "Dokumentation", + "Drag Viewport": "Dra Viewport", + "KasmVNC encountered an error:": "KasmVNC stötte på ett fel:" +} \ No newline at end of file diff --git a/app/locale/sv_FI.json b/app/locale/sv_FI.json new file mode 100644 index 0000000..c061818 --- /dev/null +++ b/app/locale/sv_FI.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ansluter...", + "Disconnecting...": "Kopplar ner...", + "Reconnecting...": "Återansluter...", + "Internal error": "Internt fel", + "Must set host": "Du måste specifiera en värd", + "Connected (encrypted) to ": "Ansluten (krypterat) till ", + "Connected (unencrypted) to ": "Ansluten (okrypterat) till ", + "Something went wrong, connection is closed": "Något gick fel, anslutningen avslutades", + "Failed to connect to server": "Misslyckades att ansluta till servern", + "Disconnected": "Frånkopplad", + "New connection has been rejected with reason: ": "Ny anslutning har blivit nekad med följande skäl: ", + "New connection has been rejected": "Ny anslutning har blivit nekad", + "Credentials are required": "Användaruppgifter krävs", + "Hide/Show the control bar": "Göm/Visa kontrollbaren", + "Drag": "Dra", + "Move/Drag Viewport": "Flytta/Dra Vyn", + "Keyboard": "Tangentbord", + "Show Keyboard": "Visa Tangentbord", + "Extra keys": "Extraknappar", + "Show Extra Keys": "Visa Extraknappar", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Växla Ctrl", + "Alt": "Alt", + "Toggle Alt": "Växla Alt", + "Toggle Windows": "Växla Windows", + "Windows": "Windows", + "Send Tab": "Skicka Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Skicka Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Skicka Ctrl-Alt-Del", + "Shutdown/Reboot": "Stäng av/Boota om", + "Shutdown/Reboot...": "Stäng av/Boota om...", + "Power": "Ström", + "Shutdown": "Stäng av", + "Reboot": "Boota om", + "Reset": "Återställ", + "Clipboard": "Urklipp", + "Clear": "Rensa", + "Fullscreen": "Fullskärm", + "Settings": "Inställningar", + "Shared Mode": "Delat Läge", + "View Only": "Endast Visning", + "Clip to Window": "Begränsa till Fönster", + "Scaling Mode:": "Skalningsläge:", + "None": "Ingen", + "Local Scaling": "Lokal Skalning", + "Remote Resizing": "Ändra Storlek", + "Advanced": "Avancerat", + "Quality:": "Kvalitet:", + "Compression level:": "Kompressionsnivå:", + "Repeater ID:": "Repeater-ID:", + "WebSocket": "WebSocket", + "Encrypt": "Kryptera", + "Host:": "Värd:", + "Port:": "Port:", + "Path:": "Sökväg:", + "Automatic Reconnect": "Automatisk Återanslutning", + "Reconnect Delay (ms):": "Fördröjning (ms):", + "Show Dot when No Cursor": "Visa prick när ingen muspekare finns", + "Logging:": "Loggning:", + "Version:": "Version:", + "Disconnect": "Koppla från", + "Connect": "Anslut", + "Username:": "Användarnamn:", + "Password:": "Lösenord:", + "Send Credentials": "Skicka Användaruppgifter", + "Cancel": "Avbryt", + "Keys": "Nycklar", + "Game Cursor Mode": "Spelmarkörläge", + "Press Esc Key to Exit Pointer Lock Mode": "Tryck på Esc-tangenten för att avsluta pekarlåsläget", + "Game Mode paused, click on screen to resume Game Mode.": "Spelläge pausat, klicka på skärmen för att återuppta spelläge.", + "Clipboard Up": "Urklipp upp", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Urklipp Seamless", + "Prefer Local Cursor": "Föredrar lokal markör", + "Translate keyboard shortcuts": "Översätt kortkommandon", + "Enable WebRTC UDP Transit": "Aktivera WebRTC UDP Transit", + "Enable WebP Compression": "Aktivera WebP-komprimering", + "Enable Performance Stats": "Aktivera prestationsstatistik", + "Enable Pointer Lock": "Aktivera peklås", + "IME Input Mode": "IME Input Mode", + "Show Virtual Keyboard Control": "Visa virtuell tangentbordskontroll", + "Toggle Control Panel via Keystrokes": "Växla kontrollpanelen via tangenttryckningar", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Tangentbordsgenvägar", + "Enable KasmVNC Keyboard Shortcuts": "Aktivera KasmVNC tangentbordsgenvägar", + "1 - Toggle Control Panel": "1 - Växla kontrollpanelen", + "2 - Toggle Game Pointer Mode": "2 - Växla spelpekarläge", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Strömkvalitet", + "Preset Modes:": "Förinställda lägen:", + "Static": "Statisk", + "Low": "Låg", + "Medium": "Medium", + "High": "Hög", + "Extreme": "Extrem", + "Lossless": "Förlust mindre", + "Custom": "Beställnings", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Av", + "On": "På", + "Dynamic Quality Min:": "Dynamisk kvalitet min:", + "Dynamic Quality Max:": "Dynamisk kvalitet Max:", + "Treat Lossless:": "Behandla Lossless:", + "Frame Rate:": "Bildfrekvens:", + "Video JPEG Quality:": "Video JPEG-kvalitet:", + "Video WEBP Quality:": "Video WEBP Quality:", + "Video Area:": "Videoområde:", + "Video Time:": "Videotid:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Videolägesbredd:", + "Video Mode Height:": "Videolägeshöjd:", + "Documentation": "Dokumentation", + "Drag Viewport": "Dra Viewport", + "KasmVNC encountered an error:": "KasmVNC stötte på ett fel:" +} \ No newline at end of file diff --git a/app/locale/sv_SE.json b/app/locale/sv_SE.json new file mode 100644 index 0000000..c061818 --- /dev/null +++ b/app/locale/sv_SE.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ansluter...", + "Disconnecting...": "Kopplar ner...", + "Reconnecting...": "Återansluter...", + "Internal error": "Internt fel", + "Must set host": "Du måste specifiera en värd", + "Connected (encrypted) to ": "Ansluten (krypterat) till ", + "Connected (unencrypted) to ": "Ansluten (okrypterat) till ", + "Something went wrong, connection is closed": "Något gick fel, anslutningen avslutades", + "Failed to connect to server": "Misslyckades att ansluta till servern", + "Disconnected": "Frånkopplad", + "New connection has been rejected with reason: ": "Ny anslutning har blivit nekad med följande skäl: ", + "New connection has been rejected": "Ny anslutning har blivit nekad", + "Credentials are required": "Användaruppgifter krävs", + "Hide/Show the control bar": "Göm/Visa kontrollbaren", + "Drag": "Dra", + "Move/Drag Viewport": "Flytta/Dra Vyn", + "Keyboard": "Tangentbord", + "Show Keyboard": "Visa Tangentbord", + "Extra keys": "Extraknappar", + "Show Extra Keys": "Visa Extraknappar", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Växla Ctrl", + "Alt": "Alt", + "Toggle Alt": "Växla Alt", + "Toggle Windows": "Växla Windows", + "Windows": "Windows", + "Send Tab": "Skicka Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Skicka Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Skicka Ctrl-Alt-Del", + "Shutdown/Reboot": "Stäng av/Boota om", + "Shutdown/Reboot...": "Stäng av/Boota om...", + "Power": "Ström", + "Shutdown": "Stäng av", + "Reboot": "Boota om", + "Reset": "Återställ", + "Clipboard": "Urklipp", + "Clear": "Rensa", + "Fullscreen": "Fullskärm", + "Settings": "Inställningar", + "Shared Mode": "Delat Läge", + "View Only": "Endast Visning", + "Clip to Window": "Begränsa till Fönster", + "Scaling Mode:": "Skalningsläge:", + "None": "Ingen", + "Local Scaling": "Lokal Skalning", + "Remote Resizing": "Ändra Storlek", + "Advanced": "Avancerat", + "Quality:": "Kvalitet:", + "Compression level:": "Kompressionsnivå:", + "Repeater ID:": "Repeater-ID:", + "WebSocket": "WebSocket", + "Encrypt": "Kryptera", + "Host:": "Värd:", + "Port:": "Port:", + "Path:": "Sökväg:", + "Automatic Reconnect": "Automatisk Återanslutning", + "Reconnect Delay (ms):": "Fördröjning (ms):", + "Show Dot when No Cursor": "Visa prick när ingen muspekare finns", + "Logging:": "Loggning:", + "Version:": "Version:", + "Disconnect": "Koppla från", + "Connect": "Anslut", + "Username:": "Användarnamn:", + "Password:": "Lösenord:", + "Send Credentials": "Skicka Användaruppgifter", + "Cancel": "Avbryt", + "Keys": "Nycklar", + "Game Cursor Mode": "Spelmarkörläge", + "Press Esc Key to Exit Pointer Lock Mode": "Tryck på Esc-tangenten för att avsluta pekarlåsläget", + "Game Mode paused, click on screen to resume Game Mode.": "Spelläge pausat, klicka på skärmen för att återuppta spelläge.", + "Clipboard Up": "Urklipp upp", + "CLipboard Down": "Clipboard Down", + "Clipboard Seamless": "Urklipp Seamless", + "Prefer Local Cursor": "Föredrar lokal markör", + "Translate keyboard shortcuts": "Översätt kortkommandon", + "Enable WebRTC UDP Transit": "Aktivera WebRTC UDP Transit", + "Enable WebP Compression": "Aktivera WebP-komprimering", + "Enable Performance Stats": "Aktivera prestationsstatistik", + "Enable Pointer Lock": "Aktivera peklås", + "IME Input Mode": "IME Input Mode", + "Show Virtual Keyboard Control": "Visa virtuell tangentbordskontroll", + "Toggle Control Panel via Keystrokes": "Växla kontrollpanelen via tangenttryckningar", + "Render Native Resolution": "Render Native Resolution", + "Keyboard Shortcuts": "Tangentbordsgenvägar", + "Enable KasmVNC Keyboard Shortcuts": "Aktivera KasmVNC tangentbordsgenvägar", + "1 - Toggle Control Panel": "1 - Växla kontrollpanelen", + "2 - Toggle Game Pointer Mode": "2 - Växla spelpekarläge", + "3 - Toggle Pointer Lock": "3 - Toggle Pointer Lock", + "Stream Quality": "Strömkvalitet", + "Preset Modes:": "Förinställda lägen:", + "Static": "Statisk", + "Low": "Låg", + "Medium": "Medium", + "High": "Hög", + "Extreme": "Extrem", + "Lossless": "Förlust mindre", + "Custom": "Beställnings", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Av", + "On": "På", + "Dynamic Quality Min:": "Dynamisk kvalitet min:", + "Dynamic Quality Max:": "Dynamisk kvalitet Max:", + "Treat Lossless:": "Behandla Lossless:", + "Frame Rate:": "Bildfrekvens:", + "Video JPEG Quality:": "Video JPEG-kvalitet:", + "Video WEBP Quality:": "Video WEBP Quality:", + "Video Area:": "Videoområde:", + "Video Time:": "Videotid:", + "Video Out Time:": "Video Out Time:", + "Video Mode Width:": "Videolägesbredd:", + "Video Mode Height:": "Videolägeshöjd:", + "Documentation": "Dokumentation", + "Drag Viewport": "Dra Viewport", + "KasmVNC encountered an error:": "KasmVNC stötte på ett fel:" +} \ No newline at end of file diff --git a/app/locale/sw.json b/app/locale/sw.json new file mode 100644 index 0000000..f1aa175 --- /dev/null +++ b/app/locale/sw.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Inaunganisha ...", + "Disconnecting...": "Inatenganisha ...", + "Reconnecting...": "Inaunganisha tena ...", + "Internal error": "Hitilafu ya ndani", + "Must set host": "Lazima uweke mwenyeji", + "Connected (encrypted) to ": "Imeunganishwa (iliyosimbwa) kwa", + "Connected (unencrypted) to ": "Imeunganishwa (isiyosimbwa) kwa", + "Something went wrong, connection is closed": "Kuna hitilafu, muunganisho umefungwa", + "Failed to connect to server": "Imeshindwa kuunganisha kwenye seva", + "Disconnected": "Imetenganishwa", + "New connection has been rejected with reason: ": "Muunganisho mpya umekataliwa kwa sababu: ", + "New connection has been rejected": "Muunganisho mpya umekataliwa", + "Credentials are required": "Vyeti vitahitajika", + "Hide/Show the control bar": "Ficha/Onyesha upau wa kudhibiti", + "Drag": "Buruta", + "Move/Drag Viewport": "Sogeza/Buruta Mtazamo", + "Keyboard": "Kibodi", + "Show Keyboard": "Onyesha Kibodi", + "Extra keys": "Funguo za ziada", + "Show Extra Keys": "Onyesha Funguo za Ziada", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Geuza Ctrl", + "Alt": "Alt", + "Toggle Alt": "Geuza Alt", + "Toggle Windows": "Geuza Windows", + "Windows": "Windows", + "Send Tab": "Tuma Kichupo", + "Tab": "Tabo", + "Esc": "Esc", + "Send Escape": "Tuma Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Tuma Ctrl-Alt-Del", + "Shutdown/Reboot": "Zima/Washa upya", + "Shutdown/Reboot...": "Zima/Washa upya ...", + "Power": "Nguvu", + "Shutdown": "Kuzimisha", + "Reboot": "Washa upya", + "Reset": "Weka upya", + "Clipboard": "Ubao wa kunakili", + "Clear": "Wazi", + "Fullscreen": "Skrini nzima", + "Settings": "Mipangilio", + "Shared Mode": "Njia iliyoshirikiwa", + "View Only": "Tazama Pekee", + "Clip to Window": "Bonyeza kwenye Dirisha", + "Scaling Mode:": "Njia ya Kuongeza:", + "None": "Hakuna", + "Local Scaling": "Upimaji wa Mitaa", + "Remote Resizing": "Kubadilisha ukubwa wa Mbali", + "Advanced": "Advanced", + "Quality:": "Ubora:", + "Compression level:": "Kiwango cha kukandamiza:", + "Repeater ID:": "Kitambulisho cha kurudia:", + "WebSocket": "WebSocket", + "Encrypt": "Simba kwa njia fiche", + "Host:": "Mwenyeji:", + "Port:": "Bandari:", + "Path:": "Njia:", + "Automatic Reconnect": "Unganisha upya kiotomatiki", + "Reconnect Delay (ms):": "Unganisha tena Ucheleweshaji (ms):", + "Show Dot when No Cursor": "Onyesha Nukta Wakati Hakuna Mshale", + "Logging:": "Ukataji miti:", + "Version:": "Toleo:", + "Disconnect": "Tenganisha", + "Connect": "Unganisha", + "Username:": "Jina la mtumiaji:", + "Password:": "Nenosiri:", + "Send Credentials": "Tuma Hati za Utambulisho", + "Cancel": "Ghairi", + "Keys": "Funguo", + "Game Cursor Mode": "Njia ya Mshale wa Mchezo", + "Press Esc Key to Exit Pointer Lock Mode": "Bonyeza kitufe cha Esc ili Kuondoka kwenye Njia ya Kufunga Kielekezi", + "Game Mode paused, click on screen to resume Game Mode.": "Njia ya Mchezo imesitishwa, bofya skrini ili kuendelea na Hali ya Mchezo.", + "Clipboard Up": "Ubao wa kunakili Juu", + "CLipboard Down": "Clipboard Chini", + "Clipboard Seamless": "Ubao wa kunakili Imefumwa", + "Prefer Local Cursor": "Pendelea Mshale wa Karibu", + "Translate keyboard shortcuts": "Tafsiri njia za mkato za kibodi", + "Enable WebRTC UDP Transit": "Washa Usafiri wa UDP wa WebRTC", + "Enable WebP Compression": "Washa Mfinyazo wa WebP", + "Enable Performance Stats": "Wezesha Takwimu za Utendaji", + "Enable Pointer Lock": "Washa Kufuli ya Kielekezi", + "IME Input Mode": "Njia ya Kuingiza IME", + "Show Virtual Keyboard Control": "Onyesha Udhibiti wa Kibodi Pekee", + "Toggle Control Panel via Keystrokes": "Geuza Paneli ya Kudhibiti kupitia Vibonyezo", + "Render Native Resolution": "Toa Azimio la Asili", + "Keyboard Shortcuts": "Njia za mkato za kibodi", + "Enable KasmVNC Keyboard Shortcuts": "Wezesha Njia za Mkato za Kibodi ya KasmVNC", + "1 - Toggle Control Panel": "1 - Geuza Paneli ya Kudhibiti", + "2 - Toggle Game Pointer Mode": "2 - Geuza Modi ya Kielekezi cha Mchezo", + "3 - Toggle Pointer Lock": "3 - Geuza Kufuli la Vielekezi", + "Stream Quality": "Ubora wa Utiririshaji", + "Preset Modes:": "Njia zilizowekwa mapema:", + "Static": "Tuli", + "Low": "Chini", + "Medium": "Kati", + "High": "Juu", + "Extreme": "Uliokithiri", + "Lossless": "Bila hasara", + "Custom": "Custom", + "Anti-Aliasing:": "Kupinga Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Zima", + "On": "Washa", + "Dynamic Quality Min:": "Dak ya Ubora wa Nguvu:", + "Dynamic Quality Max:": "Ubora wa Nguvu Zaidi:", + "Treat Lossless:": "Tibu Bila hasara:", + "Frame Rate:": "Kiwango cha Fremu:", + "Video JPEG Quality:": "Ubora wa JPEG ya Video:", + "Video WEBP Quality:": "Ubora wa WEBP ya Video:", + "Video Area:": "Eneo la Video:", + "Video Time:": "Wakati wa Video:", + "Video Out Time:": "Muda wa Kuisha kwa Video:", + "Video Mode Width:": "Upana wa Modi ya Video:", + "Video Mode Height:": "Urefu wa Modi ya Video:", + "Documentation": "Nyaraka", + "Drag Viewport": "Buruta Viewport", + "KasmVNC encountered an error:": "KasmVNC ilipata hitilafu:" +} \ No newline at end of file diff --git a/app/locale/sw_KE.json b/app/locale/sw_KE.json new file mode 100644 index 0000000..f1aa175 --- /dev/null +++ b/app/locale/sw_KE.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Inaunganisha ...", + "Disconnecting...": "Inatenganisha ...", + "Reconnecting...": "Inaunganisha tena ...", + "Internal error": "Hitilafu ya ndani", + "Must set host": "Lazima uweke mwenyeji", + "Connected (encrypted) to ": "Imeunganishwa (iliyosimbwa) kwa", + "Connected (unencrypted) to ": "Imeunganishwa (isiyosimbwa) kwa", + "Something went wrong, connection is closed": "Kuna hitilafu, muunganisho umefungwa", + "Failed to connect to server": "Imeshindwa kuunganisha kwenye seva", + "Disconnected": "Imetenganishwa", + "New connection has been rejected with reason: ": "Muunganisho mpya umekataliwa kwa sababu: ", + "New connection has been rejected": "Muunganisho mpya umekataliwa", + "Credentials are required": "Vyeti vitahitajika", + "Hide/Show the control bar": "Ficha/Onyesha upau wa kudhibiti", + "Drag": "Buruta", + "Move/Drag Viewport": "Sogeza/Buruta Mtazamo", + "Keyboard": "Kibodi", + "Show Keyboard": "Onyesha Kibodi", + "Extra keys": "Funguo za ziada", + "Show Extra Keys": "Onyesha Funguo za Ziada", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Geuza Ctrl", + "Alt": "Alt", + "Toggle Alt": "Geuza Alt", + "Toggle Windows": "Geuza Windows", + "Windows": "Windows", + "Send Tab": "Tuma Kichupo", + "Tab": "Tabo", + "Esc": "Esc", + "Send Escape": "Tuma Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Tuma Ctrl-Alt-Del", + "Shutdown/Reboot": "Zima/Washa upya", + "Shutdown/Reboot...": "Zima/Washa upya ...", + "Power": "Nguvu", + "Shutdown": "Kuzimisha", + "Reboot": "Washa upya", + "Reset": "Weka upya", + "Clipboard": "Ubao wa kunakili", + "Clear": "Wazi", + "Fullscreen": "Skrini nzima", + "Settings": "Mipangilio", + "Shared Mode": "Njia iliyoshirikiwa", + "View Only": "Tazama Pekee", + "Clip to Window": "Bonyeza kwenye Dirisha", + "Scaling Mode:": "Njia ya Kuongeza:", + "None": "Hakuna", + "Local Scaling": "Upimaji wa Mitaa", + "Remote Resizing": "Kubadilisha ukubwa wa Mbali", + "Advanced": "Advanced", + "Quality:": "Ubora:", + "Compression level:": "Kiwango cha kukandamiza:", + "Repeater ID:": "Kitambulisho cha kurudia:", + "WebSocket": "WebSocket", + "Encrypt": "Simba kwa njia fiche", + "Host:": "Mwenyeji:", + "Port:": "Bandari:", + "Path:": "Njia:", + "Automatic Reconnect": "Unganisha upya kiotomatiki", + "Reconnect Delay (ms):": "Unganisha tena Ucheleweshaji (ms):", + "Show Dot when No Cursor": "Onyesha Nukta Wakati Hakuna Mshale", + "Logging:": "Ukataji miti:", + "Version:": "Toleo:", + "Disconnect": "Tenganisha", + "Connect": "Unganisha", + "Username:": "Jina la mtumiaji:", + "Password:": "Nenosiri:", + "Send Credentials": "Tuma Hati za Utambulisho", + "Cancel": "Ghairi", + "Keys": "Funguo", + "Game Cursor Mode": "Njia ya Mshale wa Mchezo", + "Press Esc Key to Exit Pointer Lock Mode": "Bonyeza kitufe cha Esc ili Kuondoka kwenye Njia ya Kufunga Kielekezi", + "Game Mode paused, click on screen to resume Game Mode.": "Njia ya Mchezo imesitishwa, bofya skrini ili kuendelea na Hali ya Mchezo.", + "Clipboard Up": "Ubao wa kunakili Juu", + "CLipboard Down": "Clipboard Chini", + "Clipboard Seamless": "Ubao wa kunakili Imefumwa", + "Prefer Local Cursor": "Pendelea Mshale wa Karibu", + "Translate keyboard shortcuts": "Tafsiri njia za mkato za kibodi", + "Enable WebRTC UDP Transit": "Washa Usafiri wa UDP wa WebRTC", + "Enable WebP Compression": "Washa Mfinyazo wa WebP", + "Enable Performance Stats": "Wezesha Takwimu za Utendaji", + "Enable Pointer Lock": "Washa Kufuli ya Kielekezi", + "IME Input Mode": "Njia ya Kuingiza IME", + "Show Virtual Keyboard Control": "Onyesha Udhibiti wa Kibodi Pekee", + "Toggle Control Panel via Keystrokes": "Geuza Paneli ya Kudhibiti kupitia Vibonyezo", + "Render Native Resolution": "Toa Azimio la Asili", + "Keyboard Shortcuts": "Njia za mkato za kibodi", + "Enable KasmVNC Keyboard Shortcuts": "Wezesha Njia za Mkato za Kibodi ya KasmVNC", + "1 - Toggle Control Panel": "1 - Geuza Paneli ya Kudhibiti", + "2 - Toggle Game Pointer Mode": "2 - Geuza Modi ya Kielekezi cha Mchezo", + "3 - Toggle Pointer Lock": "3 - Geuza Kufuli la Vielekezi", + "Stream Quality": "Ubora wa Utiririshaji", + "Preset Modes:": "Njia zilizowekwa mapema:", + "Static": "Tuli", + "Low": "Chini", + "Medium": "Kati", + "High": "Juu", + "Extreme": "Uliokithiri", + "Lossless": "Bila hasara", + "Custom": "Custom", + "Anti-Aliasing:": "Kupinga Aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Zima", + "On": "Washa", + "Dynamic Quality Min:": "Dak ya Ubora wa Nguvu:", + "Dynamic Quality Max:": "Ubora wa Nguvu Zaidi:", + "Treat Lossless:": "Tibu Bila hasara:", + "Frame Rate:": "Kiwango cha Fremu:", + "Video JPEG Quality:": "Ubora wa JPEG ya Video:", + "Video WEBP Quality:": "Ubora wa WEBP ya Video:", + "Video Area:": "Eneo la Video:", + "Video Time:": "Wakati wa Video:", + "Video Out Time:": "Muda wa Kuisha kwa Video:", + "Video Mode Width:": "Upana wa Modi ya Video:", + "Video Mode Height:": "Urefu wa Modi ya Video:", + "Documentation": "Nyaraka", + "Drag Viewport": "Buruta Viewport", + "KasmVNC encountered an error:": "KasmVNC ilipata hitilafu:" +} \ No newline at end of file diff --git a/app/locale/ta.json b/app/locale/ta.json new file mode 100644 index 0000000..d357abe --- /dev/null +++ b/app/locale/ta.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "இணைக்கிறது...", + "Disconnecting...": "துண்டிக்கிறது...", + "Reconnecting...": "மீண்டும் இணைக்கிறது...", + "Internal error": "உள் பிழை", + "Must set host": "ஹோஸ்ட் அமைக்க வேண்டும்", + "Connected (encrypted) to ": "இணைக்கப்பட்டது (குறியாக்கம்)", + "Connected (unencrypted) to ": "இணைக்கப்பட்டது (மறைகுறியாக்கப்படாதது)", + "Something went wrong, connection is closed": "ஏதோ தவறாகிவிட்டது, இணைப்பு மூடப்பட்டுள்ளது", + "Failed to connect to server": "சேவகையத்திடம் தொடர்பு கொள்ள முடியவில்லை", + "Disconnected": "துண்டிக்கப்பட்டது", + "New connection has been rejected with reason: ": "புதிய இணைப்பு காரணத்துடன் நிராகரிக்கப்பட்டது:", + "New connection has been rejected": "புதிய இணைப்பு நிராகரிக்கப்பட்டது", + "Credentials are required": "நற்சான்றிதழ்கள் தேவை", + "Hide/Show the control bar": "கட்டுப்பாட்டு பட்டியை மறை/காட்டு", + "Drag": "இழு", + "Move/Drag Viewport": "வியூபோர்ட்டை நகர்த்த/இழுக்கவும்", + "Keyboard": "விசைப்பலகை", + "Show Keyboard": "விசைப்பலகையைக் காட்டு", + "Extra keys": "கூடுதல் விசைகள்", + "Show Extra Keys": "கூடுதல் விசைகளைக் காட்டு", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ஐ மாற்று", + "Alt": "Alt", + "Toggle Alt": "ஆல்ட்டை மாற்று", + "Toggle Windows": "விண்டோஸை மாற்று", + "Windows": "விண்டோஸ்", + "Send Tab": "அனுப்பு தாவல்", + "Tab": "தாவல்", + "Esc": "Esc", + "Send Escape": "எஸ்கேப் அனுப்பு", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ஐ அனுப்பு", + "Shutdown/Reboot": "பணிநிறுத்தம்/மறுதொடக்கம்", + "Shutdown/Reboot...": "பணிநிறுத்தம்/மறுதொடக்கம்...", + "Power": "சக்தி", + "Shutdown": "பணிநிறுத்தம்", + "Reboot": "மறுதொடக்கம்", + "Reset": "மீட்டமை", + "Clipboard": "கிளிப்போர்டு", + "Clear": "தெளிவு", + "Fullscreen": "முழு திரை", + "Settings": "அமைப்புகள்", + "Shared Mode": "பகிரப்பட்ட பயன்முறை", + "View Only": "பார்க்க மட்டும்", + "Clip to Window": "கிளிப் டு விண்டோ", + "Scaling Mode:": "அளவிடுதல் முறை:", + "None": "இல்லை", + "Local Scaling": "உள்ளூர் அளவிடுதல்", + "Remote Resizing": "ரிமோட் மறுஅளவாக்கம்", + "Advanced": "மேம்படுத்தபட்ட", + "Quality:": "தரம்:", + "Compression level:": "சுருக்க நிலை:", + "Repeater ID:": "ரிப்பீட்டர் ஐடி:", + "WebSocket": "வெப்சாக்கெட்", + "Encrypt": "குறியாக்கம்", + "Host:": "தொகுப்பாளர்:", + "Port:": "துறைமுகம்:", + "Path:": "பாதை:", + "Automatic Reconnect": "தானியங்கி மறு இணைப்பு", + "Reconnect Delay (ms):": "தாமதம் (மிஎஸ்) மீண்டும் இணைக்கவும்:", + "Show Dot when No Cursor": "கர்சர் இல்லாதபோது புள்ளியைக் காட்டு", + "Logging:": "பதிவு:", + "Version:": "பதிப்பு:", + "Disconnect": "துண்டிக்கவும்", + "Connect": "இணை", + "Username:": "பயனர் பெயர்:", + "Password:": "கடவுச்சொல்:", + "Send Credentials": "நற்சான்றிதழ்களை அனுப்பு", + "Cancel": "ரத்துசெய்", + "Keys": "விசைகள்", + "Game Cursor Mode": "கேம் கர்சர் பயன்முறை", + "Press Esc Key to Exit Pointer Lock Mode": "பாயிண்டர் லாக் பயன்முறையிலிருந்து வெளியேற Esc விசையை அழுத்தவும்", + "Game Mode paused, click on screen to resume Game Mode.": "கேம் பயன்முறை இடைநிறுத்தப்பட்டது, கேம் பயன்முறையை மீண்டும் தொடங்க திரையில் கிளிக் செய்யவும்.", + "Clipboard Up": "கிளிப்போர்டு அப்", + "CLipboard Down": "கிளிப்போர்டு டவுன்", + "Clipboard Seamless": "கிளிப்போர்டு தடையற்றது", + "Prefer Local Cursor": "உள்ளூர் கர்சரை விரும்பு", + "Translate keyboard shortcuts": "விசைப்பலகை குறுக்குவழிகளை மொழிபெயர்", + "Enable WebRTC UDP Transit": "WebRTC UDP டிரான்ஸிட்டை இயக்கு", + "Enable WebP Compression": "WebP சுருக்கத்தை இயக்கு", + "Enable Performance Stats": "செயல்திறன் புள்ளிவிவரங்களை இயக்கு", + "Enable Pointer Lock": "சுட்டி பூட்டை இயக்கு", + "IME Input Mode": "IME உள்ளீட்டு முறை", + "Show Virtual Keyboard Control": "விர்ச்சுவல் விசைப்பலகை கட்டுப்பாட்டைக் காட்டு", + "Toggle Control Panel via Keystrokes": "விசை அழுத்தங்கள் வழியாக கண்ட்ரோல் பேனலை மாற்று", + "Render Native Resolution": "இன்டர் நேட்டிவ் ரெசல்யூஷன்", + "Keyboard Shortcuts": "விசைப்பலகை குறுக்குவழிகள்", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC விசைப்பலகை குறுக்குவழிகளை இயக்கு", + "1 - Toggle Control Panel": "1 - கண்ட்ரோல் பேனலை மாற்று", + "2 - Toggle Game Pointer Mode": "2 - கேம் பாயிண்டர் பயன்முறையை மாற்று", + "3 - Toggle Pointer Lock": "3 - சுட்டி பூட்டை மாற்று", + "Stream Quality": "ஸ்ட்ரீம் தரம்", + "Preset Modes:": "முன்னமைக்கப்பட்ட முறைகள்:", + "Static": "நிலையான", + "Low": "குறைந்த", + "Medium": "நடுத்தர", + "High": "உயர்", + "Extreme": "அதிக", + "Lossless": "இழப்பற்ற", + "Custom": "விருப்ப", + "Anti-Aliasing:": "எதிர்ப்பு மாற்றுப்பெயர்:", + "Auto Dynamic": "ஆட்டோ டைனமிக்", + "Off": "ஆஃப்", + "On": "ஆன்", + "Dynamic Quality Min:": "டைனமிக் தர குறைந்தபட்சம்:", + "Dynamic Quality Max:": "டைனமிக் குவாலிட்டி மேக்ஸ்:", + "Treat Lossless:": "இழப்பற்ற சிகிச்சை:", + "Frame Rate:": "பிரேம் வீதம்:", + "Video JPEG Quality:": "வீடியோ JPEG தரம்:", + "Video WEBP Quality:": "வீடியோ WEBP தரம்:", + "Video Area:": "வீடியோ பகுதி:", + "Video Time:": "வீடியோ நேரம்:", + "Video Out Time:": "வீடியோ அவுட் நேரம்:", + "Video Mode Width:": "வீடியோ பயன்முறை அகலம்:", + "Video Mode Height:": "வீடியோ பயன்முறை உயரம்:", + "Documentation": "ஆவணம்", + "Drag Viewport": "வியூபோர்ட்டை இழுக்கவும்", + "KasmVNC encountered an error:": "KasmVNC ஒரு பிழையை எதிர்கொண்டது:" +} \ No newline at end of file diff --git a/app/locale/ta_IN.json b/app/locale/ta_IN.json new file mode 100644 index 0000000..d357abe --- /dev/null +++ b/app/locale/ta_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "இணைக்கிறது...", + "Disconnecting...": "துண்டிக்கிறது...", + "Reconnecting...": "மீண்டும் இணைக்கிறது...", + "Internal error": "உள் பிழை", + "Must set host": "ஹோஸ்ட் அமைக்க வேண்டும்", + "Connected (encrypted) to ": "இணைக்கப்பட்டது (குறியாக்கம்)", + "Connected (unencrypted) to ": "இணைக்கப்பட்டது (மறைகுறியாக்கப்படாதது)", + "Something went wrong, connection is closed": "ஏதோ தவறாகிவிட்டது, இணைப்பு மூடப்பட்டுள்ளது", + "Failed to connect to server": "சேவகையத்திடம் தொடர்பு கொள்ள முடியவில்லை", + "Disconnected": "துண்டிக்கப்பட்டது", + "New connection has been rejected with reason: ": "புதிய இணைப்பு காரணத்துடன் நிராகரிக்கப்பட்டது:", + "New connection has been rejected": "புதிய இணைப்பு நிராகரிக்கப்பட்டது", + "Credentials are required": "நற்சான்றிதழ்கள் தேவை", + "Hide/Show the control bar": "கட்டுப்பாட்டு பட்டியை மறை/காட்டு", + "Drag": "இழு", + "Move/Drag Viewport": "வியூபோர்ட்டை நகர்த்த/இழுக்கவும்", + "Keyboard": "விசைப்பலகை", + "Show Keyboard": "விசைப்பலகையைக் காட்டு", + "Extra keys": "கூடுதல் விசைகள்", + "Show Extra Keys": "கூடுதல் விசைகளைக் காட்டு", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ஐ மாற்று", + "Alt": "Alt", + "Toggle Alt": "ஆல்ட்டை மாற்று", + "Toggle Windows": "விண்டோஸை மாற்று", + "Windows": "விண்டோஸ்", + "Send Tab": "அனுப்பு தாவல்", + "Tab": "தாவல்", + "Esc": "Esc", + "Send Escape": "எஸ்கேப் அனுப்பு", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ஐ அனுப்பு", + "Shutdown/Reboot": "பணிநிறுத்தம்/மறுதொடக்கம்", + "Shutdown/Reboot...": "பணிநிறுத்தம்/மறுதொடக்கம்...", + "Power": "சக்தி", + "Shutdown": "பணிநிறுத்தம்", + "Reboot": "மறுதொடக்கம்", + "Reset": "மீட்டமை", + "Clipboard": "கிளிப்போர்டு", + "Clear": "தெளிவு", + "Fullscreen": "முழு திரை", + "Settings": "அமைப்புகள்", + "Shared Mode": "பகிரப்பட்ட பயன்முறை", + "View Only": "பார்க்க மட்டும்", + "Clip to Window": "கிளிப் டு விண்டோ", + "Scaling Mode:": "அளவிடுதல் முறை:", + "None": "இல்லை", + "Local Scaling": "உள்ளூர் அளவிடுதல்", + "Remote Resizing": "ரிமோட் மறுஅளவாக்கம்", + "Advanced": "மேம்படுத்தபட்ட", + "Quality:": "தரம்:", + "Compression level:": "சுருக்க நிலை:", + "Repeater ID:": "ரிப்பீட்டர் ஐடி:", + "WebSocket": "வெப்சாக்கெட்", + "Encrypt": "குறியாக்கம்", + "Host:": "தொகுப்பாளர்:", + "Port:": "துறைமுகம்:", + "Path:": "பாதை:", + "Automatic Reconnect": "தானியங்கி மறு இணைப்பு", + "Reconnect Delay (ms):": "தாமதம் (மிஎஸ்) மீண்டும் இணைக்கவும்:", + "Show Dot when No Cursor": "கர்சர் இல்லாதபோது புள்ளியைக் காட்டு", + "Logging:": "பதிவு:", + "Version:": "பதிப்பு:", + "Disconnect": "துண்டிக்கவும்", + "Connect": "இணை", + "Username:": "பயனர் பெயர்:", + "Password:": "கடவுச்சொல்:", + "Send Credentials": "நற்சான்றிதழ்களை அனுப்பு", + "Cancel": "ரத்துசெய்", + "Keys": "விசைகள்", + "Game Cursor Mode": "கேம் கர்சர் பயன்முறை", + "Press Esc Key to Exit Pointer Lock Mode": "பாயிண்டர் லாக் பயன்முறையிலிருந்து வெளியேற Esc விசையை அழுத்தவும்", + "Game Mode paused, click on screen to resume Game Mode.": "கேம் பயன்முறை இடைநிறுத்தப்பட்டது, கேம் பயன்முறையை மீண்டும் தொடங்க திரையில் கிளிக் செய்யவும்.", + "Clipboard Up": "கிளிப்போர்டு அப்", + "CLipboard Down": "கிளிப்போர்டு டவுன்", + "Clipboard Seamless": "கிளிப்போர்டு தடையற்றது", + "Prefer Local Cursor": "உள்ளூர் கர்சரை விரும்பு", + "Translate keyboard shortcuts": "விசைப்பலகை குறுக்குவழிகளை மொழிபெயர்", + "Enable WebRTC UDP Transit": "WebRTC UDP டிரான்ஸிட்டை இயக்கு", + "Enable WebP Compression": "WebP சுருக்கத்தை இயக்கு", + "Enable Performance Stats": "செயல்திறன் புள்ளிவிவரங்களை இயக்கு", + "Enable Pointer Lock": "சுட்டி பூட்டை இயக்கு", + "IME Input Mode": "IME உள்ளீட்டு முறை", + "Show Virtual Keyboard Control": "விர்ச்சுவல் விசைப்பலகை கட்டுப்பாட்டைக் காட்டு", + "Toggle Control Panel via Keystrokes": "விசை அழுத்தங்கள் வழியாக கண்ட்ரோல் பேனலை மாற்று", + "Render Native Resolution": "இன்டர் நேட்டிவ் ரெசல்யூஷன்", + "Keyboard Shortcuts": "விசைப்பலகை குறுக்குவழிகள்", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC விசைப்பலகை குறுக்குவழிகளை இயக்கு", + "1 - Toggle Control Panel": "1 - கண்ட்ரோல் பேனலை மாற்று", + "2 - Toggle Game Pointer Mode": "2 - கேம் பாயிண்டர் பயன்முறையை மாற்று", + "3 - Toggle Pointer Lock": "3 - சுட்டி பூட்டை மாற்று", + "Stream Quality": "ஸ்ட்ரீம் தரம்", + "Preset Modes:": "முன்னமைக்கப்பட்ட முறைகள்:", + "Static": "நிலையான", + "Low": "குறைந்த", + "Medium": "நடுத்தர", + "High": "உயர்", + "Extreme": "அதிக", + "Lossless": "இழப்பற்ற", + "Custom": "விருப்ப", + "Anti-Aliasing:": "எதிர்ப்பு மாற்றுப்பெயர்:", + "Auto Dynamic": "ஆட்டோ டைனமிக்", + "Off": "ஆஃப்", + "On": "ஆன்", + "Dynamic Quality Min:": "டைனமிக் தர குறைந்தபட்சம்:", + "Dynamic Quality Max:": "டைனமிக் குவாலிட்டி மேக்ஸ்:", + "Treat Lossless:": "இழப்பற்ற சிகிச்சை:", + "Frame Rate:": "பிரேம் வீதம்:", + "Video JPEG Quality:": "வீடியோ JPEG தரம்:", + "Video WEBP Quality:": "வீடியோ WEBP தரம்:", + "Video Area:": "வீடியோ பகுதி:", + "Video Time:": "வீடியோ நேரம்:", + "Video Out Time:": "வீடியோ அவுட் நேரம்:", + "Video Mode Width:": "வீடியோ பயன்முறை அகலம்:", + "Video Mode Height:": "வீடியோ பயன்முறை உயரம்:", + "Documentation": "ஆவணம்", + "Drag Viewport": "வியூபோர்ட்டை இழுக்கவும்", + "KasmVNC encountered an error:": "KasmVNC ஒரு பிழையை எதிர்கொண்டது:" +} \ No newline at end of file diff --git a/app/locale/ta_LK.json b/app/locale/ta_LK.json new file mode 100644 index 0000000..d357abe --- /dev/null +++ b/app/locale/ta_LK.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "இணைக்கிறது...", + "Disconnecting...": "துண்டிக்கிறது...", + "Reconnecting...": "மீண்டும் இணைக்கிறது...", + "Internal error": "உள் பிழை", + "Must set host": "ஹோஸ்ட் அமைக்க வேண்டும்", + "Connected (encrypted) to ": "இணைக்கப்பட்டது (குறியாக்கம்)", + "Connected (unencrypted) to ": "இணைக்கப்பட்டது (மறைகுறியாக்கப்படாதது)", + "Something went wrong, connection is closed": "ஏதோ தவறாகிவிட்டது, இணைப்பு மூடப்பட்டுள்ளது", + "Failed to connect to server": "சேவகையத்திடம் தொடர்பு கொள்ள முடியவில்லை", + "Disconnected": "துண்டிக்கப்பட்டது", + "New connection has been rejected with reason: ": "புதிய இணைப்பு காரணத்துடன் நிராகரிக்கப்பட்டது:", + "New connection has been rejected": "புதிய இணைப்பு நிராகரிக்கப்பட்டது", + "Credentials are required": "நற்சான்றிதழ்கள் தேவை", + "Hide/Show the control bar": "கட்டுப்பாட்டு பட்டியை மறை/காட்டு", + "Drag": "இழு", + "Move/Drag Viewport": "வியூபோர்ட்டை நகர்த்த/இழுக்கவும்", + "Keyboard": "விசைப்பலகை", + "Show Keyboard": "விசைப்பலகையைக் காட்டு", + "Extra keys": "கூடுதல் விசைகள்", + "Show Extra Keys": "கூடுதல் விசைகளைக் காட்டு", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ஐ மாற்று", + "Alt": "Alt", + "Toggle Alt": "ஆல்ட்டை மாற்று", + "Toggle Windows": "விண்டோஸை மாற்று", + "Windows": "விண்டோஸ்", + "Send Tab": "அனுப்பு தாவல்", + "Tab": "தாவல்", + "Esc": "Esc", + "Send Escape": "எஸ்கேப் அனுப்பு", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ஐ அனுப்பு", + "Shutdown/Reboot": "பணிநிறுத்தம்/மறுதொடக்கம்", + "Shutdown/Reboot...": "பணிநிறுத்தம்/மறுதொடக்கம்...", + "Power": "சக்தி", + "Shutdown": "பணிநிறுத்தம்", + "Reboot": "மறுதொடக்கம்", + "Reset": "மீட்டமை", + "Clipboard": "கிளிப்போர்டு", + "Clear": "தெளிவு", + "Fullscreen": "முழு திரை", + "Settings": "அமைப்புகள்", + "Shared Mode": "பகிரப்பட்ட பயன்முறை", + "View Only": "பார்க்க மட்டும்", + "Clip to Window": "கிளிப் டு விண்டோ", + "Scaling Mode:": "அளவிடுதல் முறை:", + "None": "இல்லை", + "Local Scaling": "உள்ளூர் அளவிடுதல்", + "Remote Resizing": "ரிமோட் மறுஅளவாக்கம்", + "Advanced": "மேம்படுத்தபட்ட", + "Quality:": "தரம்:", + "Compression level:": "சுருக்க நிலை:", + "Repeater ID:": "ரிப்பீட்டர் ஐடி:", + "WebSocket": "வெப்சாக்கெட்", + "Encrypt": "குறியாக்கம்", + "Host:": "தொகுப்பாளர்:", + "Port:": "துறைமுகம்:", + "Path:": "பாதை:", + "Automatic Reconnect": "தானியங்கி மறு இணைப்பு", + "Reconnect Delay (ms):": "தாமதம் (மிஎஸ்) மீண்டும் இணைக்கவும்:", + "Show Dot when No Cursor": "கர்சர் இல்லாதபோது புள்ளியைக் காட்டு", + "Logging:": "பதிவு:", + "Version:": "பதிப்பு:", + "Disconnect": "துண்டிக்கவும்", + "Connect": "இணை", + "Username:": "பயனர் பெயர்:", + "Password:": "கடவுச்சொல்:", + "Send Credentials": "நற்சான்றிதழ்களை அனுப்பு", + "Cancel": "ரத்துசெய்", + "Keys": "விசைகள்", + "Game Cursor Mode": "கேம் கர்சர் பயன்முறை", + "Press Esc Key to Exit Pointer Lock Mode": "பாயிண்டர் லாக் பயன்முறையிலிருந்து வெளியேற Esc விசையை அழுத்தவும்", + "Game Mode paused, click on screen to resume Game Mode.": "கேம் பயன்முறை இடைநிறுத்தப்பட்டது, கேம் பயன்முறையை மீண்டும் தொடங்க திரையில் கிளிக் செய்யவும்.", + "Clipboard Up": "கிளிப்போர்டு அப்", + "CLipboard Down": "கிளிப்போர்டு டவுன்", + "Clipboard Seamless": "கிளிப்போர்டு தடையற்றது", + "Prefer Local Cursor": "உள்ளூர் கர்சரை விரும்பு", + "Translate keyboard shortcuts": "விசைப்பலகை குறுக்குவழிகளை மொழிபெயர்", + "Enable WebRTC UDP Transit": "WebRTC UDP டிரான்ஸிட்டை இயக்கு", + "Enable WebP Compression": "WebP சுருக்கத்தை இயக்கு", + "Enable Performance Stats": "செயல்திறன் புள்ளிவிவரங்களை இயக்கு", + "Enable Pointer Lock": "சுட்டி பூட்டை இயக்கு", + "IME Input Mode": "IME உள்ளீட்டு முறை", + "Show Virtual Keyboard Control": "விர்ச்சுவல் விசைப்பலகை கட்டுப்பாட்டைக் காட்டு", + "Toggle Control Panel via Keystrokes": "விசை அழுத்தங்கள் வழியாக கண்ட்ரோல் பேனலை மாற்று", + "Render Native Resolution": "இன்டர் நேட்டிவ் ரெசல்யூஷன்", + "Keyboard Shortcuts": "விசைப்பலகை குறுக்குவழிகள்", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC விசைப்பலகை குறுக்குவழிகளை இயக்கு", + "1 - Toggle Control Panel": "1 - கண்ட்ரோல் பேனலை மாற்று", + "2 - Toggle Game Pointer Mode": "2 - கேம் பாயிண்டர் பயன்முறையை மாற்று", + "3 - Toggle Pointer Lock": "3 - சுட்டி பூட்டை மாற்று", + "Stream Quality": "ஸ்ட்ரீம் தரம்", + "Preset Modes:": "முன்னமைக்கப்பட்ட முறைகள்:", + "Static": "நிலையான", + "Low": "குறைந்த", + "Medium": "நடுத்தர", + "High": "உயர்", + "Extreme": "அதிக", + "Lossless": "இழப்பற்ற", + "Custom": "விருப்ப", + "Anti-Aliasing:": "எதிர்ப்பு மாற்றுப்பெயர்:", + "Auto Dynamic": "ஆட்டோ டைனமிக்", + "Off": "ஆஃப்", + "On": "ஆன்", + "Dynamic Quality Min:": "டைனமிக் தர குறைந்தபட்சம்:", + "Dynamic Quality Max:": "டைனமிக் குவாலிட்டி மேக்ஸ்:", + "Treat Lossless:": "இழப்பற்ற சிகிச்சை:", + "Frame Rate:": "பிரேம் வீதம்:", + "Video JPEG Quality:": "வீடியோ JPEG தரம்:", + "Video WEBP Quality:": "வீடியோ WEBP தரம்:", + "Video Area:": "வீடியோ பகுதி:", + "Video Time:": "வீடியோ நேரம்:", + "Video Out Time:": "வீடியோ அவுட் நேரம்:", + "Video Mode Width:": "வீடியோ பயன்முறை அகலம்:", + "Video Mode Height:": "வீடியோ பயன்முறை உயரம்:", + "Documentation": "ஆவணம்", + "Drag Viewport": "வியூபோர்ட்டை இழுக்கவும்", + "KasmVNC encountered an error:": "KasmVNC ஒரு பிழையை எதிர்கொண்டது:" +} \ No newline at end of file diff --git a/app/locale/te.json b/app/locale/te.json new file mode 100644 index 0000000..96c4368 --- /dev/null +++ b/app/locale/te.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "కనెక్ట్ అవుతోంది...", + "Disconnecting...": "డిస్u200cకనెక్ట్ చేస్తోంది...", + "Reconnecting...": "మళ్లీ కనెక్ట్ అవుతోంది...", + "Internal error": "అంతర్గత లోపం", + "Must set host": "తప్పనిసరిగా సెట్ చేయాలి", + "Connected (encrypted) to ": "కి కనెక్ట్ చేయబడింది (ఎన్u200cక్రిప్ట్ చేయబడింది)", + "Connected (unencrypted) to ": "కి కనెక్ట్ చేయబడింది (ఎన్u200cక్రిప్ట్ చేయబడింది)", + "Something went wrong, connection is closed": "ఏదో తప్పు జరిగింది, కనెక్షన్ మూసివేయబడింది", + "Failed to connect to server": "సర్వర్ తో అనుసంధాన ప్రయత్నం విఫలమైనది", + "Disconnected": "డిస్u200cకనెక్ట్ చేయబడింది", + "New connection has been rejected with reason: ": "కొత్త కనెక్షన్ కారణంతో తిరస్కరించబడింది:", + "New connection has been rejected": "కొత్త కనెక్షన్ తిరస్కరించబడింది", + "Credentials are required": "క్రెడెన్షియల్స్ అవసరం", + "Hide/Show the control bar": "నియంత్రణ పట్టీని దాచు/చూపించు", + "Drag": "లాగండి", + "Move/Drag Viewport": "వ్యూపోర్ట్u200cని తరలించు/లాగండి", + "Keyboard": "కీబోర్డ్", + "Show Keyboard": "కీబోర్డ్ చూపించు", + "Extra keys": "అదనపు కీలు", + "Show Extra Keys": "అదనపు కీలను చూపించు", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrlని టోగుల్ చేయి", + "Alt": "Alt", + "Toggle Alt": "Altని టోగుల్ చేయి", + "Toggle Windows": "విండోస్u200cని టోగుల్ చేయి", + "Windows": "విండోస్", + "Send Tab": "పంపు ట్యాబ్", + "Tab": "ట్యాబ్", + "Esc": "Esc", + "Send Escape": "ఎస్కేప్ పంపు", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Delని పంపు", + "Shutdown/Reboot": "షట్u200cడౌన్/రీబూట్", + "Shutdown/Reboot...": "షట్u200cడౌన్/రీబూట్...", + "Power": "శక్తి", + "Shutdown": "షట్డౌన్", + "Reboot": "రీబూట్", + "Reset": "రీసెట్", + "Clipboard": "క్లిప్u200cబోర్డ్", + "Clear": "క్లియర్", + "Fullscreen": "పూర్తి స్క్రీన్", + "Settings": "సెట్టింగ్u200cలు", + "Shared Mode": "షేర్డ్ మోడ్", + "View Only": "వీక్షణ మాత్రమే", + "Clip to Window": "క్లిప్ టు విండో", + "Scaling Mode:": "స్కేలింగ్ మోడ్:", + "None": "ఏదీ లేదు", + "Local Scaling": "స్థానిక స్కేలింగ్", + "Remote Resizing": "రిమోట్ పునఃపరిమాణం", + "Advanced": "ఆధునిక", + "Quality:": "నాణ్యత:", + "Compression level:": "కంప్రెషన్ స్థాయి:", + "Repeater ID:": "రిపీటర్ ID:", + "WebSocket": "వెబ్u200cసాకెట్", + "Encrypt": "ఎన్క్రిప్ట్", + "Host:": "హోస్ట్:", + "Port:": "పోర్ట్:", + "Path:": "మార్గం:", + "Automatic Reconnect": "ఆటోమేటిక్ రీకనెక్ట్", + "Reconnect Delay (ms):": "ఆలస్యాన్ని మళ్లీ కనెక్ట్ చేయండి (మిస్):", + "Show Dot when No Cursor": "కర్సర్ లేనప్పుడు డాట్ చూపించు", + "Logging:": "లాగింగ్:", + "Version:": "సంస్కరణ: Telugu:", + "Disconnect": "డిస్u200cకనెక్ట్", + "Connect": "కనెక్ట్", + "Username:": "వినియోగదారు పేరు:", + "Password:": "పాస్u200cవర్డ్:", + "Send Credentials": "క్రెడెన్షియల్స్ పంపండి", + "Cancel": "రద్దు చేయండి", + "Keys": "కీలు", + "Game Cursor Mode": "గేమ్ కర్సర్ మోడ్", + "Press Esc Key to Exit Pointer Lock Mode": "పాయింటర్ లాక్ మోడ్ నుండి నిష్క్రమించడానికి Esc కీని నొక్కండి", + "Game Mode paused, click on screen to resume Game Mode.": "గేమ్ మోడ్ పాజ్ చేయబడింది, గేమ్ మోడ్u200cని రెస్యూమ్ చేయడానికి స్క్రీన్u200cపై క్లిక్ చేయండి.", + "Clipboard Up": "క్లిప్u200cబోర్డ్ పైకి", + "CLipboard Down": "క్లిప్u200cబోర్డ్ డౌన్", + "Clipboard Seamless": "క్లిప్u200cబోర్డ్ అతుకులు", + "Prefer Local Cursor": "స్థానిక కర్సర్u200cకు ప్రాధాన్యత ఇవ్వండి", + "Translate keyboard shortcuts": "కీబోర్డ్ సత్వరమార్గాలను అనువదించు", + "Enable WebRTC UDP Transit": "WebRTC UDP రవాణాను ప్రారంభించు", + "Enable WebP Compression": "WebP కంప్రెషన్u200cని ప్రారంభించు", + "Enable Performance Stats": "పనితీరు గణాంకాలను ప్రారంభించు", + "Enable Pointer Lock": "పాయింటర్ లాక్u200cని ప్రారంభించు", + "IME Input Mode": "IME ఇన్u200cపుట్ మోడ్", + "Show Virtual Keyboard Control": "వర్చువల్ కీబోర్డ్ నియంత్రణను చూపించు", + "Toggle Control Panel via Keystrokes": "కీస్ట్రోక్u200cల ద్వారా కంట్రోల్ ప్యానెల్u200cని టోగుల్ చేయండి", + "Render Native Resolution": "రెండర్ స్థానిక రిజల్యూషన్", + "Keyboard Shortcuts": "కీబోర్డ్ సత్వరమార్గాలు", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC కీబోర్డ్ సత్వరమార్గాలను ప్రారంభించు", + "1 - Toggle Control Panel": "1 - కంట్రోల్ ప్యానెల్u200cని టోగుల్ చేయి", + "2 - Toggle Game Pointer Mode": "2 - గేమ్ పాయింటర్ మోడ్u200cని టోగుల్ చేయండి", + "3 - Toggle Pointer Lock": "3 - పాయింటర్ లాక్u200cని టోగుల్ చేయి", + "Stream Quality": "స్ట్రీమ్ నాణ్యత", + "Preset Modes:": "ప్రీసెట్ మోడ్u200cలు:", + "Static": "స్టాటిక్", + "Low": "తక్కువ", + "Medium": "మీడియం", + "High": "అధిక", + "Extreme": "అతి", + "Lossless": "నష్టం లేనిది", + "Custom": "కస్టమ్", + "Anti-Aliasing:": "యాంటీ అలియాసింగ్:", + "Auto Dynamic": "ఆటో డైనమిక్", + "Off": "ఆఫ్", + "On": "పై", + "Dynamic Quality Min:": "డైనమిక్ క్వాలిటీ మిని:", + "Dynamic Quality Max:": "డైనమిక్ క్వాలిటీ మ్యాక్స్:", + "Treat Lossless:": "లాస్లెస్ ట్రీట్:", + "Frame Rate:": "ఫ్రేమ్ రేట్:", + "Video JPEG Quality:": "వీడియో JPEG నాణ్యత:", + "Video WEBP Quality:": "వీడియో WEBP నాణ్యత:", + "Video Area:": "వీడియో ప్రాంతం:", + "Video Time:": "వీడియో సమయం:", + "Video Out Time:": "వీడియో అవుట్ టైమ్:", + "Video Mode Width:": "వీడియో మోడ్ వెడల్పు:", + "Video Mode Height:": "వీడియో మోడ్ ఎత్తు:", + "Documentation": "డాక్యుమెంటేషన్", + "Drag Viewport": "డ్రాగ్ వ్యూపోర్ట్", + "KasmVNC encountered an error:": "KasmVNC లోపాన్ని ఎదుర్కొంది:" +} \ No newline at end of file diff --git a/app/locale/te_IN.json b/app/locale/te_IN.json new file mode 100644 index 0000000..96c4368 --- /dev/null +++ b/app/locale/te_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "కనెక్ట్ అవుతోంది...", + "Disconnecting...": "డిస్u200cకనెక్ట్ చేస్తోంది...", + "Reconnecting...": "మళ్లీ కనెక్ట్ అవుతోంది...", + "Internal error": "అంతర్గత లోపం", + "Must set host": "తప్పనిసరిగా సెట్ చేయాలి", + "Connected (encrypted) to ": "కి కనెక్ట్ చేయబడింది (ఎన్u200cక్రిప్ట్ చేయబడింది)", + "Connected (unencrypted) to ": "కి కనెక్ట్ చేయబడింది (ఎన్u200cక్రిప్ట్ చేయబడింది)", + "Something went wrong, connection is closed": "ఏదో తప్పు జరిగింది, కనెక్షన్ మూసివేయబడింది", + "Failed to connect to server": "సర్వర్ తో అనుసంధాన ప్రయత్నం విఫలమైనది", + "Disconnected": "డిస్u200cకనెక్ట్ చేయబడింది", + "New connection has been rejected with reason: ": "కొత్త కనెక్షన్ కారణంతో తిరస్కరించబడింది:", + "New connection has been rejected": "కొత్త కనెక్షన్ తిరస్కరించబడింది", + "Credentials are required": "క్రెడెన్షియల్స్ అవసరం", + "Hide/Show the control bar": "నియంత్రణ పట్టీని దాచు/చూపించు", + "Drag": "లాగండి", + "Move/Drag Viewport": "వ్యూపోర్ట్u200cని తరలించు/లాగండి", + "Keyboard": "కీబోర్డ్", + "Show Keyboard": "కీబోర్డ్ చూపించు", + "Extra keys": "అదనపు కీలు", + "Show Extra Keys": "అదనపు కీలను చూపించు", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrlని టోగుల్ చేయి", + "Alt": "Alt", + "Toggle Alt": "Altని టోగుల్ చేయి", + "Toggle Windows": "విండోస్u200cని టోగుల్ చేయి", + "Windows": "విండోస్", + "Send Tab": "పంపు ట్యాబ్", + "Tab": "ట్యాబ్", + "Esc": "Esc", + "Send Escape": "ఎస్కేప్ పంపు", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Delని పంపు", + "Shutdown/Reboot": "షట్u200cడౌన్/రీబూట్", + "Shutdown/Reboot...": "షట్u200cడౌన్/రీబూట్...", + "Power": "శక్తి", + "Shutdown": "షట్డౌన్", + "Reboot": "రీబూట్", + "Reset": "రీసెట్", + "Clipboard": "క్లిప్u200cబోర్డ్", + "Clear": "క్లియర్", + "Fullscreen": "పూర్తి స్క్రీన్", + "Settings": "సెట్టింగ్u200cలు", + "Shared Mode": "షేర్డ్ మోడ్", + "View Only": "వీక్షణ మాత్రమే", + "Clip to Window": "క్లిప్ టు విండో", + "Scaling Mode:": "స్కేలింగ్ మోడ్:", + "None": "ఏదీ లేదు", + "Local Scaling": "స్థానిక స్కేలింగ్", + "Remote Resizing": "రిమోట్ పునఃపరిమాణం", + "Advanced": "ఆధునిక", + "Quality:": "నాణ్యత:", + "Compression level:": "కంప్రెషన్ స్థాయి:", + "Repeater ID:": "రిపీటర్ ID:", + "WebSocket": "వెబ్u200cసాకెట్", + "Encrypt": "ఎన్క్రిప్ట్", + "Host:": "హోస్ట్:", + "Port:": "పోర్ట్:", + "Path:": "మార్గం:", + "Automatic Reconnect": "ఆటోమేటిక్ రీకనెక్ట్", + "Reconnect Delay (ms):": "ఆలస్యాన్ని మళ్లీ కనెక్ట్ చేయండి (మిస్):", + "Show Dot when No Cursor": "కర్సర్ లేనప్పుడు డాట్ చూపించు", + "Logging:": "లాగింగ్:", + "Version:": "సంస్కరణ: Telugu:", + "Disconnect": "డిస్u200cకనెక్ట్", + "Connect": "కనెక్ట్", + "Username:": "వినియోగదారు పేరు:", + "Password:": "పాస్u200cవర్డ్:", + "Send Credentials": "క్రెడెన్షియల్స్ పంపండి", + "Cancel": "రద్దు చేయండి", + "Keys": "కీలు", + "Game Cursor Mode": "గేమ్ కర్సర్ మోడ్", + "Press Esc Key to Exit Pointer Lock Mode": "పాయింటర్ లాక్ మోడ్ నుండి నిష్క్రమించడానికి Esc కీని నొక్కండి", + "Game Mode paused, click on screen to resume Game Mode.": "గేమ్ మోడ్ పాజ్ చేయబడింది, గేమ్ మోడ్u200cని రెస్యూమ్ చేయడానికి స్క్రీన్u200cపై క్లిక్ చేయండి.", + "Clipboard Up": "క్లిప్u200cబోర్డ్ పైకి", + "CLipboard Down": "క్లిప్u200cబోర్డ్ డౌన్", + "Clipboard Seamless": "క్లిప్u200cబోర్డ్ అతుకులు", + "Prefer Local Cursor": "స్థానిక కర్సర్u200cకు ప్రాధాన్యత ఇవ్వండి", + "Translate keyboard shortcuts": "కీబోర్డ్ సత్వరమార్గాలను అనువదించు", + "Enable WebRTC UDP Transit": "WebRTC UDP రవాణాను ప్రారంభించు", + "Enable WebP Compression": "WebP కంప్రెషన్u200cని ప్రారంభించు", + "Enable Performance Stats": "పనితీరు గణాంకాలను ప్రారంభించు", + "Enable Pointer Lock": "పాయింటర్ లాక్u200cని ప్రారంభించు", + "IME Input Mode": "IME ఇన్u200cపుట్ మోడ్", + "Show Virtual Keyboard Control": "వర్చువల్ కీబోర్డ్ నియంత్రణను చూపించు", + "Toggle Control Panel via Keystrokes": "కీస్ట్రోక్u200cల ద్వారా కంట్రోల్ ప్యానెల్u200cని టోగుల్ చేయండి", + "Render Native Resolution": "రెండర్ స్థానిక రిజల్యూషన్", + "Keyboard Shortcuts": "కీబోర్డ్ సత్వరమార్గాలు", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC కీబోర్డ్ సత్వరమార్గాలను ప్రారంభించు", + "1 - Toggle Control Panel": "1 - కంట్రోల్ ప్యానెల్u200cని టోగుల్ చేయి", + "2 - Toggle Game Pointer Mode": "2 - గేమ్ పాయింటర్ మోడ్u200cని టోగుల్ చేయండి", + "3 - Toggle Pointer Lock": "3 - పాయింటర్ లాక్u200cని టోగుల్ చేయి", + "Stream Quality": "స్ట్రీమ్ నాణ్యత", + "Preset Modes:": "ప్రీసెట్ మోడ్u200cలు:", + "Static": "స్టాటిక్", + "Low": "తక్కువ", + "Medium": "మీడియం", + "High": "అధిక", + "Extreme": "అతి", + "Lossless": "నష్టం లేనిది", + "Custom": "కస్టమ్", + "Anti-Aliasing:": "యాంటీ అలియాసింగ్:", + "Auto Dynamic": "ఆటో డైనమిక్", + "Off": "ఆఫ్", + "On": "పై", + "Dynamic Quality Min:": "డైనమిక్ క్వాలిటీ మిని:", + "Dynamic Quality Max:": "డైనమిక్ క్వాలిటీ మ్యాక్స్:", + "Treat Lossless:": "లాస్లెస్ ట్రీట్:", + "Frame Rate:": "ఫ్రేమ్ రేట్:", + "Video JPEG Quality:": "వీడియో JPEG నాణ్యత:", + "Video WEBP Quality:": "వీడియో WEBP నాణ్యత:", + "Video Area:": "వీడియో ప్రాంతం:", + "Video Time:": "వీడియో సమయం:", + "Video Out Time:": "వీడియో అవుట్ టైమ్:", + "Video Mode Width:": "వీడియో మోడ్ వెడల్పు:", + "Video Mode Height:": "వీడియో మోడ్ ఎత్తు:", + "Documentation": "డాక్యుమెంటేషన్", + "Drag Viewport": "డ్రాగ్ వ్యూపోర్ట్", + "KasmVNC encountered an error:": "KasmVNC లోపాన్ని ఎదుర్కొంది:" +} \ No newline at end of file diff --git a/app/locale/tg.json b/app/locale/tg.json new file mode 100644 index 0000000..8706c38 --- /dev/null +++ b/app/locale/tg.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Пайваст мешавад...", + "Disconnecting...": "Қатъ карда мешавад...", + "Reconnecting...": "Аз нав пайваст карда мешавад...", + "Internal error": "Хатои дохилӣ", + "Must set host": "Бояд мизбон таъин карда шавад", + "Connected (encrypted) to ": "Пайваст (рамзшуда) ба", + "Connected (unencrypted) to ": "Пайваст (бешифрнашуда) ба", + "Something went wrong, connection is closed": "Чизе хато кард, пайвастшавӣ баста шуд", + "Failed to connect to server": "Ба сервер пайваст нашуд", + "Disconnected": "Қуръшуда", + "New connection has been rejected with reason: ": "Пайванди нав бо сабабҳо рад карда шуд:", + "New connection has been rejected": "Пайвасти нав рад карда шуд", + "Credentials are required": "Маълумотнома талаб карда мешавад", + "Hide/Show the control bar": "Пинҳон/нишон додани сатри идоракунӣ", + "Drag": "Кашола кардан", + "Move/Drag Viewport": "Намоишгоҳро интиқол додан/каш кардан", + "Keyboard": "Клавиатура", + "Show Keyboard": "Намоиши клавиатура", + "Extra keys": "Калидҳои иловагӣ", + "Show Extra Keys": "Нишон додани калидҳои иловагӣ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Тағйир додани Ctrl", + "Alt": "Алт", + "Toggle Alt": "Тағйир додани Alt", + "Toggle Windows": "Тағйир додани Windows", + "Windows": "Windows", + "Send Tab": "Варақаи ирсол", + "Tab": "Таб", + "Esc": "Фарор", + "Send Escape": "Фиристодани фирор", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ирсол Ctrl-Alt-Del", + "Shutdown/Reboot": "Хомӯш/Бозоғоз", + "Shutdown/Reboot...": "Хомӯш/Бозоғоз кардан...", + "Power": "Қувва", + "Shutdown": "Пӯшида шудан", + "Reboot": "Бозоғоз", + "Reset": "Бозсозӣ", + "Clipboard": "Буфери мухобиротӣ", + "Clear": "Тоза", + "Fullscreen": "Тамомсафҳа", + "Settings": "Танзимот", + "Shared Mode": "Усули муштарак", + "View Only": "Танҳо дидан", + "Clip to Window": "Клип ба тиреза", + "Scaling Mode:": "Усули миқёс:", + "None": "Ҳеҷ", + "Local Scaling": "Миқёси маҳаллӣ", + "Remote Resizing": "Тағйир додани андозагирии дурдаст", + "Advanced": "Мукаммал", + "Quality:": "Сифат:", + "Compression level:": "Сатҳи фишурдашавӣ:", + "Repeater ID:": "Идентификатори такрорӣ:", + "WebSocket": "WebSocket", + "Encrypt": "Рамзгузорӣ", + "Host:": "Созмон:", + "Port:": "Бандар:", + "Path:": "Роҳ:", + "Automatic Reconnect": "Бозсозии худкор", + "Reconnect Delay (ms):": "Таъхири дубора пайвастшавӣ (мс):", + "Show Dot when No Cursor": "Нуқтаро ҳангоми мавҷуд набудани курсор нишон диҳед", + "Logging:": "Бақайдгирӣ:", + "Version:": "Версия:", + "Disconnect": "Қатъ кардан", + "Connect": "Пайваст", + "Username:": "Номи корбар:", + "Password:": "Парол:", + "Send Credentials": "Ирсол кардани эътимоднома", + "Cancel": "Бекор кардан", + "Keys": "Калидҳо", + "Game Cursor Mode": "Усули курсори бозӣ", + "Press Esc Key to Exit Pointer Lock Mode": "Барои баромадан аз режими қулфи ишоратӣ тугмаи Esc -ро пахш кунед", + "Game Mode paused, click on screen to resume Game Mode.": "Усули бозӣ таваққуф карда шуд, барои идомаи режими бозӣ дар экран клик кунед.", + "Clipboard Up": "Бо буфер боло", + "CLipboard Down": "Поён кардани буфер", + "Clipboard Seamless": "Буфери бефосила", + "Prefer Local Cursor": "Курсори маҳаллиро бартарӣ диҳед", + "Translate keyboard shortcuts": "Тарҷумаи миёнабурҳои клавиатура", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit-ро фаъол созед", + "Enable WebP Compression": "Фиқшоркунии WebP-ро фаъол созед", + "Enable Performance Stats": "Омори иҷроишро фаъол созед", + "Enable Pointer Lock": "Фаъол кардани Қулфи Нишондиҳанда", + "IME Input Mode": "Усули вуруди IME", + "Show Virtual Keyboard Control": "Намоиши назорати клавиатураи виртуалӣ", + "Toggle Control Panel via Keystrokes": "Панели идоракуниро ба воситаи тугмачаҳо иваз кунед", + "Render Native Resolution": "Резолюсияи маҳаллӣ", + "Keyboard Shortcuts": "Миёнбурҳои клавиатура", + "Enable KasmVNC Keyboard Shortcuts": "Миёнбурҳои клавиатураи KasmVNC-ро фаъол созед", + "1 - Toggle Control Panel": "1 - Гузариш ба панели идоракунӣ", + "2 - Toggle Game Pointer Mode": "2 - Гузариш ба ҳолати нишондиҳандаи бозӣ", + "3 - Toggle Pointer Lock": "3 - Гузариш ба қулфи ишора", + "Stream Quality": "Сифати ҷараён", + "Preset Modes:": "Усулҳои пешакӣ:", + "Static": "статикӣ", + "Low": "паст", + "Medium": "миёна", + "High": "баланд", + "Extreme": "Аз ҳад зиёд", + "Lossless": "Бе талафот", + "Custom": "Одатӣ", + "Anti-Aliasing:": "Анти-алиасинг:", + "Auto Dynamic": "Автодинамикӣ", + "Off": "Хомуш", + "On": "Даргир", + "Dynamic Quality Min:": "Сифати динамикӣ ҳадди ақал:", + "Dynamic Quality Max:": "Максҳои сифат динамикӣ:", + "Treat Lossless:": "Муолиҷаи бе талафот:", + "Frame Rate:": "Меъёри чаҳорчӯба:", + "Video JPEG Quality:": "Сифати JPEG видео:", + "Video WEBP Quality:": "Сифати видеои WEBP:", + "Video Area:": "Майдони видео:", + "Video Time:": "Вақти видео:", + "Video Out Time:": "Вақти баромади видео:", + "Video Mode Width:": "Паснои ҳолати видео:", + "Video Mode Height:": "Бандии ҳолати видео:", + "Documentation": "Ҳуҷҷатҳо", + "Drag Viewport": "Кашолакунии Viewport", + "KasmVNC encountered an error:": "KasmVNC ба хатогӣ дучор шуд:" +} \ No newline at end of file diff --git a/app/locale/tg_TJ.json b/app/locale/tg_TJ.json new file mode 100644 index 0000000..8706c38 --- /dev/null +++ b/app/locale/tg_TJ.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Пайваст мешавад...", + "Disconnecting...": "Қатъ карда мешавад...", + "Reconnecting...": "Аз нав пайваст карда мешавад...", + "Internal error": "Хатои дохилӣ", + "Must set host": "Бояд мизбон таъин карда шавад", + "Connected (encrypted) to ": "Пайваст (рамзшуда) ба", + "Connected (unencrypted) to ": "Пайваст (бешифрнашуда) ба", + "Something went wrong, connection is closed": "Чизе хато кард, пайвастшавӣ баста шуд", + "Failed to connect to server": "Ба сервер пайваст нашуд", + "Disconnected": "Қуръшуда", + "New connection has been rejected with reason: ": "Пайванди нав бо сабабҳо рад карда шуд:", + "New connection has been rejected": "Пайвасти нав рад карда шуд", + "Credentials are required": "Маълумотнома талаб карда мешавад", + "Hide/Show the control bar": "Пинҳон/нишон додани сатри идоракунӣ", + "Drag": "Кашола кардан", + "Move/Drag Viewport": "Намоишгоҳро интиқол додан/каш кардан", + "Keyboard": "Клавиатура", + "Show Keyboard": "Намоиши клавиатура", + "Extra keys": "Калидҳои иловагӣ", + "Show Extra Keys": "Нишон додани калидҳои иловагӣ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Тағйир додани Ctrl", + "Alt": "Алт", + "Toggle Alt": "Тағйир додани Alt", + "Toggle Windows": "Тағйир додани Windows", + "Windows": "Windows", + "Send Tab": "Варақаи ирсол", + "Tab": "Таб", + "Esc": "Фарор", + "Send Escape": "Фиристодани фирор", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ирсол Ctrl-Alt-Del", + "Shutdown/Reboot": "Хомӯш/Бозоғоз", + "Shutdown/Reboot...": "Хомӯш/Бозоғоз кардан...", + "Power": "Қувва", + "Shutdown": "Пӯшида шудан", + "Reboot": "Бозоғоз", + "Reset": "Бозсозӣ", + "Clipboard": "Буфери мухобиротӣ", + "Clear": "Тоза", + "Fullscreen": "Тамомсафҳа", + "Settings": "Танзимот", + "Shared Mode": "Усули муштарак", + "View Only": "Танҳо дидан", + "Clip to Window": "Клип ба тиреза", + "Scaling Mode:": "Усули миқёс:", + "None": "Ҳеҷ", + "Local Scaling": "Миқёси маҳаллӣ", + "Remote Resizing": "Тағйир додани андозагирии дурдаст", + "Advanced": "Мукаммал", + "Quality:": "Сифат:", + "Compression level:": "Сатҳи фишурдашавӣ:", + "Repeater ID:": "Идентификатори такрорӣ:", + "WebSocket": "WebSocket", + "Encrypt": "Рамзгузорӣ", + "Host:": "Созмон:", + "Port:": "Бандар:", + "Path:": "Роҳ:", + "Automatic Reconnect": "Бозсозии худкор", + "Reconnect Delay (ms):": "Таъхири дубора пайвастшавӣ (мс):", + "Show Dot when No Cursor": "Нуқтаро ҳангоми мавҷуд набудани курсор нишон диҳед", + "Logging:": "Бақайдгирӣ:", + "Version:": "Версия:", + "Disconnect": "Қатъ кардан", + "Connect": "Пайваст", + "Username:": "Номи корбар:", + "Password:": "Парол:", + "Send Credentials": "Ирсол кардани эътимоднома", + "Cancel": "Бекор кардан", + "Keys": "Калидҳо", + "Game Cursor Mode": "Усули курсори бозӣ", + "Press Esc Key to Exit Pointer Lock Mode": "Барои баромадан аз режими қулфи ишоратӣ тугмаи Esc -ро пахш кунед", + "Game Mode paused, click on screen to resume Game Mode.": "Усули бозӣ таваққуф карда шуд, барои идомаи режими бозӣ дар экран клик кунед.", + "Clipboard Up": "Бо буфер боло", + "CLipboard Down": "Поён кардани буфер", + "Clipboard Seamless": "Буфери бефосила", + "Prefer Local Cursor": "Курсори маҳаллиро бартарӣ диҳед", + "Translate keyboard shortcuts": "Тарҷумаи миёнабурҳои клавиатура", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit-ро фаъол созед", + "Enable WebP Compression": "Фиқшоркунии WebP-ро фаъол созед", + "Enable Performance Stats": "Омори иҷроишро фаъол созед", + "Enable Pointer Lock": "Фаъол кардани Қулфи Нишондиҳанда", + "IME Input Mode": "Усули вуруди IME", + "Show Virtual Keyboard Control": "Намоиши назорати клавиатураи виртуалӣ", + "Toggle Control Panel via Keystrokes": "Панели идоракуниро ба воситаи тугмачаҳо иваз кунед", + "Render Native Resolution": "Резолюсияи маҳаллӣ", + "Keyboard Shortcuts": "Миёнбурҳои клавиатура", + "Enable KasmVNC Keyboard Shortcuts": "Миёнбурҳои клавиатураи KasmVNC-ро фаъол созед", + "1 - Toggle Control Panel": "1 - Гузариш ба панели идоракунӣ", + "2 - Toggle Game Pointer Mode": "2 - Гузариш ба ҳолати нишондиҳандаи бозӣ", + "3 - Toggle Pointer Lock": "3 - Гузариш ба қулфи ишора", + "Stream Quality": "Сифати ҷараён", + "Preset Modes:": "Усулҳои пешакӣ:", + "Static": "статикӣ", + "Low": "паст", + "Medium": "миёна", + "High": "баланд", + "Extreme": "Аз ҳад зиёд", + "Lossless": "Бе талафот", + "Custom": "Одатӣ", + "Anti-Aliasing:": "Анти-алиасинг:", + "Auto Dynamic": "Автодинамикӣ", + "Off": "Хомуш", + "On": "Даргир", + "Dynamic Quality Min:": "Сифати динамикӣ ҳадди ақал:", + "Dynamic Quality Max:": "Максҳои сифат динамикӣ:", + "Treat Lossless:": "Муолиҷаи бе талафот:", + "Frame Rate:": "Меъёри чаҳорчӯба:", + "Video JPEG Quality:": "Сифати JPEG видео:", + "Video WEBP Quality:": "Сифати видеои WEBP:", + "Video Area:": "Майдони видео:", + "Video Time:": "Вақти видео:", + "Video Out Time:": "Вақти баромади видео:", + "Video Mode Width:": "Паснои ҳолати видео:", + "Video Mode Height:": "Бандии ҳолати видео:", + "Documentation": "Ҳуҷҷатҳо", + "Drag Viewport": "Кашолакунии Viewport", + "KasmVNC encountered an error:": "KasmVNC ба хатогӣ дучор шуд:" +} \ No newline at end of file diff --git a/app/locale/th.json b/app/locale/th.json new file mode 100644 index 0000000..ec28920 --- /dev/null +++ b/app/locale/th.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "กำลังเชื่อมต่อ...", + "Disconnecting...": "กำลังตัดการเชื่อมต่อ...", + "Reconnecting...": "กำลังเชื่อมต่อใหม่...", + "Internal error": "ข้อผิดพลาดภายใน", + "Must set host": "ต้องตั้งค่าโฮสต์", + "Connected (encrypted) to ": "เชื่อมต่อ (เข้ารหัส) กับ ", + "Connected (unencrypted) to ": "เชื่อมต่อ (ไม่ได้เข้ารหัส) กับ ", + "Something went wrong, connection is closed": "เกิดข้อผิดพลาด การเชื่อมต่อถูกปิด", + "Failed to connect to server": "ล้มเหลวในการเชื่อมต่อกับเซิร์ฟเวอร์", + "Disconnected": "ตัดการเชื่อมต่อ", + "New connection has been rejected with reason: ": "การเชื่อมต่อใหม่ถูกปฏิเสธด้วยเหตุผล: ", + "New connection has been rejected": "การเชื่อมต่อใหม่ถูกปฏิเสธ", + "Credentials are required": "จำเป็นต้องมีข้อมูลประจำตัว", + "Hide/Show the control bar": "ซ่อน/แสดงแถบควบคุม", + "Drag": "ลาก", + "Move/Drag Viewport": "ย้าย/ลากวิวพอร์ต", + "Keyboard": "คีย์บอร์ด", + "Show Keyboard": "แสดงแป้นพิมพ์", + "Extra keys": "กุญแจเสริม", + "Show Extra Keys": "แสดงคีย์พิเศษ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "สลับ Ctrl", + "Alt": "อัลท์", + "Toggle Alt": "สลับ Alt", + "Toggle Windows": "สลับหน้าต่าง", + "Windows": "หน้าต่าง", + "Send Tab": "แท็บส่ง", + "Tab": "แท็บ", + "Esc": "เอส", + "Send Escape": "ส่งหนี", + "Ctrl+Alt+Del": "Ctrl+Alt+เดล", + "Send Ctrl-Alt-Del": "ส่ง Ctrl-Alt-Del", + "Shutdown/Reboot": "ปิด/รีบูต", + "Shutdown/Reboot...": "ปิด/รีบูต...", + "Power": "พลัง", + "Shutdown": "ปิดตัวลง", + "Reboot": "รีบูต", + "Reset": "รีเซ็ต", + "Clipboard": "คลิปบอร์ด", + "Clear": "ชัดเจน", + "Fullscreen": "เต็มจอ", + "Settings": "การตั้งค่า", + "Shared Mode": "โหมดแชร์", + "View Only": "สำหรับดูเท่านั้น", + "Clip to Window": "คลิปไปที่หน้าต่าง", + "Scaling Mode:": "โหมดปรับขนาด:", + "None": "ไม่มี", + "Local Scaling": "มาตราส่วนท้องถิ่น", + "Remote Resizing": "การปรับขนาดระยะไกล", + "Advanced": "ขั้นสูง", + "Quality:": "คุณภาพ:", + "Compression level:": "ระดับการบีบอัด:", + "Repeater ID:": "รหัสทวน:", + "WebSocket": "เว็บซ็อกเก็ต", + "Encrypt": "เข้ารหัส", + "Host:": "เจ้าภาพ:", + "Port:": "ท่าเรือ:", + "Path:": "เส้นทาง:", + "Automatic Reconnect": "เชื่อมต่อใหม่อัตโนมัติ", + "Reconnect Delay (ms):": "ความล่าช้าในการเชื่อมต่อใหม่ (ms):", + "Show Dot when No Cursor": "แสดงจุดเมื่อไม่มีเคอร์เซอร์", + "Logging:": "บันทึก:", + "Version:": "เวอร์ชัน:", + "Disconnect": "ยกเลิกการเชื่อมต่อ", + "Connect": "เชื่อมต่อ", + "Username:": "ชื่อผู้ใช้:", + "Password:": "รหัสผ่าน:", + "Send Credentials": "ส่งข้อมูลประจำตัว", + "Cancel": "ยกเลิก", + "Keys": "กุญแจ", + "Game Cursor Mode": "โหมดเคอร์เซอร์เกม", + "Press Esc Key to Exit Pointer Lock Mode": "กดปุ่ม Esc เพื่อออกจากโหมดล็อคตัวชี้", + "Game Mode paused, click on screen to resume Game Mode.": "โหมดเกมหยุดชั่วคราว คลิกบนหน้าจอเพื่อเล่นโหมดเกมต่อ", + "Clipboard Up": "คลิปบอร์ดขึ้น", + "CLipboard Down": "คลิปบอร์ดลง", + "Clipboard Seamless": "คลิปบอร์ดไร้รอยต่อ", + "Prefer Local Cursor": "ต้องการเคอร์เซอร์ท้องถิ่น", + "Translate keyboard shortcuts": "แปลแป้นพิมพ์ลัด", + "Enable WebRTC UDP Transit": "เปิดใช้งานการเปลี่ยน UDP ของ WebRTC", + "Enable WebP Compression": "เปิดใช้งานการบีบอัด WebP", + "Enable Performance Stats": "เปิดใช้งานสถิติประสิทธิภาพ", + "Enable Pointer Lock": "เปิดใช้งานการล็อคตัวชี้", + "IME Input Mode": "โหมดอินพุต IME", + "Show Virtual Keyboard Control": "แสดงการควบคุมแป้นพิมพ์เสมือนจริง", + "Toggle Control Panel via Keystrokes": "สลับแผงควบคุมผ่านการกดแป้นพิมพ์", + "Render Native Resolution": "เรนเดอร์ Native Resolution", + "Keyboard Shortcuts": "แป้นพิมพ์ลัด", + "Enable KasmVNC Keyboard Shortcuts": "เปิดใช้งานแป้นพิมพ์ลัด KasmVNC", + "1 - Toggle Control Panel": "1 - สลับแผงควบคุม", + "2 - Toggle Game Pointer Mode": "2 - สลับโหมดตัวชี้เกม", + "3 - Toggle Pointer Lock": "3 - ล็อคตัวชี้สลับ", + "Stream Quality": "คุณภาพการสตรีม", + "Preset Modes:": "โหมดพรีเซ็ต:", + "Static": "คงที่", + "Low": "ต่ำ", + "Medium": "ปานกลาง", + "High": "สูง", + "Extreme": "สุดขีด", + "Lossless": "ไร้พ่าย", + "Custom": "กำหนดเอง", + "Anti-Aliasing:": "ต่อต้านนามแฝง:", + "Auto Dynamic": "ไดนามิกอัตโนมัติ", + "Off": "ปิด", + "On": "บน", + "Dynamic Quality Min:": "คุณภาพไดนามิกขั้นต่ำ:", + "Dynamic Quality Max:": "ไดนามิกคุณภาพสูงสุด:", + "Treat Lossless:": "รักษาแบบไม่สูญเสีย:", + "Frame Rate:": "อัตราเฟรม:", + "Video JPEG Quality:": "คุณภาพวิดีโอ JPEG:", + "Video WEBP Quality:": "คุณภาพวิดีโอ WEBP:", + "Video Area:": "พื้นที่วิดีโอ:", + "Video Time:": "เวลาวิดีโอ:", + "Video Out Time:": "เวลาวิดีโอออก:", + "Video Mode Width:": "ความกว้างของโหมดวิดีโอ:", + "Video Mode Height:": "ความสูงของโหมดวิดีโอ:", + "Documentation": "เอกสาร", + "Drag Viewport": "ลากวิวพอร์ต", + "KasmVNC encountered an error:": "KasmVNC พบข้อผิดพลาด:" +} \ No newline at end of file diff --git a/app/locale/th_TH.json b/app/locale/th_TH.json new file mode 100644 index 0000000..ec28920 --- /dev/null +++ b/app/locale/th_TH.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "กำลังเชื่อมต่อ...", + "Disconnecting...": "กำลังตัดการเชื่อมต่อ...", + "Reconnecting...": "กำลังเชื่อมต่อใหม่...", + "Internal error": "ข้อผิดพลาดภายใน", + "Must set host": "ต้องตั้งค่าโฮสต์", + "Connected (encrypted) to ": "เชื่อมต่อ (เข้ารหัส) กับ ", + "Connected (unencrypted) to ": "เชื่อมต่อ (ไม่ได้เข้ารหัส) กับ ", + "Something went wrong, connection is closed": "เกิดข้อผิดพลาด การเชื่อมต่อถูกปิด", + "Failed to connect to server": "ล้มเหลวในการเชื่อมต่อกับเซิร์ฟเวอร์", + "Disconnected": "ตัดการเชื่อมต่อ", + "New connection has been rejected with reason: ": "การเชื่อมต่อใหม่ถูกปฏิเสธด้วยเหตุผล: ", + "New connection has been rejected": "การเชื่อมต่อใหม่ถูกปฏิเสธ", + "Credentials are required": "จำเป็นต้องมีข้อมูลประจำตัว", + "Hide/Show the control bar": "ซ่อน/แสดงแถบควบคุม", + "Drag": "ลาก", + "Move/Drag Viewport": "ย้าย/ลากวิวพอร์ต", + "Keyboard": "คีย์บอร์ด", + "Show Keyboard": "แสดงแป้นพิมพ์", + "Extra keys": "กุญแจเสริม", + "Show Extra Keys": "แสดงคีย์พิเศษ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "สลับ Ctrl", + "Alt": "อัลท์", + "Toggle Alt": "สลับ Alt", + "Toggle Windows": "สลับหน้าต่าง", + "Windows": "หน้าต่าง", + "Send Tab": "แท็บส่ง", + "Tab": "แท็บ", + "Esc": "เอส", + "Send Escape": "ส่งหนี", + "Ctrl+Alt+Del": "Ctrl+Alt+เดล", + "Send Ctrl-Alt-Del": "ส่ง Ctrl-Alt-Del", + "Shutdown/Reboot": "ปิด/รีบูต", + "Shutdown/Reboot...": "ปิด/รีบูต...", + "Power": "พลัง", + "Shutdown": "ปิดตัวลง", + "Reboot": "รีบูต", + "Reset": "รีเซ็ต", + "Clipboard": "คลิปบอร์ด", + "Clear": "ชัดเจน", + "Fullscreen": "เต็มจอ", + "Settings": "การตั้งค่า", + "Shared Mode": "โหมดแชร์", + "View Only": "สำหรับดูเท่านั้น", + "Clip to Window": "คลิปไปที่หน้าต่าง", + "Scaling Mode:": "โหมดปรับขนาด:", + "None": "ไม่มี", + "Local Scaling": "มาตราส่วนท้องถิ่น", + "Remote Resizing": "การปรับขนาดระยะไกล", + "Advanced": "ขั้นสูง", + "Quality:": "คุณภาพ:", + "Compression level:": "ระดับการบีบอัด:", + "Repeater ID:": "รหัสทวน:", + "WebSocket": "เว็บซ็อกเก็ต", + "Encrypt": "เข้ารหัส", + "Host:": "เจ้าภาพ:", + "Port:": "ท่าเรือ:", + "Path:": "เส้นทาง:", + "Automatic Reconnect": "เชื่อมต่อใหม่อัตโนมัติ", + "Reconnect Delay (ms):": "ความล่าช้าในการเชื่อมต่อใหม่ (ms):", + "Show Dot when No Cursor": "แสดงจุดเมื่อไม่มีเคอร์เซอร์", + "Logging:": "บันทึก:", + "Version:": "เวอร์ชัน:", + "Disconnect": "ยกเลิกการเชื่อมต่อ", + "Connect": "เชื่อมต่อ", + "Username:": "ชื่อผู้ใช้:", + "Password:": "รหัสผ่าน:", + "Send Credentials": "ส่งข้อมูลประจำตัว", + "Cancel": "ยกเลิก", + "Keys": "กุญแจ", + "Game Cursor Mode": "โหมดเคอร์เซอร์เกม", + "Press Esc Key to Exit Pointer Lock Mode": "กดปุ่ม Esc เพื่อออกจากโหมดล็อคตัวชี้", + "Game Mode paused, click on screen to resume Game Mode.": "โหมดเกมหยุดชั่วคราว คลิกบนหน้าจอเพื่อเล่นโหมดเกมต่อ", + "Clipboard Up": "คลิปบอร์ดขึ้น", + "CLipboard Down": "คลิปบอร์ดลง", + "Clipboard Seamless": "คลิปบอร์ดไร้รอยต่อ", + "Prefer Local Cursor": "ต้องการเคอร์เซอร์ท้องถิ่น", + "Translate keyboard shortcuts": "แปลแป้นพิมพ์ลัด", + "Enable WebRTC UDP Transit": "เปิดใช้งานการเปลี่ยน UDP ของ WebRTC", + "Enable WebP Compression": "เปิดใช้งานการบีบอัด WebP", + "Enable Performance Stats": "เปิดใช้งานสถิติประสิทธิภาพ", + "Enable Pointer Lock": "เปิดใช้งานการล็อคตัวชี้", + "IME Input Mode": "โหมดอินพุต IME", + "Show Virtual Keyboard Control": "แสดงการควบคุมแป้นพิมพ์เสมือนจริง", + "Toggle Control Panel via Keystrokes": "สลับแผงควบคุมผ่านการกดแป้นพิมพ์", + "Render Native Resolution": "เรนเดอร์ Native Resolution", + "Keyboard Shortcuts": "แป้นพิมพ์ลัด", + "Enable KasmVNC Keyboard Shortcuts": "เปิดใช้งานแป้นพิมพ์ลัด KasmVNC", + "1 - Toggle Control Panel": "1 - สลับแผงควบคุม", + "2 - Toggle Game Pointer Mode": "2 - สลับโหมดตัวชี้เกม", + "3 - Toggle Pointer Lock": "3 - ล็อคตัวชี้สลับ", + "Stream Quality": "คุณภาพการสตรีม", + "Preset Modes:": "โหมดพรีเซ็ต:", + "Static": "คงที่", + "Low": "ต่ำ", + "Medium": "ปานกลาง", + "High": "สูง", + "Extreme": "สุดขีด", + "Lossless": "ไร้พ่าย", + "Custom": "กำหนดเอง", + "Anti-Aliasing:": "ต่อต้านนามแฝง:", + "Auto Dynamic": "ไดนามิกอัตโนมัติ", + "Off": "ปิด", + "On": "บน", + "Dynamic Quality Min:": "คุณภาพไดนามิกขั้นต่ำ:", + "Dynamic Quality Max:": "ไดนามิกคุณภาพสูงสุด:", + "Treat Lossless:": "รักษาแบบไม่สูญเสีย:", + "Frame Rate:": "อัตราเฟรม:", + "Video JPEG Quality:": "คุณภาพวิดีโอ JPEG:", + "Video WEBP Quality:": "คุณภาพวิดีโอ WEBP:", + "Video Area:": "พื้นที่วิดีโอ:", + "Video Time:": "เวลาวิดีโอ:", + "Video Out Time:": "เวลาวิดีโอออก:", + "Video Mode Width:": "ความกว้างของโหมดวิดีโอ:", + "Video Mode Height:": "ความสูงของโหมดวิดีโอ:", + "Documentation": "เอกสาร", + "Drag Viewport": "ลากวิวพอร์ต", + "KasmVNC encountered an error:": "KasmVNC พบข้อผิดพลาด:" +} \ No newline at end of file diff --git a/app/locale/tl.json b/app/locale/tl.json new file mode 100644 index 0000000..e3b47f7 --- /dev/null +++ b/app/locale/tl.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Kumokonekta...", + "Disconnecting...": "Nagdidiskonekta...", + "Reconnecting...": "Muling kumonekta...", + "Internal error": "Internal na error", + "Must set host": "Dapat magtakda ng host", + "Connected (encrypted) to ": "Nakakonekta (naka-encrypt) sa ", + "Connected (unencrypted) to ": "Nakakonekta (hindi naka-encrypt) sa ", + "Something went wrong, connection is closed": "Nagkaroon ng problema, sarado ang koneksyon", + "Failed to connect to server": "Nabigong kumonekta sa server", + "Disconnected": "Nadiskonekta", + "New connection has been rejected with reason: ": "Ang bagong koneksyon ay tinanggihan nang may dahilan: ", + "New connection has been rejected": "Ang bagong koneksyon ay tinanggihan", + "Credentials are required": "Kinakailangan ang mga kredensyal", + "Hide/Show the control bar": "Itago/Ipakita ang control bar", + "Drag": "I-drag", + "Move/Drag Viewport": "Ilipat/I-drag ang Viewport", + "Keyboard": "Keyboard", + "Show Keyboard": "Ipakita ang Keyboard", + "Extra keys": "Mga karagdagang susi", + "Show Extra Keys": "Ipakita ang Mga Dagdag na Susi", + "Ctrl": "Ctrl", + "Toggle Ctrl": "I-toggle ang Ctrl", + "Alt": "Alt", + "Toggle Alt": "I-toggle ang Alt", + "Toggle Windows": "I-toggle ang Windows", + "Windows": "Windows", + "Send Tab": "Ipadala ang Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Ipadala ang Pagtakas", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ipadala ang Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Isara/I-reboot...", + "Power": "Kapangyarihan", + "Shutdown": "Shutdown", + "Reboot": "I-reboot", + "Reset": "I-reset", + "Clipboard": "Clipboard", + "Clear": "Malinaw", + "Fullscreen": "Fullscreen", + "Settings": "Mga Setting", + "Shared Mode": "Nakabahaging Mode", + "View Only": "Tingnan lamang", + "Clip to Window": "Clip sa Window", + "Scaling Mode:": "Scaling Mode:", + "None": "Wala", + "Local Scaling": "Lokal na Pagsusukat", + "Remote Resizing": "Remote Resizing", + "Advanced": "Advanced", + "Quality:": "Kalidad:", + "Compression level:": "Antas ng compression:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "I-encrypt", + "Host:": "Host:", + "Port:": "Port:", + "Path:": "Path:", + "Automatic Reconnect": "Awtomatikong Kumonekta muli", + "Reconnect Delay (ms):": "Reconnect Delay (ms):", + "Show Dot when No Cursor": "Ipakita ang Dot kapag Walang Cursor", + "Logging:": "Pagtotroso:", + "Version:": "Bersyon:", + "Disconnect": "Idiskonekta", + "Connect": "Kumonekta", + "Username:": "Username:", + "Password:": "Password:", + "Send Credentials": "Magpadala ng Mga Kredensyal", + "Cancel": "Kanselahin", + "Keys": "Mga susi", + "Game Cursor Mode": "Game Cursor Mode", + "Press Esc Key to Exit Pointer Lock Mode": "Pindutin ang Esc Key upang lumabas sa Pointer Lock Mode", + "Game Mode paused, click on screen to resume Game Mode.": "Naka-pause ang Game Mode, mag-click sa screen para ipagpatuloy ang Game Mode.", + "Clipboard Up": "Itaas ang Clipboard", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Mas gusto ang Lokal na Cursor", + "Translate keyboard shortcuts": "Isalin ang mga keyboard shortcut", + "Enable WebRTC UDP Transit": "Paganahin ang WebRTC UDP Transit", + "Enable WebP Compression": "Paganahin ang WebP Compression", + "Enable Performance Stats": "I-enable ang Performance Stats", + "Enable Pointer Lock": "Paganahin ang Pointer Lock", + "IME Input Mode": "IME Input Mode", + "Show Virtual Keyboard Control": "Ipakita ang Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "I-toggle ang Control Panel sa pamamagitan ng mga Keystroke", + "Render Native Resolution": "I-render ang Native Resolution", + "Keyboard Shortcuts": "Mga Keyboard Shortcut", + "Enable KasmVNC Keyboard Shortcuts": "Paganahin ang KasmVNC Keyboard Shortcuts", + "1 - Toggle Control Panel": "1 - I-toggle ang Control Panel", + "2 - Toggle Game Pointer Mode": "2 - I-toggle ang Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - I-toggle ang Pointer Lock", + "Stream Quality": "Kalidad ng Stream", + "Preset Modes:": "Mga Preset na Mode:", + "Static": "Static", + "Low": "Mababa", + "Medium": "Katamtaman", + "High": "Mataas", + "Extreme": "Extreme", + "Lossless": "Walang kawalan", + "Custom": "Pasadya", + "Anti-Aliasing:": "Anti aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "off", + "On": "Naka-on", + "Dynamic Quality Min:": "Dynamic na Kalidad Min:", + "Dynamic Quality Max:": "Dynamic na Marka ng Max:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Frame rate:", + "Video JPEG Quality:": "Kalidad ng JPEG ng Video:", + "Video WEBP Quality:": "Kalidad ng Video WEBP:", + "Video Area:": "Lugar ng Video:", + "Video Time:": "Oras ng Video:", + "Video Out Time:": "Oras ng Video Out:", + "Video Mode Width:": "Lapad ng Video Mode:", + "Video Mode Height:": "Taas ng Video Mode:", + "Documentation": "Dokumentasyon", + "Drag Viewport": "I-drag ang Viewport", + "KasmVNC encountered an error:": "Nakaranas ng error ang KasmVNC:" +} \ No newline at end of file diff --git a/app/locale/tl_PH.json b/app/locale/tl_PH.json new file mode 100644 index 0000000..e3b47f7 --- /dev/null +++ b/app/locale/tl_PH.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Kumokonekta...", + "Disconnecting...": "Nagdidiskonekta...", + "Reconnecting...": "Muling kumonekta...", + "Internal error": "Internal na error", + "Must set host": "Dapat magtakda ng host", + "Connected (encrypted) to ": "Nakakonekta (naka-encrypt) sa ", + "Connected (unencrypted) to ": "Nakakonekta (hindi naka-encrypt) sa ", + "Something went wrong, connection is closed": "Nagkaroon ng problema, sarado ang koneksyon", + "Failed to connect to server": "Nabigong kumonekta sa server", + "Disconnected": "Nadiskonekta", + "New connection has been rejected with reason: ": "Ang bagong koneksyon ay tinanggihan nang may dahilan: ", + "New connection has been rejected": "Ang bagong koneksyon ay tinanggihan", + "Credentials are required": "Kinakailangan ang mga kredensyal", + "Hide/Show the control bar": "Itago/Ipakita ang control bar", + "Drag": "I-drag", + "Move/Drag Viewport": "Ilipat/I-drag ang Viewport", + "Keyboard": "Keyboard", + "Show Keyboard": "Ipakita ang Keyboard", + "Extra keys": "Mga karagdagang susi", + "Show Extra Keys": "Ipakita ang Mga Dagdag na Susi", + "Ctrl": "Ctrl", + "Toggle Ctrl": "I-toggle ang Ctrl", + "Alt": "Alt", + "Toggle Alt": "I-toggle ang Alt", + "Toggle Windows": "I-toggle ang Windows", + "Windows": "Windows", + "Send Tab": "Ipadala ang Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Ipadala ang Pagtakas", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ipadala ang Ctrl-Alt-Del", + "Shutdown/Reboot": "Shutdown/Reboot", + "Shutdown/Reboot...": "Isara/I-reboot...", + "Power": "Kapangyarihan", + "Shutdown": "Shutdown", + "Reboot": "I-reboot", + "Reset": "I-reset", + "Clipboard": "Clipboard", + "Clear": "Malinaw", + "Fullscreen": "Fullscreen", + "Settings": "Mga Setting", + "Shared Mode": "Nakabahaging Mode", + "View Only": "Tingnan lamang", + "Clip to Window": "Clip sa Window", + "Scaling Mode:": "Scaling Mode:", + "None": "Wala", + "Local Scaling": "Lokal na Pagsusukat", + "Remote Resizing": "Remote Resizing", + "Advanced": "Advanced", + "Quality:": "Kalidad:", + "Compression level:": "Antas ng compression:", + "Repeater ID:": "Repeater ID:", + "WebSocket": "WebSocket", + "Encrypt": "I-encrypt", + "Host:": "Host:", + "Port:": "Port:", + "Path:": "Path:", + "Automatic Reconnect": "Awtomatikong Kumonekta muli", + "Reconnect Delay (ms):": "Reconnect Delay (ms):", + "Show Dot when No Cursor": "Ipakita ang Dot kapag Walang Cursor", + "Logging:": "Pagtotroso:", + "Version:": "Bersyon:", + "Disconnect": "Idiskonekta", + "Connect": "Kumonekta", + "Username:": "Username:", + "Password:": "Password:", + "Send Credentials": "Magpadala ng Mga Kredensyal", + "Cancel": "Kanselahin", + "Keys": "Mga susi", + "Game Cursor Mode": "Game Cursor Mode", + "Press Esc Key to Exit Pointer Lock Mode": "Pindutin ang Esc Key upang lumabas sa Pointer Lock Mode", + "Game Mode paused, click on screen to resume Game Mode.": "Naka-pause ang Game Mode, mag-click sa screen para ipagpatuloy ang Game Mode.", + "Clipboard Up": "Itaas ang Clipboard", + "CLipboard Down": "CLipboard Down", + "Clipboard Seamless": "Clipboard Seamless", + "Prefer Local Cursor": "Mas gusto ang Lokal na Cursor", + "Translate keyboard shortcuts": "Isalin ang mga keyboard shortcut", + "Enable WebRTC UDP Transit": "Paganahin ang WebRTC UDP Transit", + "Enable WebP Compression": "Paganahin ang WebP Compression", + "Enable Performance Stats": "I-enable ang Performance Stats", + "Enable Pointer Lock": "Paganahin ang Pointer Lock", + "IME Input Mode": "IME Input Mode", + "Show Virtual Keyboard Control": "Ipakita ang Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "I-toggle ang Control Panel sa pamamagitan ng mga Keystroke", + "Render Native Resolution": "I-render ang Native Resolution", + "Keyboard Shortcuts": "Mga Keyboard Shortcut", + "Enable KasmVNC Keyboard Shortcuts": "Paganahin ang KasmVNC Keyboard Shortcuts", + "1 - Toggle Control Panel": "1 - I-toggle ang Control Panel", + "2 - Toggle Game Pointer Mode": "2 - I-toggle ang Game Pointer Mode", + "3 - Toggle Pointer Lock": "3 - I-toggle ang Pointer Lock", + "Stream Quality": "Kalidad ng Stream", + "Preset Modes:": "Mga Preset na Mode:", + "Static": "Static", + "Low": "Mababa", + "Medium": "Katamtaman", + "High": "Mataas", + "Extreme": "Extreme", + "Lossless": "Walang kawalan", + "Custom": "Pasadya", + "Anti-Aliasing:": "Anti aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "off", + "On": "Naka-on", + "Dynamic Quality Min:": "Dynamic na Kalidad Min:", + "Dynamic Quality Max:": "Dynamic na Marka ng Max:", + "Treat Lossless:": "Treat Lossless:", + "Frame Rate:": "Frame rate:", + "Video JPEG Quality:": "Kalidad ng JPEG ng Video:", + "Video WEBP Quality:": "Kalidad ng Video WEBP:", + "Video Area:": "Lugar ng Video:", + "Video Time:": "Oras ng Video:", + "Video Out Time:": "Oras ng Video Out:", + "Video Mode Width:": "Lapad ng Video Mode:", + "Video Mode Height:": "Taas ng Video Mode:", + "Documentation": "Dokumentasyon", + "Drag Viewport": "I-drag ang Viewport", + "KasmVNC encountered an error:": "Nakaranas ng error ang KasmVNC:" +} \ No newline at end of file diff --git a/app/locale/tr.json b/app/locale/tr.json new file mode 100644 index 0000000..4972156 --- /dev/null +++ b/app/locale/tr.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Bağlanıyor...", + "Disconnecting...": "Bağlantı kesiliyor...", + "Reconnecting...": "Yeniden bağlantı kuruluyor...", + "Internal error": "İç hata", + "Must set host": "Sunucuyu kur", + "Connected (encrypted) to ": "Bağlı (şifrelenmiş)", + "Connected (unencrypted) to ": "Bağlandı (şifrelenmemiş)", + "Something went wrong, connection is closed": "Bir şeyler ters gitti, bağlantı kesildi", + "Disconnected": "Bağlantı kesildi", + "New connection has been rejected with reason: ": "Bağlantı aşağıdaki nedenlerden dolayı reddedildi: ", + "New connection has been rejected": "Bağlantı reddedildi", + "Password is required": "Şifre gerekli", + "Hide/Show the control bar": "Denetim masasını Gizle/Göster", + "Move/Drag Viewport": "Görünümü Taşı/Sürükle", + "viewport drag": "Görüntü penceresini sürükle", + "Active Mouse Button": "Aktif Fare Düğmesi", + "No mousebutton": "Fare düğmesi yok", + "Left mousebutton": "Farenin sol düğmesi", + "Middle mousebutton": "Farenin orta düğmesi", + "Right mousebutton": "Farenin sağ düğmesi", + "Keyboard": "Klavye", + "Show Keyboard": "Klavye Düzenini Göster", + "Extra keys": "Ekstra tuşlar", + "Show Extra Keys": "Ekstra tuşları göster", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl Değiştir ", + "Alt": "Alt", + "Toggle Alt": "Alt Değiştir", + "Send Tab": "Sekme Gönder", + "Tab": "Sekme", + "Esc": "Esc", + "Send Escape": "Boşluk Gönder", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Gönder", + "Shutdown/Reboot": "Kapat/Yeniden Başlat", + "Shutdown/Reboot...": "Kapat/Yeniden Başlat...", + "Power": "Güç", + "Shutdown": "Kapat", + "Reboot": "Yeniden Başlat", + "Reset": "Sıfırla", + "Clipboard": "Pano", + "Clear": "Temizle", + "Fullscreen": "Tam Ekran", + "Settings": "Ayarlar", + "Shared Mode": "Paylaşım Modu", + "View Only": "Sadece Görüntüle", + "Clip to Window": "Pencereye Tıkla", + "Scaling Mode:": "Ölçekleme Modu:", + "None": "Bilinmeyen", + "Local Scaling": "Yerel Ölçeklendirme", + "Remote Resizing": "Uzaktan Yeniden Boyutlandırma", + "Advanced": "Gelişmiş", + "Repeater ID:": "Tekralayıcı ID:", + "WebSocket": "WebSocket", + "Encrypt": "Şifrele", + "Host:": "Ana makine:", + "Port:": "Port:", + "Path:": "Yol:", + "Automatic Reconnect": "Otomatik Yeniden Bağlan", + "Reconnect Delay (ms):": "Yeniden Bağlanma Süreci (ms):", + "Logging:": "Giriş yapılıyor:", + "Disconnect": "Bağlantıyı Kes", + "Connect": "Bağlan", + "Password:": "Parola:", + "Cancel": "Vazgeç", + "Canvas not supported.": "Tuval desteklenmiyor.", + "Failed to connect to server": "Sunucuyla bağlantı başarısız", + "Credentials are required": "Kimlik bilgileri gerekli", + "Drag": "Sürüklemek", + "Toggle Windows": "Windows'u Değiştir", + "Windows": "Pencereler", + "Quality:": "Kalite:", + "Compression level:": "Sıkıştırma seviyesi:", + "Show Dot when No Cursor": "İmleç Yokken Noktayı Göster", + "Version:": "Sürüm:", + "Username:": "Kullanıcı adı:", + "Send Credentials": "Kimlik Bilgilerini Gönder", + "Keys": "Anahtarlar", + "Game Cursor Mode": "Oyun İmleç Modu", + "Press Esc Key to Exit Pointer Lock Mode": "İşaretçi Kilidi Modundan Çıkmak için Esc Tuşuna Basın", + "Game Mode paused, click on screen to resume Game Mode.": "Oyun Modu duraklatıldı, Oyun Moduna devam etmek için ekrana tıklayın.", + "Clipboard Up": "Pano Yukarı", + "CLipboard Down": "Pano Aşağı", + "Clipboard Seamless": "Pano Sorunsuz", + "Prefer Local Cursor": "Yerel İmleci Tercih Et", + "Translate keyboard shortcuts": "Klavye kısayollarını çevir", + "Enable WebRTC UDP Transit": "WebRTC UDP Geçişini Etkinleştir", + "Enable WebP Compression": "WebP Sıkıştırmasını Etkinleştir", + "Enable Performance Stats": "Performans İstatistiklerini Etkinleştir", + "Enable Pointer Lock": "İşaretçi Kilidini Etkinleştir", + "IME Input Mode": "IME Giriş Modu", + "Show Virtual Keyboard Control": "Sanal Klavye Denetimini Göster", + "Toggle Control Panel via Keystrokes": "Kontrol Panelini Tuş Vuruşlarıyla Değiştir", + "Render Native Resolution": "Yerel Çözünürlüğü Oluştur", + "Keyboard Shortcuts": "Klavye kısayolları", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC Klavye Kısayollarını Etkinleştir", + "1 - Toggle Control Panel": "1 - Kontrol Panelini Değiştir", + "2 - Toggle Game Pointer Mode": "2 - Oyun İşaretçisi Modunu Değiştir", + "3 - Toggle Pointer Lock": "3 - İşaretçi Kilidini Değiştir", + "Stream Quality": "Akış Kalitesi", + "Preset Modes:": "Ön Ayarlı Modlar:", + "Static": "Statik", + "Low": "Düşük", + "Medium": "Orta", + "High": "Yüksek", + "Extreme": "Aşırı", + "Lossless": "kayıpsız", + "Custom": "Gelenek", + "Anti-Aliasing:": "Kenar Yumuşatma:", + "Auto Dynamic": "Otomatik Dinamik", + "Off": "Kapalı", + "On": "Açık", + "Dynamic Quality Min:": "Dinamik Kalite Min:", + "Dynamic Quality Max:": "Dinamik Kalite Maks:", + "Treat Lossless:": "Kayıpsız Tedavi Et:", + "Frame Rate:": "Kare hızı:", + "Video JPEG Quality:": "Video JPEG Kalitesi:", + "Video WEBP Quality:": "Video WEBP Kalitesi:", + "Video Area:": "Video Alanı:", + "Video Time:": "Video Süresi:", + "Video Out Time:": "Video Çıkış Süresi:", + "Video Mode Width:": "Video Modu Genişliği:", + "Video Mode Height:": "Video Modu Yüksekliği:", + "Documentation": "Belgeler", + "Drag Viewport": "Görüntü Penceresini Sürükleyin", + "KasmVNC encountered an error:": "KasmVNC bir hatayla karşılaştı:" +} \ No newline at end of file diff --git a/app/locale/tr_CY.json b/app/locale/tr_CY.json new file mode 100644 index 0000000..4972156 --- /dev/null +++ b/app/locale/tr_CY.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Bağlanıyor...", + "Disconnecting...": "Bağlantı kesiliyor...", + "Reconnecting...": "Yeniden bağlantı kuruluyor...", + "Internal error": "İç hata", + "Must set host": "Sunucuyu kur", + "Connected (encrypted) to ": "Bağlı (şifrelenmiş)", + "Connected (unencrypted) to ": "Bağlandı (şifrelenmemiş)", + "Something went wrong, connection is closed": "Bir şeyler ters gitti, bağlantı kesildi", + "Disconnected": "Bağlantı kesildi", + "New connection has been rejected with reason: ": "Bağlantı aşağıdaki nedenlerden dolayı reddedildi: ", + "New connection has been rejected": "Bağlantı reddedildi", + "Password is required": "Şifre gerekli", + "Hide/Show the control bar": "Denetim masasını Gizle/Göster", + "Move/Drag Viewport": "Görünümü Taşı/Sürükle", + "viewport drag": "Görüntü penceresini sürükle", + "Active Mouse Button": "Aktif Fare Düğmesi", + "No mousebutton": "Fare düğmesi yok", + "Left mousebutton": "Farenin sol düğmesi", + "Middle mousebutton": "Farenin orta düğmesi", + "Right mousebutton": "Farenin sağ düğmesi", + "Keyboard": "Klavye", + "Show Keyboard": "Klavye Düzenini Göster", + "Extra keys": "Ekstra tuşlar", + "Show Extra Keys": "Ekstra tuşları göster", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl Değiştir ", + "Alt": "Alt", + "Toggle Alt": "Alt Değiştir", + "Send Tab": "Sekme Gönder", + "Tab": "Sekme", + "Esc": "Esc", + "Send Escape": "Boşluk Gönder", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Gönder", + "Shutdown/Reboot": "Kapat/Yeniden Başlat", + "Shutdown/Reboot...": "Kapat/Yeniden Başlat...", + "Power": "Güç", + "Shutdown": "Kapat", + "Reboot": "Yeniden Başlat", + "Reset": "Sıfırla", + "Clipboard": "Pano", + "Clear": "Temizle", + "Fullscreen": "Tam Ekran", + "Settings": "Ayarlar", + "Shared Mode": "Paylaşım Modu", + "View Only": "Sadece Görüntüle", + "Clip to Window": "Pencereye Tıkla", + "Scaling Mode:": "Ölçekleme Modu:", + "None": "Bilinmeyen", + "Local Scaling": "Yerel Ölçeklendirme", + "Remote Resizing": "Uzaktan Yeniden Boyutlandırma", + "Advanced": "Gelişmiş", + "Repeater ID:": "Tekralayıcı ID:", + "WebSocket": "WebSocket", + "Encrypt": "Şifrele", + "Host:": "Ana makine:", + "Port:": "Port:", + "Path:": "Yol:", + "Automatic Reconnect": "Otomatik Yeniden Bağlan", + "Reconnect Delay (ms):": "Yeniden Bağlanma Süreci (ms):", + "Logging:": "Giriş yapılıyor:", + "Disconnect": "Bağlantıyı Kes", + "Connect": "Bağlan", + "Password:": "Parola:", + "Cancel": "Vazgeç", + "Canvas not supported.": "Tuval desteklenmiyor.", + "Failed to connect to server": "Sunucuyla bağlantı başarısız", + "Credentials are required": "Kimlik bilgileri gerekli", + "Drag": "Sürüklemek", + "Toggle Windows": "Windows'u Değiştir", + "Windows": "Pencereler", + "Quality:": "Kalite:", + "Compression level:": "Sıkıştırma seviyesi:", + "Show Dot when No Cursor": "İmleç Yokken Noktayı Göster", + "Version:": "Sürüm:", + "Username:": "Kullanıcı adı:", + "Send Credentials": "Kimlik Bilgilerini Gönder", + "Keys": "Anahtarlar", + "Game Cursor Mode": "Oyun İmleç Modu", + "Press Esc Key to Exit Pointer Lock Mode": "İşaretçi Kilidi Modundan Çıkmak için Esc Tuşuna Basın", + "Game Mode paused, click on screen to resume Game Mode.": "Oyun Modu duraklatıldı, Oyun Moduna devam etmek için ekrana tıklayın.", + "Clipboard Up": "Pano Yukarı", + "CLipboard Down": "Pano Aşağı", + "Clipboard Seamless": "Pano Sorunsuz", + "Prefer Local Cursor": "Yerel İmleci Tercih Et", + "Translate keyboard shortcuts": "Klavye kısayollarını çevir", + "Enable WebRTC UDP Transit": "WebRTC UDP Geçişini Etkinleştir", + "Enable WebP Compression": "WebP Sıkıştırmasını Etkinleştir", + "Enable Performance Stats": "Performans İstatistiklerini Etkinleştir", + "Enable Pointer Lock": "İşaretçi Kilidini Etkinleştir", + "IME Input Mode": "IME Giriş Modu", + "Show Virtual Keyboard Control": "Sanal Klavye Denetimini Göster", + "Toggle Control Panel via Keystrokes": "Kontrol Panelini Tuş Vuruşlarıyla Değiştir", + "Render Native Resolution": "Yerel Çözünürlüğü Oluştur", + "Keyboard Shortcuts": "Klavye kısayolları", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC Klavye Kısayollarını Etkinleştir", + "1 - Toggle Control Panel": "1 - Kontrol Panelini Değiştir", + "2 - Toggle Game Pointer Mode": "2 - Oyun İşaretçisi Modunu Değiştir", + "3 - Toggle Pointer Lock": "3 - İşaretçi Kilidini Değiştir", + "Stream Quality": "Akış Kalitesi", + "Preset Modes:": "Ön Ayarlı Modlar:", + "Static": "Statik", + "Low": "Düşük", + "Medium": "Orta", + "High": "Yüksek", + "Extreme": "Aşırı", + "Lossless": "kayıpsız", + "Custom": "Gelenek", + "Anti-Aliasing:": "Kenar Yumuşatma:", + "Auto Dynamic": "Otomatik Dinamik", + "Off": "Kapalı", + "On": "Açık", + "Dynamic Quality Min:": "Dinamik Kalite Min:", + "Dynamic Quality Max:": "Dinamik Kalite Maks:", + "Treat Lossless:": "Kayıpsız Tedavi Et:", + "Frame Rate:": "Kare hızı:", + "Video JPEG Quality:": "Video JPEG Kalitesi:", + "Video WEBP Quality:": "Video WEBP Kalitesi:", + "Video Area:": "Video Alanı:", + "Video Time:": "Video Süresi:", + "Video Out Time:": "Video Çıkış Süresi:", + "Video Mode Width:": "Video Modu Genişliği:", + "Video Mode Height:": "Video Modu Yüksekliği:", + "Documentation": "Belgeler", + "Drag Viewport": "Görüntü Penceresini Sürükleyin", + "KasmVNC encountered an error:": "KasmVNC bir hatayla karşılaştı:" +} \ No newline at end of file diff --git a/app/locale/tr_TR.json b/app/locale/tr_TR.json new file mode 100644 index 0000000..4972156 --- /dev/null +++ b/app/locale/tr_TR.json @@ -0,0 +1,128 @@ +{ + "Connecting...": "Bağlanıyor...", + "Disconnecting...": "Bağlantı kesiliyor...", + "Reconnecting...": "Yeniden bağlantı kuruluyor...", + "Internal error": "İç hata", + "Must set host": "Sunucuyu kur", + "Connected (encrypted) to ": "Bağlı (şifrelenmiş)", + "Connected (unencrypted) to ": "Bağlandı (şifrelenmemiş)", + "Something went wrong, connection is closed": "Bir şeyler ters gitti, bağlantı kesildi", + "Disconnected": "Bağlantı kesildi", + "New connection has been rejected with reason: ": "Bağlantı aşağıdaki nedenlerden dolayı reddedildi: ", + "New connection has been rejected": "Bağlantı reddedildi", + "Password is required": "Şifre gerekli", + "Hide/Show the control bar": "Denetim masasını Gizle/Göster", + "Move/Drag Viewport": "Görünümü Taşı/Sürükle", + "viewport drag": "Görüntü penceresini sürükle", + "Active Mouse Button": "Aktif Fare Düğmesi", + "No mousebutton": "Fare düğmesi yok", + "Left mousebutton": "Farenin sol düğmesi", + "Middle mousebutton": "Farenin orta düğmesi", + "Right mousebutton": "Farenin sağ düğmesi", + "Keyboard": "Klavye", + "Show Keyboard": "Klavye Düzenini Göster", + "Extra keys": "Ekstra tuşlar", + "Show Extra Keys": "Ekstra tuşları göster", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl Değiştir ", + "Alt": "Alt", + "Toggle Alt": "Alt Değiştir", + "Send Tab": "Sekme Gönder", + "Tab": "Sekme", + "Esc": "Esc", + "Send Escape": "Boşluk Gönder", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del Gönder", + "Shutdown/Reboot": "Kapat/Yeniden Başlat", + "Shutdown/Reboot...": "Kapat/Yeniden Başlat...", + "Power": "Güç", + "Shutdown": "Kapat", + "Reboot": "Yeniden Başlat", + "Reset": "Sıfırla", + "Clipboard": "Pano", + "Clear": "Temizle", + "Fullscreen": "Tam Ekran", + "Settings": "Ayarlar", + "Shared Mode": "Paylaşım Modu", + "View Only": "Sadece Görüntüle", + "Clip to Window": "Pencereye Tıkla", + "Scaling Mode:": "Ölçekleme Modu:", + "None": "Bilinmeyen", + "Local Scaling": "Yerel Ölçeklendirme", + "Remote Resizing": "Uzaktan Yeniden Boyutlandırma", + "Advanced": "Gelişmiş", + "Repeater ID:": "Tekralayıcı ID:", + "WebSocket": "WebSocket", + "Encrypt": "Şifrele", + "Host:": "Ana makine:", + "Port:": "Port:", + "Path:": "Yol:", + "Automatic Reconnect": "Otomatik Yeniden Bağlan", + "Reconnect Delay (ms):": "Yeniden Bağlanma Süreci (ms):", + "Logging:": "Giriş yapılıyor:", + "Disconnect": "Bağlantıyı Kes", + "Connect": "Bağlan", + "Password:": "Parola:", + "Cancel": "Vazgeç", + "Canvas not supported.": "Tuval desteklenmiyor.", + "Failed to connect to server": "Sunucuyla bağlantı başarısız", + "Credentials are required": "Kimlik bilgileri gerekli", + "Drag": "Sürüklemek", + "Toggle Windows": "Windows'u Değiştir", + "Windows": "Pencereler", + "Quality:": "Kalite:", + "Compression level:": "Sıkıştırma seviyesi:", + "Show Dot when No Cursor": "İmleç Yokken Noktayı Göster", + "Version:": "Sürüm:", + "Username:": "Kullanıcı adı:", + "Send Credentials": "Kimlik Bilgilerini Gönder", + "Keys": "Anahtarlar", + "Game Cursor Mode": "Oyun İmleç Modu", + "Press Esc Key to Exit Pointer Lock Mode": "İşaretçi Kilidi Modundan Çıkmak için Esc Tuşuna Basın", + "Game Mode paused, click on screen to resume Game Mode.": "Oyun Modu duraklatıldı, Oyun Moduna devam etmek için ekrana tıklayın.", + "Clipboard Up": "Pano Yukarı", + "CLipboard Down": "Pano Aşağı", + "Clipboard Seamless": "Pano Sorunsuz", + "Prefer Local Cursor": "Yerel İmleci Tercih Et", + "Translate keyboard shortcuts": "Klavye kısayollarını çevir", + "Enable WebRTC UDP Transit": "WebRTC UDP Geçişini Etkinleştir", + "Enable WebP Compression": "WebP Sıkıştırmasını Etkinleştir", + "Enable Performance Stats": "Performans İstatistiklerini Etkinleştir", + "Enable Pointer Lock": "İşaretçi Kilidini Etkinleştir", + "IME Input Mode": "IME Giriş Modu", + "Show Virtual Keyboard Control": "Sanal Klavye Denetimini Göster", + "Toggle Control Panel via Keystrokes": "Kontrol Panelini Tuş Vuruşlarıyla Değiştir", + "Render Native Resolution": "Yerel Çözünürlüğü Oluştur", + "Keyboard Shortcuts": "Klavye kısayolları", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC Klavye Kısayollarını Etkinleştir", + "1 - Toggle Control Panel": "1 - Kontrol Panelini Değiştir", + "2 - Toggle Game Pointer Mode": "2 - Oyun İşaretçisi Modunu Değiştir", + "3 - Toggle Pointer Lock": "3 - İşaretçi Kilidini Değiştir", + "Stream Quality": "Akış Kalitesi", + "Preset Modes:": "Ön Ayarlı Modlar:", + "Static": "Statik", + "Low": "Düşük", + "Medium": "Orta", + "High": "Yüksek", + "Extreme": "Aşırı", + "Lossless": "kayıpsız", + "Custom": "Gelenek", + "Anti-Aliasing:": "Kenar Yumuşatma:", + "Auto Dynamic": "Otomatik Dinamik", + "Off": "Kapalı", + "On": "Açık", + "Dynamic Quality Min:": "Dinamik Kalite Min:", + "Dynamic Quality Max:": "Dinamik Kalite Maks:", + "Treat Lossless:": "Kayıpsız Tedavi Et:", + "Frame Rate:": "Kare hızı:", + "Video JPEG Quality:": "Video JPEG Kalitesi:", + "Video WEBP Quality:": "Video WEBP Kalitesi:", + "Video Area:": "Video Alanı:", + "Video Time:": "Video Süresi:", + "Video Out Time:": "Video Çıkış Süresi:", + "Video Mode Width:": "Video Modu Genişliği:", + "Video Mode Height:": "Video Modu Yüksekliği:", + "Documentation": "Belgeler", + "Drag Viewport": "Görüntü Penceresini Sürükleyin", + "KasmVNC encountered an error:": "KasmVNC bir hatayla karşılaştı:" +} \ No newline at end of file diff --git a/app/locale/tt.json b/app/locale/tt.json new file mode 100644 index 0000000..af0acc9 --- /dev/null +++ b/app/locale/tt.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Тоташу ...", + "Disconnecting...": "Аеру ...", + "Reconnecting...": "Тоташу ...", + "Internal error": "Эчке хата", + "Must set host": "Хост урнаштырырга тиеш", + "Connected (encrypted) to ": "Бәйләнгән (шифрланган)", + "Connected (unencrypted) to ": "Бәйләнгән (шифрланмаган)", + "Something went wrong, connection is closed": "Нәрсәдер дөрес булмаган, тоташу ябылган", + "Failed to connect to server": "Серверга тоташа алмады", + "Disconnected": "Аерылган", + "New connection has been rejected with reason: ": "Яңа бәйләнеш сәбәп белән кире кагылды:", + "New connection has been rejected": "Яңа элемтә кире кагылды", + "Credentials are required": "Сертификатлар кирәк", + "Hide/Show the control bar": "Контроль тактаны яшерегез / күрсәтегез", + "Drag": "Сөйләү", + "Move/Drag Viewport": "Күрү / Күчереп карау", + "Keyboard": "Клавиатура", + "Show Keyboard": "Клавиатураны күрсәт", + "Extra keys": "Өстәмә ачкычлар", + "Show Extra Keys": "Өстәмә ачкычларны күрсәт", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl алыштырыгыз", + "Alt": "Alt", + "Toggle Alt": "Алтны алыштырыгыз", + "Toggle Windows": "Windows'ны алыштырыгыз", + "Windows": "Windows", + "Send Tab": "Таблицаны җибәр", + "Tab": "Таблица", + "Esc": "Esc", + "Send Escape": "Качарга җибәр", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del җибәрегез", + "Shutdown/Reboot": "Ябу / кабызу", + "Shutdown/Reboot...": "Ябу / кабызу ...", + "Power": "Көч", + "Shutdown": "Cүндерү", + "Reboot": "Яңарту", + "Reset": "Яңарту", + "Clipboard": "Такта", + "Clear": "Чиста", + "Fullscreen": "Тулы экран", + "Settings": "Көйләүләр", + "Shared Mode": "Уртак режим", + "View Only": "Тик карау", + "Clip to Window": "Тәрәзәгә клип", + "Scaling Mode:": "Масштаб режимы:", + "None": "Беркем дә", + "Local Scaling": "Localирле масштаб", + "Remote Resizing": "Ерактан үзгәртү", + "Advanced": "Алга", + "Quality:": "Сыйфат:", + "Compression level:": "Кысу дәрәҗәсе:", + "Repeater ID:": "Кабатлаучы ID:", + "WebSocket": "Веб-Сокет", + "Encrypt": "Шифрлау", + "Host:": "Алып баручы:", + "Port:": "Порт:", + "Path:": "Athл:", + "Automatic Reconnect": "Автоматик тоташу", + "Reconnect Delay (ms):": "Соңга калу (мс):", + "Show Dot when No Cursor": "Курсор булмаганда ноктаны күрсәт", + "Logging:": "Керү:", + "Version:": "Вариант:", + "Disconnect": "Аерыгыз", + "Connect": "Тоташ", + "Username:": "Кулланучы исеме:", + "Password:": "Серсүз:", + "Send Credentials": "Сертификатлар җибәрегез", + "Cancel": "Баш тарту", + "Keys": "Ачкычлар", + "Game Cursor Mode": "Уен курсоры режимы", + "Press Esc Key to Exit Pointer Lock Mode": "Күрсәткеч йозак режимыннан чыгу өчен Esc төймәсенә басыгыз", + "Game Mode paused, click on screen to resume Game Mode.": "Уен режимы туктады, Уен режимын дәвам итү өчен экранга басыгыз.", + "Clipboard Up": "Такта өстә", + "CLipboard Down": "Такта асты", + "Clipboard Seamless": "Такта тактасы", + "Prefer Local Cursor": "Localирле курсорга өстенлек бирегез", + "Translate keyboard shortcuts": "Клавиатура кыска юлларын тәрҗемә итегез", + "Enable WebRTC UDP Transit": "WebRTC UDP транзитын рөхсәт итегез", + "Enable WebP Compression": "ВебП кысуны кушу", + "Enable Performance Stats": "Спектакль статистикасын кушу", + "Enable Pointer Lock": "Күрсәткеч йозакны кушу", + "IME Input Mode": "IME кертү режимы", + "Show Virtual Keyboard Control": "Виртуаль клавиатура контролен күрсәт", + "Toggle Control Panel via Keystrokes": "Контроль панельне ачкычлар аша алыштырыгыз", + "Render Native Resolution": "Туган як резолюциясе бирегез", + "Keyboard Shortcuts": "Клавиатура кыска юллары", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC клавиатура кыска юлларын эшләгез", + "1 - Toggle Control Panel": "1 - Контроль панельне алыштырыгыз", + "2 - Toggle Game Pointer Mode": "2 - Уен күрсәткеч режимын алыштырыгыз", + "3 - Toggle Pointer Lock": "3 - Күрсәткеч йозакны алыштырыгыз", + "Stream Quality": "Агым сыйфаты", + "Preset Modes:": "Алдан билгеләнгән режимнар:", + "Static": "Статик", + "Low": "Түбән", + "Medium": "Урта", + "High": "Биек", + "Extreme": "Экстремаль", + "Lossless": "Ossгалтмый", + "Custom": "Гадәт", + "Anti-Aliasing:": "Анти-Ализинг:", + "Auto Dynamic": "Авто Динамик", + "Off": "Сүндерелгән", + "On": "Яна", + "Dynamic Quality Min:": "Динамик сыйфат мин:", + "Dynamic Quality Max:": "Динамик сыйфат макс:", + "Treat Lossless:": "Ossгалтмыйча эшләгез:", + "Frame Rate:": "Кадр ставкасы:", + "Video JPEG Quality:": "Видео JPEG сыйфаты:", + "Video WEBP Quality:": "Видео WEBP сыйфаты:", + "Video Area:": "Видео өлкәсе:", + "Video Time:": "Видео вакыты:", + "Video Out Time:": "Видео вакыты:", + "Video Mode Width:": "Видео режимының киңлеге:", + "Video Mode Height:": "Видео режим биеклеге:", + "Documentation": "Документация", + "Drag Viewport": "Визпортны тарту", + "KasmVNC encountered an error:": "KasmVNC хата белән очрашты:" +} \ No newline at end of file diff --git a/app/locale/tt_RU.json b/app/locale/tt_RU.json new file mode 100644 index 0000000..af0acc9 --- /dev/null +++ b/app/locale/tt_RU.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Тоташу ...", + "Disconnecting...": "Аеру ...", + "Reconnecting...": "Тоташу ...", + "Internal error": "Эчке хата", + "Must set host": "Хост урнаштырырга тиеш", + "Connected (encrypted) to ": "Бәйләнгән (шифрланган)", + "Connected (unencrypted) to ": "Бәйләнгән (шифрланмаган)", + "Something went wrong, connection is closed": "Нәрсәдер дөрес булмаган, тоташу ябылган", + "Failed to connect to server": "Серверга тоташа алмады", + "Disconnected": "Аерылган", + "New connection has been rejected with reason: ": "Яңа бәйләнеш сәбәп белән кире кагылды:", + "New connection has been rejected": "Яңа элемтә кире кагылды", + "Credentials are required": "Сертификатлар кирәк", + "Hide/Show the control bar": "Контроль тактаны яшерегез / күрсәтегез", + "Drag": "Сөйләү", + "Move/Drag Viewport": "Күрү / Күчереп карау", + "Keyboard": "Клавиатура", + "Show Keyboard": "Клавиатураны күрсәт", + "Extra keys": "Өстәмә ачкычлар", + "Show Extra Keys": "Өстәмә ачкычларны күрсәт", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl алыштырыгыз", + "Alt": "Alt", + "Toggle Alt": "Алтны алыштырыгыз", + "Toggle Windows": "Windows'ны алыштырыгыз", + "Windows": "Windows", + "Send Tab": "Таблицаны җибәр", + "Tab": "Таблица", + "Esc": "Esc", + "Send Escape": "Качарга җибәр", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del җибәрегез", + "Shutdown/Reboot": "Ябу / кабызу", + "Shutdown/Reboot...": "Ябу / кабызу ...", + "Power": "Көч", + "Shutdown": "Cүндерү", + "Reboot": "Яңарту", + "Reset": "Яңарту", + "Clipboard": "Такта", + "Clear": "Чиста", + "Fullscreen": "Тулы экран", + "Settings": "Көйләүләр", + "Shared Mode": "Уртак режим", + "View Only": "Тик карау", + "Clip to Window": "Тәрәзәгә клип", + "Scaling Mode:": "Масштаб режимы:", + "None": "Беркем дә", + "Local Scaling": "Localирле масштаб", + "Remote Resizing": "Ерактан үзгәртү", + "Advanced": "Алга", + "Quality:": "Сыйфат:", + "Compression level:": "Кысу дәрәҗәсе:", + "Repeater ID:": "Кабатлаучы ID:", + "WebSocket": "Веб-Сокет", + "Encrypt": "Шифрлау", + "Host:": "Алып баручы:", + "Port:": "Порт:", + "Path:": "Athл:", + "Automatic Reconnect": "Автоматик тоташу", + "Reconnect Delay (ms):": "Соңга калу (мс):", + "Show Dot when No Cursor": "Курсор булмаганда ноктаны күрсәт", + "Logging:": "Керү:", + "Version:": "Вариант:", + "Disconnect": "Аерыгыз", + "Connect": "Тоташ", + "Username:": "Кулланучы исеме:", + "Password:": "Серсүз:", + "Send Credentials": "Сертификатлар җибәрегез", + "Cancel": "Баш тарту", + "Keys": "Ачкычлар", + "Game Cursor Mode": "Уен курсоры режимы", + "Press Esc Key to Exit Pointer Lock Mode": "Күрсәткеч йозак режимыннан чыгу өчен Esc төймәсенә басыгыз", + "Game Mode paused, click on screen to resume Game Mode.": "Уен режимы туктады, Уен режимын дәвам итү өчен экранга басыгыз.", + "Clipboard Up": "Такта өстә", + "CLipboard Down": "Такта асты", + "Clipboard Seamless": "Такта тактасы", + "Prefer Local Cursor": "Localирле курсорга өстенлек бирегез", + "Translate keyboard shortcuts": "Клавиатура кыска юлларын тәрҗемә итегез", + "Enable WebRTC UDP Transit": "WebRTC UDP транзитын рөхсәт итегез", + "Enable WebP Compression": "ВебП кысуны кушу", + "Enable Performance Stats": "Спектакль статистикасын кушу", + "Enable Pointer Lock": "Күрсәткеч йозакны кушу", + "IME Input Mode": "IME кертү режимы", + "Show Virtual Keyboard Control": "Виртуаль клавиатура контролен күрсәт", + "Toggle Control Panel via Keystrokes": "Контроль панельне ачкычлар аша алыштырыгыз", + "Render Native Resolution": "Туган як резолюциясе бирегез", + "Keyboard Shortcuts": "Клавиатура кыска юллары", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC клавиатура кыска юлларын эшләгез", + "1 - Toggle Control Panel": "1 - Контроль панельне алыштырыгыз", + "2 - Toggle Game Pointer Mode": "2 - Уен күрсәткеч режимын алыштырыгыз", + "3 - Toggle Pointer Lock": "3 - Күрсәткеч йозакны алыштырыгыз", + "Stream Quality": "Агым сыйфаты", + "Preset Modes:": "Алдан билгеләнгән режимнар:", + "Static": "Статик", + "Low": "Түбән", + "Medium": "Урта", + "High": "Биек", + "Extreme": "Экстремаль", + "Lossless": "Ossгалтмый", + "Custom": "Гадәт", + "Anti-Aliasing:": "Анти-Ализинг:", + "Auto Dynamic": "Авто Динамик", + "Off": "Сүндерелгән", + "On": "Яна", + "Dynamic Quality Min:": "Динамик сыйфат мин:", + "Dynamic Quality Max:": "Динамик сыйфат макс:", + "Treat Lossless:": "Ossгалтмыйча эшләгез:", + "Frame Rate:": "Кадр ставкасы:", + "Video JPEG Quality:": "Видео JPEG сыйфаты:", + "Video WEBP Quality:": "Видео WEBP сыйфаты:", + "Video Area:": "Видео өлкәсе:", + "Video Time:": "Видео вакыты:", + "Video Out Time:": "Видео вакыты:", + "Video Mode Width:": "Видео режимының киңлеге:", + "Video Mode Height:": "Видео режим биеклеге:", + "Documentation": "Документация", + "Drag Viewport": "Визпортны тарту", + "KasmVNC encountered an error:": "KasmVNC хата белән очрашты:" +} \ No newline at end of file diff --git a/app/locale/uk.json b/app/locale/uk.json new file mode 100644 index 0000000..39f0f55 --- /dev/null +++ b/app/locale/uk.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Підключення...", + "Disconnecting...": "Відключення...", + "Reconnecting...": "Повторне підключення...", + "Internal error": "Внутрішня помилка", + "Must set host": "Потрібно встановити хост", + "Connected (encrypted) to ": "Підключено (зашифровано) до ", + "Connected (unencrypted) to ": "Підключено (не зашифровано) до ", + "Something went wrong, connection is closed": "Щось пішло не так, з'єднання закрито", + "Failed to connect to server": "Не вдалося підключитися до сервера", + "Disconnected": "Відключено", + "New connection has been rejected with reason: ": "Нове підключення відхилено з причиною: ", + "New connection has been rejected": "Нове підключення відхилено", + "Credentials are required": "Потрібні облікові дані", + "Hide/Show the control bar": "Приховати/показати панель керування", + "Drag": "перетягнути", + "Move/Drag Viewport": "Перемістити/перетягнути вікно перегляду", + "Keyboard": "Клавіатура", + "Show Keyboard": "Показати клавіатуру", + "Extra keys": "Додаткові ключі", + "Show Extra Keys": "Показати додаткові ключі", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Переключити Ctrl", + "Alt": "Alt", + "Toggle Alt": "Переключити Alt", + "Toggle Windows": "Переключити вікна", + "Windows": "Windows", + "Send Tab": "Надіслати вкладку", + "Tab": "Вкладка", + "Esc": "Вихід", + "Send Escape": "Надіслати Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Надіслати Ctrl-Alt-Del", + "Shutdown/Reboot": "Вимкнення/перезавантаження", + "Shutdown/Reboot...": "Вимкнення/перезавантаження...", + "Power": "Влада", + "Shutdown": "Закрити", + "Reboot": "Перезавантажити", + "Reset": "Скинути", + "Clipboard": "Буфер обміну", + "Clear": "Очистити", + "Fullscreen": "Повноекранний", + "Settings": "Налаштування", + "Shared Mode": "Спільний режим", + "View Only": "Тільки перегляд", + "Clip to Window": "Кліп до вікна", + "Scaling Mode:": "Режим масштабування:", + "None": "Жодного", + "Local Scaling": "Локальне масштабування", + "Remote Resizing": "Віддалена зміна розміру", + "Advanced": "Просунутий", + "Quality:": "Якість:", + "Compression level:": "Рівень стиснення:", + "Repeater ID:": "Ідентифікатор ретранслятора:", + "WebSocket": "WebSocket", + "Encrypt": "Зашифрувати", + "Host:": "Ведучий:", + "Port:": "Порт:", + "Path:": "Шлях:", + "Automatic Reconnect": "Автоматичне повторне підключення", + "Reconnect Delay (ms):": "Затримка повторного підключення (мс):", + "Show Dot when No Cursor": "Показувати точку, коли курсор відсутній", + "Logging:": "Введення журналу:", + "Version:": "Версія:", + "Disconnect": "Відключити", + "Connect": "Підключити", + "Username:": "Ім'я користувача:", + "Password:": "Пароль:", + "Send Credentials": "Надіслати облікові дані", + "Cancel": "Скасувати", + "Keys": "Ключі", + "Game Cursor Mode": "Режим ігрового курсора", + "Press Esc Key to Exit Pointer Lock Mode": "Натисніть клавішу Esc, щоб вийти з режиму блокування вказівника", + "Game Mode paused, click on screen to resume Game Mode.": "Ігровий режим призупинено, клацніть на екрані, щоб відновити ігровий режим.", + "Clipboard Up": "Буфер обміну вгору", + "CLipboard Down": "Буфер обміну вниз", + "Clipboard Seamless": "Безшовний буфер обміну", + "Prefer Local Cursor": "Надати перевагу локальному курсору", + "Translate keyboard shortcuts": "Перекласти комбінації клавіш", + "Enable WebRTC UDP Transit": "Увімкнути WebRTC UDP Transit", + "Enable WebP Compression": "Увімкнути стиснення WebP", + "Enable Performance Stats": "Увімкнути статистику продуктивності", + "Enable Pointer Lock": "Увімкнути блокування вказівника", + "IME Input Mode": "Режим введення IME", + "Show Virtual Keyboard Control": "Показати керування віртуальною клавіатурою", + "Toggle Control Panel via Keystrokes": "Переключити панель керування за допомогою натискання клавіш", + "Render Native Resolution": "Візуалізація рідної роздільної здатності", + "Keyboard Shortcuts": "Гарячі клавіши", + "Enable KasmVNC Keyboard Shortcuts": "Увімкнути комбінації клавіш KasmVNC", + "1 - Toggle Control Panel": "1 – Перемкнути панель керування", + "2 - Toggle Game Pointer Mode": "2 - Перемкнути режим покажчика гри", + "3 - Toggle Pointer Lock": "3 - Перемкнути блокування вказівника", + "Stream Quality": "Якість потоку", + "Preset Modes:": "Попередньо встановлені режими:", + "Static": "Статичний", + "Low": "Низький", + "Medium": "Середній", + "High": "Високий", + "Extreme": "Екстремальний", + "Lossless": "без втрат", + "Custom": "На замовлення", + "Anti-Aliasing:": "Згладжування:", + "Auto Dynamic": "Авто динамічний", + "Off": "Вимкнено", + "On": "Увімкнено", + "Dynamic Quality Min:": "Мін. динамічна якість:", + "Dynamic Quality Max:": "Макс. динамічна якість", + "Treat Lossless:": "Лікувати Lossless:", + "Frame Rate:": "Частота кадрів:", + "Video JPEG Quality:": "Якість відео JPEG:", + "Video WEBP Quality:": "Якість відео WEBP:", + "Video Area:": "Зона відео:", + "Video Time:": "Час відео:", + "Video Out Time:": "Час виходу відео:", + "Video Mode Width:": "Ширина режиму відео:", + "Video Mode Height:": "Висота режиму відео:", + "Documentation": "Документація", + "Drag Viewport": "Перетягнути вікно перегляду", + "KasmVNC encountered an error:": "KasmVNC виявив помилку:" +} \ No newline at end of file diff --git a/app/locale/uk_UA.json b/app/locale/uk_UA.json new file mode 100644 index 0000000..39f0f55 --- /dev/null +++ b/app/locale/uk_UA.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Підключення...", + "Disconnecting...": "Відключення...", + "Reconnecting...": "Повторне підключення...", + "Internal error": "Внутрішня помилка", + "Must set host": "Потрібно встановити хост", + "Connected (encrypted) to ": "Підключено (зашифровано) до ", + "Connected (unencrypted) to ": "Підключено (не зашифровано) до ", + "Something went wrong, connection is closed": "Щось пішло не так, з'єднання закрито", + "Failed to connect to server": "Не вдалося підключитися до сервера", + "Disconnected": "Відключено", + "New connection has been rejected with reason: ": "Нове підключення відхилено з причиною: ", + "New connection has been rejected": "Нове підключення відхилено", + "Credentials are required": "Потрібні облікові дані", + "Hide/Show the control bar": "Приховати/показати панель керування", + "Drag": "перетягнути", + "Move/Drag Viewport": "Перемістити/перетягнути вікно перегляду", + "Keyboard": "Клавіатура", + "Show Keyboard": "Показати клавіатуру", + "Extra keys": "Додаткові ключі", + "Show Extra Keys": "Показати додаткові ключі", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Переключити Ctrl", + "Alt": "Alt", + "Toggle Alt": "Переключити Alt", + "Toggle Windows": "Переключити вікна", + "Windows": "Windows", + "Send Tab": "Надіслати вкладку", + "Tab": "Вкладка", + "Esc": "Вихід", + "Send Escape": "Надіслати Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Надіслати Ctrl-Alt-Del", + "Shutdown/Reboot": "Вимкнення/перезавантаження", + "Shutdown/Reboot...": "Вимкнення/перезавантаження...", + "Power": "Влада", + "Shutdown": "Закрити", + "Reboot": "Перезавантажити", + "Reset": "Скинути", + "Clipboard": "Буфер обміну", + "Clear": "Очистити", + "Fullscreen": "Повноекранний", + "Settings": "Налаштування", + "Shared Mode": "Спільний режим", + "View Only": "Тільки перегляд", + "Clip to Window": "Кліп до вікна", + "Scaling Mode:": "Режим масштабування:", + "None": "Жодного", + "Local Scaling": "Локальне масштабування", + "Remote Resizing": "Віддалена зміна розміру", + "Advanced": "Просунутий", + "Quality:": "Якість:", + "Compression level:": "Рівень стиснення:", + "Repeater ID:": "Ідентифікатор ретранслятора:", + "WebSocket": "WebSocket", + "Encrypt": "Зашифрувати", + "Host:": "Ведучий:", + "Port:": "Порт:", + "Path:": "Шлях:", + "Automatic Reconnect": "Автоматичне повторне підключення", + "Reconnect Delay (ms):": "Затримка повторного підключення (мс):", + "Show Dot when No Cursor": "Показувати точку, коли курсор відсутній", + "Logging:": "Введення журналу:", + "Version:": "Версія:", + "Disconnect": "Відключити", + "Connect": "Підключити", + "Username:": "Ім'я користувача:", + "Password:": "Пароль:", + "Send Credentials": "Надіслати облікові дані", + "Cancel": "Скасувати", + "Keys": "Ключі", + "Game Cursor Mode": "Режим ігрового курсора", + "Press Esc Key to Exit Pointer Lock Mode": "Натисніть клавішу Esc, щоб вийти з режиму блокування вказівника", + "Game Mode paused, click on screen to resume Game Mode.": "Ігровий режим призупинено, клацніть на екрані, щоб відновити ігровий режим.", + "Clipboard Up": "Буфер обміну вгору", + "CLipboard Down": "Буфер обміну вниз", + "Clipboard Seamless": "Безшовний буфер обміну", + "Prefer Local Cursor": "Надати перевагу локальному курсору", + "Translate keyboard shortcuts": "Перекласти комбінації клавіш", + "Enable WebRTC UDP Transit": "Увімкнути WebRTC UDP Transit", + "Enable WebP Compression": "Увімкнути стиснення WebP", + "Enable Performance Stats": "Увімкнути статистику продуктивності", + "Enable Pointer Lock": "Увімкнути блокування вказівника", + "IME Input Mode": "Режим введення IME", + "Show Virtual Keyboard Control": "Показати керування віртуальною клавіатурою", + "Toggle Control Panel via Keystrokes": "Переключити панель керування за допомогою натискання клавіш", + "Render Native Resolution": "Візуалізація рідної роздільної здатності", + "Keyboard Shortcuts": "Гарячі клавіши", + "Enable KasmVNC Keyboard Shortcuts": "Увімкнути комбінації клавіш KasmVNC", + "1 - Toggle Control Panel": "1 – Перемкнути панель керування", + "2 - Toggle Game Pointer Mode": "2 - Перемкнути режим покажчика гри", + "3 - Toggle Pointer Lock": "3 - Перемкнути блокування вказівника", + "Stream Quality": "Якість потоку", + "Preset Modes:": "Попередньо встановлені режими:", + "Static": "Статичний", + "Low": "Низький", + "Medium": "Середній", + "High": "Високий", + "Extreme": "Екстремальний", + "Lossless": "без втрат", + "Custom": "На замовлення", + "Anti-Aliasing:": "Згладжування:", + "Auto Dynamic": "Авто динамічний", + "Off": "Вимкнено", + "On": "Увімкнено", + "Dynamic Quality Min:": "Мін. динамічна якість:", + "Dynamic Quality Max:": "Макс. динамічна якість", + "Treat Lossless:": "Лікувати Lossless:", + "Frame Rate:": "Частота кадрів:", + "Video JPEG Quality:": "Якість відео JPEG:", + "Video WEBP Quality:": "Якість відео WEBP:", + "Video Area:": "Зона відео:", + "Video Time:": "Час відео:", + "Video Out Time:": "Час виходу відео:", + "Video Mode Width:": "Ширина режиму відео:", + "Video Mode Height:": "Висота режиму відео:", + "Documentation": "Документація", + "Drag Viewport": "Перетягнути вікно перегляду", + "KasmVNC encountered an error:": "KasmVNC виявив помилку:" +} \ No newline at end of file diff --git a/app/locale/ur.json b/app/locale/ur.json new file mode 100644 index 0000000..1b0b149 --- /dev/null +++ b/app/locale/ur.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﮯﮨ ﺎﮨﺭ ﮌﻮﺟ", + "Disconnecting...": "ﮯﮨ ﺎﮨﺭ ﻮﮨ ﻊﻄﻘﻨﻣ", + "Reconnecting...": "ﮯﮨ ﺎﮨﺭ ﻮﮨ ﮏﻠﺴﻨﻣ ﮦﺭﺎﺑﻭﺩ", + "Internal error": "ﯽﻣﺎﺧ ﯽﻠﺧﺍﺩ", + "Must set host": "ﮯﮨ ﯼﺭﻭﺮﺿ ﺎﻧﺮﮐ ﺭﺮﻘﻣ ﻥﺎﺑﺰﯿﻣ", + "Connected (encrypted) to ": "ﮯﺳ (ﮉﭩﭘﺮﮑﻧﺍ) ﮏﻠﺴﻨﻣ", + "Connected (unencrypted) to ": "ﮯﺳ (ﮦﺩﺮﮐ ﮧﯿﻔﺧ ﺮﯿﻏ) ﮏﻠﺴﻨﻣ", + "Something went wrong, connection is closed": "ﮯﮨ ﺪﻨﺑ ﻦﺸﮑﻨﮐ ،ﺎﯿﮔ ﻮﮨ ﻂﻠﻏ ﮫﭽﮐ", + "Failed to connect to server": "ﻡﺎﮐﺎﻧ ﮟﯿﻣ ﮯﻧﺮﮐ ﮧﻄﺑﺍﺭ ﮯﺳ ﺭﻭﺮﺳ", + "Disconnected": "ﻊﻄﻘﻨﻣ", + "New connection has been rejected with reason: ": "ﮯﮨ ﺎﯿﮔ ﺎﯾﺩ ﺮﮐ ﺩﺮﺘﺴﻣ ﮫﺗﺎﺳ ﮯﮐ ﮧﺟﻭ ﻮﮐ ﻦﺸﮑﻨﮐ ﮯﺌﻧ", + "New connection has been rejected": "ﮯﮨ ﺎﯿﮔ ﺎﯾﺩ ﺮﮐ ﺩﺮﺘﺴﻣ ﻦﺸﮑﻨﮐ ﺎﯿﻧ", + "Credentials are required": "ﮟﯿﮨ ﺭﺎﮐﺭﺩ ﺩﺎﻨﺳﺍ ", + "Hide/Show the control bar": "ﮟﯿﺋﺎﮭﮐﺩ/ﮟﯿﺋﺎﭙﮭﭼ ﻮﮐ ﺭﺎﺑ ﻝﻭﺮﭩﻨﮐ", + "Drag": "ﮟﯿﭩﯿﺴﮭﮔ", + "Move/Drag Viewport": "ﮟﯾﺮﮐ ﮓﯾﺭﮈ/ﻞﻘﺘﻨﻣ ﻮﮐ ﭦﺭﻮﭘ ﻮﯾﻭ", + "Keyboard": "ﮈﺭﻮﺑ ﯽﮐ", + "Show Keyboard": "ﮟﯿﺋﺎﮭﮐﺩ ﮈﺭﻮﺑ ﯽﮐ", + "Extra keys": "ﮞﺎﯿﺑﺎﭼ ﯽﻓﺎﺿﺍ", + "Show Extra Keys": "ﮟﯿﺋﺎﮭﮐﺩ ﮞﺎﯿﺑﺎﭼ ﯽﻓﺎﺿﺍ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ﮟﯾﺮﮐ ﻞﮔﻮﭨ", + "Alt": "Alt", + "Toggle Alt": "Alt ﮟﯾﺮﮐ ﻞﮔﻮﭨ", + "Toggle Windows": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﺯﻭﮉﻧﻭ", + "Windows": "ﺯﻭﮉﻧﻭ", + "Send Tab": "ﮟﯿﺠﯿﮭﺑ ﺐﯿﭨ", + "Tab": "ﺐﯿﭨ", + "Esc": "Esc", + "Send Escape": "ﮟﯿﺠﯿﮭﺑ ﺭﺍﺮﻓ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﮟﯿﺠﯿﮭﺑ", + "Shutdown/Reboot": "ﭦﻮﺒﯾﺭ/ﻥﺅﺍﮈ ﭧﺷ", + "Shutdown/Reboot...": "ﭦﻮﺒﯾﺭ/ﻥﺅﺍﮈ ﭧﺷ", + "Power": "ﺖﻗﺎﻃ", + "Shutdown": "ﺪﻨﺑ", + "Reboot": "ﭦﻮﺒﯾﺭ", + "Reset": "ﮟﯾﺮﮐ ﭧﯿﺳ ﯼﺭ", + "Clipboard": "ﮈﺭﻮﺑ ﭗﻠﮐ", + "Clear": "ﻑﺎﺻ", + "Fullscreen": "ﻦﯾﺮﮑﺳﺍ ﯼﮍﺑ ﺎﯾ ﻦﯾﺮﮑﺳﺍ ﻞﻤﮑﻣ", + "Settings": "ﺕﺎﺒﯿﺗﺮﺗ", + "Shared Mode": "ﮈﻮﻣ ﮧﮐﺮﺘﺸﻣ", + "View Only": "ﮟﯿﮭﮑﯾﺩ ﻑﺮﺻ", + "Clip to Window": "ﭗﻠﮐ ﺮﭘ ﯽﮐﮍﮭﮐ", + "Scaling Mode:": "ﮈﻮﻣ ﮓﻨﻠﯿﮑﺳﺍ", + "None": "ﮟﯿﮩﻧ ﯽﺋﻮﮐ", + "Local Scaling": "ﮓﻨﻠﯿﮑﺳﺍ ﯽﻣﺎﻘﻣ", + "Remote Resizing": "ﮓﻧﺰﺋﺎﯾﺭ ﭦﻮﻤﯾﺭ", + "Advanced": "ﯽﮐ ﮯﺟﺭﺩ ﯽﻠﻋﺍ", + "Quality:": "ﺭﺎﯿﻌﻣ", + "Compression level:": "ﻝﻮﯿﻟ ﻦﺸﯾﺮﭙﻤﮐ", + "Repeater ID:": "ID ﺮﭩﯿﭙﯾﺭ", + "WebSocket": "ﭧﮐﺎﺳ ﺐﯾﻭ", + "Encrypt": "ﭧﭘﺮﮑﻧﺍ", + "Host:": "ﻥﺎﺑﺰﯿﻣ", + "Port:": "ﭦﺭﻮﭘ", + "Path:": "ﮧﺘﺳﺍﺭ", + "Automatic Reconnect": "ﮟﯾﮍﺟ ﮦﺭﺎﺑﻭﺩ ﺭﺎﮐﺩﻮﺧ", + "Reconnect Delay (ms):": "(ms) ﮟﯾﮌﻮﺟ ﮦﺭﺎﺑﻭﺩ ﻮﮐ ﺮﯿﺧﺎﺗ", + "Show Dot when No Cursor": "ﮟﯿﺋﺎﮭﮐﺩ ﭦﺍﮈ ﻮﺗ ﻮﮨ ﮧﻧ ﺮﺳﺮﮐ ﺐﺟ", + "Logging:": "ﮓﻨﮔﻻ", + "Version:": "ﻥﮊﺭﻭ", + "Disconnect": "ﮟﯾﺮﮐ ﻊﻄﻘﻨﻣ", + "Connect": "ﮟﯾﮌﻮﺟ", + "Username:": "ﻡﺎﻧ ﺎﮐ ﻑﺭﺎﺻ", + "Password:": "ﮈﺭﻭ ﺱﺎﭘ", + "Send Credentials": " ﮟﯿﺠﯿﮭﺑ ﺩﺎﻨﺳﺍ ", + "Cancel": "ﮟﯾﺮﮐ ﺥﻮﺴﻨﻣ", + "Keys": "ﮞﺎﯿﺑﺎﭼ", + "Game Cursor Mode": "ﮈﻮﻣ ﺮﺳﺮﮐ ﻢﯿﮔ", + "Press Esc Key to Exit Pointer Lock Mode": "ﮟﯿﺋﺎﺑﺩ ﯽﮐ Esc ﮯﯿﻟ ﮯﮐ ﮯﻨﻠﮑﻧ ﺮﮨﺎﺑ ﮯﺳ ﮈﻮﻣ ﮎﻻ ﺮﭩﻨﺋﺍﻮﭘ", + "Game Mode paused, click on screen to resume Game Mode.": "۔ﮟﯾﺮﮐ ﮏﻠﮐ ﺮﭘ ﻦﯾﺮﮑﺳﺍ ﮯﯿﻟ ﮯﮐ ﮯﻧﺮﮐ ﻉﻭﺮﺷ ﮦﺭﺎﺑﻭﺩ ﻮﮐ ﮈﻮﻣ ﻢﯿﮔ ،ﺎﯿﮔ ﺎﯾﺩ ﮎﻭﺭ ﮈﻮﻣ ﻢﯿﮔ", + "Clipboard Up": "ﺮﭘﻭﺍ ﮈﺭﻮﺑ ﭗﻠﮐ", + "CLipboard Down": "ﮯﭽﯿﻧ ﮈﺭﻮﺑ ﭗﻠﮐ", + "Clipboard Seamless": "ﺭﺍﻮﻤﮨ ﮈﺭﻮﺑ ﭗﻠﮐ", + "Prefer Local Cursor": "ﮟﯾﺩ ﺢﯿﺟﺮﺗ ﻮﮐ ﺮﺳﺮﮐ ﯽﻣﺎﻘﻣ", + "Translate keyboard shortcuts": "ﮟﯾﺮﮐ ﮧﻤﺟﺮﺗ ﺎﮐ ﺲﭩﮐ ﭦﺭﺎﺷ ﮈﺭﻮﺑ ﯽﮐ", + "Enable WebRTC UDP Transit": "WebRTC UDP ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﭦﺰﻧﺍﺮﭨ", + "Enable WebP Compression": "WebP ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﻦﺸﯾﺮﭙﻤﮐ", + "Enable Performance Stats": "ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﺭﺎﻤﺷﻭﺩﺍﺪﻋﺍ ﮯﮐ ﯽﮔﺩﺮﮐﺭﺎﮐ", + "Enable Pointer Lock": "ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﮎﻻ ﺮﭩﻨﺋﺍﻮﭘ", + "IME Input Mode": "IME ﮈﻮﻣ ﭧﭘ ﻥﺍ", + "Show Virtual Keyboard Control": "ﮟﯿﺋﺎﮭﮐﺩ ﻝﻭﺮﭩﻨﮐ ﮈﺭﻮﺑ ﯽﮐ ﻞﺋﻮﭼﺭﻭ", + "Toggle Control Panel via Keystrokes": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﻞﻨﯿﭘ ﻝﻭﺮﭩﻨﮐ ﮯﻌﯾﺭﺫ ﮯﮐ ﺲﮐﻭﺮﭩﺳﺍ ﯽﮐ", + "Render Native Resolution": "ﮟﯾﺮﮐ ﺶﯿﭘ ﺩﺍﺩﺭﺍﺮﻗ ﯽﺋﺎﺑﺁ", + "Keyboard Shortcuts": "ﺲﭩﮐ ﭦﺭﺎﺷ ﮈﺭﻮﺑ ﯽﮐ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﭧﮐ ﭦﺭﺎﺷ ﮈﺭﻮﺑ ﯽﮐ", + "1 - Toggle Control Panel": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﻞﻨﯿﭘ ﻝﻭﺮﭩﻨﮐ - 1", + "2 - Toggle Game Pointer Mode": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﮈﻮﻣ ﺮﭩﻨﺋﺍﻮﭘ ﻢﯿﮔ - 2", + "3 - Toggle Pointer Lock": "ﮎﻻ ﺮﭩﻨﺋﺍﻮﭘ ﻞﮔﻮﭨ - 3", + "Stream Quality": "ﯽﭩﻟﺍﻮﮐ ﻢﯾﺮﭩﺳ", + "Preset Modes:": "ﺯﮈﻮﻣ ﭧﯿﺳ ﺶﯿﭘ", + "Static": "ﺪﻣﺎﺟ", + "Low": "ﻢﮐ", + "Medium": "ﻢﯾﮉﯿﻣ", + "High": "ﯽﻠﻋﺍ", + "Extreme": "ﯽﺋﺎﮩﺘﻧﺍ", + "Lossless": "ﻥﺎﺼﻘﻧ ﮯﺑ", + "Custom": "ﻖﺑﺎﻄﻣ ﮯﮐ ﯽﺿﺮﻣ ﯽﻨﭘﺍ", + "Anti-Aliasing:": "ﺎﻨﯾﺩ ﺐﻘﻟ ﻒﻟﺎﺨﻣ", + "Auto Dynamic": "ﮏﻣﺎﻨﺋﺍﮈ ﻮﭨﺁ", + "Off": "ﺪﻨﺑ", + "On": "ﻥﺁ", + "Dynamic Quality Min:": "ﻢﮐ ﮯﺳ ﻢﮐ ﺭﺎﯿﻌﻣ ﮎﺮﺤﺘﻣ", + "Dynamic Quality Max:": "ﮦﺩﺎﯾﺯ ﮯﺳ ﮦﺩﺎﯾﺯ ﺭﺎﯿﻌﻣ ﮎﺮﺤﺘﻣ", + "Treat Lossless:": "ﮟﯾﺮﮐ ﺝﻼﻋ ﺎﮐ ﻥﺎﺼﻘﻧ ﮯﺑ", + "Frame Rate:": "ﺡﺮﺷ ﯽﮐ ﻢﯾﺮﻓ", + "Video JPEG Quality:": "ﯽﭩﻟﺍﻮﮐ JPEG ﻮﯾﮉﯾﻭ", + "Video WEBP Quality:": "ﺭﺎﯿﻌﻣ WEBP ﻮﯾﮉﯾﻭ", + "Video Area:": "ﺎﯾﺮﯾﺍ ﻮﯾﮉﯾﻭ", + "Video Time:": "ﺖﻗﻭ ﺎﮐ ﻮﯾﮉﯾﻭ", + "Video Out Time:": "ﺖﻗﻭ ﺎﮐ ﮯﻧﻮﮨ ﻢﺘﺧ ﻮﯾﮉﯾﻭ", + "Video Mode Width:": "ﯽﺋﺍﮌﻮﭼ ﮈﻮﻣ ﻮﯾﮉﯾﻭ", + "Video Mode Height:": "ﯽﺋﺎﭽﻧﻭﺍ ﯽﮐ ﮈﻮﻣ ﻮﯾﮉﯾﻭ", + "Documentation": "ﺕﺍﺰﯾﻭﺎﺘﺳﺩ", + "Drag Viewport": "ﭦﺭﻮﭘ ﻮﯾﻭ ﮓﯾﺭﮈ", + "KasmVNC encountered an error:": "KasmVNC ﺍﮍﭘ ﺎﻧﺮﮐ ﺎﻨﻣﺎﺳ ﺎﮐ ﯽﺑﺍﺮﺧ ﮏﯾﺍ ﻮﮐ:" +} \ No newline at end of file diff --git a/app/locale/ur_IN.json b/app/locale/ur_IN.json new file mode 100644 index 0000000..1b0b149 --- /dev/null +++ b/app/locale/ur_IN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﮯﮨ ﺎﮨﺭ ﮌﻮﺟ", + "Disconnecting...": "ﮯﮨ ﺎﮨﺭ ﻮﮨ ﻊﻄﻘﻨﻣ", + "Reconnecting...": "ﮯﮨ ﺎﮨﺭ ﻮﮨ ﮏﻠﺴﻨﻣ ﮦﺭﺎﺑﻭﺩ", + "Internal error": "ﯽﻣﺎﺧ ﯽﻠﺧﺍﺩ", + "Must set host": "ﮯﮨ ﯼﺭﻭﺮﺿ ﺎﻧﺮﮐ ﺭﺮﻘﻣ ﻥﺎﺑﺰﯿﻣ", + "Connected (encrypted) to ": "ﮯﺳ (ﮉﭩﭘﺮﮑﻧﺍ) ﮏﻠﺴﻨﻣ", + "Connected (unencrypted) to ": "ﮯﺳ (ﮦﺩﺮﮐ ﮧﯿﻔﺧ ﺮﯿﻏ) ﮏﻠﺴﻨﻣ", + "Something went wrong, connection is closed": "ﮯﮨ ﺪﻨﺑ ﻦﺸﮑﻨﮐ ،ﺎﯿﮔ ﻮﮨ ﻂﻠﻏ ﮫﭽﮐ", + "Failed to connect to server": "ﻡﺎﮐﺎﻧ ﮟﯿﻣ ﮯﻧﺮﮐ ﮧﻄﺑﺍﺭ ﮯﺳ ﺭﻭﺮﺳ", + "Disconnected": "ﻊﻄﻘﻨﻣ", + "New connection has been rejected with reason: ": "ﮯﮨ ﺎﯿﮔ ﺎﯾﺩ ﺮﮐ ﺩﺮﺘﺴﻣ ﮫﺗﺎﺳ ﮯﮐ ﮧﺟﻭ ﻮﮐ ﻦﺸﮑﻨﮐ ﮯﺌﻧ", + "New connection has been rejected": "ﮯﮨ ﺎﯿﮔ ﺎﯾﺩ ﺮﮐ ﺩﺮﺘﺴﻣ ﻦﺸﮑﻨﮐ ﺎﯿﻧ", + "Credentials are required": "ﮟﯿﮨ ﺭﺎﮐﺭﺩ ﺩﺎﻨﺳﺍ ", + "Hide/Show the control bar": "ﮟﯿﺋﺎﮭﮐﺩ/ﮟﯿﺋﺎﭙﮭﭼ ﻮﮐ ﺭﺎﺑ ﻝﻭﺮﭩﻨﮐ", + "Drag": "ﮟﯿﭩﯿﺴﮭﮔ", + "Move/Drag Viewport": "ﮟﯾﺮﮐ ﮓﯾﺭﮈ/ﻞﻘﺘﻨﻣ ﻮﮐ ﭦﺭﻮﭘ ﻮﯾﻭ", + "Keyboard": "ﮈﺭﻮﺑ ﯽﮐ", + "Show Keyboard": "ﮟﯿﺋﺎﮭﮐﺩ ﮈﺭﻮﺑ ﯽﮐ", + "Extra keys": "ﮞﺎﯿﺑﺎﭼ ﯽﻓﺎﺿﺍ", + "Show Extra Keys": "ﮟﯿﺋﺎﮭﮐﺩ ﮞﺎﯿﺑﺎﭼ ﯽﻓﺎﺿﺍ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ﮟﯾﺮﮐ ﻞﮔﻮﭨ", + "Alt": "Alt", + "Toggle Alt": "Alt ﮟﯾﺮﮐ ﻞﮔﻮﭨ", + "Toggle Windows": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﺯﻭﮉﻧﻭ", + "Windows": "ﺯﻭﮉﻧﻭ", + "Send Tab": "ﮟﯿﺠﯿﮭﺑ ﺐﯿﭨ", + "Tab": "ﺐﯿﭨ", + "Esc": "Esc", + "Send Escape": "ﮟﯿﺠﯿﮭﺑ ﺭﺍﺮﻓ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﮟﯿﺠﯿﮭﺑ", + "Shutdown/Reboot": "ﭦﻮﺒﯾﺭ/ﻥﺅﺍﮈ ﭧﺷ", + "Shutdown/Reboot...": "ﭦﻮﺒﯾﺭ/ﻥﺅﺍﮈ ﭧﺷ", + "Power": "ﺖﻗﺎﻃ", + "Shutdown": "ﺪﻨﺑ", + "Reboot": "ﭦﻮﺒﯾﺭ", + "Reset": "ﮟﯾﺮﮐ ﭧﯿﺳ ﯼﺭ", + "Clipboard": "ﮈﺭﻮﺑ ﭗﻠﮐ", + "Clear": "ﻑﺎﺻ", + "Fullscreen": "ﻦﯾﺮﮑﺳﺍ ﯼﮍﺑ ﺎﯾ ﻦﯾﺮﮑﺳﺍ ﻞﻤﮑﻣ", + "Settings": "ﺕﺎﺒﯿﺗﺮﺗ", + "Shared Mode": "ﮈﻮﻣ ﮧﮐﺮﺘﺸﻣ", + "View Only": "ﮟﯿﮭﮑﯾﺩ ﻑﺮﺻ", + "Clip to Window": "ﭗﻠﮐ ﺮﭘ ﯽﮐﮍﮭﮐ", + "Scaling Mode:": "ﮈﻮﻣ ﮓﻨﻠﯿﮑﺳﺍ", + "None": "ﮟﯿﮩﻧ ﯽﺋﻮﮐ", + "Local Scaling": "ﮓﻨﻠﯿﮑﺳﺍ ﯽﻣﺎﻘﻣ", + "Remote Resizing": "ﮓﻧﺰﺋﺎﯾﺭ ﭦﻮﻤﯾﺭ", + "Advanced": "ﯽﮐ ﮯﺟﺭﺩ ﯽﻠﻋﺍ", + "Quality:": "ﺭﺎﯿﻌﻣ", + "Compression level:": "ﻝﻮﯿﻟ ﻦﺸﯾﺮﭙﻤﮐ", + "Repeater ID:": "ID ﺮﭩﯿﭙﯾﺭ", + "WebSocket": "ﭧﮐﺎﺳ ﺐﯾﻭ", + "Encrypt": "ﭧﭘﺮﮑﻧﺍ", + "Host:": "ﻥﺎﺑﺰﯿﻣ", + "Port:": "ﭦﺭﻮﭘ", + "Path:": "ﮧﺘﺳﺍﺭ", + "Automatic Reconnect": "ﮟﯾﮍﺟ ﮦﺭﺎﺑﻭﺩ ﺭﺎﮐﺩﻮﺧ", + "Reconnect Delay (ms):": "(ms) ﮟﯾﮌﻮﺟ ﮦﺭﺎﺑﻭﺩ ﻮﮐ ﺮﯿﺧﺎﺗ", + "Show Dot when No Cursor": "ﮟﯿﺋﺎﮭﮐﺩ ﭦﺍﮈ ﻮﺗ ﻮﮨ ﮧﻧ ﺮﺳﺮﮐ ﺐﺟ", + "Logging:": "ﮓﻨﮔﻻ", + "Version:": "ﻥﮊﺭﻭ", + "Disconnect": "ﮟﯾﺮﮐ ﻊﻄﻘﻨﻣ", + "Connect": "ﮟﯾﮌﻮﺟ", + "Username:": "ﻡﺎﻧ ﺎﮐ ﻑﺭﺎﺻ", + "Password:": "ﮈﺭﻭ ﺱﺎﭘ", + "Send Credentials": " ﮟﯿﺠﯿﮭﺑ ﺩﺎﻨﺳﺍ ", + "Cancel": "ﮟﯾﺮﮐ ﺥﻮﺴﻨﻣ", + "Keys": "ﮞﺎﯿﺑﺎﭼ", + "Game Cursor Mode": "ﮈﻮﻣ ﺮﺳﺮﮐ ﻢﯿﮔ", + "Press Esc Key to Exit Pointer Lock Mode": "ﮟﯿﺋﺎﺑﺩ ﯽﮐ Esc ﮯﯿﻟ ﮯﮐ ﮯﻨﻠﮑﻧ ﺮﮨﺎﺑ ﮯﺳ ﮈﻮﻣ ﮎﻻ ﺮﭩﻨﺋﺍﻮﭘ", + "Game Mode paused, click on screen to resume Game Mode.": "۔ﮟﯾﺮﮐ ﮏﻠﮐ ﺮﭘ ﻦﯾﺮﮑﺳﺍ ﮯﯿﻟ ﮯﮐ ﮯﻧﺮﮐ ﻉﻭﺮﺷ ﮦﺭﺎﺑﻭﺩ ﻮﮐ ﮈﻮﻣ ﻢﯿﮔ ،ﺎﯿﮔ ﺎﯾﺩ ﮎﻭﺭ ﮈﻮﻣ ﻢﯿﮔ", + "Clipboard Up": "ﺮﭘﻭﺍ ﮈﺭﻮﺑ ﭗﻠﮐ", + "CLipboard Down": "ﮯﭽﯿﻧ ﮈﺭﻮﺑ ﭗﻠﮐ", + "Clipboard Seamless": "ﺭﺍﻮﻤﮨ ﮈﺭﻮﺑ ﭗﻠﮐ", + "Prefer Local Cursor": "ﮟﯾﺩ ﺢﯿﺟﺮﺗ ﻮﮐ ﺮﺳﺮﮐ ﯽﻣﺎﻘﻣ", + "Translate keyboard shortcuts": "ﮟﯾﺮﮐ ﮧﻤﺟﺮﺗ ﺎﮐ ﺲﭩﮐ ﭦﺭﺎﺷ ﮈﺭﻮﺑ ﯽﮐ", + "Enable WebRTC UDP Transit": "WebRTC UDP ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﭦﺰﻧﺍﺮﭨ", + "Enable WebP Compression": "WebP ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﻦﺸﯾﺮﭙﻤﮐ", + "Enable Performance Stats": "ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﺭﺎﻤﺷﻭﺩﺍﺪﻋﺍ ﮯﮐ ﯽﮔﺩﺮﮐﺭﺎﮐ", + "Enable Pointer Lock": "ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﮎﻻ ﺮﭩﻨﺋﺍﻮﭘ", + "IME Input Mode": "IME ﮈﻮﻣ ﭧﭘ ﻥﺍ", + "Show Virtual Keyboard Control": "ﮟﯿﺋﺎﮭﮐﺩ ﻝﻭﺮﭩﻨﮐ ﮈﺭﻮﺑ ﯽﮐ ﻞﺋﻮﭼﺭﻭ", + "Toggle Control Panel via Keystrokes": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﻞﻨﯿﭘ ﻝﻭﺮﭩﻨﮐ ﮯﻌﯾﺭﺫ ﮯﮐ ﺲﮐﻭﺮﭩﺳﺍ ﯽﮐ", + "Render Native Resolution": "ﮟﯾﺮﮐ ﺶﯿﭘ ﺩﺍﺩﺭﺍﺮﻗ ﯽﺋﺎﺑﺁ", + "Keyboard Shortcuts": "ﺲﭩﮐ ﭦﺭﺎﺷ ﮈﺭﻮﺑ ﯽﮐ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﭧﮐ ﭦﺭﺎﺷ ﮈﺭﻮﺑ ﯽﮐ", + "1 - Toggle Control Panel": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﻞﻨﯿﭘ ﻝﻭﺮﭩﻨﮐ - 1", + "2 - Toggle Game Pointer Mode": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﮈﻮﻣ ﺮﭩﻨﺋﺍﻮﭘ ﻢﯿﮔ - 2", + "3 - Toggle Pointer Lock": "ﮎﻻ ﺮﭩﻨﺋﺍﻮﭘ ﻞﮔﻮﭨ - 3", + "Stream Quality": "ﯽﭩﻟﺍﻮﮐ ﻢﯾﺮﭩﺳ", + "Preset Modes:": "ﺯﮈﻮﻣ ﭧﯿﺳ ﺶﯿﭘ", + "Static": "ﺪﻣﺎﺟ", + "Low": "ﻢﮐ", + "Medium": "ﻢﯾﮉﯿﻣ", + "High": "ﯽﻠﻋﺍ", + "Extreme": "ﯽﺋﺎﮩﺘﻧﺍ", + "Lossless": "ﻥﺎﺼﻘﻧ ﮯﺑ", + "Custom": "ﻖﺑﺎﻄﻣ ﮯﮐ ﯽﺿﺮﻣ ﯽﻨﭘﺍ", + "Anti-Aliasing:": "ﺎﻨﯾﺩ ﺐﻘﻟ ﻒﻟﺎﺨﻣ", + "Auto Dynamic": "ﮏﻣﺎﻨﺋﺍﮈ ﻮﭨﺁ", + "Off": "ﺪﻨﺑ", + "On": "ﻥﺁ", + "Dynamic Quality Min:": "ﻢﮐ ﮯﺳ ﻢﮐ ﺭﺎﯿﻌﻣ ﮎﺮﺤﺘﻣ", + "Dynamic Quality Max:": "ﮦﺩﺎﯾﺯ ﮯﺳ ﮦﺩﺎﯾﺯ ﺭﺎﯿﻌﻣ ﮎﺮﺤﺘﻣ", + "Treat Lossless:": "ﮟﯾﺮﮐ ﺝﻼﻋ ﺎﮐ ﻥﺎﺼﻘﻧ ﮯﺑ", + "Frame Rate:": "ﺡﺮﺷ ﯽﮐ ﻢﯾﺮﻓ", + "Video JPEG Quality:": "ﯽﭩﻟﺍﻮﮐ JPEG ﻮﯾﮉﯾﻭ", + "Video WEBP Quality:": "ﺭﺎﯿﻌﻣ WEBP ﻮﯾﮉﯾﻭ", + "Video Area:": "ﺎﯾﺮﯾﺍ ﻮﯾﮉﯾﻭ", + "Video Time:": "ﺖﻗﻭ ﺎﮐ ﻮﯾﮉﯾﻭ", + "Video Out Time:": "ﺖﻗﻭ ﺎﮐ ﮯﻧﻮﮨ ﻢﺘﺧ ﻮﯾﮉﯾﻭ", + "Video Mode Width:": "ﯽﺋﺍﮌﻮﭼ ﮈﻮﻣ ﻮﯾﮉﯾﻭ", + "Video Mode Height:": "ﯽﺋﺎﭽﻧﻭﺍ ﯽﮐ ﮈﻮﻣ ﻮﯾﮉﯾﻭ", + "Documentation": "ﺕﺍﺰﯾﻭﺎﺘﺳﺩ", + "Drag Viewport": "ﭦﺭﻮﭘ ﻮﯾﻭ ﮓﯾﺭﮈ", + "KasmVNC encountered an error:": "KasmVNC ﺍﮍﭘ ﺎﻧﺮﮐ ﺎﻨﻣﺎﺳ ﺎﮐ ﯽﺑﺍﺮﺧ ﮏﯾﺍ ﻮﮐ:" +} \ No newline at end of file diff --git a/app/locale/ur_PK.json b/app/locale/ur_PK.json new file mode 100644 index 0000000..1b0b149 --- /dev/null +++ b/app/locale/ur_PK.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "ﮯﮨ ﺎﮨﺭ ﮌﻮﺟ", + "Disconnecting...": "ﮯﮨ ﺎﮨﺭ ﻮﮨ ﻊﻄﻘﻨﻣ", + "Reconnecting...": "ﮯﮨ ﺎﮨﺭ ﻮﮨ ﮏﻠﺴﻨﻣ ﮦﺭﺎﺑﻭﺩ", + "Internal error": "ﯽﻣﺎﺧ ﯽﻠﺧﺍﺩ", + "Must set host": "ﮯﮨ ﯼﺭﻭﺮﺿ ﺎﻧﺮﮐ ﺭﺮﻘﻣ ﻥﺎﺑﺰﯿﻣ", + "Connected (encrypted) to ": "ﮯﺳ (ﮉﭩﭘﺮﮑﻧﺍ) ﮏﻠﺴﻨﻣ", + "Connected (unencrypted) to ": "ﮯﺳ (ﮦﺩﺮﮐ ﮧﯿﻔﺧ ﺮﯿﻏ) ﮏﻠﺴﻨﻣ", + "Something went wrong, connection is closed": "ﮯﮨ ﺪﻨﺑ ﻦﺸﮑﻨﮐ ،ﺎﯿﮔ ﻮﮨ ﻂﻠﻏ ﮫﭽﮐ", + "Failed to connect to server": "ﻡﺎﮐﺎﻧ ﮟﯿﻣ ﮯﻧﺮﮐ ﮧﻄﺑﺍﺭ ﮯﺳ ﺭﻭﺮﺳ", + "Disconnected": "ﻊﻄﻘﻨﻣ", + "New connection has been rejected with reason: ": "ﮯﮨ ﺎﯿﮔ ﺎﯾﺩ ﺮﮐ ﺩﺮﺘﺴﻣ ﮫﺗﺎﺳ ﮯﮐ ﮧﺟﻭ ﻮﮐ ﻦﺸﮑﻨﮐ ﮯﺌﻧ", + "New connection has been rejected": "ﮯﮨ ﺎﯿﮔ ﺎﯾﺩ ﺮﮐ ﺩﺮﺘﺴﻣ ﻦﺸﮑﻨﮐ ﺎﯿﻧ", + "Credentials are required": "ﮟﯿﮨ ﺭﺎﮐﺭﺩ ﺩﺎﻨﺳﺍ ", + "Hide/Show the control bar": "ﮟﯿﺋﺎﮭﮐﺩ/ﮟﯿﺋﺎﭙﮭﭼ ﻮﮐ ﺭﺎﺑ ﻝﻭﺮﭩﻨﮐ", + "Drag": "ﮟﯿﭩﯿﺴﮭﮔ", + "Move/Drag Viewport": "ﮟﯾﺮﮐ ﮓﯾﺭﮈ/ﻞﻘﺘﻨﻣ ﻮﮐ ﭦﺭﻮﭘ ﻮﯾﻭ", + "Keyboard": "ﮈﺭﻮﺑ ﯽﮐ", + "Show Keyboard": "ﮟﯿﺋﺎﮭﮐﺩ ﮈﺭﻮﺑ ﯽﮐ", + "Extra keys": "ﮞﺎﯿﺑﺎﭼ ﯽﻓﺎﺿﺍ", + "Show Extra Keys": "ﮟﯿﺋﺎﮭﮐﺩ ﮞﺎﯿﺑﺎﭼ ﯽﻓﺎﺿﺍ", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl ﮟﯾﺮﮐ ﻞﮔﻮﭨ", + "Alt": "Alt", + "Toggle Alt": "Alt ﮟﯾﺮﮐ ﻞﮔﻮﭨ", + "Toggle Windows": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﺯﻭﮉﻧﻭ", + "Windows": "ﺯﻭﮉﻧﻭ", + "Send Tab": "ﮟﯿﺠﯿﮭﺑ ﺐﯿﭨ", + "Tab": "ﺐﯿﭨ", + "Esc": "Esc", + "Send Escape": "ﮟﯿﺠﯿﮭﺑ ﺭﺍﺮﻓ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ﮟﯿﺠﯿﮭﺑ", + "Shutdown/Reboot": "ﭦﻮﺒﯾﺭ/ﻥﺅﺍﮈ ﭧﺷ", + "Shutdown/Reboot...": "ﭦﻮﺒﯾﺭ/ﻥﺅﺍﮈ ﭧﺷ", + "Power": "ﺖﻗﺎﻃ", + "Shutdown": "ﺪﻨﺑ", + "Reboot": "ﭦﻮﺒﯾﺭ", + "Reset": "ﮟﯾﺮﮐ ﭧﯿﺳ ﯼﺭ", + "Clipboard": "ﮈﺭﻮﺑ ﭗﻠﮐ", + "Clear": "ﻑﺎﺻ", + "Fullscreen": "ﻦﯾﺮﮑﺳﺍ ﯼﮍﺑ ﺎﯾ ﻦﯾﺮﮑﺳﺍ ﻞﻤﮑﻣ", + "Settings": "ﺕﺎﺒﯿﺗﺮﺗ", + "Shared Mode": "ﮈﻮﻣ ﮧﮐﺮﺘﺸﻣ", + "View Only": "ﮟﯿﮭﮑﯾﺩ ﻑﺮﺻ", + "Clip to Window": "ﭗﻠﮐ ﺮﭘ ﯽﮐﮍﮭﮐ", + "Scaling Mode:": "ﮈﻮﻣ ﮓﻨﻠﯿﮑﺳﺍ", + "None": "ﮟﯿﮩﻧ ﯽﺋﻮﮐ", + "Local Scaling": "ﮓﻨﻠﯿﮑﺳﺍ ﯽﻣﺎﻘﻣ", + "Remote Resizing": "ﮓﻧﺰﺋﺎﯾﺭ ﭦﻮﻤﯾﺭ", + "Advanced": "ﯽﮐ ﮯﺟﺭﺩ ﯽﻠﻋﺍ", + "Quality:": "ﺭﺎﯿﻌﻣ", + "Compression level:": "ﻝﻮﯿﻟ ﻦﺸﯾﺮﭙﻤﮐ", + "Repeater ID:": "ID ﺮﭩﯿﭙﯾﺭ", + "WebSocket": "ﭧﮐﺎﺳ ﺐﯾﻭ", + "Encrypt": "ﭧﭘﺮﮑﻧﺍ", + "Host:": "ﻥﺎﺑﺰﯿﻣ", + "Port:": "ﭦﺭﻮﭘ", + "Path:": "ﮧﺘﺳﺍﺭ", + "Automatic Reconnect": "ﮟﯾﮍﺟ ﮦﺭﺎﺑﻭﺩ ﺭﺎﮐﺩﻮﺧ", + "Reconnect Delay (ms):": "(ms) ﮟﯾﮌﻮﺟ ﮦﺭﺎﺑﻭﺩ ﻮﮐ ﺮﯿﺧﺎﺗ", + "Show Dot when No Cursor": "ﮟﯿﺋﺎﮭﮐﺩ ﭦﺍﮈ ﻮﺗ ﻮﮨ ﮧﻧ ﺮﺳﺮﮐ ﺐﺟ", + "Logging:": "ﮓﻨﮔﻻ", + "Version:": "ﻥﮊﺭﻭ", + "Disconnect": "ﮟﯾﺮﮐ ﻊﻄﻘﻨﻣ", + "Connect": "ﮟﯾﮌﻮﺟ", + "Username:": "ﻡﺎﻧ ﺎﮐ ﻑﺭﺎﺻ", + "Password:": "ﮈﺭﻭ ﺱﺎﭘ", + "Send Credentials": " ﮟﯿﺠﯿﮭﺑ ﺩﺎﻨﺳﺍ ", + "Cancel": "ﮟﯾﺮﮐ ﺥﻮﺴﻨﻣ", + "Keys": "ﮞﺎﯿﺑﺎﭼ", + "Game Cursor Mode": "ﮈﻮﻣ ﺮﺳﺮﮐ ﻢﯿﮔ", + "Press Esc Key to Exit Pointer Lock Mode": "ﮟﯿﺋﺎﺑﺩ ﯽﮐ Esc ﮯﯿﻟ ﮯﮐ ﮯﻨﻠﮑﻧ ﺮﮨﺎﺑ ﮯﺳ ﮈﻮﻣ ﮎﻻ ﺮﭩﻨﺋﺍﻮﭘ", + "Game Mode paused, click on screen to resume Game Mode.": "۔ﮟﯾﺮﮐ ﮏﻠﮐ ﺮﭘ ﻦﯾﺮﮑﺳﺍ ﮯﯿﻟ ﮯﮐ ﮯﻧﺮﮐ ﻉﻭﺮﺷ ﮦﺭﺎﺑﻭﺩ ﻮﮐ ﮈﻮﻣ ﻢﯿﮔ ،ﺎﯿﮔ ﺎﯾﺩ ﮎﻭﺭ ﮈﻮﻣ ﻢﯿﮔ", + "Clipboard Up": "ﺮﭘﻭﺍ ﮈﺭﻮﺑ ﭗﻠﮐ", + "CLipboard Down": "ﮯﭽﯿﻧ ﮈﺭﻮﺑ ﭗﻠﮐ", + "Clipboard Seamless": "ﺭﺍﻮﻤﮨ ﮈﺭﻮﺑ ﭗﻠﮐ", + "Prefer Local Cursor": "ﮟﯾﺩ ﺢﯿﺟﺮﺗ ﻮﮐ ﺮﺳﺮﮐ ﯽﻣﺎﻘﻣ", + "Translate keyboard shortcuts": "ﮟﯾﺮﮐ ﮧﻤﺟﺮﺗ ﺎﮐ ﺲﭩﮐ ﭦﺭﺎﺷ ﮈﺭﻮﺑ ﯽﮐ", + "Enable WebRTC UDP Transit": "WebRTC UDP ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﭦﺰﻧﺍﺮﭨ", + "Enable WebP Compression": "WebP ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﻦﺸﯾﺮﭙﻤﮐ", + "Enable Performance Stats": "ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﺭﺎﻤﺷﻭﺩﺍﺪﻋﺍ ﮯﮐ ﯽﮔﺩﺮﮐﺭﺎﮐ", + "Enable Pointer Lock": "ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﮎﻻ ﺮﭩﻨﺋﺍﻮﭘ", + "IME Input Mode": "IME ﮈﻮﻣ ﭧﭘ ﻥﺍ", + "Show Virtual Keyboard Control": "ﮟﯿﺋﺎﮭﮐﺩ ﻝﻭﺮﭩﻨﮐ ﮈﺭﻮﺑ ﯽﮐ ﻞﺋﻮﭼﺭﻭ", + "Toggle Control Panel via Keystrokes": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﻞﻨﯿﭘ ﻝﻭﺮﭩﻨﮐ ﮯﻌﯾﺭﺫ ﮯﮐ ﺲﮐﻭﺮﭩﺳﺍ ﯽﮐ", + "Render Native Resolution": "ﮟﯾﺮﮐ ﺶﯿﭘ ﺩﺍﺩﺭﺍﺮﻗ ﯽﺋﺎﺑﺁ", + "Keyboard Shortcuts": "ﺲﭩﮐ ﭦﺭﺎﺷ ﮈﺭﻮﺑ ﯽﮐ", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC ﮟﯾﺮﮐ ﻝﺎﻌﻓ ﻮﮐ ﭧﮐ ﭦﺭﺎﺷ ﮈﺭﻮﺑ ﯽﮐ", + "1 - Toggle Control Panel": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﻞﻨﯿﭘ ﻝﻭﺮﭩﻨﮐ - 1", + "2 - Toggle Game Pointer Mode": "ﮟﯾﺮﮐ ﻞﮔﻮﭨ ﻮﮐ ﮈﻮﻣ ﺮﭩﻨﺋﺍﻮﭘ ﻢﯿﮔ - 2", + "3 - Toggle Pointer Lock": "ﮎﻻ ﺮﭩﻨﺋﺍﻮﭘ ﻞﮔﻮﭨ - 3", + "Stream Quality": "ﯽﭩﻟﺍﻮﮐ ﻢﯾﺮﭩﺳ", + "Preset Modes:": "ﺯﮈﻮﻣ ﭧﯿﺳ ﺶﯿﭘ", + "Static": "ﺪﻣﺎﺟ", + "Low": "ﻢﮐ", + "Medium": "ﻢﯾﮉﯿﻣ", + "High": "ﯽﻠﻋﺍ", + "Extreme": "ﯽﺋﺎﮩﺘﻧﺍ", + "Lossless": "ﻥﺎﺼﻘﻧ ﮯﺑ", + "Custom": "ﻖﺑﺎﻄﻣ ﮯﮐ ﯽﺿﺮﻣ ﯽﻨﭘﺍ", + "Anti-Aliasing:": "ﺎﻨﯾﺩ ﺐﻘﻟ ﻒﻟﺎﺨﻣ", + "Auto Dynamic": "ﮏﻣﺎﻨﺋﺍﮈ ﻮﭨﺁ", + "Off": "ﺪﻨﺑ", + "On": "ﻥﺁ", + "Dynamic Quality Min:": "ﻢﮐ ﮯﺳ ﻢﮐ ﺭﺎﯿﻌﻣ ﮎﺮﺤﺘﻣ", + "Dynamic Quality Max:": "ﮦﺩﺎﯾﺯ ﮯﺳ ﮦﺩﺎﯾﺯ ﺭﺎﯿﻌﻣ ﮎﺮﺤﺘﻣ", + "Treat Lossless:": "ﮟﯾﺮﮐ ﺝﻼﻋ ﺎﮐ ﻥﺎﺼﻘﻧ ﮯﺑ", + "Frame Rate:": "ﺡﺮﺷ ﯽﮐ ﻢﯾﺮﻓ", + "Video JPEG Quality:": "ﯽﭩﻟﺍﻮﮐ JPEG ﻮﯾﮉﯾﻭ", + "Video WEBP Quality:": "ﺭﺎﯿﻌﻣ WEBP ﻮﯾﮉﯾﻭ", + "Video Area:": "ﺎﯾﺮﯾﺍ ﻮﯾﮉﯾﻭ", + "Video Time:": "ﺖﻗﻭ ﺎﮐ ﻮﯾﮉﯾﻭ", + "Video Out Time:": "ﺖﻗﻭ ﺎﮐ ﮯﻧﻮﮨ ﻢﺘﺧ ﻮﯾﮉﯾﻭ", + "Video Mode Width:": "ﯽﺋﺍﮌﻮﭼ ﮈﻮﻣ ﻮﯾﮉﯾﻭ", + "Video Mode Height:": "ﯽﺋﺎﭽﻧﻭﺍ ﯽﮐ ﮈﻮﻣ ﻮﯾﮉﯾﻭ", + "Documentation": "ﺕﺍﺰﯾﻭﺎﺘﺳﺩ", + "Drag Viewport": "ﭦﺭﻮﭘ ﻮﯾﻭ ﮓﯾﺭﮈ", + "KasmVNC encountered an error:": "KasmVNC ﺍﮍﭘ ﺎﻧﺮﮐ ﺎﻨﻣﺎﺳ ﺎﮐ ﯽﺑﺍﺮﺧ ﮏﯾﺍ ﻮﮐ:" +} \ No newline at end of file diff --git a/app/locale/uz.json b/app/locale/uz.json new file mode 100644 index 0000000..ce7f7b6 --- /dev/null +++ b/app/locale/uz.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ulanilmoqda...", + "Disconnecting...": "Uzilish uzilmoqda...", + "Reconnecting...": "Qayta ulanmoqda...", + "Internal error": "Ichki xato", + "Must set host": "Xostni sozlash kerak", + "Connected (encrypted) to ": "Ulangan (shifrlangan)", + "Connected (unencrypted) to ": "Ulangan (shifrlanmagan)", + "Something went wrong, connection is closed": "Nimadir xato ketdi, ulanish yopildi", + "Failed to connect to server": "Serverga ulanib bo'lmadi", + "Disconnected": "Uzilgan", + "New connection has been rejected with reason: ": "Yangi ulanish sabab bilan rad etildi:", + "New connection has been rejected": "Yangi ulanish rad etildi", + "Credentials are required": "Hisob ma'lumotlari talab qilinadi", + "Hide/Show the control bar": "Boshqaruv panelini yashirish/ko'rsatish", + "Drag": "Tartib tashlang", + "Move/Drag Viewport": "Ko'rish maydonini ko'chirish/tortish", + "Keyboard": "Klaviatura", + "Show Keyboard": "Klaviaturani ko'rsatish", + "Extra keys": "Qo'shimcha kalitlar", + "Show Extra Keys": "Qo'shimcha kalitlarni ko'rsatish", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl tugmachasini o'zgartirish", + "Alt": "Alt", + "Toggle Alt": "Alt tugmachasini o'zgartirish", + "Toggle Windows": "Windows-ni almashtirish", + "Windows": "Windows", + "Send Tab": "Yuborish yorlig'i", + "Tab": "tab", + "Esc": "Esc", + "Send Escape": "Qochishni yuborish", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del-ni yuborish", + "Shutdown/Reboot": "O'chirish/qayta yuklash", + "Shutdown/Reboot...": "O'chirish/qayta yuklash...", + "Power": "Kuch", + "Shutdown": "O'chirish; yopish", + "Reboot": "Qayta ishga tushirish", + "Reset": "Qayta o'rnatish", + "Clipboard": "Bufer yozuvi", + "Clear": "Tozalash", + "Fullscreen": "To'liq ekran", + "Settings": "Sozlamalar", + "Shared Mode": "Umumiy rejim", + "View Only": "Faqat ko'rish", + "Clip to Window": "Oynaga klip", + "Scaling Mode:": "Majshlash rejimi:", + "None": "Yo'q", + "Local Scaling": "Mahalliy o'lchov", + "Remote Resizing": "Masofaviy o'lchamni o'zgartirish", + "Advanced": "Kengaytirilgan", + "Quality:": "Sifat:", + "Compression level:": "Siqish darajasi:", + "Repeater ID:": "Takrorlovchi identifikatori:", + "WebSocket": "WebSocket", + "Encrypt": "shifrlash", + "Host:": "Mezbon:", + "Port:": "Port:", + "Path:": "Yo'l:", + "Automatic Reconnect": "Avtomatik qayta ulanish", + "Reconnect Delay (ms):": "Qayta ulanish kechikishi (ms):", + "Show Dot when No Cursor": "Kursor bo'lmaganda nuqtani ko'rsatish", + "Logging:": "Ro'yxatga olish:", + "Version:": "Versiya:", + "Disconnect": "Ajratish", + "Connect": "Ulanmoq", + "Username:": "Foydalanuvchi nomi:", + "Password:": "Parol:", + "Send Credentials": "Hisob ma'lumotlarini yuborish", + "Cancel": "Bekor qilish", + "Keys": "Kalitlar", + "Game Cursor Mode": "O'yin kursori rejimi", + "Press Esc Key to Exit Pointer Lock Mode": "Ko'rsatkichni blokirovka qilish rejimidan chiqish uchun Esc tugmasini bosing", + "Game Mode paused, click on screen to resume Game Mode.": "O'yin rejimi to'xtatildi, o'yin rejimini davom ettirish uchun ekranni bosing.", + "Clipboard Up": "Bufer yuqoriga", + "CLipboard Down": "Klipboard pastga", + "Clipboard Seamless": "Clipboard uzluksiz", + "Prefer Local Cursor": "Mahalliy kursorni afzal ko'ring", + "Translate keyboard shortcuts": "Klaviatura yorliqlarini tarjima qilish", + "Enable WebRTC UDP Transit": "WebRTC UDP tranzitini yoqish", + "Enable WebP Compression": "WebP siqishni yoqish", + "Enable Performance Stats": "Umumiylik statistikasini yoqish", + "Enable Pointer Lock": "Ko'rsatkich blokini yoqish", + "IME Input Mode": "IME kiritish rejimi", + "Show Virtual Keyboard Control": "Virtual klaviatura boshqaruvini ko'rsatish", + "Toggle Control Panel via Keystrokes": "Boshqarish panelini tugmachalarni bosish orqali almashtirish", + "Render Native Resolution": "Native rezolyutsiyani ko'rsatish", + "Keyboard Shortcuts": "Klaviatura yorliqlari", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC klaviatura yorliqlarini yoqish", + "1 - Toggle Control Panel": "1 - Boshqaruv panelini almashtirish", + "2 - Toggle Game Pointer Mode": "2 - o'yin ko'rsatkichi rejimini almashtirish", + "3 - Toggle Pointer Lock": "3 - Pointer qulfini almashtirish", + "Stream Quality": "Oqim sifati", + "Preset Modes:": "Oldindan o'rnatilgan rejimlar:", + "Static": "Statik", + "Low": "past", + "Medium": "O'rta", + "High": "Yuqori", + "Extreme": "Ekstremal", + "Lossless": "Yo'qotishsiz", + "Custom": "Maxsus", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Avto dinamik", + "Off": "O'chirilgan", + "On": "yoqilgan", + "Dynamic Quality Min:": "Dinamik sifat minimal:", + "Dynamic Quality Max:": "Maksimum dinamik sifat:", + "Treat Lossless:": "Yo'qotmasdan davolang:", + "Frame Rate:": "Kadr tezligi:", + "Video JPEG Quality:": "Video JPEG sifati:", + "Video WEBP Quality:": "Video WEBP sifati:", + "Video Area:": "Video maydoni:", + "Video Time:": "Video vaqti:", + "Video Out Time:": "Video chiqish vaqti:", + "Video Mode Width:": "Video rejimining kengligi:", + "Video Mode Height:": "Video rejimi balandligi:", + "Documentation": "Hujjatlar", + "Drag Viewport": "Ko'rish oynasini sudrab olib boring", + "KasmVNC encountered an error:": "KasmVNC xatolikka duch keldi:" +} \ No newline at end of file diff --git a/app/locale/uz_UZ.json b/app/locale/uz_UZ.json new file mode 100644 index 0000000..ce7f7b6 --- /dev/null +++ b/app/locale/uz_UZ.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Ulanilmoqda...", + "Disconnecting...": "Uzilish uzilmoqda...", + "Reconnecting...": "Qayta ulanmoqda...", + "Internal error": "Ichki xato", + "Must set host": "Xostni sozlash kerak", + "Connected (encrypted) to ": "Ulangan (shifrlangan)", + "Connected (unencrypted) to ": "Ulangan (shifrlanmagan)", + "Something went wrong, connection is closed": "Nimadir xato ketdi, ulanish yopildi", + "Failed to connect to server": "Serverga ulanib bo'lmadi", + "Disconnected": "Uzilgan", + "New connection has been rejected with reason: ": "Yangi ulanish sabab bilan rad etildi:", + "New connection has been rejected": "Yangi ulanish rad etildi", + "Credentials are required": "Hisob ma'lumotlari talab qilinadi", + "Hide/Show the control bar": "Boshqaruv panelini yashirish/ko'rsatish", + "Drag": "Tartib tashlang", + "Move/Drag Viewport": "Ko'rish maydonini ko'chirish/tortish", + "Keyboard": "Klaviatura", + "Show Keyboard": "Klaviaturani ko'rsatish", + "Extra keys": "Qo'shimcha kalitlar", + "Show Extra Keys": "Qo'shimcha kalitlarni ko'rsatish", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Ctrl tugmachasini o'zgartirish", + "Alt": "Alt", + "Toggle Alt": "Alt tugmachasini o'zgartirish", + "Toggle Windows": "Windows-ni almashtirish", + "Windows": "Windows", + "Send Tab": "Yuborish yorlig'i", + "Tab": "tab", + "Esc": "Esc", + "Send Escape": "Qochishni yuborish", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del-ni yuborish", + "Shutdown/Reboot": "O'chirish/qayta yuklash", + "Shutdown/Reboot...": "O'chirish/qayta yuklash...", + "Power": "Kuch", + "Shutdown": "O'chirish; yopish", + "Reboot": "Qayta ishga tushirish", + "Reset": "Qayta o'rnatish", + "Clipboard": "Bufer yozuvi", + "Clear": "Tozalash", + "Fullscreen": "To'liq ekran", + "Settings": "Sozlamalar", + "Shared Mode": "Umumiy rejim", + "View Only": "Faqat ko'rish", + "Clip to Window": "Oynaga klip", + "Scaling Mode:": "Majshlash rejimi:", + "None": "Yo'q", + "Local Scaling": "Mahalliy o'lchov", + "Remote Resizing": "Masofaviy o'lchamni o'zgartirish", + "Advanced": "Kengaytirilgan", + "Quality:": "Sifat:", + "Compression level:": "Siqish darajasi:", + "Repeater ID:": "Takrorlovchi identifikatori:", + "WebSocket": "WebSocket", + "Encrypt": "shifrlash", + "Host:": "Mezbon:", + "Port:": "Port:", + "Path:": "Yo'l:", + "Automatic Reconnect": "Avtomatik qayta ulanish", + "Reconnect Delay (ms):": "Qayta ulanish kechikishi (ms):", + "Show Dot when No Cursor": "Kursor bo'lmaganda nuqtani ko'rsatish", + "Logging:": "Ro'yxatga olish:", + "Version:": "Versiya:", + "Disconnect": "Ajratish", + "Connect": "Ulanmoq", + "Username:": "Foydalanuvchi nomi:", + "Password:": "Parol:", + "Send Credentials": "Hisob ma'lumotlarini yuborish", + "Cancel": "Bekor qilish", + "Keys": "Kalitlar", + "Game Cursor Mode": "O'yin kursori rejimi", + "Press Esc Key to Exit Pointer Lock Mode": "Ko'rsatkichni blokirovka qilish rejimidan chiqish uchun Esc tugmasini bosing", + "Game Mode paused, click on screen to resume Game Mode.": "O'yin rejimi to'xtatildi, o'yin rejimini davom ettirish uchun ekranni bosing.", + "Clipboard Up": "Bufer yuqoriga", + "CLipboard Down": "Klipboard pastga", + "Clipboard Seamless": "Clipboard uzluksiz", + "Prefer Local Cursor": "Mahalliy kursorni afzal ko'ring", + "Translate keyboard shortcuts": "Klaviatura yorliqlarini tarjima qilish", + "Enable WebRTC UDP Transit": "WebRTC UDP tranzitini yoqish", + "Enable WebP Compression": "WebP siqishni yoqish", + "Enable Performance Stats": "Umumiylik statistikasini yoqish", + "Enable Pointer Lock": "Ko'rsatkich blokini yoqish", + "IME Input Mode": "IME kiritish rejimi", + "Show Virtual Keyboard Control": "Virtual klaviatura boshqaruvini ko'rsatish", + "Toggle Control Panel via Keystrokes": "Boshqarish panelini tugmachalarni bosish orqali almashtirish", + "Render Native Resolution": "Native rezolyutsiyani ko'rsatish", + "Keyboard Shortcuts": "Klaviatura yorliqlari", + "Enable KasmVNC Keyboard Shortcuts": "KasmVNC klaviatura yorliqlarini yoqish", + "1 - Toggle Control Panel": "1 - Boshqaruv panelini almashtirish", + "2 - Toggle Game Pointer Mode": "2 - o'yin ko'rsatkichi rejimini almashtirish", + "3 - Toggle Pointer Lock": "3 - Pointer qulfini almashtirish", + "Stream Quality": "Oqim sifati", + "Preset Modes:": "Oldindan o'rnatilgan rejimlar:", + "Static": "Statik", + "Low": "past", + "Medium": "O'rta", + "High": "Yuqori", + "Extreme": "Ekstremal", + "Lossless": "Yo'qotishsiz", + "Custom": "Maxsus", + "Anti-Aliasing:": "Anti-aliasing:", + "Auto Dynamic": "Avto dinamik", + "Off": "O'chirilgan", + "On": "yoqilgan", + "Dynamic Quality Min:": "Dinamik sifat minimal:", + "Dynamic Quality Max:": "Maksimum dinamik sifat:", + "Treat Lossless:": "Yo'qotmasdan davolang:", + "Frame Rate:": "Kadr tezligi:", + "Video JPEG Quality:": "Video JPEG sifati:", + "Video WEBP Quality:": "Video WEBP sifati:", + "Video Area:": "Video maydoni:", + "Video Time:": "Video vaqti:", + "Video Out Time:": "Video chiqish vaqti:", + "Video Mode Width:": "Video rejimining kengligi:", + "Video Mode Height:": "Video rejimi balandligi:", + "Documentation": "Hujjatlar", + "Drag Viewport": "Ko'rish oynasini sudrab olib boring", + "KasmVNC encountered an error:": "KasmVNC xatolikka duch keldi:" +} \ No newline at end of file diff --git a/app/locale/vi.json b/app/locale/vi.json new file mode 100644 index 0000000..a2c2c84 --- /dev/null +++ b/app/locale/vi.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Đang kết nối...", + "Disconnecting...": "Ngắt kết nối...", + "Reconnecting...": "Kết nối lại...", + "Internal error": "Lỗi bên trong", + "Must set host": "Phải đặt máy chủ", + "Connected (encrypted) to ": "Đã kết nối (được mã hóa) với", + "Connected (unencrypted) to ": "Đã kết nối (không được mã hóa) với", + "Something went wrong, connection is closed": "Đã xảy ra sự cố, kết nối bị ngắt", + "Failed to connect to server": "Kết nối thất bại", + "Disconnected": "Đã ngắt kết nối", + "New connection has been rejected with reason: ": "Kết nối mới đã bị từ chối với lý do:", + "New connection has been rejected": "Kết nối mới đã bị từ chối", + "Credentials are required": "Bằng chứng được yêu cầu", + "Hide/Show the control bar": "Ẩn/Hiện thanh điều khiển", + "Drag": "Lôi kéo", + "Move/Drag Viewport": "Di chuyển/Kéo cổng xem", + "Keyboard": "bàn phím", + "Show Keyboard": "Hiển thị bàn phím", + "Extra keys": "Chìa khóa phụ", + "Show Extra Keys": "Hiển thị các phím phụ", + "Ctrl": "Điều khiển", + "Toggle Ctrl": "Chuyển đổi Ctrl", + "Alt": "thay thế", + "Toggle Alt": "Chuyển đổi Alt", + "Toggle Windows": "Chuyển đổi Windows", + "Windows": "Các cửa sổ", + "Send Tab": "Gửi thẻ", + "Tab": "Chuyển hướng", + "Esc": "Thoát ra", + "Send Escape": "Gửi lối thoát", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Gửi Ctrl-Alt-Del", + "Shutdown/Reboot": "Tắt máy/Khởi động lại", + "Shutdown/Reboot...": "Tắt máy/Khởi động lại...", + "Power": "Quyền lực", + "Shutdown": "Tắt", + "Reboot": "Khởi động lại", + "Reset": "Cài lại", + "Clipboard": "Khay nhớ tạm", + "Clear": "Thông thoáng", + "Fullscreen": "Toàn màn hình", + "Settings": "Cài đặt", + "Shared Mode": "Chế độ chia sẻ", + "View Only": "Chỉ xem", + "Clip to Window": "Kẹp vào cửa sổ", + "Scaling Mode:": "Chế độ mở rộng quy mô:", + "None": "Không có", + "Local Scaling": "Quy mô cục bộ", + "Remote Resizing": "Thay đổi kích thước từ xa", + "Advanced": "Trình độ cao", + "Quality:": "Chất lượng:", + "Compression level:": "Mức độ nén:", + "Repeater ID:": "ID bộ lặp:", + "WebSocket": "Ổ cắm Web", + "Encrypt": "Mã hóa", + "Host:": "Chủ nhà:", + "Port:": "Hải cảng:", + "Path:": "Con đường:", + "Automatic Reconnect": "Tự động kết nối lại", + "Reconnect Delay (ms):": "Trễ kết nối lại (ms):", + "Show Dot when No Cursor": "Hiển thị dấu chấm khi không có con trỏ", + "Logging:": "Ghi nhật ký:", + "Version:": "Phiên bản:", + "Disconnect": "Ngắt kết nối", + "Connect": "Kết nối", + "Username:": "Tên tài khoản:", + "Password:": "Mật khẩu:", + "Send Credentials": "Gửi thông tin xác thực", + "Cancel": "Hủy bỏ", + "Keys": "Chìa khóa", + "Game Cursor Mode": "Chế độ con trỏ trò chơi", + "Press Esc Key to Exit Pointer Lock Mode": "Nhấn phím Esc để thoát chế độ khóa con trỏ", + "Game Mode paused, click on screen to resume Game Mode.": "Chế độ Trò chơi đã tạm dừng, nhấp vào màn hình để tiếp tục Chế độ Trò chơi.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Xuống Clipboard", + "Clipboard Seamless": "Clipboard liền mạch", + "Prefer Local Cursor": "Ưu tiên con trỏ cục bộ", + "Translate keyboard shortcuts": "Dịch phím tắt", + "Enable WebRTC UDP Transit": "Bật Chuyển tuyến UDP WebRTC", + "Enable WebP Compression": "Kích hoạt tính năng nén WebP", + "Enable Performance Stats": "Bật thống kê hiệu suất", + "Enable Pointer Lock": "Kích hoạt khóa con trỏ", + "IME Input Mode": "Chế độ nhập IME", + "Show Virtual Keyboard Control": "Hiển thị điều khiển bàn phím ảo", + "Toggle Control Panel via Keystrokes": "Chuyển đổi Bảng điều khiển thông qua tổ hợp phím", + "Render Native Resolution": "Kết xuất độ phân giải gốc", + "Keyboard Shortcuts": "Các phím tắt bàn phím", + "Enable KasmVNC Keyboard Shortcuts": "Bật phím tắt KasmVNC", + "1 - Toggle Control Panel": "1 - Chuyển đổi bảng điều khiển", + "2 - Toggle Game Pointer Mode": "2 - Chuyển đổi chế độ con trỏ trò chơi", + "3 - Toggle Pointer Lock": "3 - Chuyển đổi khóa con trỏ", + "Stream Quality": "Chất lượng luồng", + "Preset Modes:": "Chế độ cài sẵn:", + "Static": "Tĩnh", + "Low": "Thấp", + "Medium": "Trung bình", + "High": "Cao", + "Extreme": "Vô cùng", + "Lossless": "Không mất mát", + "Custom": "Phong tục", + "Anti-Aliasing:": "Chống răng cưa:", + "Auto Dynamic": "Tự động động", + "Off": "Tắt", + "On": "TRÊN", + "Dynamic Quality Min:": "Chất lượng động tối thiểu:", + "Dynamic Quality Max:": "Tối đa chất lượng động:", + "Treat Lossless:": "Điều trị Lossless:", + "Frame Rate:": "Tỷ lệ khung hình:", + "Video JPEG Quality:": "Chất lượng JPEG của video:", + "Video WEBP Quality:": "Chất lượng WEBP video:", + "Video Area:": "Khu vực video:", + "Video Time:": "Thời gian quay video:", + "Video Out Time:": "Thời gian phát video:", + "Video Mode Width:": "Chiều rộng chế độ video:", + "Video Mode Height:": "Chiều cao chế độ video:", + "Documentation": "Tài liệu", + "Drag Viewport": "Kéo khung nhìn", + "KasmVNC encountered an error:": "KasmVNC gặp lỗi:" +} \ No newline at end of file diff --git a/app/locale/vi_VN.json b/app/locale/vi_VN.json new file mode 100644 index 0000000..a2c2c84 --- /dev/null +++ b/app/locale/vi_VN.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Đang kết nối...", + "Disconnecting...": "Ngắt kết nối...", + "Reconnecting...": "Kết nối lại...", + "Internal error": "Lỗi bên trong", + "Must set host": "Phải đặt máy chủ", + "Connected (encrypted) to ": "Đã kết nối (được mã hóa) với", + "Connected (unencrypted) to ": "Đã kết nối (không được mã hóa) với", + "Something went wrong, connection is closed": "Đã xảy ra sự cố, kết nối bị ngắt", + "Failed to connect to server": "Kết nối thất bại", + "Disconnected": "Đã ngắt kết nối", + "New connection has been rejected with reason: ": "Kết nối mới đã bị từ chối với lý do:", + "New connection has been rejected": "Kết nối mới đã bị từ chối", + "Credentials are required": "Bằng chứng được yêu cầu", + "Hide/Show the control bar": "Ẩn/Hiện thanh điều khiển", + "Drag": "Lôi kéo", + "Move/Drag Viewport": "Di chuyển/Kéo cổng xem", + "Keyboard": "bàn phím", + "Show Keyboard": "Hiển thị bàn phím", + "Extra keys": "Chìa khóa phụ", + "Show Extra Keys": "Hiển thị các phím phụ", + "Ctrl": "Điều khiển", + "Toggle Ctrl": "Chuyển đổi Ctrl", + "Alt": "thay thế", + "Toggle Alt": "Chuyển đổi Alt", + "Toggle Windows": "Chuyển đổi Windows", + "Windows": "Các cửa sổ", + "Send Tab": "Gửi thẻ", + "Tab": "Chuyển hướng", + "Esc": "Thoát ra", + "Send Escape": "Gửi lối thoát", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Gửi Ctrl-Alt-Del", + "Shutdown/Reboot": "Tắt máy/Khởi động lại", + "Shutdown/Reboot...": "Tắt máy/Khởi động lại...", + "Power": "Quyền lực", + "Shutdown": "Tắt", + "Reboot": "Khởi động lại", + "Reset": "Cài lại", + "Clipboard": "Khay nhớ tạm", + "Clear": "Thông thoáng", + "Fullscreen": "Toàn màn hình", + "Settings": "Cài đặt", + "Shared Mode": "Chế độ chia sẻ", + "View Only": "Chỉ xem", + "Clip to Window": "Kẹp vào cửa sổ", + "Scaling Mode:": "Chế độ mở rộng quy mô:", + "None": "Không có", + "Local Scaling": "Quy mô cục bộ", + "Remote Resizing": "Thay đổi kích thước từ xa", + "Advanced": "Trình độ cao", + "Quality:": "Chất lượng:", + "Compression level:": "Mức độ nén:", + "Repeater ID:": "ID bộ lặp:", + "WebSocket": "Ổ cắm Web", + "Encrypt": "Mã hóa", + "Host:": "Chủ nhà:", + "Port:": "Hải cảng:", + "Path:": "Con đường:", + "Automatic Reconnect": "Tự động kết nối lại", + "Reconnect Delay (ms):": "Trễ kết nối lại (ms):", + "Show Dot when No Cursor": "Hiển thị dấu chấm khi không có con trỏ", + "Logging:": "Ghi nhật ký:", + "Version:": "Phiên bản:", + "Disconnect": "Ngắt kết nối", + "Connect": "Kết nối", + "Username:": "Tên tài khoản:", + "Password:": "Mật khẩu:", + "Send Credentials": "Gửi thông tin xác thực", + "Cancel": "Hủy bỏ", + "Keys": "Chìa khóa", + "Game Cursor Mode": "Chế độ con trỏ trò chơi", + "Press Esc Key to Exit Pointer Lock Mode": "Nhấn phím Esc để thoát chế độ khóa con trỏ", + "Game Mode paused, click on screen to resume Game Mode.": "Chế độ Trò chơi đã tạm dừng, nhấp vào màn hình để tiếp tục Chế độ Trò chơi.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Xuống Clipboard", + "Clipboard Seamless": "Clipboard liền mạch", + "Prefer Local Cursor": "Ưu tiên con trỏ cục bộ", + "Translate keyboard shortcuts": "Dịch phím tắt", + "Enable WebRTC UDP Transit": "Bật Chuyển tuyến UDP WebRTC", + "Enable WebP Compression": "Kích hoạt tính năng nén WebP", + "Enable Performance Stats": "Bật thống kê hiệu suất", + "Enable Pointer Lock": "Kích hoạt khóa con trỏ", + "IME Input Mode": "Chế độ nhập IME", + "Show Virtual Keyboard Control": "Hiển thị điều khiển bàn phím ảo", + "Toggle Control Panel via Keystrokes": "Chuyển đổi Bảng điều khiển thông qua tổ hợp phím", + "Render Native Resolution": "Kết xuất độ phân giải gốc", + "Keyboard Shortcuts": "Các phím tắt bàn phím", + "Enable KasmVNC Keyboard Shortcuts": "Bật phím tắt KasmVNC", + "1 - Toggle Control Panel": "1 - Chuyển đổi bảng điều khiển", + "2 - Toggle Game Pointer Mode": "2 - Chuyển đổi chế độ con trỏ trò chơi", + "3 - Toggle Pointer Lock": "3 - Chuyển đổi khóa con trỏ", + "Stream Quality": "Chất lượng luồng", + "Preset Modes:": "Chế độ cài sẵn:", + "Static": "Tĩnh", + "Low": "Thấp", + "Medium": "Trung bình", + "High": "Cao", + "Extreme": "Vô cùng", + "Lossless": "Không mất mát", + "Custom": "Phong tục", + "Anti-Aliasing:": "Chống răng cưa:", + "Auto Dynamic": "Tự động động", + "Off": "Tắt", + "On": "TRÊN", + "Dynamic Quality Min:": "Chất lượng động tối thiểu:", + "Dynamic Quality Max:": "Tối đa chất lượng động:", + "Treat Lossless:": "Điều trị Lossless:", + "Frame Rate:": "Tỷ lệ khung hình:", + "Video JPEG Quality:": "Chất lượng JPEG của video:", + "Video WEBP Quality:": "Chất lượng WEBP video:", + "Video Area:": "Khu vực video:", + "Video Time:": "Thời gian quay video:", + "Video Out Time:": "Thời gian phát video:", + "Video Mode Width:": "Chiều rộng chế độ video:", + "Video Mode Height:": "Chiều cao chế độ video:", + "Documentation": "Tài liệu", + "Drag Viewport": "Kéo khung nhìn", + "KasmVNC encountered an error:": "KasmVNC gặp lỗi:" +} \ No newline at end of file diff --git a/app/locale/xh.json b/app/locale/xh.json new file mode 100644 index 0000000..ae4e5bd --- /dev/null +++ b/app/locale/xh.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Idibanisa...", + "Disconnecting...": "Iyaqhawulwa...", + "Reconnecting...": "Iqhagamshela kwakhona...", + "Internal error": "Impazamo yangaphakathi", + "Must set host": "Kufuneka usete umamkeli", + "Connected (encrypted) to ": "Iqhagamshelwe (ifihliwe) ukuya ", + "Connected (unencrypted) to ": "Iqhagamshelwe (engafihlwanga) ku ", + "Something went wrong, connection is closed": "Ikhona into engalunganga, unxibelelwano luvaliwe", + "Failed to connect to server": "Ayiphumelelanga ukudibanisa kwiseva", + "Disconnected": "Iqhawulwe", + "New connection has been rejected with reason: ": "Unxibelelwano olutsha lwaliwe ngesizathu: ", + "New connection has been rejected": "Uqhagamshelwano olutsha lwaliwe", + "Credentials are required": "Iziqinisekiso ziyafuneka", + "Hide/Show the control bar": "Fihla / Bonisa ibha yokulawula", + "Drag": "Thamba", + "Move/Drag Viewport": "Hambisa/ Tsala izibuko lokujonga", + "Keyboard": "Ikhibhodi", + "Show Keyboard": "Bonisa ikhibhodi", + "Extra keys": "Izitshixo ezongezelelweyo", + "Show Extra Keys": "Bonisa amaqhosha awongezelelweyo", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Qinisekisa uCtrl", + "Alt": "Alt", + "Toggle Alt": "Guqula i-Alt", + "Toggle Windows": "Guqula iiWindows", + "Windows": "IiWindows", + "Send Tab": "Thumela iTab", + "Tab": "Ithebhu", + "Esc": "I-Esc", + "Send Escape": "Thumela Ukubaleka", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Thumela i-Ctrl-Alt-Del", + "Shutdown/Reboot": "Cima / uqalise kwakhona", + "Shutdown/Reboot...": "Cima / uqalise kwakhona...", + "Power": "Amandla", + "Shutdown": "Cima", + "Reboot": "Qalisa kwakhona", + "Reset": "Seta kwakhona", + "Clipboard": "Ibhodi eqhotyoshwayo", + "Clear": "Sula", + "Fullscreen": "Isikrini esiphelele", + "Settings": "Iisetingi", + "Shared Mode": "Imo ekwabelwana ngayo", + "View Only": "Jonga Kuphela", + "Clip to Window": "Clipha kwifestile", + "Scaling Mode:": "Indlela Yokukala:", + "None": "Akukho", + "Local Scaling": "Ukukala kwendawo", + "Remote Resizing": "Ukwandiswa kweRemote", + "Advanced": "Advanced", + "Quality:": "Umgangatho:", + "Compression level:": "Inqanaba loxinzelelo:", + "Repeater ID:": "I-ID yoMphindi:", + "WebSocket": "WebSocket", + "Encrypt": "Shicilela", + "Host:": "Umamkeli:", + "Port:": "Bhayi:", + "Path:": "Indlela:", + "Automatic Reconnect": "Qhagamshela kwakhona ngokuzenzekelayo", + "Reconnect Delay (ms):": "Qhagamshela kwakhona ulibaziseko (ms):", + "Show Dot when No Cursor": "Bonisa ichaphaza xa kungekho salathisi", + "Logging:": "Ukugawula:", + "Version:": "Uguqulelo:", + "Disconnect": "Nqamula", + "Connect": "Qhagamshela", + "Username:": "Igama lomsebenzisi:", + "Password:": "Inombolo yokuvula:", + "Send Credentials": "Thumela iiNkcazo", + "Cancel": "Rhoxisa", + "Keys": "Izitshixo", + "Game Cursor Mode": "Imowudi yeSikhesa soMdlalo", + "Press Esc Key to Exit Pointer Lock Mode": "Cofa iSitshixo sika-Esc ukuze uphume kwiNdlela yokutshixa isalathisi", + "Game Mode paused, click on screen to resume Game Mode.": "Imo yomdlalo imisiwe, cofa kwiscreen ukuze uqalise iMowudi yoMdlalo.", + "Clipboard Up": "Ibhodi eqhotyoshwayo phezulu", + "CLipboard Down": "Clipboard Phantsi", + "Clipboard Seamless": "I-Clipboard ayinamthungo", + "Prefer Local Cursor": "Khetha isalathisi salapha", + "Translate keyboard shortcuts": "Tolika iindlela ezimfutshane zebhodibhodi", + "Enable WebRTC UDP Transit": "Vula i-WebRTC UDP Transit", + "Enable WebP Compression": "Vumela iWebP Compression", + "Enable Performance Stats": "Vula izibalo zokuSebenza", + "Enable Pointer Lock": "Vula isitshixo sesalathiso", + "IME Input Mode": "IME Imo yokuNgena", + "Show Virtual Keyboard Control": "Bonisa Ulawulo lwekhibhodi ye-Virtual", + "Toggle Control Panel via Keystrokes": "Guqula iPhaneli yoLawulo ngokusebenzisa ii-keystrokes", + "Render Native Resolution": "Nikela iSigqibo seNdawo", + "Keyboard Shortcuts": "Iindlela ezimfutshane zekhibhodi", + "Enable KasmVNC Keyboard Shortcuts": "Yenza i-KasmVNC Iindlela ezimfutshane zekhibhodi", + "1 - Toggle Control Panel": "1-Guqula iPhaneli yoLawulo", + "2 - Toggle Game Pointer Mode": "2-Guqula iMowudi yesikhombisi somdlalo", + "3 - Toggle Pointer Lock": "3-Guqula isitshixo sesalathisi", + "Stream Quality": "Umgangatho wokusasaza", + "Preset Modes:": "Iindlela zokuSeta kwangaphambili:", + "Static": "I-static", + "Low": "Phantsi", + "Medium": "Phakathi", + "High": "Phezulu", + "Extreme": "Kakhulu", + "Lossless": "Ilahleko", + "Custom": "Custom", + "Anti-Aliasing:": "Okungadibananga nokuthethathethana:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Cima", + "On": "Vula", + "Dynamic Quality Min:": "uMgangatho oNcincisayo:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Phatha iLassless:", + "Frame Rate:": "Umgangatho wefreyimu:", + "Video JPEG Quality:": "Umgangatho weJPEG wevidiyo:", + "Video WEBP Quality:": "Umgangatho we-WEBP yevidiyo:", + "Video Area:": "Indawo yeVidiyo:", + "Video Time:": "Ixesha leVidiyo:", + "Video Out Time:": "Ixesha lokuphuma kwevidiyo:", + "Video Mode Width:": "Ububanzi beModi yeVidiyo:", + "Video Mode Height:": "Ubude beModi yeVidiyo:", + "Documentation": "Amaxwebhu", + "Drag Viewport": "Thatha indawo yokujonga", + "KasmVNC encountered an error:": "I-KasmVNC ifumene impazamo:" +} \ No newline at end of file diff --git a/app/locale/xh_ZA.json b/app/locale/xh_ZA.json new file mode 100644 index 0000000..ae4e5bd --- /dev/null +++ b/app/locale/xh_ZA.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Idibanisa...", + "Disconnecting...": "Iyaqhawulwa...", + "Reconnecting...": "Iqhagamshela kwakhona...", + "Internal error": "Impazamo yangaphakathi", + "Must set host": "Kufuneka usete umamkeli", + "Connected (encrypted) to ": "Iqhagamshelwe (ifihliwe) ukuya ", + "Connected (unencrypted) to ": "Iqhagamshelwe (engafihlwanga) ku ", + "Something went wrong, connection is closed": "Ikhona into engalunganga, unxibelelwano luvaliwe", + "Failed to connect to server": "Ayiphumelelanga ukudibanisa kwiseva", + "Disconnected": "Iqhawulwe", + "New connection has been rejected with reason: ": "Unxibelelwano olutsha lwaliwe ngesizathu: ", + "New connection has been rejected": "Uqhagamshelwano olutsha lwaliwe", + "Credentials are required": "Iziqinisekiso ziyafuneka", + "Hide/Show the control bar": "Fihla / Bonisa ibha yokulawula", + "Drag": "Thamba", + "Move/Drag Viewport": "Hambisa/ Tsala izibuko lokujonga", + "Keyboard": "Ikhibhodi", + "Show Keyboard": "Bonisa ikhibhodi", + "Extra keys": "Izitshixo ezongezelelweyo", + "Show Extra Keys": "Bonisa amaqhosha awongezelelweyo", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Qinisekisa uCtrl", + "Alt": "Alt", + "Toggle Alt": "Guqula i-Alt", + "Toggle Windows": "Guqula iiWindows", + "Windows": "IiWindows", + "Send Tab": "Thumela iTab", + "Tab": "Ithebhu", + "Esc": "I-Esc", + "Send Escape": "Thumela Ukubaleka", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Thumela i-Ctrl-Alt-Del", + "Shutdown/Reboot": "Cima / uqalise kwakhona", + "Shutdown/Reboot...": "Cima / uqalise kwakhona...", + "Power": "Amandla", + "Shutdown": "Cima", + "Reboot": "Qalisa kwakhona", + "Reset": "Seta kwakhona", + "Clipboard": "Ibhodi eqhotyoshwayo", + "Clear": "Sula", + "Fullscreen": "Isikrini esiphelele", + "Settings": "Iisetingi", + "Shared Mode": "Imo ekwabelwana ngayo", + "View Only": "Jonga Kuphela", + "Clip to Window": "Clipha kwifestile", + "Scaling Mode:": "Indlela Yokukala:", + "None": "Akukho", + "Local Scaling": "Ukukala kwendawo", + "Remote Resizing": "Ukwandiswa kweRemote", + "Advanced": "Advanced", + "Quality:": "Umgangatho:", + "Compression level:": "Inqanaba loxinzelelo:", + "Repeater ID:": "I-ID yoMphindi:", + "WebSocket": "WebSocket", + "Encrypt": "Shicilela", + "Host:": "Umamkeli:", + "Port:": "Bhayi:", + "Path:": "Indlela:", + "Automatic Reconnect": "Qhagamshela kwakhona ngokuzenzekelayo", + "Reconnect Delay (ms):": "Qhagamshela kwakhona ulibaziseko (ms):", + "Show Dot when No Cursor": "Bonisa ichaphaza xa kungekho salathisi", + "Logging:": "Ukugawula:", + "Version:": "Uguqulelo:", + "Disconnect": "Nqamula", + "Connect": "Qhagamshela", + "Username:": "Igama lomsebenzisi:", + "Password:": "Inombolo yokuvula:", + "Send Credentials": "Thumela iiNkcazo", + "Cancel": "Rhoxisa", + "Keys": "Izitshixo", + "Game Cursor Mode": "Imowudi yeSikhesa soMdlalo", + "Press Esc Key to Exit Pointer Lock Mode": "Cofa iSitshixo sika-Esc ukuze uphume kwiNdlela yokutshixa isalathisi", + "Game Mode paused, click on screen to resume Game Mode.": "Imo yomdlalo imisiwe, cofa kwiscreen ukuze uqalise iMowudi yoMdlalo.", + "Clipboard Up": "Ibhodi eqhotyoshwayo phezulu", + "CLipboard Down": "Clipboard Phantsi", + "Clipboard Seamless": "I-Clipboard ayinamthungo", + "Prefer Local Cursor": "Khetha isalathisi salapha", + "Translate keyboard shortcuts": "Tolika iindlela ezimfutshane zebhodibhodi", + "Enable WebRTC UDP Transit": "Vula i-WebRTC UDP Transit", + "Enable WebP Compression": "Vumela iWebP Compression", + "Enable Performance Stats": "Vula izibalo zokuSebenza", + "Enable Pointer Lock": "Vula isitshixo sesalathiso", + "IME Input Mode": "IME Imo yokuNgena", + "Show Virtual Keyboard Control": "Bonisa Ulawulo lwekhibhodi ye-Virtual", + "Toggle Control Panel via Keystrokes": "Guqula iPhaneli yoLawulo ngokusebenzisa ii-keystrokes", + "Render Native Resolution": "Nikela iSigqibo seNdawo", + "Keyboard Shortcuts": "Iindlela ezimfutshane zekhibhodi", + "Enable KasmVNC Keyboard Shortcuts": "Yenza i-KasmVNC Iindlela ezimfutshane zekhibhodi", + "1 - Toggle Control Panel": "1-Guqula iPhaneli yoLawulo", + "2 - Toggle Game Pointer Mode": "2-Guqula iMowudi yesikhombisi somdlalo", + "3 - Toggle Pointer Lock": "3-Guqula isitshixo sesalathisi", + "Stream Quality": "Umgangatho wokusasaza", + "Preset Modes:": "Iindlela zokuSeta kwangaphambili:", + "Static": "I-static", + "Low": "Phantsi", + "Medium": "Phakathi", + "High": "Phezulu", + "Extreme": "Kakhulu", + "Lossless": "Ilahleko", + "Custom": "Custom", + "Anti-Aliasing:": "Okungadibananga nokuthethathethana:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Cima", + "On": "Vula", + "Dynamic Quality Min:": "uMgangatho oNcincisayo:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Phatha iLassless:", + "Frame Rate:": "Umgangatho wefreyimu:", + "Video JPEG Quality:": "Umgangatho weJPEG wevidiyo:", + "Video WEBP Quality:": "Umgangatho we-WEBP yevidiyo:", + "Video Area:": "Indawo yeVidiyo:", + "Video Time:": "Ixesha leVidiyo:", + "Video Out Time:": "Ixesha lokuphuma kwevidiyo:", + "Video Mode Width:": "Ububanzi beModi yeVidiyo:", + "Video Mode Height:": "Ubude beModi yeVidiyo:", + "Documentation": "Amaxwebhu", + "Drag Viewport": "Thatha indawo yokujonga", + "KasmVNC encountered an error:": "I-KasmVNC ifumene impazamo:" +} \ No newline at end of file diff --git a/app/locale/yi.json b/app/locale/yi.json new file mode 100644 index 0000000..47270f2 --- /dev/null +++ b/app/locale/yi.json @@ -0,0 +1,120 @@ +{ + "Connecting...": " ןדניבראַפ", + "Disconnecting...": " גניטקענאַקסיד", + "Reconnecting...": " גניטקענאַקיר", + "Internal error": "תועט ךעלרעני", + "Must set host": "סאָבעלאַב ןלעטש ןזומ", + "Connected (encrypted) to ": "וצ (דיטפּירקנע) ןדנובראפ", + "Connected (unencrypted) to ": "וצ (דיטפּירקנענאַ) ןדנובראפ", + "Something went wrong, connection is closed": "טכאמראפ זיא רשק יד ,שלאַפ זיא סעפּע", + "Failed to connect to server": "רעוורעס וצ ןדניבראַפ וצ שרעדנאַ טינ", + "Disconnected": "דיטקענאַקסיד", + "New connection has been rejected with reason: ": "הביס טימ ןפראווראפ זיא רשק עיַינ", + "New connection has been rejected": "ןפראווראפ זיא רשק עיַינ", + "Credentials are required": "טגנאלראפ ןענעז זלאַשנעדערק", + "Hide/Show the control bar": "ראַב לאָרטנאָק יד ןזיַיוו / ןטלאַהאַב", + "Drag": "ןפּעלש", + "Move/Drag Viewport": "טראָפּויוו ןפּעלש / ךאַמ", + "Keyboard": "דראביק", + "Show Keyboard": "רוטאַיוואַלק ןזיַיוו", + "Extra keys": "ןעלסילש ערטסקע", + "Show Extra Keys": "ןעלסילש ערטסקע ןזיַיוו", + "Ctrl": "Ctrl", + "Toggle Ctrl": "לרטק ךאַמ", + "Alt": "טלא", + "Toggle Alt": "טלאַ ןדער", + "Toggle Windows": "רעטצנעפֿ ןכאַמ", + "Windows": "זואָדניוו", + "Send Tab": "לטיווק ןקיש", + "Tab": "באט", + "Esc": "קסע", + "Send Escape": "ןפיולטנאַ ןקיש", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ןקיש", + "Shutdown/Reboot": "טאָאָבער / ןואַדטאַש", + "Shutdown/Reboot...": " טאָאָבער / ןואַדטאַש", + "Power": "טפאַרק", + "Shutdown": "ןואַדטאַש", + "Reboot": "טאָאָבער", + "Reset": "קיטעטשאַב", + "Clipboard": "דראָבפּילק", + "Clear": "ראלק", + "Fullscreen": "ןירקס עצנאג", + "Settings": "סגניטטעס", + "Shared Mode": "עדאָמ דרעש", + "View Only": "View זיולב", + "Clip to Window": "רעטצנעפֿ וצ פּילק", + "Scaling Mode:": "עדאָמ גנילאַקס", + "None": "ןייק", + "Local Scaling": "גנילייקס לאַקאָל", + "Remote Resizing": "גניזיסער טיַיוו", + "Advanced": "עטריסנאַוואַ", + "Quality:": "טעטילאַווק", + "Compression level:": "הגרדמ ןאַשערפּמאַק", + "Repeater ID:": "ןיַיש רעטאַעפּער", + "WebSocket": "טעקקאָס בעוו", + "Encrypt": "טפּירקנע", + "Host:": "סאָבעלאַב", + "Port:": "טראָפּ", + "Path:": "ךרד", + "Automatic Reconnect": "טקענאַקיר קיטאַמאַטאָ", + "Reconnect Delay (ms):": "(סמ) ןטלאַהראַפ טקענאַקיר", + "Show Dot when No Cursor": "רעפֿיול ןייק ןעוו טקנופּ ןזיַיוו", + "Logging:": "גניגאָל", + "Version:": "עיסרעוו", + "Disconnect": "טקענאַקסיד", + "Connect": "ןדניבראַפ", + "Username:": "ןעמאָנ רעצינאַב", + "Password:": "טראָווכירפּש", + "Send Credentials": "זלאַשטנעדאַרק ןקיש", + "Cancel": "ןכאַמ לטאָב", + "Keys": "ןעלסילש", + "Game Cursor Mode": "עדאָמ רעפֿיול ליפּש", + "Press Esc Key to Exit Pointer Lock Mode": "עדאָמ קאַל רעטניופּ יד גנאַגסיוראַ וצ Esc Key ןקירד", + "Game Mode paused, click on screen to resume Game Mode.": "עדאָמ ליפּש רעדיוו כיז נעמענ וצ ןלעטשראַפ ףיוא טיג ,דזאָפּ עדאָמ ליפּש", + "Clipboard Up": "ףיוראַ דראָבפּילק", + "CLipboard Down": "פּאָראַ דראָבפּילק", + "Clipboard Seamless": "סאַלמיס דראָבפּילק", + "Prefer Local Cursor": "רעפֿיול עלאקאל רעכליב", + "Translate keyboard shortcuts": "געווכרוד רוטאַיוואַלק ןצעזרעביא", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ןבעג", + "Enable WebP Compression": "ןאַשערפּמאַק פּבעוו ןבעג", + "Enable Performance Stats": "ץאַטס גנולעטשראָפ ןבעג", + "Enable Pointer Lock": "Enable Pointer Lock", + "IME Input Mode": "IME עדאָמ ביַירשניַיראַ", + "Show Virtual Keyboard Control": "לאָרטנאָק רוטאַיוואַלק לאַוטריוו ןזיַיוו", + "Toggle Control Panel via Keystrokes": "סקואָרטסיק ךרוד לענאַפּ לאָרטנאָק ךאַמ", + "Render Native Resolution": "עטאָלכאַה ןריובעג ןבעגסיוראַ", + "Keyboard Shortcuts": "ץאַקטראָש רוטאַיוואַלק", + "Enable KasmVNC Keyboard Shortcuts": "ץאַקטראָש רוטאַיוואַלק KasmVNC ןבעג", + "1 - Toggle Control Panel": "לענאַפּ לאָרטנאָק לאַגאַט - 1", + "2 - Toggle Game Pointer Mode": "עדאָמ לטיַיט ליפּש לאַגאַט - 2", + "3 - Toggle Pointer Lock": "קאַל רעטניופּ לאַגאַט - 3", + "Stream Quality": "יטילאַווק םירטס", + "Preset Modes:": "סעדאָמ טעסירפּ", + "Static": "קיטאַטס", + "Low": "קירעדינ", + "Medium": "לטימ", + "High": "ךיוה", + "Extreme": "םערטסקע", + "Lossless": "ססעלססאָל", + "Custom": "גהנמ", + "Anti-Aliasing:": "גניסאַילאַ-יטנאַ", + "Auto Dynamic": "קימאַניד אָטואַ", + "Off": "קעוואַ", + "On": "ףיוא", + "Dynamic Quality Min:": "ןימ יטילאַווק שימאַניד", + "Dynamic Quality Max:": "סקאַמ יטילאַווק שימאַניד", + "Treat Lossless:": "ססעלססאָל ןעלדנאַהאַב", + "Frame Rate:": "סרוק םאַר", + "Video JPEG Quality:": "טעטילאַווק געפּשזד אעדיוו", + "Video WEBP Quality:": "טעטילאַווק פּבעוו אעדיוו", + "Video Area:": "חטש אעדיוו", + "Video Time:": "טייצ אעדיוו", + "Video Out Time:": "טייצ טואָ אעדיוו", + "Video Mode Width:": "טיירב עדאָמ אעדיוו", + "Video Mode Height:": "ךייה עדאָמ אעדיוו", + "Documentation": "ןאָיטאַטנעמוקאָד", + "Drag Viewport": "טראָפּויוו ןפּעלש", + "KasmVNC encountered an error:": "KasmVNC תועט אַ טרעטנאָלפּעג:" +} \ No newline at end of file diff --git a/app/locale/yi_US.json b/app/locale/yi_US.json new file mode 100644 index 0000000..47270f2 --- /dev/null +++ b/app/locale/yi_US.json @@ -0,0 +1,120 @@ +{ + "Connecting...": " ןדניבראַפ", + "Disconnecting...": " גניטקענאַקסיד", + "Reconnecting...": " גניטקענאַקיר", + "Internal error": "תועט ךעלרעני", + "Must set host": "סאָבעלאַב ןלעטש ןזומ", + "Connected (encrypted) to ": "וצ (דיטפּירקנע) ןדנובראפ", + "Connected (unencrypted) to ": "וצ (דיטפּירקנענאַ) ןדנובראפ", + "Something went wrong, connection is closed": "טכאמראפ זיא רשק יד ,שלאַפ זיא סעפּע", + "Failed to connect to server": "רעוורעס וצ ןדניבראַפ וצ שרעדנאַ טינ", + "Disconnected": "דיטקענאַקסיד", + "New connection has been rejected with reason: ": "הביס טימ ןפראווראפ זיא רשק עיַינ", + "New connection has been rejected": "ןפראווראפ זיא רשק עיַינ", + "Credentials are required": "טגנאלראפ ןענעז זלאַשנעדערק", + "Hide/Show the control bar": "ראַב לאָרטנאָק יד ןזיַיוו / ןטלאַהאַב", + "Drag": "ןפּעלש", + "Move/Drag Viewport": "טראָפּויוו ןפּעלש / ךאַמ", + "Keyboard": "דראביק", + "Show Keyboard": "רוטאַיוואַלק ןזיַיוו", + "Extra keys": "ןעלסילש ערטסקע", + "Show Extra Keys": "ןעלסילש ערטסקע ןזיַיוו", + "Ctrl": "Ctrl", + "Toggle Ctrl": "לרטק ךאַמ", + "Alt": "טלא", + "Toggle Alt": "טלאַ ןדער", + "Toggle Windows": "רעטצנעפֿ ןכאַמ", + "Windows": "זואָדניוו", + "Send Tab": "לטיווק ןקיש", + "Tab": "באט", + "Esc": "קסע", + "Send Escape": "ןפיולטנאַ ןקיש", + "Ctrl+Alt+Del": "Ctrl + Alt + Del", + "Send Ctrl-Alt-Del": "Ctrl-Alt-Del ןקיש", + "Shutdown/Reboot": "טאָאָבער / ןואַדטאַש", + "Shutdown/Reboot...": " טאָאָבער / ןואַדטאַש", + "Power": "טפאַרק", + "Shutdown": "ןואַדטאַש", + "Reboot": "טאָאָבער", + "Reset": "קיטעטשאַב", + "Clipboard": "דראָבפּילק", + "Clear": "ראלק", + "Fullscreen": "ןירקס עצנאג", + "Settings": "סגניטטעס", + "Shared Mode": "עדאָמ דרעש", + "View Only": "View זיולב", + "Clip to Window": "רעטצנעפֿ וצ פּילק", + "Scaling Mode:": "עדאָמ גנילאַקס", + "None": "ןייק", + "Local Scaling": "גנילייקס לאַקאָל", + "Remote Resizing": "גניזיסער טיַיוו", + "Advanced": "עטריסנאַוואַ", + "Quality:": "טעטילאַווק", + "Compression level:": "הגרדמ ןאַשערפּמאַק", + "Repeater ID:": "ןיַיש רעטאַעפּער", + "WebSocket": "טעקקאָס בעוו", + "Encrypt": "טפּירקנע", + "Host:": "סאָבעלאַב", + "Port:": "טראָפּ", + "Path:": "ךרד", + "Automatic Reconnect": "טקענאַקיר קיטאַמאַטאָ", + "Reconnect Delay (ms):": "(סמ) ןטלאַהראַפ טקענאַקיר", + "Show Dot when No Cursor": "רעפֿיול ןייק ןעוו טקנופּ ןזיַיוו", + "Logging:": "גניגאָל", + "Version:": "עיסרעוו", + "Disconnect": "טקענאַקסיד", + "Connect": "ןדניבראַפ", + "Username:": "ןעמאָנ רעצינאַב", + "Password:": "טראָווכירפּש", + "Send Credentials": "זלאַשטנעדאַרק ןקיש", + "Cancel": "ןכאַמ לטאָב", + "Keys": "ןעלסילש", + "Game Cursor Mode": "עדאָמ רעפֿיול ליפּש", + "Press Esc Key to Exit Pointer Lock Mode": "עדאָמ קאַל רעטניופּ יד גנאַגסיוראַ וצ Esc Key ןקירד", + "Game Mode paused, click on screen to resume Game Mode.": "עדאָמ ליפּש רעדיוו כיז נעמענ וצ ןלעטשראַפ ףיוא טיג ,דזאָפּ עדאָמ ליפּש", + "Clipboard Up": "ףיוראַ דראָבפּילק", + "CLipboard Down": "פּאָראַ דראָבפּילק", + "Clipboard Seamless": "סאַלמיס דראָבפּילק", + "Prefer Local Cursor": "רעפֿיול עלאקאל רעכליב", + "Translate keyboard shortcuts": "געווכרוד רוטאַיוואַלק ןצעזרעביא", + "Enable WebRTC UDP Transit": "WebRTC UDP Transit ןבעג", + "Enable WebP Compression": "ןאַשערפּמאַק פּבעוו ןבעג", + "Enable Performance Stats": "ץאַטס גנולעטשראָפ ןבעג", + "Enable Pointer Lock": "Enable Pointer Lock", + "IME Input Mode": "IME עדאָמ ביַירשניַיראַ", + "Show Virtual Keyboard Control": "לאָרטנאָק רוטאַיוואַלק לאַוטריוו ןזיַיוו", + "Toggle Control Panel via Keystrokes": "סקואָרטסיק ךרוד לענאַפּ לאָרטנאָק ךאַמ", + "Render Native Resolution": "עטאָלכאַה ןריובעג ןבעגסיוראַ", + "Keyboard Shortcuts": "ץאַקטראָש רוטאַיוואַלק", + "Enable KasmVNC Keyboard Shortcuts": "ץאַקטראָש רוטאַיוואַלק KasmVNC ןבעג", + "1 - Toggle Control Panel": "לענאַפּ לאָרטנאָק לאַגאַט - 1", + "2 - Toggle Game Pointer Mode": "עדאָמ לטיַיט ליפּש לאַגאַט - 2", + "3 - Toggle Pointer Lock": "קאַל רעטניופּ לאַגאַט - 3", + "Stream Quality": "יטילאַווק םירטס", + "Preset Modes:": "סעדאָמ טעסירפּ", + "Static": "קיטאַטס", + "Low": "קירעדינ", + "Medium": "לטימ", + "High": "ךיוה", + "Extreme": "םערטסקע", + "Lossless": "ססעלססאָל", + "Custom": "גהנמ", + "Anti-Aliasing:": "גניסאַילאַ-יטנאַ", + "Auto Dynamic": "קימאַניד אָטואַ", + "Off": "קעוואַ", + "On": "ףיוא", + "Dynamic Quality Min:": "ןימ יטילאַווק שימאַניד", + "Dynamic Quality Max:": "סקאַמ יטילאַווק שימאַניד", + "Treat Lossless:": "ססעלססאָל ןעלדנאַהאַב", + "Frame Rate:": "סרוק םאַר", + "Video JPEG Quality:": "טעטילאַווק געפּשזד אעדיוו", + "Video WEBP Quality:": "טעטילאַווק פּבעוו אעדיוו", + "Video Area:": "חטש אעדיוו", + "Video Time:": "טייצ אעדיוו", + "Video Out Time:": "טייצ טואָ אעדיוו", + "Video Mode Width:": "טיירב עדאָמ אעדיוו", + "Video Mode Height:": "ךייה עדאָמ אעדיוו", + "Documentation": "ןאָיטאַטנעמוקאָד", + "Drag Viewport": "טראָפּויוו ןפּעלש", + "KasmVNC encountered an error:": "KasmVNC תועט אַ טרעטנאָלפּעג:" +} \ No newline at end of file diff --git a/app/locale/yo.json b/app/locale/yo.json new file mode 100644 index 0000000..dc4f04c --- /dev/null +++ b/app/locale/yo.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Nsopọmọra...", + "Disconnecting...": "Ti npa asopọ kuro...", + "Reconnecting...": "Tunsopọ...", + "Internal error": "Aṣiṣe inu", + "Must set host": "A gbọdọ ṣeto olugbalejo", + "Connected (encrypted) to ": "Ti sopọ (ti paroko) si", + "Connected (unencrypted) to ": "Ti sopọ (ti ko paṣiparọ) si", + "Something went wrong, connection is closed": "Nkankan ti ko tọ, asopọ ti wa ni pipade", + "Failed to connect to server": "O kuna lati sopọ si olupin", + "Disconnected": "Ti ge asopọ", + "New connection has been rejected with reason: ": "A ti kọ asopọ tuntun pẹlu idi:", + "New connection has been rejected": "A ti kọ asopọ tuntun", + "Credentials are required": "A nilo awọn iwe-ẹri", + "Hide/Show the control bar": "Fipamọ/Fi ọpa iṣakoso han", + "Drag": "Fa", + "Move/Drag Viewport": "Gbe/Fa Iwowo", + "Keyboard": " Keyboard", + "Show Keyboard": "Fi Keyboard han", + "Extra keys": "Awọn bọtini afikun", + "Show Extra Keys": "Fi awọn bọtini afikun han", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Yi Ctrl pada", + "Alt": "Alt", + "Toggle Alt": "Yi Alt pada", + "Toggle Windows": "Yi Windows pada", + "Windows": "Windows", + "Send Tab": "Fi Taabu ranṣẹ", + "Tab": "Taabu", + "Esc": "Esc", + "Send Escape": "Firanṣẹ Sa lọ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Firanṣẹ Ctrl-Alt-Del", + "Shutdown/Reboot": "Tiipa/Atunbere", + "Shutdown/Reboot...": "Tiipa/Atunbere...", + "Power": "Agbara", + "Shutdown": "Paade", + "Reboot": "Atunbere", + "Reset": "Tunto", + "Clipboard": "Agekuru", + "Clear": "Paarẹ", + "Fullscreen": "Gbogbo sikirini", + "Settings": "Ètò", + "Shared Mode": "Ipo Pipin", + "View Only": "Wo nikan", + "Clip to Window": "Agekuru si Ferese", + "Scaling Mode:": "Ipo Iwọn:", + "None": "Ko si", + "Local Scaling": "Iwọn iwọn agbegbe", + "Remote Resizing": "Iwọn isọdọtun latọna jijin", + "Advanced": "To ti ni ilọsiwaju", + "Quality:": "Didara:", + "Compression level:": "Ipele titẹ:", + "Repeater ID:": "Atunṣe ID:", + "WebSocket": "WebSocket", + "Encrypt": "Fipamọ", + "Host:": "Olugbalejo:", + "Port:": "ibudo:", + "Path:": "Ọna:", + "Automatic Reconnect": "Atunṣe aifọwọyi", + "Reconnect Delay (ms):": "Tun Idaduro (ms):", + "Show Dot when No Cursor": "Fi aami han nigbati Ko si kọsọ", + "Logging:": "Wiwọle:", + "Version:": "Ẹya:", + "Disconnect": "Ge asopọ", + "Connect": "Sopọ", + "Username:": "Orukọ olumulo:", + "Password:": "Ọrọigbaniwọle:", + "Send Credentials": "Firanṣẹ awọn iwe-ẹri", + "Cancel": "Fagilee", + "Keys": "Awọn bọtini", + "Game Cursor Mode": "Ipo Kọsọ Ere", + "Press Esc Key to Exit Pointer Lock Mode": "Tẹ bọtini Esc lati Jade Ipo Titiipa Atọka", + "Game Mode paused, click on screen to resume Game Mode.": "Ipo ere ti daduro, tẹ loju iboju lati bẹrẹ Ipo Ere.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard isalẹ", + "Clipboard Seamless": "Alaini agekuru fidio", + "Prefer Local Cursor": "Ṣeyan Kọsọ Agbegbe", + "Translate keyboard shortcuts": "Tumọ awọn ọna abuja keyboard", + "Enable WebRTC UDP Transit": "Mu WebRTC UDP Transit ṣiṣẹ", + "Enable WebP Compression": "Jeki funmorawon WebP", + "Enable Performance Stats": "Mu awọn iṣiro iṣẹ ṣiṣẹ", + "Enable Pointer Lock": "Mu Titiipa itọka ṣiṣẹ", + "IME Input Mode": "Ipo Iṣawọle IME", + "Show Virtual Keyboard Control": "Ṣafihan Iṣakoso Keyboard Foju", + "Toggle Control Panel via Keystrokes": "Yi Panel Iṣakoso Lọ nipasẹ Awọn bọtini bọtini", + "Render Native Resolution": "Ṣe Ipinnu Ilu abinibi", + "Keyboard Shortcuts": "Awọn ọna abuja keyboard", + "Enable KasmVNC Keyboard Shortcuts": "Mu awọn ọna abuja Keyboard KasmVNC ṣiṣẹ", + "1 - Toggle Control Panel": "1 - Panel Iṣakoso Yipada", + "2 - Toggle Game Pointer Mode": "2 - Yipada Ipo Atọka Ere", + "3 - Toggle Pointer Lock": "3 - Titiipa Atọka Yipada", + "Stream Quality": "Didara ṣiṣan", + "Preset Modes:": "Awọn ipo tito tẹlẹ:", + "Static": "aiduro", + "Low": "Kekere", + "Medium": "Alabọde", + "High": "O ga", + "Extreme": "Alaju", + "Lossless": "Ailafo", + "Custom": "Aṣa", + "Anti-Aliasing:": "Atako-Aliasing:", + "Auto Dynamic": "Aiyipada Aifọwọyi", + "Off": "Paa", + "On": "Lori", + "Dynamic Quality Min:": " Min Didara Didara:", + "Dynamic Quality Max:": "O pọju Didara Didara:", + "Treat Lossless:": "Toju Ainipadanu:", + "Frame Rate:": "Oṣuwọn fireemu:", + "Video JPEG Quality:": "Didara JPEG fidio:", + "Video WEBP Quality:": "Didara WEBP fidio:", + "Video Area:": "Agbegbe Fidio:", + "Video Time:": "Aago fidio:", + "Video Out Time:": "Fidio Jade Akoko:", + "Video Mode Width:": "Ipo Fidio:", + "Video Mode Height:": "Ipo Fidio Giga:", + "Documentation": "Iwe iwe", + "Drag Viewport": "Fa Wiwo", + "KasmVNC encountered an error:": "KasmVNC pade aṣiṣe kan:" +} \ No newline at end of file diff --git a/app/locale/yo_NG.json b/app/locale/yo_NG.json new file mode 100644 index 0000000..dc4f04c --- /dev/null +++ b/app/locale/yo_NG.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Nsopọmọra...", + "Disconnecting...": "Ti npa asopọ kuro...", + "Reconnecting...": "Tunsopọ...", + "Internal error": "Aṣiṣe inu", + "Must set host": "A gbọdọ ṣeto olugbalejo", + "Connected (encrypted) to ": "Ti sopọ (ti paroko) si", + "Connected (unencrypted) to ": "Ti sopọ (ti ko paṣiparọ) si", + "Something went wrong, connection is closed": "Nkankan ti ko tọ, asopọ ti wa ni pipade", + "Failed to connect to server": "O kuna lati sopọ si olupin", + "Disconnected": "Ti ge asopọ", + "New connection has been rejected with reason: ": "A ti kọ asopọ tuntun pẹlu idi:", + "New connection has been rejected": "A ti kọ asopọ tuntun", + "Credentials are required": "A nilo awọn iwe-ẹri", + "Hide/Show the control bar": "Fipamọ/Fi ọpa iṣakoso han", + "Drag": "Fa", + "Move/Drag Viewport": "Gbe/Fa Iwowo", + "Keyboard": " Keyboard", + "Show Keyboard": "Fi Keyboard han", + "Extra keys": "Awọn bọtini afikun", + "Show Extra Keys": "Fi awọn bọtini afikun han", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Yi Ctrl pada", + "Alt": "Alt", + "Toggle Alt": "Yi Alt pada", + "Toggle Windows": "Yi Windows pada", + "Windows": "Windows", + "Send Tab": "Fi Taabu ranṣẹ", + "Tab": "Taabu", + "Esc": "Esc", + "Send Escape": "Firanṣẹ Sa lọ", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Firanṣẹ Ctrl-Alt-Del", + "Shutdown/Reboot": "Tiipa/Atunbere", + "Shutdown/Reboot...": "Tiipa/Atunbere...", + "Power": "Agbara", + "Shutdown": "Paade", + "Reboot": "Atunbere", + "Reset": "Tunto", + "Clipboard": "Agekuru", + "Clear": "Paarẹ", + "Fullscreen": "Gbogbo sikirini", + "Settings": "Ètò", + "Shared Mode": "Ipo Pipin", + "View Only": "Wo nikan", + "Clip to Window": "Agekuru si Ferese", + "Scaling Mode:": "Ipo Iwọn:", + "None": "Ko si", + "Local Scaling": "Iwọn iwọn agbegbe", + "Remote Resizing": "Iwọn isọdọtun latọna jijin", + "Advanced": "To ti ni ilọsiwaju", + "Quality:": "Didara:", + "Compression level:": "Ipele titẹ:", + "Repeater ID:": "Atunṣe ID:", + "WebSocket": "WebSocket", + "Encrypt": "Fipamọ", + "Host:": "Olugbalejo:", + "Port:": "ibudo:", + "Path:": "Ọna:", + "Automatic Reconnect": "Atunṣe aifọwọyi", + "Reconnect Delay (ms):": "Tun Idaduro (ms):", + "Show Dot when No Cursor": "Fi aami han nigbati Ko si kọsọ", + "Logging:": "Wiwọle:", + "Version:": "Ẹya:", + "Disconnect": "Ge asopọ", + "Connect": "Sopọ", + "Username:": "Orukọ olumulo:", + "Password:": "Ọrọigbaniwọle:", + "Send Credentials": "Firanṣẹ awọn iwe-ẹri", + "Cancel": "Fagilee", + "Keys": "Awọn bọtini", + "Game Cursor Mode": "Ipo Kọsọ Ere", + "Press Esc Key to Exit Pointer Lock Mode": "Tẹ bọtini Esc lati Jade Ipo Titiipa Atọka", + "Game Mode paused, click on screen to resume Game Mode.": "Ipo ere ti daduro, tẹ loju iboju lati bẹrẹ Ipo Ere.", + "Clipboard Up": "Clipboard Up", + "CLipboard Down": "Clipboard isalẹ", + "Clipboard Seamless": "Alaini agekuru fidio", + "Prefer Local Cursor": "Ṣeyan Kọsọ Agbegbe", + "Translate keyboard shortcuts": "Tumọ awọn ọna abuja keyboard", + "Enable WebRTC UDP Transit": "Mu WebRTC UDP Transit ṣiṣẹ", + "Enable WebP Compression": "Jeki funmorawon WebP", + "Enable Performance Stats": "Mu awọn iṣiro iṣẹ ṣiṣẹ", + "Enable Pointer Lock": "Mu Titiipa itọka ṣiṣẹ", + "IME Input Mode": "Ipo Iṣawọle IME", + "Show Virtual Keyboard Control": "Ṣafihan Iṣakoso Keyboard Foju", + "Toggle Control Panel via Keystrokes": "Yi Panel Iṣakoso Lọ nipasẹ Awọn bọtini bọtini", + "Render Native Resolution": "Ṣe Ipinnu Ilu abinibi", + "Keyboard Shortcuts": "Awọn ọna abuja keyboard", + "Enable KasmVNC Keyboard Shortcuts": "Mu awọn ọna abuja Keyboard KasmVNC ṣiṣẹ", + "1 - Toggle Control Panel": "1 - Panel Iṣakoso Yipada", + "2 - Toggle Game Pointer Mode": "2 - Yipada Ipo Atọka Ere", + "3 - Toggle Pointer Lock": "3 - Titiipa Atọka Yipada", + "Stream Quality": "Didara ṣiṣan", + "Preset Modes:": "Awọn ipo tito tẹlẹ:", + "Static": "aiduro", + "Low": "Kekere", + "Medium": "Alabọde", + "High": "O ga", + "Extreme": "Alaju", + "Lossless": "Ailafo", + "Custom": "Aṣa", + "Anti-Aliasing:": "Atako-Aliasing:", + "Auto Dynamic": "Aiyipada Aifọwọyi", + "Off": "Paa", + "On": "Lori", + "Dynamic Quality Min:": " Min Didara Didara:", + "Dynamic Quality Max:": "O pọju Didara Didara:", + "Treat Lossless:": "Toju Ainipadanu:", + "Frame Rate:": "Oṣuwọn fireemu:", + "Video JPEG Quality:": "Didara JPEG fidio:", + "Video WEBP Quality:": "Didara WEBP fidio:", + "Video Area:": "Agbegbe Fidio:", + "Video Time:": "Aago fidio:", + "Video Out Time:": "Fidio Jade Akoko:", + "Video Mode Width:": "Ipo Fidio:", + "Video Mode Height:": "Ipo Fidio Giga:", + "Documentation": "Iwe iwe", + "Drag Viewport": "Fa Wiwo", + "KasmVNC encountered an error:": "KasmVNC pade aṣiṣe kan:" +} \ No newline at end of file diff --git a/app/locale/zh_CN.json b/app/locale/zh_CN.json new file mode 100644 index 0000000..89c7489 --- /dev/null +++ b/app/locale/zh_CN.json @@ -0,0 +1,127 @@ +{ + "Connecting...": "连接中...", + "Disconnecting...": "正在断开连接...", + "Reconnecting...": "重新连接中...", + "Internal error": "内部错误", + "Must set host": "请提供主机名", + "Connected (encrypted) to ": "已连接到(加密)", + "Connected (unencrypted) to ": "已连接到(未加密)", + "Something went wrong, connection is closed": "发生错误,连接已关闭", + "Failed to connect to server": "无法连接到服务器", + "Disconnected": "已断开连接", + "New connection has been rejected with reason: ": "连接被拒绝,原因:", + "New connection has been rejected": "连接被拒绝", + "Password is required": "请提供密码", + "Hide/Show the control bar": "显示/隐藏控制栏", + "Move/Drag Viewport": "拖放显示范围", + "viewport drag": "显示范围拖放", + "Active Mouse Button": "启动鼠标按鍵", + "No mousebutton": "禁用鼠标按鍵", + "Left mousebutton": "鼠标左鍵", + "Middle mousebutton": "鼠标中鍵", + "Right mousebutton": "鼠标右鍵", + "Keyboard": "键盘", + "Show Keyboard": "显示键盘", + "Extra keys": "额外按键", + "Show Extra Keys": "显示额外按键", + "Ctrl": "Ctrl", + "Toggle Ctrl": "切换 Ctrl", + "Alt": "Alt", + "Toggle Alt": "切换 Alt", + "Send Tab": "发送 Tab 键", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "发送 Escape 键", + "Ctrl+Alt+Del": "Ctrl-Alt-Del", + "Send Ctrl-Alt-Del": "发送 Ctrl-Alt-Del 键", + "Shutdown/Reboot": "关机/重新启动", + "Shutdown/Reboot...": "关机/重新启动...", + "Power": "电源", + "Shutdown": "关机", + "Reboot": "重新启动", + "Reset": "重置", + "Clipboard": "剪贴板", + "Clear": "清除", + "Fullscreen": "全屏", + "Settings": "设置", + "Shared Mode": "分享模式", + "View Only": "仅查看", + "Clip to Window": "限制/裁切窗口大小", + "Scaling Mode:": "缩放模式:", + "None": "无", + "Local Scaling": "本地缩放", + "Remote Resizing": "远程调整大小", + "Advanced": "高级", + "Repeater ID:": "中继站 ID", + "WebSocket": "WebSocket", + "Encrypt": "加密", + "Host:": "主机:", + "Port:": "端口:", + "Path:": "路径:", + "Automatic Reconnect": "自动重新连接", + "Reconnect Delay (ms):": "重新连接间隔 (ms):", + "Logging:": "日志级别:", + "Disconnect": "中断连接", + "Connect": "连接", + "Password:": "密码:", + "Cancel": "取消", + "Credentials are required": "需要证件", + "Drag": "拖", + "Toggle Windows": "切换窗口", + "Windows": "视窗", + "Quality:": "质量:", + "Compression level:": "压缩级别:", + "Show Dot when No Cursor": "没有光标时显示点", + "Version:": "版本:", + "Username:": "用户名:", + "Send Credentials": "发送凭证", + "Keys": "钥匙", + "Game Cursor Mode": "游戏光标模式", + "Press Esc Key to Exit Pointer Lock Mode": "按 Esc 键退出指针锁定模式", + "Game Mode paused, click on screen to resume Game Mode.": "游戏模式暂停,点击屏幕恢复游戏模式。", + "Clipboard Up": "向上剪贴板", + "CLipboard Down": "剪贴板下", + "Clipboard Seamless": "无缝剪贴板", + "Prefer Local Cursor": "首选本地光标", + "Translate keyboard shortcuts": "翻译键盘快捷键", + "Enable WebRTC UDP Transit": "启用 WebRTC UDP 传输", + "Enable WebP Compression": "启用 WebP 压缩", + "Enable Performance Stats": "启用性能统计", + "Enable Pointer Lock": "启用指针锁定", + "IME Input Mode": "输入法输入法", + "Show Virtual Keyboard Control": "显示虚拟键盘控制", + "Toggle Control Panel via Keystrokes": "通过击键切换控制面板", + "Render Native Resolution": "渲染本机分辨率", + "Keyboard Shortcuts": "键盘快捷键", + "Enable KasmVNC Keyboard Shortcuts": "启用 KasmVNC 键盘快捷键", + "1 - Toggle Control Panel": "1 - 切换控制面板", + "2 - Toggle Game Pointer Mode": "2 - 切换游戏指针模式", + "3 - Toggle Pointer Lock": "3 - 切换指针锁定", + "Stream Quality": "流媒体质量", + "Preset Modes:": "预设模式:", + "Static": "静止的", + "Low": "低的", + "Medium": "中等的", + "High": "高的", + "Extreme": "极端", + "Lossless": "无损", + "Custom": "风俗", + "Anti-Aliasing:": "抗锯齿:", + "Auto Dynamic": "自动动态", + "Off": "离开", + "On": "在", + "Dynamic Quality Min:": "动态质量分钟:", + "Dynamic Quality Max:": "动态质量最大值:", + "Treat Lossless:": "对待无损:", + "Frame Rate:": "帧率:", + "Video JPEG Quality:": "视频 JPEG 质量:", + "Video WEBP Quality:": "视频 WEBP 质量:", + "Video Area:": "视频区:", + "Video Time:": "视频时间:", + "Video Out Time:": "视频输出时间:", + "Video Mode Width:": "视频模式宽度:", + "Video Mode Height:": "视频模式高度:", + "Documentation": "文档", + "Drag Viewport": "拖动视口", + "KasmVNC encountered an error:": "KasmVNC 遇到错误:" +} \ No newline at end of file diff --git a/app/locale/zh_TW.json b/app/locale/zh_TW.json new file mode 100644 index 0000000..0b5adde --- /dev/null +++ b/app/locale/zh_TW.json @@ -0,0 +1,127 @@ +{ + "Connecting...": "連線中...", + "Disconnecting...": "正在中斷連線...", + "Reconnecting...": "重新連線中...", + "Internal error": "內部錯誤", + "Must set host": "請提供主機資訊", + "Connected (encrypted) to ": "已加密連線到", + "Connected (unencrypted) to ": "未加密連線到", + "Something went wrong, connection is closed": "發生錯誤,連線已關閉", + "Failed to connect to server": "無法連線到伺服器", + "Disconnected": "連線已中斷", + "New connection has been rejected with reason: ": "連線被拒絕,原因:", + "New connection has been rejected": "連線被拒絕", + "Password is required": "請提供密碼", + "Hide/Show the control bar": "顯示/隱藏控制列", + "Move/Drag Viewport": "拖放顯示範圍", + "viewport drag": "顯示範圍拖放", + "Active Mouse Button": "啟用滑鼠按鍵", + "No mousebutton": "無滑鼠按鍵", + "Left mousebutton": "滑鼠左鍵", + "Middle mousebutton": "滑鼠中鍵", + "Right mousebutton": "滑鼠右鍵", + "Keyboard": "鍵盤", + "Show Keyboard": "顯示鍵盤", + "Extra keys": "額外按鍵", + "Show Extra Keys": "顯示額外按鍵", + "Ctrl": "Ctrl", + "Toggle Ctrl": "切換 Ctrl", + "Alt": "Alt", + "Toggle Alt": "切換 Alt", + "Send Tab": "送出 Tab 鍵", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "送出 Escape 鍵", + "Ctrl+Alt+Del": "Ctrl-Alt-Del", + "Send Ctrl-Alt-Del": "送出 Ctrl-Alt-Del 快捷鍵", + "Shutdown/Reboot": "關機/重新啟動", + "Shutdown/Reboot...": "關機/重新啟動...", + "Power": "電源", + "Shutdown": "關機", + "Reboot": "重新啟動", + "Reset": "重設", + "Clipboard": "剪貼簿", + "Clear": "清除", + "Fullscreen": "全螢幕", + "Settings": "設定", + "Shared Mode": "分享模式", + "View Only": "僅檢視", + "Clip to Window": "限制/裁切視窗大小", + "Scaling Mode:": "縮放模式:", + "None": "無", + "Local Scaling": "本機縮放", + "Remote Resizing": "遠端調整大小", + "Advanced": "進階", + "Repeater ID:": "中繼站 ID", + "WebSocket": "WebSocket", + "Encrypt": "加密", + "Host:": "主機:", + "Port:": "連接埠:", + "Path:": "路徑:", + "Automatic Reconnect": "自動重新連線", + "Reconnect Delay (ms):": "重新連線間隔 (ms):", + "Logging:": "日誌級別:", + "Disconnect": "中斷連線", + "Connect": "連線", + "Password:": "密碼:", + "Cancel": "取消", + "Credentials are required": "需要證件", + "Drag": "拖", + "Toggle Windows": "切換窗口", + "Windows": "視窗", + "Quality:": "質量:", + "Compression level:": "壓縮級別:", + "Show Dot when No Cursor": "沒有光標時顯示點", + "Version:": "版本:", + "Username:": "用戶名:", + "Send Credentials": "發送憑證", + "Keys": "鑰匙", + "Game Cursor Mode": "遊戲光標模式", + "Press Esc Key to Exit Pointer Lock Mode": "按 Esc 鍵退出指針鎖定模式", + "Game Mode paused, click on screen to resume Game Mode.": "遊戲模式暫停,點擊屏幕恢復遊戲模式。", + "Clipboard Up": "向上剪貼板", + "CLipboard Down": "剪貼板下", + "Clipboard Seamless": "無縫剪貼板", + "Prefer Local Cursor": "首選本地光標", + "Translate keyboard shortcuts": "翻譯鍵盤快捷鍵", + "Enable WebRTC UDP Transit": "啟用 WebRTC UDP 傳輸", + "Enable WebP Compression": "啟用 WebP 壓縮", + "Enable Performance Stats": "啟用性能統計", + "Enable Pointer Lock": "啟用指針鎖定", + "IME Input Mode": "輸入法輸入法", + "Show Virtual Keyboard Control": "顯示虛擬鍵盤控制", + "Toggle Control Panel via Keystrokes": "通過擊鍵切換控制面板", + "Render Native Resolution": "渲染本機分辨率", + "Keyboard Shortcuts": "鍵盤快捷鍵", + "Enable KasmVNC Keyboard Shortcuts": "啟用 KasmVNC 鍵盤快捷鍵", + "1 - Toggle Control Panel": "1 - 切換控制面板", + "2 - Toggle Game Pointer Mode": "2 - 切換遊戲指針模式", + "3 - Toggle Pointer Lock": "3 - 切換指針鎖定", + "Stream Quality": "流媒體質量", + "Preset Modes:": "預設模式:", + "Static": "靜止的", + "Low": "低的", + "Medium": "中等的", + "High": "高的", + "Extreme": "極端", + "Lossless": "無損", + "Custom": "風俗", + "Anti-Aliasing:": "抗鋸齒:", + "Auto Dynamic": "自動動態", + "Off": "離開", + "On": "在", + "Dynamic Quality Min:": "動態質量分鐘:", + "Dynamic Quality Max:": "動態質量最大值:", + "Treat Lossless:": "對待無損:", + "Frame Rate:": "幀率:", + "Video JPEG Quality:": "視頻 JPEG 質量:", + "Video WEBP Quality:": "視頻 WEBP 質量:", + "Video Area:": "視頻區:", + "Video Time:": "視頻時間:", + "Video Out Time:": "視頻輸出時間:", + "Video Mode Width:": "視頻模式寬度:", + "Video Mode Height:": "視頻模式高度:", + "Documentation": "文檔", + "Drag Viewport": "拖動視口", + "KasmVNC encountered an error:": "KasmVNC 遇到錯誤:" +} \ No newline at end of file diff --git a/app/locale/zu.json b/app/locale/zu.json new file mode 100644 index 0000000..7ecd937 --- /dev/null +++ b/app/locale/zu.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Iyaxhuma...", + "Disconnecting...": "Inqamula...", + "Reconnecting...": "Iyaxhuma futhi...", + "Internal error": "Iphutha langaphakathi", + "Must set host": "Kumelwe usethe umsingathi", + "Connected (encrypted) to ": "Kuxhunywe (kubethelwe) ku-", + "Connected (unencrypted) to ": "Kuxhunywe (akubetheliwe) ku-", + "Something went wrong, connection is closed": "Kukhona okungahambanga kahle, ukuxhumana kuvaliwe", + "Failed to connect to server": "Yehlulekile ukuxhuma kuseva", + "Disconnected": "Inqanyuliwe", + "New connection has been rejected with reason: ": "Uxhumano olusha lunqatshiwe ngesizathu: ", + "New connection has been rejected": "Uxhumano olusha lunqatshiwe", + "Credentials are required": "Kudingeka izifakazo", + "Hide/Show the control bar": "Fihla/Bonisa ibha yokulawula", + "Drag": "Hudula", + "Move/Drag Viewport": "Hambisa/Hudula imbobo yokubuka", + "Keyboard": "Ikhibhodi", + "Show Keyboard": "Bonisa Ikhibhodi", + "Extra keys": "Okhiye abengeziwe", + "Show Extra Keys": "Bonisa Okhiye Abangeziwe", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Shintsha u-Ctrl", + "Alt": "Alt", + "Toggle Alt": "Shintsha i-Alt", + "Toggle Windows": "Shintsha iWindows", + "Windows": "IWindows", + "Send Tab": "Thumela Ithebhu", + "Tab": "Ithebhu", + "Esc": "Esc", + "Send Escape": "Thumela u-Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Thumela u-Ctrl-Alt-Del", + "Shutdown/Reboot": "Vala/Qalisa kabusha", + "Shutdown/Reboot...": "Vala/Qalisa kabusha...", + "Power": "Amandla", + "Shutdown": "Vala shaqa", + "Reboot": "Qalisa kabusha", + "Reset": "Setha kabusha", + "Clipboard": "Ibhodi lokunamathisela", + "Clear": "Sula", + "Fullscreen": "Iskrini esigcwele", + "Settings": "Izilungiselelo", + "Shared Mode": "Imodi eyabiwe", + "View Only": "Buka Kuphela", + "Clip to Window": "Clip efasiteleni", + "Scaling Mode:": "Imodi yokukala:", + "None": "Lutho", + "Local Scaling": "Ukukala kwendawo", + "Remote Resizing": "Ukushintsha usayizi wesilawuli kude", + "Advanced": "Okuthuthukile", + "Quality:": "Ikhwalithi:", + "Compression level:": "Izinga lokucindezela:", + "Repeater ID:": "I-ID yesiphindi:", + "WebSocket": "WebSocket", + "Encrypt": "Bethela", + "Host:": "Umphathi:", + "Port:": "Imbobo:", + "Path:": "Indlela:", + "Automatic Reconnect": "Ukuxhuma kabusha okuzenzakalelayo", + "Reconnect Delay (ms):": "Xhuma kabusha Ukubambezeleka (ms):", + "Show Dot when No Cursor": "Bonisa Ichashazi uma Lingekho Ikhesa", + "Logging:": "Ukugawula:", + "Version:": "Inguqulo:", + "Disconnect": "Nqamula", + "Connect": "Xhuma", + "Username:": "Igama lomsebenzisi:", + "Password:": "Iphasiwedi:", + "Send Credentials": "Thumela Imininingwane", + "Cancel": "Khansela", + "Keys": "Okhiye", + "Game Cursor Mode": "Imodi Yekhesa Yegeyimu", + "Press Esc Key to Exit Pointer Lock Mode": "Cindezela u-Esc Key ukuze uphume kumodi yokukhiya isikhombi", + "Game Mode paused, click on screen to resume Game Mode.": "Imodi yegeyimu imisiwe, chofoza esikrinini ukuze uqalise kabusha i-Game Mode.", + "Clipboard Up": "Ibhodi lokunamathisela phezulu", + "CLipboard Down": "I-Clipboard Phansi", + "Clipboard Seamless": "Ibhodi lokunamathisela elingenamthungo", + "Prefer Local Cursor": "Ncamela ikhesa yasendaweni", + "Translate keyboard shortcuts": "Humusha izinqamuleli zekhibhodi", + "Enable WebRTC UDP Transit": "Vumela i-WebRTC UDP Transit", + "Enable WebP Compression": "Vumela i-WebP Compression", + "Enable Performance Stats": "Vumela Izibalo Zokusebenza", + "Enable Pointer Lock": "Vumela Ukukhiya Kwesikhombi", + "IME Input Mode": "Imodi yokufaka ye-IME", + "Show Virtual Keyboard Control": "Show Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "Guqula Iphaneli Yokulawula ngokusebenzisa Izinkinobho Zokhiye", + "Render Native Resolution": "Nikeza isixazululo somdabu", + "Keyboard Shortcuts": "Izinqamuleli zekhibhodi", + "Enable KasmVNC Keyboard Shortcuts": "Vumela Izinqamuleli Zekhibhodi ye-KasmVNC", + "1 - Toggle Control Panel": "1 - Guqula Iphaneli Yokulawula", + "2 - Toggle Game Pointer Mode": "2 - Guqula Imodi Yesikhombi Segeyimu", + "3 - Toggle Pointer Lock": "3 - Guqula Isikhiya Sesikhombi", + "Stream Quality": "Ikhwalithi yokusakaza", + "Preset Modes:": "Amamodi Asethiwe:", + "Static": "I-Static", + "Low": "Phansi", + "Medium": "Medium", + "High": "Phezulu", + "Extreme": "Okudlulele", + "Lossless": "Ngalahlekelwa", + "Custom": "Ngokwezifiso", + "Anti-Aliasing:": "I-anti aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Valiwe", + "On": "Vula", + "Dynamic Quality Min:": "Dynamic Quality Min:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Phatha Ukulahlekelwa:", + "Frame Rate:": "Ukukalwa kwe fulemu:", + "Video JPEG Quality:": "Ikhwalithi ye-JPEG yevidiyo:", + "Video WEBP Quality:": "Ikhwalithi ye-WEBP yevidiyo:", + "Video Area:": "Indawo yevidiyo:", + "Video Time:": "Isikhathi Sevidiyo:", + "Video Out Time:": "Isikhathi Sokuphela Kwevidiyo:", + "Video Mode Width:": "Ububanzi bemodi yevidiyo:", + "Video Mode Height:": "Ubude bemodi yevidiyo:", + "Documentation": "Amadokhumenti", + "Drag Viewport": "Hudula imbobo yokubuka", + "KasmVNC encountered an error:": "I-KasmVNC ihlangabezane nephutha:" +} \ No newline at end of file diff --git a/app/locale/zu_ZA.json b/app/locale/zu_ZA.json new file mode 100644 index 0000000..7ecd937 --- /dev/null +++ b/app/locale/zu_ZA.json @@ -0,0 +1,120 @@ +{ + "Connecting...": "Iyaxhuma...", + "Disconnecting...": "Inqamula...", + "Reconnecting...": "Iyaxhuma futhi...", + "Internal error": "Iphutha langaphakathi", + "Must set host": "Kumelwe usethe umsingathi", + "Connected (encrypted) to ": "Kuxhunywe (kubethelwe) ku-", + "Connected (unencrypted) to ": "Kuxhunywe (akubetheliwe) ku-", + "Something went wrong, connection is closed": "Kukhona okungahambanga kahle, ukuxhumana kuvaliwe", + "Failed to connect to server": "Yehlulekile ukuxhuma kuseva", + "Disconnected": "Inqanyuliwe", + "New connection has been rejected with reason: ": "Uxhumano olusha lunqatshiwe ngesizathu: ", + "New connection has been rejected": "Uxhumano olusha lunqatshiwe", + "Credentials are required": "Kudingeka izifakazo", + "Hide/Show the control bar": "Fihla/Bonisa ibha yokulawula", + "Drag": "Hudula", + "Move/Drag Viewport": "Hambisa/Hudula imbobo yokubuka", + "Keyboard": "Ikhibhodi", + "Show Keyboard": "Bonisa Ikhibhodi", + "Extra keys": "Okhiye abengeziwe", + "Show Extra Keys": "Bonisa Okhiye Abangeziwe", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Shintsha u-Ctrl", + "Alt": "Alt", + "Toggle Alt": "Shintsha i-Alt", + "Toggle Windows": "Shintsha iWindows", + "Windows": "IWindows", + "Send Tab": "Thumela Ithebhu", + "Tab": "Ithebhu", + "Esc": "Esc", + "Send Escape": "Thumela u-Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Thumela u-Ctrl-Alt-Del", + "Shutdown/Reboot": "Vala/Qalisa kabusha", + "Shutdown/Reboot...": "Vala/Qalisa kabusha...", + "Power": "Amandla", + "Shutdown": "Vala shaqa", + "Reboot": "Qalisa kabusha", + "Reset": "Setha kabusha", + "Clipboard": "Ibhodi lokunamathisela", + "Clear": "Sula", + "Fullscreen": "Iskrini esigcwele", + "Settings": "Izilungiselelo", + "Shared Mode": "Imodi eyabiwe", + "View Only": "Buka Kuphela", + "Clip to Window": "Clip efasiteleni", + "Scaling Mode:": "Imodi yokukala:", + "None": "Lutho", + "Local Scaling": "Ukukala kwendawo", + "Remote Resizing": "Ukushintsha usayizi wesilawuli kude", + "Advanced": "Okuthuthukile", + "Quality:": "Ikhwalithi:", + "Compression level:": "Izinga lokucindezela:", + "Repeater ID:": "I-ID yesiphindi:", + "WebSocket": "WebSocket", + "Encrypt": "Bethela", + "Host:": "Umphathi:", + "Port:": "Imbobo:", + "Path:": "Indlela:", + "Automatic Reconnect": "Ukuxhuma kabusha okuzenzakalelayo", + "Reconnect Delay (ms):": "Xhuma kabusha Ukubambezeleka (ms):", + "Show Dot when No Cursor": "Bonisa Ichashazi uma Lingekho Ikhesa", + "Logging:": "Ukugawula:", + "Version:": "Inguqulo:", + "Disconnect": "Nqamula", + "Connect": "Xhuma", + "Username:": "Igama lomsebenzisi:", + "Password:": "Iphasiwedi:", + "Send Credentials": "Thumela Imininingwane", + "Cancel": "Khansela", + "Keys": "Okhiye", + "Game Cursor Mode": "Imodi Yekhesa Yegeyimu", + "Press Esc Key to Exit Pointer Lock Mode": "Cindezela u-Esc Key ukuze uphume kumodi yokukhiya isikhombi", + "Game Mode paused, click on screen to resume Game Mode.": "Imodi yegeyimu imisiwe, chofoza esikrinini ukuze uqalise kabusha i-Game Mode.", + "Clipboard Up": "Ibhodi lokunamathisela phezulu", + "CLipboard Down": "I-Clipboard Phansi", + "Clipboard Seamless": "Ibhodi lokunamathisela elingenamthungo", + "Prefer Local Cursor": "Ncamela ikhesa yasendaweni", + "Translate keyboard shortcuts": "Humusha izinqamuleli zekhibhodi", + "Enable WebRTC UDP Transit": "Vumela i-WebRTC UDP Transit", + "Enable WebP Compression": "Vumela i-WebP Compression", + "Enable Performance Stats": "Vumela Izibalo Zokusebenza", + "Enable Pointer Lock": "Vumela Ukukhiya Kwesikhombi", + "IME Input Mode": "Imodi yokufaka ye-IME", + "Show Virtual Keyboard Control": "Show Virtual Keyboard Control", + "Toggle Control Panel via Keystrokes": "Guqula Iphaneli Yokulawula ngokusebenzisa Izinkinobho Zokhiye", + "Render Native Resolution": "Nikeza isixazululo somdabu", + "Keyboard Shortcuts": "Izinqamuleli zekhibhodi", + "Enable KasmVNC Keyboard Shortcuts": "Vumela Izinqamuleli Zekhibhodi ye-KasmVNC", + "1 - Toggle Control Panel": "1 - Guqula Iphaneli Yokulawula", + "2 - Toggle Game Pointer Mode": "2 - Guqula Imodi Yesikhombi Segeyimu", + "3 - Toggle Pointer Lock": "3 - Guqula Isikhiya Sesikhombi", + "Stream Quality": "Ikhwalithi yokusakaza", + "Preset Modes:": "Amamodi Asethiwe:", + "Static": "I-Static", + "Low": "Phansi", + "Medium": "Medium", + "High": "Phezulu", + "Extreme": "Okudlulele", + "Lossless": "Ngalahlekelwa", + "Custom": "Ngokwezifiso", + "Anti-Aliasing:": "I-anti aliasing:", + "Auto Dynamic": "Auto Dynamic", + "Off": "Valiwe", + "On": "Vula", + "Dynamic Quality Min:": "Dynamic Quality Min:", + "Dynamic Quality Max:": "Dynamic Quality Max:", + "Treat Lossless:": "Phatha Ukulahlekelwa:", + "Frame Rate:": "Ukukalwa kwe fulemu:", + "Video JPEG Quality:": "Ikhwalithi ye-JPEG yevidiyo:", + "Video WEBP Quality:": "Ikhwalithi ye-WEBP yevidiyo:", + "Video Area:": "Indawo yevidiyo:", + "Video Time:": "Isikhathi Sevidiyo:", + "Video Out Time:": "Isikhathi Sokuphela Kwevidiyo:", + "Video Mode Width:": "Ububanzi bemodi yevidiyo:", + "Video Mode Height:": "Ubude bemodi yevidiyo:", + "Documentation": "Amadokhumenti", + "Drag Viewport": "Hudula imbobo yokubuka", + "KasmVNC encountered an error:": "I-KasmVNC ihlangabezane nephutha:" +} \ No newline at end of file diff --git a/app/localization.js b/app/localization.js new file mode 100644 index 0000000..100901c --- /dev/null +++ b/app/localization.js @@ -0,0 +1,172 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2018 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +/* + * Localization Utilities + */ + +export class Localizer { + constructor() { + // Currently configured language + this.language = 'en'; + + // Current dictionary of translations + this.dictionary = undefined; + } + + // Configure suitable language based on user preferences + setup(supportedLanguages) { + this.language = 'en'; // Default: US English + + /* + * Navigator.languages only available in Chrome (32+) and FireFox (32+) + * Fall back to navigator.language for other browsers + */ + let userLanguages; + if (typeof window.navigator.languages == 'object') { + userLanguages = window.navigator.languages; + } else { + userLanguages = [navigator.language || navigator.userLanguage]; + } + + for (let i = 0;i < userLanguages.length;i++) { + const userLang = userLanguages[i] + .toLowerCase() + .replace("_", "-") + .split("-"); + + // Built-in default? + if ((userLang[0] === 'en') && + ((userLang[1] === undefined) || (userLang[1] === 'us'))) { + return; + } + + // First pass: perfect match + for (let j = 0; j < supportedLanguages.length; j++) { + const supLang = supportedLanguages[j] + .toLowerCase() + .replace("_", "-") + .split("-"); + + if (userLang[0] !== supLang[0]) { + continue; + } + if (userLang[1] !== supLang[1]) { + continue; + } + + this.language = supportedLanguages[j]; + return; + } + + // Second pass: fallback + for (let j = 0;j < supportedLanguages.length;j++) { + const supLang = supportedLanguages[j] + .toLowerCase() + .replace("_", "-") + .split("-"); + + if (userLang[0] !== supLang[0]) { + continue; + } + if (supLang[1] !== undefined) { + continue; + } + + this.language = supportedLanguages[j]; + return; + } + } + } + + // Retrieve localised text + get(id) { + if (typeof this.dictionary !== 'undefined' && this.dictionary[id]) { + return this.dictionary[id]; + } else { + return id; + } + } + + // Traverses the DOM and translates relevant fields + // See https://html.spec.whatwg.org/multipage/dom.html#attr-translate + translateDOM() { + const self = this; + + function process(elem, enabled) { + function isAnyOf(searchElement, items) { + return items.indexOf(searchElement) !== -1; + } + + function translateAttribute(elem, attr) { + const str = self.get(elem.getAttribute(attr)); + elem.setAttribute(attr, str); + } + + function translateTextNode(node) { + const str = self.get(node.data.trim()); + node.data = str; + } + + if (elem.hasAttribute("translate")) { + if (isAnyOf(elem.getAttribute("translate"), ["", "yes"])) { + enabled = true; + } else if (isAnyOf(elem.getAttribute("translate"), ["no"])) { + enabled = false; + } + } + + if (enabled) { + if (elem.hasAttribute("abbr") && + elem.tagName === "TH") { + translateAttribute(elem, "abbr"); + } + if (elem.hasAttribute("alt") && + isAnyOf(elem.tagName, ["AREA", "IMG", "INPUT"])) { + translateAttribute(elem, "alt"); + } + if (elem.hasAttribute("download") && + isAnyOf(elem.tagName, ["A", "AREA"])) { + translateAttribute(elem, "download"); + } + if (elem.hasAttribute("label") && + isAnyOf(elem.tagName, ["MENUITEM", "MENU", "OPTGROUP", + "OPTION", "TRACK"])) { + translateAttribute(elem, "label"); + } + // FIXME: Should update "lang" + if (elem.hasAttribute("placeholder") && + isAnyOf(elem.tagName, ["INPUT", "TEXTAREA"])) { + translateAttribute(elem, "placeholder"); + } + if (elem.hasAttribute("title")) { + translateAttribute(elem, "title"); + } + if (elem.hasAttribute("value") && + elem.tagName === "INPUT" && + isAnyOf(elem.getAttribute("type"), ["reset", "button", "submit"])) { + translateAttribute(elem, "value"); + } + } + + for (let i = 0; i < elem.childNodes.length; i++) { + const node = elem.childNodes[i]; + if (node.nodeType === node.ELEMENT_NODE) { + process(node, enabled); + } else if (node.nodeType === node.TEXT_NODE && enabled) { + translateTextNode(node); + } + } + } + + process(document.body, true); + } +} + +export const l10n = new Localizer(); +export default l10n.get.bind(l10n); diff --git a/app/sounds/CREDITS b/app/sounds/CREDITS new file mode 100644 index 0000000..ec1fb55 --- /dev/null +++ b/app/sounds/CREDITS @@ -0,0 +1,4 @@ +bell + Copyright: Dr. Richard Boulanger et al + URL: http://www.archive.org/details/Berklee44v12 + License: CC-BY Attribution 3.0 Unported diff --git a/app/sounds/bell.mp3 b/app/sounds/bell.mp3 new file mode 100644 index 0000000..fdbf149 Binary files /dev/null and b/app/sounds/bell.mp3 differ diff --git a/app/sounds/bell.oga b/app/sounds/bell.oga new file mode 100644 index 0000000..144d2b3 Binary files /dev/null and b/app/sounds/bell.oga differ diff --git a/app/styles/Orbitron700.ttf b/app/styles/Orbitron700.ttf new file mode 100644 index 0000000..e28729d Binary files /dev/null and b/app/styles/Orbitron700.ttf differ diff --git a/app/styles/Orbitron700.woff b/app/styles/Orbitron700.woff new file mode 100644 index 0000000..61db630 Binary files /dev/null and b/app/styles/Orbitron700.woff differ diff --git a/app/styles/base.css b/app/styles/base.css new file mode 100644 index 0000000..5a71fdc --- /dev/null +++ b/app/styles/base.css @@ -0,0 +1,1193 @@ +/* + * noVNC base CSS + * Copyright (C) 2019 The noVNC Authors + * noVNC is licensed under the MPL 2.0 (see LICENSE.txt) + * This file is licensed under the 2-Clause BSD license (see LICENSE.txt). + */ + +/* + * Z index layers: + * + * 0: Main screen + * 10: Control bar + * 50: Transition blocker + * 60: Connection popups + * 100: Status bar + * ... + * 1000: Javascript crash + * ... + * 10000: Max (used for polyfills) + */ + +body { + margin:0; + padding:0; + font-family: "Poppins", "Helvetica"; + letter-spacing: 0.05em; + background: white url('../images/icons/kasm_logo.svg') no-repeat fixed center; + height:100%; + touch-action: none; +} + +html { + height:100%; +} + +.noVNC_only_touch.noVNC_hidden { + display: none; +} + +.noVNC_disabled { + color: rgb(128, 128, 128) !important; +} + +/* ---------------------------------------- + * Spinner + * ---------------------------------------- + */ + +.noVNC_spinner { + position: relative; +} +.noVNC_spinner, .noVNC_spinner::before, .noVNC_spinner::after { + width: 10px; + height: 10px; + border-radius: 2px; + box-shadow: -60px 10px 0 white; + animation: noVNC_spinner 1.0s linear infinite; +} +.noVNC_spinner::before { + content: ""; + position: absolute; + left: 0px; + top: 0px; + animation-delay: -0.1s; +} +.noVNC_spinner::after { + content: ""; + position: absolute; + top: 0px; + left: 0px; + animation-delay: 0.1s; +} +@keyframes noVNC_spinner { + 0% { box-shadow: -60px 10px 0 rgba(0, 135, 200, 0); width: 20px; } + 25% { box-shadow: 20px 10px 0 rgba(0, 135, 200, 1); width: 10px; } + 50% { box-shadow: 60px 10px 0 rgba(0, 135, 200, 0); width: 10px; } +} + +/* ---------------------------------------- + * Input Elements + * ---------------------------------------- + */ + +input:not([type]), +input[type=date], +input[type=datetime-local], +input[type=email], +input[type=month], +input[type=number], +input[type=password], +input[type=search], +input[type=tel], +input[type=text], +input[type=time], +input[type=url], +input[type=week], +textarea { + /* Disable default rendering */ + -webkit-appearance: none; + -moz-appearance: none; + background: none; + + margin: 2px; + padding: 2px; + border: 1px solid rgb(192, 192, 192); + border-radius: 5px; + color: black; + background: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); +} + +input[type=button], +input[type=color], +input[type=reset], +input[type=submit], +select { + /* Disable default rendering */ + -webkit-appearance: none; + -moz-appearance: none; + background: none; + + margin: 2px; + padding: 2px; + border: 1px solid rgb(192, 192, 192); + border-bottom-width: 2px; + border-radius: 5px; + color: black; + background: linear-gradient(to top, rgb(255, 255, 255), rgb(240, 240, 240)); + + /* This avoids it jumping around when :active */ + vertical-align: middle; +} + +input[type=button], +input[type=color], +input[type=reset], +input[type=submit] { + padding-left: 20px; + padding-right: 20px; +} + +option { + color: black; + background: white; +} + +input:not([type]):focus, +input[type=button]:focus, +input[type=color]:focus, +input[type=date]:focus, +input[type=datetime-local]:focus, +input[type=email]:focus, +input[type=month]:focus, +input[type=number]:focus, +input[type=password]:focus, +input[type=reset]:focus, +input[type=search]:focus, +input[type=submit]:focus, +input[type=tel]:focus, +input[type=text]:focus, +input[type=time]:focus, +input[type=url]:focus, +input[type=week]:focus, +select:focus, +textarea:focus { + box-shadow: 0px 0px 3px rgba(74, 144, 217, 0.5); + border-color: rgb(74, 144, 217); + outline: none; +} + +input[type=button]::-moz-focus-inner, +input[type=color]::-moz-focus-inner, +input[type=reset]::-moz-focus-inner, +input[type=submit]::-moz-focus-inner { + border: none; +} + +input:not([type]):disabled, +input[type=button]:disabled, +input[type=color]:disabled, +input[type=date]:disabled, +input[type=datetime-local]:disabled, +input[type=email]:disabled, +input[type=month]:disabled, +input[type=number]:disabled, +input[type=password]:disabled, +input[type=reset]:disabled, +input[type=search]:disabled, +input[type=submit]:disabled, +input[type=tel]:disabled, +input[type=text]:disabled, +input[type=time]:disabled, +input[type=url]:disabled, +input[type=week]:disabled, +select:disabled, +textarea:disabled { + color: rgb(128, 128, 128); + background: rgb(240, 240, 240); +} + +input[type=button]:active, +input[type=color]:active, +input[type=reset]:active, +input[type=submit]:active, +select:active { + border-bottom-width: 1px; + margin-top: 3px; +} + +:root:not(.noVNC_touch) input[type=button]:hover:not(:disabled), +:root:not(.noVNC_touch) input[type=color]:hover:not(:disabled), +:root:not(.noVNC_touch) input[type=reset]:hover:not(:disabled), +:root:not(.noVNC_touch) input[type=submit]:hover:not(:disabled), +:root:not(.noVNC_touch) select:hover:not(:disabled) { + background: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250)); +} + +/* ---------------------------------------- + * WebKit centering hacks + * ---------------------------------------- + */ + +.noVNC_center { + /* + * This is a workaround because webkit misrenders transforms and + * uses non-integer coordinates, resulting in blurry content. + * Ideally we'd use "top: 50%; transform: translateY(-50%);" on + * the objects instead. + */ + display: flex; + align-items: center; + justify-content: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; +} +.noVNC_center > * { + pointer-events: auto; +} +.noVNC_vcenter { + display: flex; + flex-direction: column; + justify-content: center; + position: fixed; + top: 0; + left: 0; + height: 100%; + pointer-events: none; +} +.noVNC_vcenter > * { + pointer-events: auto; +} + +/* ---------------------------------------- + * Layering + * ---------------------------------------- + */ + +.noVNC_connect_layer { + z-index: 60; +} + +/* ---------------------------------------- + * Fallback error + * ---------------------------------------- + */ + +#noVNC_fallback_error { + z-index: 1000; + visibility: hidden; +} +#noVNC_fallback_error.noVNC_open { + visibility: visible; +} + +#noVNC_fallback_error > div { + max-width: 90%; + padding: 15px; + + opacity: 0; + + text-align: center; + font-weight: bold; + color: #fff; + + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + background: rgba(33, 130, 177, 0.8); +} +#noVNC_fallback_error.noVNC_open > div { + transition: 0.5s ease-in-out; + opacity: 1; +} + +#noVNC_fallback_errormsg { + font-weight: normal; +} + +#noVNC_fallback_errormsg .noVNC_message { + display: inline-block; + text-align: left; + font-family: monospace; + white-space: pre-wrap; +} + +#noVNC_fallback_error .noVNC_location { + font-style: italic; + font-size: 0.8em; + color: rgba(255, 255, 255, 0.8); +} + +#noVNC_fallback_error .noVNC_stack { + max-height: 50vh; + padding: 10px; + margin: 10px; + font-size: 0.8em; + text-align: left; + font-family: monospace; + white-space: pre; + border: 1px solid rgba(0, 0, 0, 0.5); + background: rgba(0, 0, 0, 0.2); + overflow: auto; +} + +#noVNC_close_error { + position: flex; + margin-left: auto; + margin-right: 0; + cursor: pointer; + width: 20px; + height: 20px; + z-index: 3; + border-radius: 50%; + border: 1px solid rgba(0, 0, 0, 0.5); + background: rgba(0, 0, 0, 0.2); +} + +#noVNC_close_error:hover { + background: rgba(0, 0, 0, 0.4); +} + +/* ---------------------------------------- + * Connection Stats + * ---------------------------------------- + */ + #noVNC_connection_stats { + top: 0; + left: auto; + right: 0; + position: fixed; + background: #9fa5a2d4; + color: #00ffa2d4; + visibility: hidden; +} + +/* ---------------------------------------- + * Control Bar + * ---------------------------------------- + */ + +#noVNC_control_bar_anchor { + /* The anchor is needed to get z-stacking to work */ + position: fixed; + z-index: 10; + + transition: 0.5s ease-in-out; + + /* Edge misrenders animations wihthout this */ + transform: translateX(0); +} + +:root.noVNC_connected #noVNC_control_bar_anchor.noVNC_idle { + /* opacity: 0.8; */ +} +#noVNC_control_bar_anchor.noVNC_right { + left: auto; + right: 0; +} + +#noVNC_control_bar { + position: relative; + left: -100%; + + transition: 0.5s ease-in-out; + + background-color: rgb(9 2 2 / 0.6); + border-radius: 0 10px 10px 0; + border-style: inset; + border-color: rgb(255 255 255 / 0.6); +} +#noVNC_control_bar.noVNC_open { + left: 0; +} +#noVNC_control_bar::before { + /* This extra element is to get a proper shadow */ + content: ""; + position: absolute; + z-index: -1; + height: 100%; + width: 30px; + left: -30px; + transition: box-shadow 0.5s ease-in-out; +} +#noVNC_control_bar.noVNC_open::before { + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); +} +.noVNC_right #noVNC_control_bar { + left: 100%; + border-radius: 10px 0 0 10px; +} +.noVNC_right #noVNC_control_bar.noVNC_open { + left: 0; +} +.noVNC_right #noVNC_control_bar::before { + visibility: hidden; +} + +#noVNC_control_bar_handle { + position: absolute; + left: -15px; + transform: translateY(35px); + width: calc(100% + 30px); + height: 50px; + z-index: -1; + cursor: pointer; + border-radius: 5px; + background-image: url("../images/handle_bg.svg"); + background-repeat: no-repeat; + background-position: right; +} +#noVNC_control_bar_handle:after { + content: ""; + transition: transform 0.5s ease-in-out; + background: url("../images/handle.svg"); + background-repeat: no-repeat; + background-position: center; + position: absolute; + right: 0px; + width: 15px; + height: 60px; + background-color: rgb(9 2 2 / 0.6); + border-bottom-right-radius: 10px; + border-top-right-radius: 10px; + border-color: rgb(255 255 255 / 0.6); + border-style: inset; +} +#noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { + transform: translateX(1px) rotate(180deg); +} +:root:not(.noVNC_connected) #noVNC_control_bar_handle { + display: none; +} +.noVNC_right #noVNC_control_bar_handle { + background-position: left; + +} +.noVNC_right #noVNC_control_bar_handle:after { + left: 5px; + right: 0; + transform: translateX(1px) rotate(180deg); +} +.noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { + transform: none; +} +#noVNC_control_bar_handle div { + position: absolute; + right: -35px; + top: 0; + width: 50px; + height: 50px; +} +:root:not(.noVNC_touch) #noVNC_control_bar_handle div { + display: none; +} +.noVNC_right #noVNC_control_bar_handle div { + left: -35px; + right: auto; +} + +#noVNC_control_bar .noVNC_scroll { + max-height: 100vh; /* Chrome is buggy with 100% */ + overflow-x: hidden; + overflow-y: auto; + padding: 0 10px 0 5px; +} +.noVNC_right #noVNC_control_bar .noVNC_scroll { + padding: 0 5px 0 10px; +} + +/* Control bar hint */ +#noVNC_control_bar_hint { + position: fixed; + left: calc(100vw - 50px); + right: auto; + top: 50%; + transform: translateY(-50%) scale(0); + width: 100px; + height: 50%; + max-height: 600px; + + visibility: hidden; + opacity: 0; + transition: 0.2s ease-in-out; + background: transparent; + box-shadow: 0 0 10px black, inset 0 0 10px 10px rgba(110, 132, 163, 0.8); + border-radius: 10px; + transition-delay: 0s; +} +#noVNC_control_bar_anchor.noVNC_right #noVNC_control_bar_hint{ + left: auto; + right: calc(100vw - 50px); +} +#noVNC_control_bar_hint.noVNC_active { + visibility: visible; + opacity: 1; + transition-delay: 0.2s; + transform: translateY(-50%) scale(1); +} + +.noVNC_button_div { + display: block; + color: #fff; + font-size: 13px; +} + +/* General button style */ +.noVNC_button { + display: inline; + padding: 4px 4px; + margin: 10px 0; + vertical-align: middle; +} + +.noVNC_button.noVNC_selected { + border-color: rgba(0, 0, 0, 0.8); + background: rgba(153, 151, 157, 0.68); +} +.noVNC_button:disabled { + opacity: 0.4; +} +.noVNC_button:focus { + outline: none; +} +.noVNC_button:active { + padding-top: 5px; + padding-bottom: 3px; +} +/* Android browsers don't properly update hover state if touch events + * are intercepted, but focus should be safe to display */ +:root:not(.noVNC_touch) .noVNC_button.noVNC_selected:hover, +.noVNC_button.noVNC_selected:focus { + border-color: rgba(0, 0, 0, 0.4); + background: rgba(153, 151, 157, 0.68); +} +:root:not(.noVNC_touch) .noVNC_button_div:hover, +.noVNC_button_div:focus { + background: rgba(255, 255, 255, 0.2); +} +.noVNC_button.noVNC_hidden { + display: none; +} + +/* Panels */ +.noVNC_panel { + transform: translateX(25px); + + transition: 0.5s ease-in-out; + + width: 300px; + max-height: 100vh; /* Chrome is buggy with 100% */ + overflow-x: hidden; + overflow-y: auto; + + visibility: hidden; + opacity: 0; + + padding: 15px; + + background: rgb(9 9 0 / 0.77); + border-radius: 10px; + color: #000; +} +.noVNC_panel.noVNC_open { + visibility: visible; + opacity: 1; + transform: translateX(75px); +} +.noVNC_right .noVNC_vcenter { + left: auto; + right: 0; +} +.noVNC_right .noVNC_panel { + transform: translateX(-25px); +} +.noVNC_right .noVNC_panel.noVNC_open { + transform: translateX(-75px); +} + +.noVNC_panel hr { + border: none; + border-top: 1px solid rgb(192, 192, 192); +} + +.noVNC_panel label { + display: block; + white-space: nowrap; + color:white; +} + +.noVNC_panel .noVNC_heading { + background-color: rgb(54,58,64); + border-radius: 5px; + padding: 5px; + /* Compensate for padding in image */ + padding-right: 8px; + color: white; + font-size: 20px; + margin-bottom: 10px; + white-space: nowrap; +} +.noVNC_panel .noVNC_heading img { + vertical-align: bottom; +} + +.noVNC_submit { + float: right; +} + +/* Expanders */ +.noVNC_expander { + cursor: pointer; + color:white; + +} +.noVNC_expander::before { + content: url("../images/expander.svg"); + display: inline-block; + margin-right: 5px; + transition: 0.2s ease-in-out; + -webkit-filter: invert(.75); /* safari 6.0 - 9.0 */ + filter: invert(.75); +} +.noVNC_expander.noVNC_open::before { + transform: rotateZ(90deg); +} +.noVNC_expander ~ * { + margin: 5px; + margin-left: 10px; + padding: 5px; + background: rgba(0, 0, 0, 0.05); + border-radius: 5px; +} +.noVNC_expander:not(.noVNC_open) ~ * { + display: none; +} + +/* Control bar content */ + +#noVNC_control_bar .noVNC_logo { + font-size: 13px; + text-align: center; +} + +:root:not(.noVNC_disconnected) .noVNC_hide_on_connect { + display: none +} + +:root:not(.noVNC_connected) .noVNC_hide_on_disconnect { + display: none; +} + +:root:not(.noVNC_connected) #noVNC_view_drag_button { + display: none; +} + +/* noVNC Touch Device only buttons */ +:root:not(.noVNC_connected) #noVNC_mobile_buttons { + display: none; +} +:root:not(.noVNC_touch) #noVNC_mobile_buttons { + display: none; +} + +/* Extra manual keys */ +:root:not(.noVNC_connected) #noVNC_toggle_extra_keys_button { + display: none; +} + +#noVNC_modifiers { + background-color: rgb(92, 92, 92); + border: none; + padding: 0 10px; +} + +/* Shutdown/Reboot */ +:root:not(.noVNC_connected) #noVNC_power_button { + display: none; +} +#noVNC_power { +} +#noVNC_power_buttons { + display: none; +} + +#noVNC_power input[type=button] { + width: 100%; +} + +/* Clipboard */ +:root:not(.noVNC_connected) #noVNC_clipboard_button { + display: none; +} +#noVNC_clipboard { + /* Full screen, minus padding and left and right margins */ + max-width: calc(100vw - 2*15px - 75px - 25px); +} +#noVNC_clipboard_text { + width: 500px; + max-width: 100%; +} + +/* Settings */ +#noVNC_settings { +} +#noVNC_settings ul { + list-style: none; + margin: 0px; + padding: 0px; + color:white; +} +#noVNC_setting_port { + width: 80px; +} +#noVNC_setting_path { + width: 100px; +} + +/* Version */ + +.noVNC_version_wrapper { + font-size: small; +} + +.noVNC_version { + margin-left: 1rem; +} + +/* Connection Controls */ +:root:not(.noVNC_connected) #noVNC_disconnect_button { + display: none; +} + +/* ---------------------------------------- + * Status Dialog + * ---------------------------------------- + */ + +#noVNC_status { + position: fixed; + top: 0; + left: 0; + width: 100%; + z-index: 100; + transform: translateY(-100%); + + cursor: pointer; + + transition: 0.5s ease-in-out; + + visibility: hidden; + opacity: 0; + + padding: 5px; + + display: flex; + flex-direction: row; + justify-content: center; + align-content: center; + + line-height: 25px; + word-wrap: break-word; + color: #fff; + + border-bottom: 1px solid rgba(0, 0, 0, 0.9); +} +#noVNC_status.noVNC_open { + transform: translateY(0); + visibility: visible; + opacity: 1; +} + +#noVNC_status::before { + content: ""; + display: inline-block; + width: 25px; + height: 25px; + margin-right: 5px; +} + +#noVNC_status.noVNC_status_normal { + background: rgba(128,128,128,0.9); +} +#noVNC_status.noVNC_status_normal::before { + content: url("../images/info.svg") " "; +} +#noVNC_status.noVNC_status_error { + background: rgba(200,55,55,0.9); +} +#noVNC_status.noVNC_status_error::before { + content: url("../images/error.svg") " "; +} +#noVNC_status.noVNC_status_warn { + background: rgba(180,180,30,0.9); +} +#noVNC_status.noVNC_status_warn::before { + content: url("../images/warning.svg") " "; +} + + +/* ---------------------------------------- + * Password Dialog + * ---------------------------------------- + */ + +#noVNC_credentials_dlg { + position: relative; +} + +#noVNC_credentials_dlg ul { + list-style: none; + margin: 0px; + padding: 0px; +} + +#noVNC_credentials_dlg.noVNC_panel { + transition: none; + transform: none; +} + +#noVNC_credentials_dlg.noVNC_panel.noVNC_open { + transition: none; + transform: none; +} + +.noVNC_hidden { + display: none; +} + + +/* ---------------------------------------- + * Main Area + * ---------------------------------------- + */ + +/* Transition screen */ +#noVNC_transition { + display: none; + + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + + color: #0084C2; + background: white url('../images/icons/kasm_logo.svg') no-repeat fixed center; + background-size: 20%; + z-index: 50; + + /*display: flex;*/ + align-items: center; + justify-content: center; + flex-direction: column; + + -webkit-transition: opacity 1s ease-in-out; + -moz-transition: opacity 1s ease-in-out; + -ms-transition: opacity 1s ease-in-out; + -o-transition: opacity 1s ease-in-out; + opacity: 1; +} +:root.noVNC_loading #noVNC_transition, +:root.noVNC_connecting #noVNC_transition, +:root.noVNC_disconnecting #noVNC_transition, +:root.noVNC_reconnecting #noVNC_transition { + display: flex; +} +:root:not(.noVNC_reconnecting) #noVNC_cancel_reconnect_button { + display: none; +} +#noVNC_transition_text { + font-size: 1.5em; + margin-top: 125px; +} + +/* Main container */ +#noVNC_container { + width: 100%; + height: 100%; + background-image: url('../images/splash.jpg') +} + +#noVNC_keyboardinput { + width: 0px; + height: 0px; + background-color: #fff0; + color: rgba(5, 5, 5, 0); + border: 0; + position: absolute; + left: 35%; + top: 40%; + z-index: -1; +} + +/*Default noVNC logo.*/ +/* From: http://fonts.googleapis.com/css?family=Orbitron:700 */ +@font-face { + font-family: 'Orbitron'; + font-style: normal; + font-weight: 700; + src: local('?'), url('Orbitron700.woff') format('woff'), + url('Orbitron700.ttf') format('truetype'); +} + +.noVNC_logo { + color:yellow; + font-family: 'Orbitron', 'OrbitronTTF', sans-serif; + line-height:90%; + text-shadow: 0.1em 0.1em 0 black; + margin-bottom: 0px; + background: white; + padding: 5px; + border-radius: 5px; +} +.noVNC_logo img { + width: 45% +} +.noVNC_logo span{ + color:green; +} + +#noVNC_bell { + display: none; +} + +/* prevent selection */ +body { + -webkit-tap-highlight-color: transparent; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* + * + */ +.keyboard-controls { + display: none; + position: fixed; + bottom: 5%; + right: 5%; + z-index: 100000; + cursor: pointer; +} + +.keyboard-controls .buttons { + display: none; + flex-direction: column; +} + +.keyboard-controls .buttons .button { + border-radius: 0px; +} + +.keyboard-controls .buttons .button:first-of-type { + border-top-left-radius: 6px; + border-top-right-radius: 6px; +} + +.keyboard-controls .button { + display: inline-block; + width: 35px; + height: 35px; + + background-color:rgb(24, 31, 71); + border: 6px rgb(24, 31, 71) solid; + + border-radius: 6px; + outline: none; + user-select: none; +} + +#noVNC_keyboard_control .noVNC_selected { + background-color:rgb(15, 36, 153); + border: 6px rgb(15, 36, 153) solid; +} + +.keyboard-controls .button.ctrl { + background-image: url("../images/ctrl.svg"); + background-size: contain; +} + +.keyboard-controls .button.alt { + background-image: url("../images/alt.svg"); + background-size: contain; +} + +.keyboard-controls .button.windows { + background-size: contain; + background-image: url("../images/windows.svg"); +} + +.keyboard-controls .button.tab { + background-size: contain; + background-image: url("../images/tab.svg"); +} + +.keyboard-controls .button.escape { + background-size: contain; + background-image: url("../images/esc.svg"); +} + +.keyboard-controls .button.ctrlaltdel { + background-size: contain; + background-image: url("../images/ctrlaltdel.svg"); +} + +.keyboard-controls .button.keyboard { + background-size: contain; + background-image: url("../images/keyboard.svg"); +} + +.keyboard-controls .button.selected { + filter: brightness(150%); +} + +.keyboard-controls.is-visible { + display: flex; + flex-direction: column; +} + +.keyboard-controls.is-open .button.handle { + border-top-left-radius: 0px; + border-top-right-radius: 0px; +} + +.keyboard-controls.is-open .buttons { + display: flex; + flex-direction: column; + + animation-name: showKeyboardControls; + animation-duration: 0.2s; + animation-timing-function: linear; + animation-fill-mode: both; +} + +.keyboard-controls.was-open .buttons { + display: flex; + flex-direction: column; + + animation-name: hideKeyboardControls; + animation-duration: 0.2s; + animation-timing-function: linear; + animation-fill-mode: both; +} + +@keyframes showKeyboardControls { + 0% { + transform: scale(1, 0.2); + transform-origin: bottom center; + } + 100% { + transform: scale(1, 1); + transform-origin: bottom center; + } +} + +@keyframes hideKeyboardControls { + 0% { + transform: scale(1, 1); + transform-origin: bottom center; + } + 100% { + transform: scale(1, 0); + transform-origin: bottom center; + } +} + +/* ---------------------------------------- + * Media sizing + * ---------------------------------------- + */ + +@media screen and (max-width: 640px){ + #noVNC_logo { + font-size: 150px; + } +} + +@media screen and (min-width: 321px) and (max-width: 480px) { + #noVNC_logo { + font-size: 110px; + } +} + +@media screen and (max-width: 320px) { + #noVNC_logo { + font-size: 90px; + } +} + +/* ---------------------------------------- + * Slider Check boxes + * ---------------------------------------- + */ +/* The switch - the box around the slider */ +.switch { + position: relative; + display: inline-block; + width: 30px; + height: 16px; + margin: 5px; +} + +/* Hide default HTML checkbox */ +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +/* The slider */ +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s; +} + +.slider:before { + position: absolute; + content: ""; + height: 14px; + width: 14px; + left: 4px; + bottom: 1px; + background-color: white; + -webkit-transition: .4s; + transition: .4s; +} + +input:checked + .slider { + background-color: #2196F3; +} + +input:focus + .slider { + box-shadow: 0 0 1px #2196F3; +} + +input:checked + .slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(10px); +} + +/* Rounded sliders */ +.slider.round { + border-radius: 34px; +} + +.slider.round:before { + border-radius: 50%; +} + +.slider-label { + padding-left: 26px; +} + +/* Do not use default link colors */ +a:link { + color: white; +} +a:visited { + color: white; +} diff --git a/app/styles/bootstrap.min.css b/app/styles/bootstrap.min.css new file mode 100644 index 0000000..ed3905e --- /dev/null +++ b/app/styles/bootstrap.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/app/ui.js b/app/ui.js new file mode 100644 index 0000000..3d67485 --- /dev/null +++ b/app/ui.js @@ -0,0 +1,2549 @@ +/* + * KasmVNC: HTML5 VNC client + * Copyright (C) 2020 Kasm Technologies + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ +window._noVNC_has_module_support = true; +window.addEventListener("load", function() { + if (window._noVNC_has_module_support) return; + var loader = document.createElement("script"); + loader.src = "vendor/browser-es-module-loader/dist/browser-es-module-loader.js"; + document.head.appendChild(loader); +}); +window.addEventListener("load", function() { + var connect_btn_el = document.getElementById("noVNC_connect_button"); + if (typeof(connect_btn_el) != 'undefined' && connect_btn_el != null) + { + connect_btn_el.click(); + } +}); + +window.updateSetting = (name, value) => { + WebUtil.writeSetting(name, value); + + switch (name) { + case "translate_shortcuts": + UI.updateShortcutTranslation(); + break; + } +} + +import "core-js/stable"; +import "regenerator-runtime/runtime"; +import * as Log from '../core/util/logging.js'; +import _, { l10n } from './localization.js'; +import { isTouchDevice, isSafari, hasScrollbarGutter, dragThreshold, supportsBinaryClipboard, isFirefox, isWindows, isIOS, supportsPointerLock } + from '../core/util/browser.js'; +import { setCapture, getPointerEvent } from '../core/util/events.js'; +import KeyTable from "../core/input/keysym.js"; +import keysyms from "../core/input/keysymdef.js"; +import Keyboard from "../core/input/keyboard.js"; +import RFB from "../core/rfb.js"; +import { MouseButtonMapper, XVNC_BUTTONS } from "../core/mousebuttonmapper.js"; +import * as WebUtil from "./webutil.js"; + +const PAGE_TITLE = "KasmVNC"; + +var currentEventCount = -1; +var idleCounter = 0; + +const UI = { + + connected: false, + desktopName: "", + + statusTimeout: null, + hideKeyboardTimeout: null, + idleControlbarTimeout: null, + closeControlbarTimeout: null, + + controlbarGrabbed: false, + controlbarDrag: false, + controlbarMouseDownClientY: 0, + controlbarMouseDownOffsetY: 0, + + inhibitReconnect: true, + reconnectCallback: null, + reconnectPassword: null, + + prime() { + return WebUtil.initSettings().then(() => { + if (document.readyState === "interactive" || document.readyState === "complete") { + return UI.start(); + } + + return new Promise((resolve, reject) => { + document.addEventListener('DOMContentLoaded', () => UI.start().then(resolve).catch(reject)); + }); + }); + }, + + // Render default UI and initialize settings menu + start() { + //initialize settings then apply quality presents + UI.initSettings(); + UI.updateQuality(); + + // Translate the DOM + l10n.translateDOM(); + + fetch('./package.json') + .then((response) => { + if (!response.ok) { + throw Error("" + response.status + " " + response.statusText); + } + return response.json(); + }) + .then((packageInfo) => { + Array.from(document.getElementsByClassName('noVNC_version')).forEach(el => el.innerText = packageInfo.version); + }) + .catch((err) => { + Log.Error("Couldn't fetch package.json: " + err); + Array.from(document.getElementsByClassName('noVNC_version_wrapper')) + .concat(Array.from(document.getElementsByClassName('noVNC_version_separator'))) + .forEach(el => el.style.display = 'none'); + }); + + // Adapt the interface for touch screen devices + if (isTouchDevice) { + document.documentElement.classList.add("noVNC_touch"); + // Remove the address bar + setTimeout(() => window.scrollTo(0, 1), 100); + } + + // Restore control bar position + if (WebUtil.readSetting('controlbar_pos') === 'right') { + UI.toggleControlbarSide(); + } + + UI.initFullscreen(); + + // Setup event handlers + UI.addKeyboardControlsPanelHandlers(); + UI.addControlbarHandlers(); + UI.addTouchSpecificHandlers(); + UI.addExtraKeysHandlers(); + UI.addGamingHandlers(); + UI.addMachineHandlers(); + UI.addConnectionControlHandlers(); + UI.addClipboardHandlers(); + UI.addSettingsHandlers(); + document.getElementById("noVNC_status") + .addEventListener('click', UI.hideStatus); + UI.openControlbar(); + + // + + UI.updateVisualState('init'); + + document.documentElement.classList.remove("noVNC_loading"); + + let autoconnect = WebUtil.getConfigVar('autoconnect', true); + if (autoconnect === 'true' || autoconnect == '1') { + autoconnect = true; + UI.connect(); + } else { + autoconnect = false; + } + + window.parent.postMessage({ + action: "noVNC_initialized", + value: null + }, "*"); + + window.addEventListener("message", (e) => { + if (typeof e.data !== "object" || !e.data.action) { + return; + } + + if (e.data.action === "show_keyboard_controls") { + UI.showKeyboardControls(); + } else if (e.data.action === "hide_keyboard_controls") { + UI.hideKeyboardControls(); + } + }); + + window.addEventListener("beforeunload", (e) => { + if (UI.rfb) { + UI.disconnect(); + } + }); + + return Promise.resolve(UI.rfb); + }, + + initFullscreen() { + // Only show the button if fullscreen is properly supported + // * Safari doesn't support alphanumerical input while in fullscreen + if (!isSafari() && + (document.documentElement.requestFullscreen || + document.documentElement.mozRequestFullScreen || + document.documentElement.webkitRequestFullscreen || + document.body.msRequestFullscreen)) { + UI.showControlInput("noVNC_fullscreen_button") + UI.addFullscreenHandlers(); + } + }, + + initSettings() { + // Logging selection dropdown + const llevels = ['error', 'warn', 'info', 'debug']; + for (let i = 0; i < llevels.length; i += 1) { + UI.addOption(document.getElementById('noVNC_setting_logging'), llevels[i], llevels[i]); + } + + // Settings with immediate effects + UI.initSetting('logging', 'warn'); + UI.updateLogging(); + + // Stream Quality Presets + let qualityDropdown = document.getElementById("noVNC_setting_video_quality"); + let supportsSharedArrayBuffers = typeof SharedArrayBuffer !== "undefined"; + qualityDropdown.appendChild(Object.assign(document.createElement("option"),{value:0,label:"Static"})) + qualityDropdown.appendChild(Object.assign(document.createElement("option"),{value:1,label:"Low"})) + qualityDropdown.appendChild(Object.assign(document.createElement("option"),{value:2,label:"Medium"})) + qualityDropdown.appendChild(Object.assign(document.createElement("option"),{value:3,label:"High"})) + qualityDropdown.appendChild(Object.assign(document.createElement("option"),{value:4,label:"Extreme"})) + if (supportsSharedArrayBuffers) { + qualityDropdown.appendChild(Object.assign(document.createElement("option"),{value:5,label:"Lossless"})) + } + qualityDropdown.appendChild(Object.assign(document.createElement("option"),{value:10,label:"Custom"})) + + // if port == 80 (or 443) then it won't be present and should be + // set manually + let port = window.location.port; + if (!port) { + if (window.location.protocol.substring(0, 5) == 'https') { + port = 443; + } else if (window.location.protocol.substring(0, 4) == 'http') { + port = 80; + } + } + + /* Populate the controls if defaults are provided in the URL */ + UI.initSetting('host', window.location.hostname); + UI.initSetting('port', port); + UI.initSetting('encrypt', (window.location.protocol === "https:")); + UI.initSetting('view_clip', false); + /* UI.initSetting('resize', 'off'); */ + UI.initSetting('quality', 6); + UI.initSetting('dynamic_quality_min', 3); + UI.initSetting('dynamic_quality_max', 9); + UI.initSetting('translate_shortcuts', true); + UI.initSetting('treat_lossless', 7); + UI.initSetting('jpeg_video_quality', 5); + UI.initSetting('webp_video_quality', 5); + UI.initSetting('video_quality', 2); + UI.initSetting('anti_aliasing', 0); + UI.initSetting('video_area', 65); + UI.initSetting('video_time', 5); + UI.initSetting('video_out_time', 3); + UI.initSetting('video_scaling', 2); + UI.initSetting('max_video_resolution_x', 960); + UI.initSetting('max_video_resolution_y', 540); + UI.initSetting('framerate', 30); + UI.initSetting('compression', 2); + UI.initSetting('shared', true); + UI.initSetting('view_only', false); + UI.initSetting('show_dot', false); + UI.initSetting('path', 'websockify'); + UI.initSetting('repeaterID', ''); + UI.initSetting('reconnect', false); + UI.initSetting('reconnect_delay', 5000); + UI.initSetting('idle_disconnect', 20); + UI.initSetting('prefer_local_cursor', true); + UI.initSetting('toggle_control_panel', false); + UI.initSetting('enable_perf_stats', false); + UI.initSetting('virtual_keyboard_visible', false); + UI.initSetting('enable_ime', false); + UI.initSetting('enable_webrtc', false); + UI.initSetting('enable_hidpi', false); + UI.toggleKeyboardControls(); + + if (WebUtil.isInsideKasmVDI()) { + UI.initSetting('clipboard_up', false); + UI.initSetting('clipboard_down', false); + UI.initSetting('clipboard_seamless', false); + UI.initSetting('enable_webp', false); + UI.initSetting('resize', 'off'); + } else { + UI.initSetting('clipboard_up', true); + UI.initSetting('clipboard_down', true); + UI.initSetting('clipboard_seamless', true); + UI.initSetting('enable_webp', true); + UI.initSetting('resize', 'remote'); + } + + UI.setupSettingLabels(); + UI.updateQuality(); + }, + initMouseButtonMapper() { + const mouseButtonMapper = new MouseButtonMapper(); + + const settings = WebUtil.readSetting("mouseButtonMapper"); + if (settings) { + mouseButtonMapper.load(settings); + return mouseButtonMapper; + } + + mouseButtonMapper.set(0, XVNC_BUTTONS.LEFT_BUTTON); + mouseButtonMapper.set(1, XVNC_BUTTONS.MIDDLE_BUTTON); + mouseButtonMapper.set(2, XVNC_BUTTONS.RIGHT_BUTTON); + mouseButtonMapper.set(3, XVNC_BUTTONS.BACK_BUTTON); + mouseButtonMapper.set(4, XVNC_BUTTONS.FORWARD_BUTTON); + WebUtil.writeSetting("mouseButtonMapper", mouseButtonMapper.dump()); + + return mouseButtonMapper; + }, + // Adds a link to the label elements on the corresponding input elements + setupSettingLabels() { + const labels = document.getElementsByTagName('LABEL'); + for (let i = 0; i < labels.length; i++) { + const htmlFor = labels[i].htmlFor; + if (htmlFor != '') { + const elem = document.getElementById(htmlFor); + if (elem) elem.label = labels[i]; + } else { + // If 'for' isn't set, use the first input element child + const children = labels[i].children; + for (let j = 0; j < children.length; j++) { + if (children[j].form !== undefined) { + children[j].label = labels[i]; + break; + } + } + } + } + }, + +/* ------^------- +* /INIT +* ============== +* EVENT HANDLERS +* ------v------*/ + + addKeyboardControlsPanelHandlers() { + // panel dragging + interact(".keyboard-controls").draggable({ + allowFrom: ".handle", + listeners: { + move: (e) => { + const target = e.target; + const x = (parseFloat(target.getAttribute("data-x")) || 0) + e.dx; + const y = (parseFloat(target.getAttribute("data-y")) || 0) + e.dy; + target.style.transform = `translate(${x}px, ${y}px)`; + target.setAttribute("data-x", x); + target.setAttribute("data-y", y); + }, + }, + }); + + // panel expanding + interact(".keyboard-controls .handle") + .pointerEvents({ holdDuration: 350 }) + .on("hold", (e) => { + const buttonsEl = document.querySelector(".keyboard-controls"); + + const isOpen = buttonsEl.classList.contains("is-open"); + buttonsEl.classList.toggle("was-open", isOpen); + buttonsEl.classList.toggle("is-open", !isOpen); + + setTimeout(() => buttonsEl.classList.remove("was-open"), 500); + }); + + // keyboard showing + interact(".keyboard-controls .handle").on("tap", (e) => { + if (e.dt < 150) { + UI.toggleVirtualKeyboard(); + } + }); + + // panel buttons + interact(".keyboard-controls .button.ctrl").on("tap", UI.toggleCtrl); + interact(".keyboard-controls .button.alt").on("tap", UI.toggleAlt); + interact(".keyboard-controls .button.windows").on("tap", UI.toggleWindows); + interact(".keyboard-controls .button.tab").on("tap", UI.sendTab); + interact(".keyboard-controls .button.escape").on("tap", UI.sendEsc); + interact(".keyboard-controls .button.ctrlaltdel").on("tap", UI.sendCtrlAltDel); + }, + + addControlbarHandlers() { + document.getElementById("noVNC_control_bar") + .addEventListener('mousemove', UI.activateControlbar); + document.getElementById("noVNC_control_bar") + .addEventListener('mouseup', UI.activateControlbar); + document.getElementById("noVNC_control_bar") + .addEventListener('mousedown', UI.activateControlbar); + document.getElementById("noVNC_control_bar") + .addEventListener('keydown', UI.activateControlbar); + + document.getElementById("noVNC_control_bar") + .addEventListener('mousedown', UI.keepControlbar); + document.getElementById("noVNC_control_bar") + .addEventListener('keydown', UI.keepControlbar); + + UI.addClickHandle('noVNC_view_drag_button', UI.toggleViewDrag); + + document.getElementById("noVNC_control_bar_handle") + .addEventListener('mousedown', UI.controlbarHandleMouseDown); + document.getElementById("noVNC_control_bar_handle") + .addEventListener('mouseup', UI.controlbarHandleMouseUp); + document.getElementById("noVNC_control_bar_handle") + .addEventListener('mousemove', UI.dragControlbarHandle); + // resize events aren't available for elements + window.addEventListener('resize', UI.updateControlbarHandle); + + const exps = document.getElementsByClassName("noVNC_expander"); + for (let i = 0;i < exps.length;i++) { + exps[i].addEventListener('click', UI.toggleExpander); + } + }, + + addTouchSpecificHandlers() { + document.getElementById("noVNC_keyboard_button") + .addEventListener('click', UI.toggleVirtualKeyboard); + document.getElementById("noVNC_keyboardinput") + .addEventListener('focus', UI.onfocusVirtualKeyboard); + document.getElementById("noVNC_keyboardinput") + .addEventListener('blur', UI.onblurVirtualKeyboard); + document.getElementById("noVNC_keyboardinput") + .addEventListener('submit', () => false); + + document.documentElement + .addEventListener('mousedown', UI.keepVirtualKeyboard, true); + + document.getElementById("noVNC_control_bar") + .addEventListener('touchstart', UI.activateControlbar); + document.getElementById("noVNC_control_bar") + .addEventListener('touchmove', UI.activateControlbar); + document.getElementById("noVNC_control_bar") + .addEventListener('touchend', UI.activateControlbar); + document.getElementById("noVNC_control_bar") + .addEventListener('input', UI.activateControlbar); + + document.getElementById("noVNC_control_bar") + .addEventListener('touchstart', UI.keepControlbar); + document.getElementById("noVNC_control_bar") + .addEventListener('input', UI.keepControlbar); + + document.getElementById("noVNC_control_bar_handle") + .addEventListener('touchstart', UI.controlbarHandleMouseDown); + document.getElementById("noVNC_control_bar_handle") + .addEventListener('touchend', UI.controlbarHandleMouseUp); + document.getElementById("noVNC_control_bar_handle") + .addEventListener('touchmove', UI.dragControlbarHandle); + }, + + addExtraKeysHandlers() { + UI.addClickHandle('noVNC_toggle_extra_keys_button', UI.toggleExtraKeys); + + document.getElementById("noVNC_toggle_ctrl_button") + .addEventListener('click', UI.toggleCtrl); + document.getElementById("noVNC_toggle_windows_button") + .addEventListener('click', UI.toggleWindows); + document.getElementById("noVNC_toggle_alt_button") + .addEventListener('click', UI.toggleAlt); + document.getElementById("noVNC_send_tab_button") + .addEventListener('click', UI.sendTab); + document.getElementById("noVNC_send_esc_button") + .addEventListener('click', UI.sendEsc); + document.getElementById("noVNC_send_ctrl_alt_del_button") + .addEventListener('click', UI.sendCtrlAltDel); + }, + + addGamingHandlers() { + UI.addClickHandle('noVNC_game_mode_button', UI.toggleRelativePointer); + document + .getElementById("noVNC_setting_pointer_lock") + .addEventListener("click", UI.togglePointerLock); + }, + + addMachineHandlers() { + UI.addClickHandle('noVNC_power_button', UI.togglePowerPanel); + + document.getElementById("noVNC_shutdown_button") + .addEventListener('click', () => UI.rfb.machineShutdown()); + document.getElementById("noVNC_reboot_button") + .addEventListener('click', () => UI.rfb.machineReboot()); + document.getElementById("noVNC_reset_button") + .addEventListener('click', () => UI.rfb.machineReset()); + }, + + addConnectionControlHandlers() { + UI.addClickHandle('noVNC_disconnect_button', UI.disconnect); + + var connect_btn_el = document.getElementById("noVNC_connect_button"); + if (typeof(connect_btn_el) != 'undefined' && connect_btn_el != null) + { + connect_btn_el.addEventListener('click', UI.connect); + } + document.getElementById("noVNC_cancel_reconnect_button") + .addEventListener('click', UI.cancelReconnect); + + document.getElementById("noVNC_credentials_button") + .addEventListener('click', UI.setCredentials); + }, + + addClipboardHandlers() { + UI.addClickHandle('noVNC_clipboard_button', UI.toggleClipboardPanel); + + document.getElementById("noVNC_clipboard_text") + .addEventListener('change', UI.clipboardSend); + document.getElementById("noVNC_clipboard_clear_button") + .addEventListener('click', UI.clipboardClear); + }, + + // Add a call to save settings when the element changes, + // unless the optional parameter changeFunc is used instead. + addSettingChangeHandler(name, changeFunc) { + const settingElem = document.getElementById("noVNC_setting_" + name); + if (changeFunc === undefined) { + changeFunc = () => UI.saveSetting(name); + } + settingElem.addEventListener('change', changeFunc); + }, + + addSettingsHandlers() { + UI.addClickHandle('noVNC_settings_button', UI.toggleSettingsPanel); + + document.getElementById("noVNC_setting_enable_perf_stats").addEventListener('click', UI.showStats); + + UI.addSettingChangeHandler('encrypt'); + UI.addSettingChangeHandler('resize'); + UI.addSettingChangeHandler('resize', UI.applyResizeMode); + UI.addSettingChangeHandler('resize', UI.updateViewClip); + UI.addSettingChangeHandler('quality'); + UI.addSettingChangeHandler('quality', UI.updateQuality); + UI.addSettingChangeHandler('dynamic_quality_min'); + UI.addSettingChangeHandler('dynamic_quality_min', UI.updateQuality); + UI.addSettingChangeHandler('dynamic_quality_max'); + UI.addSettingChangeHandler('dynamic_quality_max', UI.updateQuality); + UI.addSettingChangeHandler('translate_shortcuts'); + UI.addSettingChangeHandler('translate_shortcuts', UI.updateShortcutTranslation); + UI.addSettingChangeHandler('treat_lossless'); + UI.addSettingChangeHandler('treat_lossless', UI.updateQuality); + UI.addSettingChangeHandler('anti_aliasing'); + UI.addSettingChangeHandler('anti_aliasing', UI.updateQuality); + UI.addSettingChangeHandler('video_quality'); + UI.addSettingChangeHandler('video_quality', UI.updateQuality); + UI.addSettingChangeHandler('jpeg_video_quality'); + UI.addSettingChangeHandler('jpeg_video_quality', UI.updateQuality); + UI.addSettingChangeHandler('webp_video_quality'); + UI.addSettingChangeHandler('webp_video_quality', UI.updateQuality); + UI.addSettingChangeHandler('video_area'); + UI.addSettingChangeHandler('video_area', UI.updateQuality); + UI.addSettingChangeHandler('video_time'); + UI.addSettingChangeHandler('video_time', UI.updateQuality); + UI.addSettingChangeHandler('video_out_time'); + UI.addSettingChangeHandler('video_out_time', UI.updateQuality); + UI.addSettingChangeHandler('video_scaling'); + UI.addSettingChangeHandler('video_scaling', UI.updateQuality); + UI.addSettingChangeHandler('max_video_resolution_x'); + UI.addSettingChangeHandler('max_video_resolution_x', UI.updateQuality); + UI.addSettingChangeHandler('max_video_resolution_y'); + UI.addSettingChangeHandler('max_video_resolution_y', UI.updateQuality); + UI.addSettingChangeHandler('framerate'); + UI.addSettingChangeHandler('framerate', UI.updateQuality); + UI.addSettingChangeHandler('compression'); + UI.addSettingChangeHandler('compression', UI.updateCompression); + UI.addSettingChangeHandler('view_clip'); + UI.addSettingChangeHandler('view_clip', UI.updateViewClip); + UI.addSettingChangeHandler('shared'); + UI.addSettingChangeHandler('view_only'); + UI.addSettingChangeHandler('view_only', UI.updateViewOnly); + UI.addSettingChangeHandler('show_dot'); + UI.addSettingChangeHandler('show_dot', UI.updateShowDotCursor); + UI.addSettingChangeHandler('host'); + UI.addSettingChangeHandler('port'); + UI.addSettingChangeHandler('path'); + UI.addSettingChangeHandler('repeaterID'); + UI.addSettingChangeHandler('logging'); + UI.addSettingChangeHandler('logging', UI.updateLogging); + UI.addSettingChangeHandler('reconnect'); + UI.addSettingChangeHandler('reconnect_delay'); + UI.addSettingChangeHandler('enable_webp'); + UI.addSettingChangeHandler('clipboard_seamless'); + UI.addSettingChangeHandler('clipboard_up'); + UI.addSettingChangeHandler('clipboard_down'); + UI.addSettingChangeHandler('toggle_control_panel'); + UI.addSettingChangeHandler('virtual_keyboard_visible'); + UI.addSettingChangeHandler('virtual_keyboard_visible', UI.toggleKeyboardControls); + UI.addSettingChangeHandler('enable_ime'); + UI.addSettingChangeHandler('enable_ime', UI.toggleIMEMode); + UI.addSettingChangeHandler('enable_webrtc'); + UI.addSettingChangeHandler('enable_webrtc', UI.toggleWebRTC); + UI.addSettingChangeHandler('enable_hidpi'); + UI.addSettingChangeHandler('enable_hidpi', UI.enableHiDpi); + }, + + addFullscreenHandlers() { + UI.addClickHandle('noVNC_fullscreen_button', UI.toggleFullscreen); + + window.addEventListener('fullscreenchange', UI.updateFullscreenButton); + window.addEventListener('mozfullscreenchange', UI.updateFullscreenButton); + window.addEventListener('webkitfullscreenchange', UI.updateFullscreenButton); + window.addEventListener('msfullscreenchange', UI.updateFullscreenButton); + }, + +/* ------^------- + * /EVENT HANDLERS + * ============== + * VISUAL + * ------v------*/ + // Ignore clicks that are propogated from child elements in sub panels + isControlPanelItemClick(e) { + if (!(e && e.target && e.target.classList && e.target.parentNode && + ( + e.target.classList.contains('noVNC_button') && e.target.parentNode.id !== 'noVNC_modifiers' || + e.target.classList.contains('noVNC_button_div') || + e.target.classList.contains('noVNC_heading') + ) + )) { + return false; + } + + return true; + }, + + // Disable/enable controls depending on connection state + updateVisualState(state) { + document.documentElement.classList.remove("noVNC_connecting"); + document.documentElement.classList.remove("noVNC_connected"); + document.documentElement.classList.remove("noVNC_disconnecting"); + document.documentElement.classList.remove("noVNC_reconnecting"); + document.documentElement.classList.remove("noVNC_disconnected"); + + const transitionElem = document.getElementById("noVNC_transition_text"); + if (WebUtil.isInsideKasmVDI()) + { + parent.postMessage({ action: 'connection_state', value: state}, '*' ); + } + + switch (state) { + case 'init': + break; + case 'connecting': + transitionElem.textContent = _("Connecting..."); + document.documentElement.classList.add("noVNC_connecting"); + break; + case 'connected': + document.documentElement.classList.add("noVNC_connected"); + break; + case 'disconnecting': + transitionElem.textContent = _("Disconnecting..."); + document.documentElement.classList.add("noVNC_disconnecting"); + break; + case 'disconnected': + document.documentElement.classList.add("noVNC_disconnected"); + break; + case 'reconnecting': + transitionElem.textContent = _("Reconnecting..."); + document.documentElement.classList.add("noVNC_reconnecting"); + break; + default: + Log.Error("Invalid visual state: " + state); + UI.showStatus(_("Internal error"), 'error'); + return; + } + + if (UI.connected) { + UI.updateViewClip(); + + UI.disableSetting('encrypt'); + UI.disableSetting('shared'); + UI.disableSetting('host'); + UI.disableSetting('port'); + UI.disableSetting('path'); + UI.disableSetting('repeaterID'); + + // Hide the controlbar after 2 seconds + UI.closeControlbarTimeout = setTimeout(UI.closeControlbar, 2000); + } else { + UI.enableSetting('encrypt'); + UI.enableSetting('shared'); + UI.enableSetting('host'); + UI.enableSetting('port'); + UI.enableSetting('path'); + UI.enableSetting('repeaterID'); + UI.updatePowerButton(); + UI.keepControlbar(); + } + //UI.updatePointerLockButton(); + + // State change closes dialogs as they may not be relevant + // anymore + UI.closeAllPanels(); + document.getElementById('noVNC_credentials_dlg') + .classList.remove('noVNC_open'); + }, + + showStats() { + UI.saveSetting('enable_perf_stats'); + + let enable_stats = UI.getSetting('enable_perf_stats'); + if (enable_stats === true && UI.statsInterval == undefined) { + document.getElementById("noVNC_connection_stats").style.visibility = "visible"; + UI.statsInterval = setInterval(function() { + if (UI.rfb !== undefined) { + UI.rfb.requestBottleneckStats(); + } + } , 5000); + } else { + document.getElementById("noVNC_connection_stats").style.visibility = "hidden"; + UI.statsInterval = null; + } + + }, + + showStatus(text, statusType, time, kasm = false) { + // If inside the full Kasm CDI framework, don't show messages unless explicitly told to + if (WebUtil.isInsideKasmVDI() && !kasm) { + return; + } + + const statusElem = document.getElementById('noVNC_status'); + + if (typeof statusType === 'undefined') { + statusType = 'normal'; + } + + // Don't overwrite more severe visible statuses and never + // errors. Only shows the first error. + if (statusElem.classList.contains("noVNC_open")) { + if (statusElem.classList.contains("noVNC_status_error")) { + return; + } + if (statusElem.classList.contains("noVNC_status_warn") && + statusType === 'normal') { + return; + } + } + + clearTimeout(UI.statusTimeout); + + switch (statusType) { + case 'error': + statusElem.classList.remove("noVNC_status_warn"); + statusElem.classList.remove("noVNC_status_normal"); + statusElem.classList.add("noVNC_status_error"); + break; + case 'warning': + case 'warn': + statusElem.classList.remove("noVNC_status_error"); + statusElem.classList.remove("noVNC_status_normal"); + statusElem.classList.add("noVNC_status_warn"); + break; + case 'normal': + case 'info': + default: + statusElem.classList.remove("noVNC_status_error"); + statusElem.classList.remove("noVNC_status_warn"); + statusElem.classList.add("noVNC_status_normal"); + break; + } + + statusElem.textContent = text; + statusElem.classList.add("noVNC_open"); + + // If no time was specified, show the status for 1.5 seconds + if (typeof time === 'undefined') { + time = 1500; + } + + // Error messages do not timeout + if (statusType !== 'error') { + UI.statusTimeout = window.setTimeout(UI.hideStatus, time); + } + }, + + hideStatus() { + clearTimeout(UI.statusTimeout); + document.getElementById('noVNC_status').classList.remove("noVNC_open"); + }, + + activateControlbar(event) { + clearTimeout(UI.idleControlbarTimeout); + // We manipulate the anchor instead of the actual control + // bar in order to avoid creating new a stacking group + document.getElementById('noVNC_control_bar_anchor') + .classList.remove("noVNC_idle"); + UI.idleControlbarTimeout = window.setTimeout(UI.idleControlbar, 2000); + }, + + idleControlbar() { + // Don't fade if a child of the control bar has focus + if (document.getElementById('noVNC_control_bar') + .contains(document.activeElement) && document.hasFocus()) { + UI.activateControlbar(); + return; + } + + document.getElementById('noVNC_control_bar_anchor') + .classList.add("noVNC_idle"); + }, + + keepControlbar() { + clearTimeout(UI.closeControlbarTimeout); + }, + + openControlbar() { + document.getElementById('noVNC_control_bar') + .classList.add("noVNC_open"); + if (WebUtil.isInsideKasmVDI()) { + parent.postMessage({ action: 'control_open', value: 'Control bar opened'}, '*' ); + } + }, + + closeControlbar() { + UI.closeAllPanels(); + document.getElementById('noVNC_control_bar') + .classList.remove("noVNC_open"); + if (UI.rfb) { + UI.rfb.focus(); + } + if (WebUtil.isInsideKasmVDI()) { + parent.postMessage({ action: 'control_close', value: 'Control bar closed'}, '*' ); + } + }, + + toggleControlbar() { + if (document.getElementById('noVNC_control_bar') + .classList.contains("noVNC_open")) { + UI.closeControlbar(); + } else { + UI.openControlbar(); + } + }, + + toggleControlbarSide() { + // Temporarily disable animation, if bar is displayed, to avoid weird + // movement. The transitionend-event will not fire when display=none. + const bar = document.getElementById('noVNC_control_bar'); + const barDisplayStyle = window.getComputedStyle(bar).display; + if (barDisplayStyle !== 'none') { + bar.style.transitionDuration = '0s'; + bar.addEventListener('transitionend', () => bar.style.transitionDuration = ''); + } + + const anchor = document.getElementById('noVNC_control_bar_anchor'); + if (anchor.classList.contains("noVNC_right")) { + WebUtil.writeSetting('controlbar_pos', 'left'); + anchor.classList.remove("noVNC_right"); + } else { + WebUtil.writeSetting('controlbar_pos', 'right'); + anchor.classList.add("noVNC_right"); + } + + // Consider this a movement of the handle + UI.controlbarDrag = true; + }, + + showControlbarHint(show) { + const hint = document.getElementById('noVNC_control_bar_hint'); + if (show) { + hint.classList.add("noVNC_active"); + } else { + hint.classList.remove("noVNC_active"); + } + }, + + dragControlbarHandle(e) { + if (!UI.controlbarGrabbed) return; + + const ptr = getPointerEvent(e); + + const anchor = document.getElementById('noVNC_control_bar_anchor'); + if (ptr.clientX < (window.innerWidth * 0.1)) { + if (anchor.classList.contains("noVNC_right")) { + UI.toggleControlbarSide(); + } + } else if (ptr.clientX > (window.innerWidth * 0.9)) { + if (!anchor.classList.contains("noVNC_right")) { + UI.toggleControlbarSide(); + } + } + + if (!UI.controlbarDrag) { + const dragDistance = Math.abs(ptr.clientY - UI.controlbarMouseDownClientY); + + if (dragDistance < dragThreshold) return; + + UI.controlbarDrag = true; + } + + const eventY = ptr.clientY - UI.controlbarMouseDownOffsetY; + + UI.moveControlbarHandle(eventY); + + e.preventDefault(); + e.stopPropagation(); + UI.keepControlbar(); + UI.activateControlbar(); + }, + + // Move the handle but don't allow any position outside the bounds + moveControlbarHandle(viewportRelativeY) { + const handle = document.getElementById("noVNC_control_bar_handle"); + const handleHeight = handle.getBoundingClientRect().height; + const controlbarBounds = document.getElementById("noVNC_control_bar") + .getBoundingClientRect(); + const margin = 10; + + // These heights need to be non-zero for the below logic to work + if (handleHeight === 0 || controlbarBounds.height === 0) { + return; + } + + let newY = viewportRelativeY; + + // Check if the coordinates are outside the control bar + if (newY < controlbarBounds.top + margin) { + // Force coordinates to be below the top of the control bar + newY = controlbarBounds.top + margin; + + } else if (newY > controlbarBounds.top + + controlbarBounds.height - handleHeight - margin) { + // Force coordinates to be above the bottom of the control bar + newY = controlbarBounds.top + + controlbarBounds.height - handleHeight - margin; + } + + // Corner case: control bar too small for stable position + if (controlbarBounds.height < (handleHeight + margin * 2)) { + newY = controlbarBounds.top + + (controlbarBounds.height - handleHeight) / 2; + } + + // The transform needs coordinates that are relative to the parent + const parentRelativeY = newY - controlbarBounds.top; + handle.style.transform = "translateY(" + parentRelativeY + "px)"; + }, + + updateControlbarHandle() { + // Since the control bar is fixed on the viewport and not the page, + // the move function expects coordinates relative the the viewport. + const handle = document.getElementById("noVNC_control_bar_handle"); + const handleBounds = handle.getBoundingClientRect(); + UI.moveControlbarHandle(handleBounds.top); + }, + + controlbarHandleMouseUp(e) { + if ((e.type == "mouseup") && (e.button != 0)) return; + + // mouseup and mousedown on the same place toggles the controlbar + if (UI.controlbarGrabbed && !UI.controlbarDrag) { + UI.toggleControlbar(); + e.preventDefault(); + e.stopPropagation(); + UI.keepControlbar(); + UI.activateControlbar(); + } + UI.controlbarGrabbed = false; + UI.showControlbarHint(false); + }, + + controlbarHandleMouseDown(e) { + if ((e.type == "mousedown") && (e.button != 0)) return; + + const ptr = getPointerEvent(e); + + const handle = document.getElementById("noVNC_control_bar_handle"); + const bounds = handle.getBoundingClientRect(); + + // Touch events have implicit capture + if (e.type === "mousedown") { + setCapture(handle); + } + + UI.controlbarGrabbed = true; + UI.controlbarDrag = false; + + UI.showControlbarHint(true); + + UI.controlbarMouseDownClientY = ptr.clientY; + UI.controlbarMouseDownOffsetY = ptr.clientY - bounds.top; + e.preventDefault(); + e.stopPropagation(); + UI.keepControlbar(); + UI.activateControlbar(); + }, + + toggleExpander(e) { + if (this.classList.contains("noVNC_open")) { + this.classList.remove("noVNC_open"); + } else { + this.classList.add("noVNC_open"); + } + }, + + addClickHandle(domElementName, funcToCall) { + /* Add click handler, will attach to parent if appropriate */ + var control = document.getElementById(domElementName); + if (control.parentNode.classList.contains('noVNC_button_div')) { + control.parentNode.addEventListener('click', funcToCall); + } else { + control.addEventListener('click', funcToCall); + } + }, + + showControlInput(name) { + var control = document.getElementById(name); + /*var control_label = document.getElementById(name + '_label'); + if (control) { + control.classList.remove("noVNC_hidden"); + } + if (control_label) { + control_label.classList.remove("noVNC_hidden"); + } */ + if (control.parentNode.classList.contains('noVNC_button_div')) { + control.parentNode.classList.remove("noVNC_hidden") + } else { + control.classList.remove("noVNC_hidden") + } + }, + + hideControlInput(name) { + var control = document.getElementById(name); + /*var control_label = document.getElementById(name + '_label'); + if (control) { + control.classList.add("noVNC_hidden"); + } + if (control_label) { + control_label.classList.add("noVNC_hidden"); + }*/ + if (control.parentNode.classList.contains('noVNC_button_div')) { + control.parentNode.classList.add("noVNC_hidden") + } else { + control.classList.add("noVNC_hidden") + } + }, + +/* ------^------- + * /VISUAL + * ============== + * SETTINGS + * ------v------*/ + + // Initial page load read/initialization of settings + initSetting(name, defVal) { + // Check Query string followed by cookie + let val = WebUtil.getConfigVar(name); + if (val === null) { + val = WebUtil.readSetting(name, defVal); + } + WebUtil.setSetting(name, val); + UI.updateSetting(name); + return val; + }, + + // Set the new value, update and disable form control setting + forceSetting(name, val, disable=true) { + WebUtil.setSetting(name, val); + UI.updateSetting(name); + if (disable) { + UI.disableSetting(name); + } else { + UI.enableSetting(name); + } + UI.saveSetting(name); + }, + + // Update cookie and form control setting. If value is not set, then + // updates from control to current cookie setting. + updateSetting(name) { + + // Update the settings control + let value = UI.getSetting(name); + + const ctrl = document.getElementById('noVNC_setting_' + name); + if (ctrl.type === 'checkbox') { + ctrl.checked = value; + + } else if (typeof ctrl.options !== 'undefined') { + value = String(value); + for (let i = 0; i < ctrl.options.length; i += 1) { + if (ctrl.options[i].value === value) { + ctrl.selectedIndex = i; + break; + } + } + } else { + let value_label = document.getElementById('noVNC_setting_' + name + '_output'); + ctrl.value = value; + if (value_label) { + value_label.value = value; + } + } + }, + + // Save control setting to cookie + saveSetting(name) { + const ctrl = document.getElementById('noVNC_setting_' + name); + let val; + if (ctrl.type === 'checkbox') { + val = ctrl.checked; + } else if (typeof ctrl.options !== 'undefined') { + val = ctrl.options[ctrl.selectedIndex].value; + } else { + val = ctrl.value; + } + WebUtil.writeSetting(name, val); + //Log.Debug("Setting saved '" + name + "=" + val + "'"); + return val; + }, + + // Read form control compatible setting from cookie + getSetting(name) { + const ctrl = document.getElementById('noVNC_setting_' + name); + let val = WebUtil.readSetting(name); + if (typeof val !== 'undefined' && val !== null && ctrl.type === 'checkbox') { + if (val.toString().toLowerCase() in {'0': 1, 'no': 1, 'false': 1}) { + val = false; + } else { + val = true; + } + } + return val; + }, + + // These helpers compensate for the lack of parent-selectors and + // previous-sibling-selectors in CSS which are needed when we want to + // disable the labels that belong to disabled input elements. + disableSetting(name) { + const ctrl = document.getElementById('noVNC_setting_' + name); + ctrl.disabled = true; + ctrl.label.classList.add('noVNC_disabled'); + }, + + enableSetting(name) { + const ctrl = document.getElementById('noVNC_setting_' + name); + ctrl.disabled = false; + ctrl.label.classList.remove('noVNC_disabled'); + }, + +/* ------^------- + * /SETTINGS + * ============== + * PANELS + * ------v------*/ + + closeAllPanels() { + UI.closeSettingsPanel(); + UI.closePowerPanel(); + UI.closeClipboardPanel(); + UI.closeExtraKeys(); + }, + +/* ------^------- + * /PANELS + * ============== + * SETTINGS (panel) + * ------v------*/ + + openSettingsPanel() { + UI.closeAllPanels(); + UI.openControlbar(); + + // Refresh UI elements from saved cookies + UI.updateSetting('encrypt'); + UI.updateSetting('view_clip'); + UI.updateSetting('resize'); + UI.updateSetting('quality'); + UI.updateSetting('dynamic_quality_min', 3); + UI.updateSetting('dynamic_quality_max', 9); + UI.updateSetting('treat_lossless', 7); + UI.updateSetting('anti_aliasing', 0); + UI.updateSetting('jpeg_video_quality', 5); + UI.updateSetting('webp_video_quality', 5); + UI.updateSetting('video_quality', 2); + UI.updateSetting('video_area', 65); + UI.updateSetting('video_time', 5); + UI.updateSetting('video_out_time', 3); + UI.updateSetting('video_scaling', 2); + UI.updateSetting('max_video_resolution_x', 960); + UI.updateSetting('max_video_resolution_y', 540); + UI.updateSetting('framerate', 30); + UI.updateSetting('compression'); + UI.updateSetting('shared'); + UI.updateSetting('view_only'); + UI.updateSetting('path'); + UI.updateSetting('repeaterID'); + UI.updateSetting('logging'); + UI.updateSetting('reconnect'); + UI.updateSetting('reconnect_delay'); + + document.getElementById('noVNC_settings') + .classList.add("noVNC_open"); + document.getElementById('noVNC_settings_button') + .classList.add("noVNC_selected"); + }, + + closeSettingsPanel() { + document.getElementById('noVNC_settings') + .classList.remove("noVNC_open"); + document.getElementById('noVNC_settings_button') + .classList.remove("noVNC_selected"); + }, + + toggleSettingsPanel(e) { + if (!UI.isControlPanelItemClick(e)) { + return false; + } + + if (document.getElementById('noVNC_settings') + .classList.contains("noVNC_open")) { + UI.closeSettingsPanel(); + } else { + UI.openSettingsPanel(); + } + }, + +/* ------^------- + * /SETTINGS + * ============== + * POWER + * ------v------*/ + + openPowerPanel() { + UI.closeAllPanels(); + UI.openControlbar(); + + document.getElementById('noVNC_power') + .classList.add("noVNC_open"); + document.getElementById('noVNC_power_button') + .classList.add("noVNC_selected"); + }, + + closePowerPanel() { + document.getElementById('noVNC_power') + .classList.remove("noVNC_open"); + document.getElementById('noVNC_power_button') + .classList.remove("noVNC_selected"); + }, + + togglePowerPanel(e) { + if (!UI.isControlPanelItemClick(e)) { + return false; + } + + if (document.getElementById('noVNC_power') + .classList.contains("noVNC_open")) { + UI.closePowerPanel(); + } else { + UI.openPowerPanel(); + } + }, + + // Disable/enable power button + updatePowerButton() { + if (UI.connected && + UI.rfb.capabilities.power && + !UI.rfb.viewOnly) { + UI.showControlInput('noVNC_power_button') + } else { + UI.hideControlInput('noVNC_power_button'); + // Close power panel if open + UI.closePowerPanel(); + } + }, + +/* ------^------- + * /POWER + * ============== + * CLIPBOARD + * ------v------*/ + + openClipboardPanel() { + UI.closeAllPanels(); + UI.openControlbar(); + + document.getElementById('noVNC_clipboard') + .classList.add("noVNC_open"); + document.getElementById('noVNC_clipboard_button') + .classList.add("noVNC_selected"); + }, + + closeClipboardPanel() { + document.getElementById('noVNC_clipboard') + .classList.remove("noVNC_open"); + document.getElementById('noVNC_clipboard_button') + .classList.remove("noVNC_selected"); + }, + + toggleClipboardPanel(e) { + if (!UI.isControlPanelItemClick(e)) { + return false; + } + + if (document.getElementById('noVNC_clipboard') + .classList.contains("noVNC_open")) { + UI.closeClipboardPanel(); + } else { + UI.openClipboardPanel(); + } + }, + + clipboardReceive(e) { + if (UI.rfb.clipboardDown) { + var curvalue = document.getElementById('noVNC_clipboard_text').value; + if (curvalue != e.detail.text) { + Log.Debug(">> UI.clipboardReceive: " + e.detail.text.substr(0, 40) + "..."); + document.getElementById('noVNC_clipboard_text').value = e.detail.text; + Log.Debug("<< UI.clipboardReceive"); + } + } + }, + + //recieved bottleneck stats + bottleneckStatsRecieve(e) { + if (UI.rfb) { + try { + let obj = JSON.parse(e.detail.text); + let fps = UI.rfb.statsFps; + document.getElementById("noVNC_connection_stats").innerHTML = "CPU: " + obj[0] + "/" + obj[1] + " | Network: " + obj[2] + "/" + obj[3] + " | FPS: " + fps; + console.log(e.detail.text); + } catch (err) { + console.log('Invalid bottleneck stats recieved from server.') + } + } + }, + + popupMessage: function(msg, secs) { + if (!secs){ + secs = 500; + } + // Quick popup to give feedback that selection was copied + setTimeout(UI.showOverlay.bind(this, msg, secs), 200); + }, + + clipboardClear() { + document.getElementById('noVNC_clipboard_text').value = ""; + UI.rfb.clipboardPasteFrom(""); + }, + + clipboardSend() { + const text = document.getElementById('noVNC_clipboard_text').value; + Log.Debug(">> UI.clipboardSend: " + text.substr(0, 40) + "..."); + UI.rfb.clipboardPasteFrom(text); + Log.Debug("<< UI.clipboardSend"); + }, + +/* ------^------- + * /CLIPBOARD + * ============== + * CONNECTION + * ------v------*/ + + connect(event, password) { + + // Ignore when rfb already exists + if (typeof UI.rfb !== 'undefined') { + return; + } + + const host = UI.getSetting('host'); + const port = UI.getSetting('port'); + const path = UI.getSetting('path'); + + if (typeof password === 'undefined') { + password = WebUtil.getConfigVar('password'); + UI.reconnectPassword = password; + } + + if (password === null) { + password = undefined; + } + + UI.hideStatus(); + + if (!host) { + Log.Error("Can't connect when host is: " + host); + UI.showStatus(_("Must set host"), 'error'); + return; + } + + UI.updateVisualState('connecting'); + + let url; + + url = UI.getSetting('encrypt') ? 'wss' : 'ws'; + + url += '://' + host; + if (port) { + url += ':' + port; + } + url += '/' + path; + + UI.rfb = new RFB(document.getElementById('noVNC_container'), + document.getElementById('noVNC_keyboardinput'), + url, + { shared: UI.getSetting('shared'), + repeaterID: UI.getSetting('repeaterID'), + credentials: { password: password } }); + UI.rfb.addEventListener("connect", UI.connectFinished); + UI.rfb.addEventListener("disconnect", UI.disconnectFinished); + UI.rfb.addEventListener("credentialsrequired", UI.credentials); + UI.rfb.addEventListener("securityfailure", UI.securityFailed); + UI.rfb.addEventListener("capabilities", UI.updatePowerButton); + UI.rfb.addEventListener("clipboard", UI.clipboardReceive); + UI.rfb.addEventListener("bottleneck_stats", UI.bottleneckStatsRecieve); + UI.rfb.addEventListener("bell", UI.bell); + UI.rfb.addEventListener("desktopname", UI.updateDesktopName); + UI.rfb.addEventListener("inputlock", UI.inputLockChanged); + UI.rfb.addEventListener("inputlockerror", UI.inputLockError); + UI.rfb.translateShortcuts = UI.getSetting('translate_shortcuts'); + UI.rfb.clipViewport = UI.getSetting('view_clip'); + UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale'; + UI.rfb.resizeSession = UI.getSetting('resize') === 'remote'; + UI.rfb.qualityLevel = parseInt(UI.getSetting('quality')); + UI.rfb.dynamicQualityMin = parseInt(UI.getSetting('dynamic_quality_min')); + UI.rfb.dynamicQualityMax = parseInt(UI.getSetting('dynamic_quality_max')); + UI.rfb.jpegVideoQuality = parseInt(UI.getSetting('jpeg_video_quality')); + UI.rfb.webpVideoQuality = parseInt(UI.getSetting('webp_video_quality')); + UI.rfb.videoArea = parseInt(UI.getSetting('video_area')); + UI.rfb.videoTime = parseInt(UI.getSetting('video_time')); + UI.rfb.videoOutTime = parseInt(UI.getSetting('video_out_time')); + UI.rfb.videoScaling = parseInt(UI.getSetting('video_scaling')); + UI.rfb.treatLossless = parseInt(UI.getSetting('treat_lossless')); + UI.rfb.maxVideoResolutionX = parseInt(UI.getSetting('max_video_resolution_x')); + UI.rfb.maxVideoResolutionY = parseInt(UI.getSetting('max_video_resolution_y')); + UI.rfb.frameRate = parseInt(UI.getSetting('framerate')); + UI.rfb.compressionLevel = parseInt(UI.getSetting('compression')); + UI.rfb.showDotCursor = UI.getSetting('show_dot'); + UI.rfb.idleDisconnect = UI.getSetting('idle_disconnect'); + UI.rfb.pointerRelative = UI.getSetting('pointer_relative'); + UI.rfb.videoQuality = parseInt(UI.getSetting('video_quality')); + UI.rfb.antiAliasing = UI.getSetting('anti_aliasing'); + UI.rfb.clipboardUp = UI.getSetting('clipboard_up'); + UI.rfb.clipboardDown = UI.getSetting('clipboard_down'); + UI.rfb.clipboardSeamless = UI.getSetting('clipboard_seamless'); + UI.rfb.keyboard.enableIME = UI.getSetting('enable_ime'); + UI.rfb.clipboardBinary = supportsBinaryClipboard() && UI.rfb.clipboardSeamless; + UI.rfb.enableWebRTC = UI.getSetting('enable_webrtc'); + UI.rfb.enableHiDpi = UI.getSetting('enable_hidpi'); + UI.rfb.mouseButtonMapper = UI.initMouseButtonMapper(); + if (UI.rfb.videoQuality === 5) { + UI.rfb.enableQOI = true; + } + + //Only explicitly request permission to clipboard on browsers that support binary clipboard access + if (supportsBinaryClipboard()) { + // explicitly request permission to the clipboard + navigator.permissions.query({ name: "clipboard-read" }).then((result) => { Log.Debug('binary clipboard enabled') }); + } + // KASM-960 workaround, disable seamless on Safari + if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) + { + UI.rfb.clipboardSeamless = false; + } + UI.rfb.preferLocalCursor = UI.getSetting('prefer_local_cursor'); + UI.rfb.enableWebP = UI.getSetting('enable_webp'); + UI.updateViewOnly(); // requires UI.rfb + + /**** + * Kasm VDI specific + *****/ + if (WebUtil.isInsideKasmVDI()) { + if (window.addEventListener) { // Mozilla, Netscape, Firefox + //window.addEventListener('load', WindowLoad, false); + window.addEventListener('message', UI.receiveMessage, false); + } else if (window.attachEvent) { //IE + window.attachEvent('onload', WindowLoad); + window.attachEvent('message', UI.receiveMessage); + } + if (UI.rfb.clipboardDown){ + UI.rfb.addEventListener("clipboard", UI.clipboardRx); + } + UI.rfb.addEventListener("disconnect", UI.disconnectedRx); + if (! WebUtil.getConfigVar('show_control_bar')) { + document.getElementById('noVNC_control_bar_anchor').setAttribute('style', 'display: none'); + } + + //keep alive for websocket connection to stay open, since we may not control reverse proxies + //send a keep alive within a window that we control + UI._sessionTimeoutInterval = setInterval(function() { + + const timeSinceLastActivityInS = (Date.now() - UI.rfb.lastActiveAt) / 1000; + let idleDisconnectInS = 1200; //20 minute default + if (Number.isFinite(parseFloat(UI.rfb.idleDisconnect))) { + idleDisconnectInS = parseFloat(UI.rfb.idleDisconnect) * 60; + } + + if (timeSinceLastActivityInS > idleDisconnectInS) { + parent.postMessage({ action: 'idle_session_timeout', value: 'Idle session timeout exceeded'}, '*' ); + } else { + //send keep-alive + UI.rfb.sendKey(1, null, false); + } + }, 5000); + } else { + document.getElementById('noVNC_status').style.visibility = "visible"; + } + + //key events for KasmVNC control + document.addEventListener('keyup', function (event) { + if (event.ctrlKey && event.shiftKey) { + switch(event.keyCode) { + case 49: + UI.toggleNav(); + break; + case 50: + UI.toggleRelativePointer(); + break; + case 51: + UI.togglePointerLock(); + break; + } + } + + }, true); + }, + + disconnect() { + UI.rfb.disconnect(); + + UI.connected = false; + + // Disable automatic reconnecting + UI.inhibitReconnect = true; + + UI.updateVisualState('disconnecting'); + + clearInterval(UI._sessionTimeoutInterval); + }, + + reconnect() { + UI.reconnectCallback = null; + + // if reconnect has been disabled in the meantime, do nothing. + if (UI.inhibitReconnect) { + return; + } + + + UI.connect(null, UI.reconnectPassword); + }, + + cancelReconnect() { + if (UI.reconnectCallback !== null) { + clearTimeout(UI.reconnectCallback); + UI.reconnectCallback = null; + } + + UI.updateVisualState('disconnected'); + + UI.openControlbar(); + }, + + connectFinished(e) { + UI.connected = true; + UI.inhibitReconnect = false; + + let msg; + if (UI.getSetting('encrypt')) { + msg = _("Connected (encrypted) to ") + UI.desktopName; + } else { + msg = _("Connected (unencrypted) to ") + UI.desktopName; + } + UI.showStatus(msg); + UI.showStats(); + UI.updateVisualState('connected'); + + // Do this last because it can only be used on rendered elements + UI.rfb.focus(); + }, + + disconnectFinished(e) { + const wasConnected = UI.connected; + + // This variable is ideally set when disconnection starts, but + // when the disconnection isn't clean or if it is initiated by + // the server, we need to do it here as well since + // UI.disconnect() won't be used in those cases. + UI.connected = false; + + UI.rfb = undefined; + + if (!e.detail.clean) { + UI.updateVisualState('disconnected'); + if (wasConnected) { + UI.showStatus(_("Something went wrong, connection is closed"), + 'error'); + } else { + UI.showStatus(_("Failed to connect to server"), 'error'); + } + } else if (UI.getSetting('reconnect', false) === true && !UI.inhibitReconnect) { + UI.updateVisualState('reconnecting'); + + const delay = parseInt(UI.getSetting('reconnect_delay')); + UI.reconnectCallback = setTimeout(UI.reconnect, delay); + return; + } else { + UI.updateVisualState('disconnected'); + UI.showStatus(_("Disconnected"), 'normal'); + } + + document.title = PAGE_TITLE; + + UI.openControlbar(); + + if (UI.forceReconnect) { + UI.forceReconnect = false; + UI.connect(null, UI.reconnectPassword); + } + }, + + securityFailed(e) { + let msg = ""; + // On security failures we might get a string with a reason + // directly from the server. Note that we can't control if + // this string is translated or not. + if ('reason' in e.detail) { + msg = _("New connection has been rejected with reason: ") + + e.detail.reason; + } else { + msg = _("New connection has been rejected"); + } + UI.showStatus(msg, 'error'); + }, + + //send message to parent window + sendMessage(name, value) { + if (WebUtil.isInsideKasmVDI()) { + parent.postMessage({ action: name, value: value }, '*' ); + } + }, + + //receive message from parent window + receiveMessage(event) { + if (event.data && event.data.action) { + switch (event.data.action) { + case 'clipboardsnd': + if (UI.rfb && UI.rfb.clipboardUp) { + UI.rfb.clipboardPasteFrom(event.data.value); + } + break; + case 'setvideoquality': + if (event.data.qualityLevel !== undefined) { + //apply preset mode values, but don't apply to connection + UI.forceSetting('video_quality', parseInt(event.data.qualityLevel), false); + // apply quality preset quality level and override some settings (fps) + UI.updateQuality(event.data.frameRate); + } else { + UI.forceSetting('video_quality', parseInt(event.data.value), false); + UI.updateQuality(); + } + break; + case 'enable_game_mode': + if (UI.rfb && !UI.rfb.pointerRelative) { + UI.toggleRelativePointer(); + } + break; + case 'disable_game_mode': + if (UI.rfb && UI.rfb.pointerRelative) { + UI.toggleRelativePointer(); + } + break; + case 'enable_pointer_lock': + if (UI.rfb && !UI.rfb.pointerLock) { + UI.togglePointerLock(); + } + break; + case 'disable_pointer_lock': + if (UI.rfb && UI.rfb.pointerLock) { + UI.togglePointerLock(); + } + break; + case 'show_keyboard_controls': + if (!UI.getSetting('virtual_keyboard_visible')) { + UI.forceSetting('virtual_keyboard_visible', true, false); + UI.showKeyboardControls(); + } + break; + case 'hide_keyboard_controls': + if (UI.getSetting('virtual_keyboard_visible')) { + UI.forceSetting('virtual_keyboard_visible', true, false); + UI.hideKeyboardControls(); + } + break; + case 'enable_ime_mode': + if (!UI.getSetting('enable_ime')) { + UI.forceSetting('enable_ime', true, false); + UI.toggleIMEMode(); + } + break; + case 'disable_ime_mode': + if (UI.getSetting('enable_ime')) { + UI.forceSetting('enable_ime', false, false); + UI.toggleIMEMode(); + } + break; + case 'enable_webrtc': + if (!UI.getSetting('enable_webrtc')) { + UI.forceSetting('enable_webrtc', true, false); + UI.toggleWebRTC(); + } + break; + case 'disable_webrtc': + if (UI.getSetting('enable_webrtc')) { + UI.forceSetting('enable_webrtc', false, false); + UI.toggleWebRTC(); + } + break; + case 'resize': + UI.forceSetting('resize', event.data.value, false); + UI.applyResizeMode(); + break; + case 'set_resolution': + if (UI.rfb) { + UI.rfb.forcedResolutionX = event.data.value_x; + UI.rfb.forcedResolutionY = event.data.value_y; + UI.applyResizeMode(); + UI.rfb.forcedResolutionX = null; + UI.rfb.forcedResolutionY = null; + UI.rfb._resizeSession = UI.getSetting('resize') === 'remote'; + } + break; + case 'set_perf_stats': + UI.forceSetting('enable_perf_stats', event.data.value, false); + UI.showStats(); + break; + case 'set_idle_timeout': + //message value in seconds + const idle_timeout_min = Math.ceil(event.data.value / 60); + UI.forceSetting('idle_disconnect', idle_timeout_min, false); + UI.rfb.idleDisconnect = idle_timeout_min; + console.log(`Updated the idle timeout to ${event.data.value}s`); + break; + case 'enable_hidpi': + UI.forceSetting('enable_hidpi', event.data.value, false); + UI.enableHiDpi(); + break; + } + } + }, + + disconnectedRx(event) { + parent.postMessage({ action: 'disconnectrx', value: event.detail.reason}, '*' ); + }, + + toggleNav(){ + if (WebUtil.isInsideKasmVDI()) { + parent.postMessage({ action: 'togglenav', value: null}, '*' ); + } else { + UI.toggleControlbar(); + UI.keepControlbar(); + UI.activateControlbar(); + UI.controlbarGrabbed = false; + UI.showControlbarHint(false); + } + }, + + clipboardRx(event) { + parent.postMessage({ action: 'clipboardrx', value: event.detail.text}, '*' ); //TODO fix star + }, + +/* ------^------- + * /CONNECTION + * ============== + * PASSWORD + * ------v------*/ + + credentials(e) { + // FIXME: handle more types + + document.getElementById("noVNC_username_block").classList.remove("noVNC_hidden"); + document.getElementById("noVNC_password_block").classList.remove("noVNC_hidden"); + + let inputFocus = "none"; + if (e.detail.types.indexOf("username") === -1) { + document.getElementById("noVNC_username_block").classList.add("noVNC_hidden"); + } else { + inputFocus = inputFocus === "none" ? "noVNC_username_input" : inputFocus; + } + if (e.detail.types.indexOf("password") === -1) { + document.getElementById("noVNC_password_block").classList.add("noVNC_hidden"); + } else { + inputFocus = inputFocus === "none" ? "noVNC_password_input" : inputFocus; + } + document.getElementById('noVNC_credentials_dlg') + .classList.add('noVNC_open'); + + setTimeout(() => document + .getElementById(inputFocus).focus(), 100); + + Log.Warn("Server asked for credentials"); + UI.showStatus(_("Credentials are required"), "warning"); + }, + + setCredentials(e) { + // Prevent actually submitting the form + e.preventDefault(); + + let inputElemUsername = document.getElementById('noVNC_username_input'); + const username = inputElemUsername.value; + + let inputElemPassword = document.getElementById('noVNC_password_input'); + const password = inputElemPassword.value; + // Clear the input after reading the password + inputElemPassword.value = ""; + + UI.rfb.sendCredentials({ username: username, password: password }); + UI.reconnectPassword = password; + document.getElementById('noVNC_credentials_dlg') + .classList.remove('noVNC_open'); + }, + +/* ------^------- + * /PASSWORD + * ============== + * FULLSCREEN + * ------v------*/ + + toggleFullscreen() { + if (WebUtil.isInsideKasmVDI()) { + parent.postMessage({ action: 'fullscreen', value: 'Fullscreen clicked'}, '*' ); + return; + } + if (document.fullscreenElement || // alternative standard method + document.mozFullScreenElement || // currently working methods + document.webkitFullscreenElement || + document.msFullscreenElement) { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } + } else { + if (document.documentElement.requestFullscreen) { + document.documentElement.requestFullscreen(); + } else if (document.documentElement.mozRequestFullScreen) { + document.documentElement.mozRequestFullScreen(); + } else if (document.documentElement.webkitRequestFullscreen) { + document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); + } else if (document.body.msRequestFullscreen) { + document.body.msRequestFullscreen(); + } + } + UI.updateFullscreenButton(); + }, + + updateFullscreenButton() { + if (document.fullscreenElement || // alternative standard method + document.mozFullScreenElement || // currently working methods + document.webkitFullscreenElement || + document.msFullscreenElement ) { + document.getElementById('noVNC_fullscreen_button') + .classList.add("noVNC_selected"); + } else { + document.getElementById('noVNC_fullscreen_button') + .classList.remove("noVNC_selected"); + } + UI.updatePointerLockButton(); + }, + +/* ------^------- + * /FULLSCREEN + * ============== + * RESIZE + * ------v------*/ + + // Apply remote resizing or local scaling + applyResizeMode() { + if (!UI.rfb) return; + + UI.rfb.scaleViewport = UI.getSetting('resize') === 'scale'; + UI.rfb.resizeSession = UI.getSetting('resize') === 'remote' || UI.rfb.forcedResolutionX && UI.rfb.forcedResolutionY; + UI.rfb.idleDisconnect = UI.getSetting('idle_disconnect'); + UI.rfb.videoQuality = UI.getSetting('video_quality'); + UI.rfb.enableWebP = UI.getSetting('enable_webp'); + UI.rfb.enableHiDpi = UI.getSetting('enable_hidpi'); + }, + +/* ------^------- + * /RESIZE + * ============== + * VIEW CLIPPING + * ------v------*/ + + // Update viewport clipping property for the connection. The normal + // case is to get the value from the setting. There are special cases + // for when the viewport is scaled or when a touch device is used. + updateViewClip() { + if (!UI.rfb) return; + + const scaling = UI.getSetting('resize') === 'scale'; + + if (scaling) { + // Can't be clipping if viewport is scaled to fit + UI.forceSetting('view_clip', false); + UI.rfb.clipViewport = false; + } else if (!hasScrollbarGutter) { + // Some platforms have scrollbars that are difficult + // to use in our case, so we always use our own panning + UI.forceSetting('view_clip', true); + UI.rfb.clipViewport = true; + } else { + UI.enableSetting('view_clip'); + UI.rfb.clipViewport = UI.getSetting('view_clip'); + } + + // Changing the viewport may change the state of + // the dragging button + UI.updateViewDrag(); + }, + + /* ------^------- + * /VIEW CLIPPING + * ============== + * POINTER LOCK + * ------v------*/ + + updatePointerLockButton() { + // Only show the button if the pointer lock API is properly supported + // AND in fullscreen. + if ( + UI.connected && + (document.pointerLockElement !== undefined || + document.mozPointerLockElement !== undefined) + ) { + UI.showControlInput("noVNC_setting_pointer_lock"); + UI.showControlInput("noVNC_game_mode_button"); + } else { + UI.hideControlInput("noVNC_setting_pointer_lock"); + UI.hideControlInput("noVNC_game_mode_button"); + } + }, + + togglePointerLock() { + if (!supportsPointerLock()) { + UI.showStatus('Your browser does not support pointer lock.', 'info', 1500, true); + //force pointer lock in UI to false and disable control + UI.forceSetting('pointer_lock', false, true); + } else { + UI.rfb.pointerLock = !UI.rfb.pointerLock; + if (UI.getSetting('pointer_lock') !== UI.rfb.pointerLock) { + UI.forceSetting('pointer_lock', UI.rfb.pointerLock, false); + } + } + }, + + toggleRelativePointer(event=null, forcedToggleValue=null) { + if (!supportsPointerLock()) { + UI.showStatus('Your browser does not support pointer lock.', 'info', 1500, true); + return; + } + + var togglePosition = !UI.rfb.pointerRelative; + + if (UI.rfb.pointerLock !== togglePosition) { + UI.rfb.pointerLock = togglePosition; + } + if (UI.rfb.pointerRelative !== togglePosition) { + UI.rfb.pointerRelative = togglePosition; + } + + if (togglePosition) { + document.getElementById('noVNC_game_mode_button').classList.add("noVNC_selected"); + } else { + document.getElementById('noVNC_game_mode_button').classList.remove("noVNC_selected"); + UI.forceSetting('pointer_lock', false, false); + } + + UI.sendMessage('enable_game_mode', togglePosition); + UI.sendMessage('enable_pointer_lock', togglePosition); + + }, + +/* ------^------- + * /VIEW CLIPPING + * ============== + * VIEWDRAG + * ------v------*/ + + toggleViewDrag() { + if (!UI.rfb) return; + + UI.rfb.dragViewport = !UI.rfb.dragViewport; + UI.updateViewDrag(); + }, + + updateViewDrag() { + if (!UI.connected) return; + + const viewDragButton = document.getElementById('noVNC_view_drag_button'); + + if (!UI.rfb.clipViewport && UI.rfb.dragViewport) { + // We are no longer clipping the viewport. Make sure + // viewport drag isn't active when it can't be used. + UI.rfb.dragViewport = false; + } + + if (UI.rfb.dragViewport) { + viewDragButton.classList.add("noVNC_selected"); + } else { + viewDragButton.classList.remove("noVNC_selected"); + } + + if (UI.rfb.clipViewport) { + UI.showControlInput('noVNC_view_drag_button'); + } else { + UI.hideControlInput('noVNC_view_drag_button'); + } + }, + +/* ------^------- + * /VIEWDRAG + * ============== + * QUALITY + * ------v------*/ + + updateQuality(fps) { + let present_mode = parseInt(UI.getSetting('video_quality')); + let enable_qoi = false; + + // video_quality preset values + switch (present_mode) { + case 10: //custom + UI.enableSetting('dynamic_quality_min'); + UI.enableSetting('dynamic_quality_max'); + UI.enableSetting('treat_lossless'); + UI.enableSetting('video_time'); + UI.enableSetting('video_area'); + UI.enableSetting('max_video_resolution_x'); + UI.enableSetting('max_video_resolution_y'); + UI.enableSetting('jpeg_video_quality'); + UI.enableSetting('webp_video_quality'); + UI.enableSetting('framerate'); + UI.enableSetting('video_scaling'); + UI.enableSetting('video_out_time'); + break; + case 5: //lossless + enable_qoi = true; + fps = (fps && Number.isFinite(fps)) ? fps : 60; + UI.forceSetting('dynamic_quality_min', 9); + UI.forceSetting('dynamic_quality_max', 9); + UI.forceSetting('framerate', fps); + UI.forceSetting('treat_lossless', 9); + UI.forceSetting('video_time', 100); + UI.forceSetting('video_area', 100); + UI.forceSetting('max_video_resolution_x', 1920); + UI.forceSetting('max_video_resolution_y', 1080); + UI.forceSetting('jpeg_video_quality', 9); + UI.forceSetting('webp_video_quality', 9); + UI.forceSetting('video_scaling', 0); + UI.forceSetting('video_out_time', 3); + break; + case 4: //extreme + fps = (fps && Number.isFinite(fps)) ? fps : 60; + UI.forceSetting('dynamic_quality_min', 8); + UI.forceSetting('dynamic_quality_max', 9); + UI.forceSetting('framerate', fps); + UI.forceSetting('treat_lossless', 9); + UI.forceSetting('video_time', 100); + UI.forceSetting('video_area', 100); + UI.forceSetting('max_video_resolution_x', 1920); + UI.forceSetting('max_video_resolution_y', 1080); + UI.forceSetting('jpeg_video_quality', 9); + UI.forceSetting('webp_video_quality', 9); + UI.forceSetting('video_scaling', 0); + UI.forceSetting('video_out_time', 3); + break; + case 3: // high + fps = (fps && Number.isFinite(fps)) ? fps : 60; + UI.forceSetting('jpeg_video_quality', 8); + UI.forceSetting('webp_video_quality', 8); + UI.forceSetting('dynamic_quality_min', 7); + UI.forceSetting('dynamic_quality_max', 9); + UI.forceSetting('max_video_resolution_x', 1920); + UI.forceSetting('max_video_resolution_y', 1080); + UI.forceSetting('framerate', fps); + UI.forceSetting('treat_lossless', 8); + UI.forceSetting('video_time', 5); + UI.forceSetting('video_area', 65); + UI.forceSetting('video_scaling', 0); + UI.forceSetting('video_out_time', 3); + break; + case 1: // low, resolution capped at 720p keeping aspect ratio + fps = (fps && Number.isFinite(fps)) ? fps : 24; + UI.forceSetting('jpeg_video_quality', 5); + UI.forceSetting('webp_video_quality', 4); + UI.forceSetting('dynamic_quality_min', 3); + UI.forceSetting('dynamic_quality_max', 7); + UI.forceSetting('max_video_resolution_x', 960); + UI.forceSetting('max_video_resolution_y', 540); + UI.forceSetting('framerate', fps); + UI.forceSetting('treat_lossless', 7); + UI.forceSetting('video_time', 5); + UI.forceSetting('video_area', 65); + UI.forceSetting('video_scaling', 0); + UI.forceSetting('video_out_time', 3); + break; + case 2: // medium + case 0: // static resolution, but same settings as medium + default: + fps = (fps && Number.isFinite(fps)) ? fps : 24; + UI.forceSetting('jpeg_video_quality', 7); + UI.forceSetting('webp_video_quality', 7); + UI.forceSetting('dynamic_quality_min', 4); + UI.forceSetting('dynamic_quality_max', 9); + UI.forceSetting('max_video_resolution_x', 960); + UI.forceSetting('max_video_resolution_y', 540); + UI.forceSetting('framerate', (fps) ? fps : 24); + UI.forceSetting('treat_lossless', 7); + UI.forceSetting('video_time', 5); + UI.forceSetting('video_area', 65); + UI.forceSetting('video_scaling', 0); + UI.forceSetting('video_out_time', 3); + break; + } + + if (UI.rfb) { + UI.rfb.qualityLevel = parseInt(UI.getSetting('quality')); + UI.rfb.antiAliasing = parseInt(UI.getSetting('anti_aliasing')); + UI.rfb.dynamicQualityMin = parseInt(UI.getSetting('dynamic_quality_min')); + UI.rfb.dynamicQualityMax = parseInt(UI.getSetting('dynamic_quality_max')); + UI.rfb.jpegVideoQuality = parseInt(UI.getSetting('jpeg_video_quality')); + UI.rfb.webpVideoQuality = parseInt(UI.getSetting('webp_video_quality')); + UI.rfb.videoArea = parseInt(UI.getSetting('video_area')); + UI.rfb.videoTime = parseInt(UI.getSetting('video_time')); + UI.rfb.videoOutTime = parseInt(UI.getSetting('video_out_time')); + UI.rfb.videoScaling = parseInt(UI.getSetting('video_scaling')); + UI.rfb.treatLossless = parseInt(UI.getSetting('treat_lossless')); + UI.rfb.maxVideoResolutionX = parseInt(UI.getSetting('max_video_resolution_x')); + UI.rfb.maxVideoResolutionY = parseInt(UI.getSetting('max_video_resolution_y')); + UI.rfb.frameRate = parseInt(UI.getSetting('framerate')); + UI.rfb.enableWebP = UI.getSetting('enable_webp'); + UI.rfb.videoQuality = parseInt(UI.getSetting('video_quality')); + UI.rfb.enableQOI = enable_qoi; + UI.rfb.enableHiDpi = UI.getSetting('enable_hidpi'); + + // Gracefully update settings server side + UI.rfb.updateConnectionSettings(); + } + }, + +/* ------^------- + * /QUALITY + * ============== + * COMPRESSION + * ------v------*/ + + updateCompression() { + if (!UI.rfb) return; + + UI.rfb.compressionLevel = parseInt(UI.getSetting('compression')); + }, + + + +/* ------^------- + * /COMPRESSION + * ============== + * MOUSE AND KEYBOARD + * ------v------*/ + + updateShortcutTranslation() { + UI.rfb.translateShortcuts = UI.getSetting('translate_shortcuts'); + }, + + toggleKeyboardControls() { + if (UI.getSetting('virtual_keyboard_visible')) { + UI.showKeyboardControls(); + } else { + UI.hideKeyboardControls(); + } + }, + + toggleIMEMode() { + if (UI.rfb) { + if (UI.getSetting('enable_ime')) { + UI.rfb.keyboard.enableIME = true; + } else { + UI.rfb.keyboard.enableIME = false; + } + } + }, + + toggleWebRTC() { + if (UI.rfb) { + if (typeof RTCPeerConnection === 'undefined') { + UI.showStatus('This browser does not support WebRTC UDP Data Channels.', 'warn', 5000, true); + return; + } + + if (UI.getSetting('enable_webrtc')) { + UI.rfb.enableWebRTC = true; + } else { + UI.rfb.enableWebRTC = false; + } + UI.updateQuality(); + } + }, + + enableHiDpi() { + if (UI.rfb) { + if (UI.getSetting('enable_hidpi')) { + UI.rfb.enableHiDpi = true; + } else { + UI.rfb.enableHiDpi = false; + } + } + }, + + showKeyboardControls() { + document.getElementById('noVNC_keyboard_control').classList.add("is-visible"); + }, + + hideKeyboardControls() { + document.getElementById('noVNC_keyboard_control').classList.remove("is-visible"); + }, + + showVirtualKeyboard() { + const input = document.getElementById('noVNC_keyboardinput'); + + if (document.activeElement == input || !UI.rfb) return; + + if (UI.getSetting('virtual_keyboard_visible')) { + document.getElementById('noVNC_keyboard_control_handle') + .classList.add("noVNC_selected"); + } + + input.focus(); + + try { + const l = input.value.length; + // Move the caret to the end + input.setSelectionRange(l, l); + } catch (err) { + // setSelectionRange is undefined in Google Chrome + } + + // ensure that the hidden input used for showing the virutal keyboard + // does not steal focus if the user has closed it manually + document.querySelector("canvas").addEventListener("touchstart", () => { + if (document.activeElement === input) { + input.blur(); + } + }, { once: true }); + }, + + hideVirtualKeyboard() { + const input = document.getElementById('noVNC_keyboardinput'); + + if (document.activeElement != input || !UI.rfb) return; + + if (UI.getSetting('virtual_keyboard_visible')) { + document.getElementById('noVNC_keyboard_control_handle') + .classList.remove("noVNC_selected"); + } + + input.blur(); + }, + + toggleVirtualKeyboard() { + if (document.getElementById('noVNC_keyboard_button') + .classList.contains("noVNC_selected")) { + UI.hideVirtualKeyboard(); + } else { + UI.showVirtualKeyboard(); + } + }, + + onfocusVirtualKeyboard(event) { + document.getElementById('noVNC_keyboard_button') + .classList.add("noVNC_selected"); + if (UI.rfb) { + UI.rfb.focusOnClick = false; + } + }, + + onblurVirtualKeyboard(event) { + document.getElementById('noVNC_keyboard_button') + .classList.remove("noVNC_selected"); + + if (UI.getSetting('virtual_keyboard_visible')) { + document.getElementById('noVNC_keyboard_control_handle') + .classList.remove("noVNC_selected"); + } + + if (UI.rfb) { + UI.rfb.focusOnClick = true; + } + }, + + keepVirtualKeyboard(event) { + const input = document.getElementById('noVNC_keyboardinput'); + + // Only prevent focus change if the virtual keyboard is active + if (document.activeElement != input) { + return; + } + + // Only allow focus to move to other elements that need + // focus to function properly + if (event.target.form !== undefined) { + switch (event.target.type) { + case 'text': + case 'email': + case 'search': + case 'password': + case 'tel': + case 'url': + case 'textarea': + case 'select-one': + case 'select-multiple': + return; + } + } + + event.preventDefault(); + }, + +/* ------^------- + * /KEYBOARD + * ============== + * EXTRA KEYS + * ------v------*/ + + openExtraKeys() { + UI.closeAllPanels(); + UI.openControlbar(); + + document.getElementById('noVNC_modifiers') + .classList.add("noVNC_open"); + document.getElementById('noVNC_toggle_extra_keys_button') + .classList.add("noVNC_selected"); + }, + + disableSoftwareKeyboard() { + document.querySelector("#noVNC_keyboard_button").disabled = true; + }, + + enableSoftwareKeyboard() { + document.querySelector("#noVNC_keyboard_button").disabled = false; + }, + + closeExtraKeys() { + document.getElementById('noVNC_modifiers') + .classList.remove("noVNC_open"); + document.getElementById('noVNC_toggle_extra_keys_button') + .classList.remove("noVNC_selected"); + }, + + toggleExtraKeys(e) { + if (!UI.isControlPanelItemClick(e)) { + return false; + } + + if (document.getElementById('noVNC_modifiers').classList.contains("noVNC_open")) { + UI.closeExtraKeys(); + } else { + UI.openExtraKeys(); + } + }, + + sendEsc() { + UI.sendKey(KeyTable.XK_Escape, "Escape"); + }, + + sendTab() { + UI.sendKey(KeyTable.XK_Tab, "Tab"); + }, + + toggleCtrl() { + const btn = document.getElementById('noVNC_toggle_ctrl_button'); + if (btn.classList.contains("noVNC_selected")) { + UI.sendKey(KeyTable.XK_Control_L, "ControlLeft", false); + btn.classList.remove("noVNC_selected"); + } else { + UI.sendKey(KeyTable.XK_Control_L, "ControlLeft", true); + btn.classList.add("noVNC_selected"); + } + + document.querySelector(".keyboard-controls .button.ctrl").classList.toggle("selected"); + }, + + toggleWindows() { + const btn = document.getElementById('noVNC_toggle_windows_button'); + if (btn.classList.contains("noVNC_selected")) { + UI.sendKey(KeyTable.XK_Super_L, "MetaLeft", false); + btn.classList.remove("noVNC_selected"); + } else { + UI.sendKey(KeyTable.XK_Super_L, "MetaLeft", true); + btn.classList.add("noVNC_selected"); + } + + document.querySelector(".keyboard-controls .button.windows").classList.toggle("selected"); + }, + + toggleAlt() { + const btn = document.getElementById('noVNC_toggle_alt_button'); + if (btn.classList.contains("noVNC_selected")) { + UI.sendKey(KeyTable.XK_Alt_L, "AltLeft", false); + btn.classList.remove("noVNC_selected"); + } else { + UI.sendKey(KeyTable.XK_Alt_L, "AltLeft", true); + btn.classList.add("noVNC_selected"); + } + + document.querySelector(".keyboard-controls .button.alt").classList.toggle("selected"); + }, + + sendCtrlAltDel() { + UI.rfb.sendCtrlAltDel(); + // See below + UI.rfb.focus(); + UI.idleControlbar(); + }, + + sendKey(keysym, code, down) { + UI.rfb.sendKey(keysym, code, down); + + // Move focus to the screen in order to be able to use the + // keyboard right after these extra keys. + // The exception is when a virtual keyboard is used, because + // if we focus the screen the virtual keyboard would be closed. + // In this case we focus our special virtual keyboard input + // element instead. + if (document.getElementById('noVNC_keyboard_button') + .classList.contains("noVNC_selected")) { + document.getElementById('noVNC_keyboardinput').focus(); + } else { + UI.rfb.focus(); + } + // fade out the controlbar to highlight that + // the focus has been moved to the screen + UI.idleControlbar(); + }, + +/* ------^------- + * /EXTRA KEYS + * ============== + * MISC + * ------v------*/ + + updateViewOnly() { + if (!UI.rfb) return; + UI.rfb.viewOnly = UI.getSetting('view_only'); + + // Hide input related buttons in view only mode + if (UI.rfb.viewOnly) { + UI.hideControlInput("noVNC_keyboard_button"); + UI.hideControlInput("noVNC_toggle_extra_keys_button"); + UI.hideControlInput("noVNC_clipboard_button"); + UI.hideControlInput("noVNC_game_mode_button"); + } else { + UI.showControlInput("noVNC_keyboard_button"); + UI.showControlInput("noVNC_toggle_extra_keys_button"); + UI.showControlInput("noVNC_clipboard_button"); + UI.showControlInput("noVNC_game_mode_button"); + } + }, + + updateShowDotCursor() { + if (!UI.rfb) return; + UI.rfb.showDotCursor = UI.getSetting('show_dot'); + }, + + updateLogging() { + WebUtil.initLogging(UI.getSetting('logging')); + }, + + updateDesktopName(e) { + UI.desktopName = e.detail.name; + // Display the desktop name in the document title + document.title = e.detail.name + " - " + PAGE_TITLE; + }, + + inputLockChanged(e) { + var pointer_lock_el = document.getElementById("noVNC_setting_pointer_lock"); + var pointer_rel_el = document.getElementById("noVNC_game_mode_button"); + + if (e.detail.pointer) { + pointer_lock_el.checked = true; + UI.sendMessage('enable_pointer_lock', true); + UI.closeControlbar(); + UI.showStatus('Press Esc Key to Exit Pointer Lock Mode', 'warn', 5000, true); + } else { + //If in game mode + if (UI.rfb.pointerRelative) { + UI.showStatus('Game Mode paused, click on screen to resume Game Mode.', 'warn', 5000, true); + } else { + UI.forceSetting('pointer_lock', false, false); + document.getElementById('noVNC_game_mode_button') + .classList.remove("noVNC_selected"); + UI.sendMessage('enable_pointer_lock', false); + } + } + }, + + inputLockError(e) { + UI.showStatus('Unable to enter pointer lock mode.', 'warn', 5000, true); + UI.rfb.pointerRelative = false; + + document.getElementById('noVNC_game_mode_button').classList.remove("noVNC_selected"); + UI.forceSetting('pointer_lock', false, false); + + UI.sendMessage('enable_game_mode', false); + UI.sendMessage('enable_pointer_lock', false); + }, + + bell(e) { + if (WebUtil.getConfigVar('bell', 'on') === 'on') { + const promise = document.getElementById('noVNC_bell').play(); + // The standards disagree on the return value here + if (promise) { + promise.catch((e) => { + if (e.name === "NotAllowedError") { + // Ignore when the browser doesn't let us play audio. + // It is common that the browsers require audio to be + // initiated from a user action. + } else { + Log.Error("Unable to play bell: " + e); + } + }); + } + } + }, + + //Helper to add options to dropdown. + addOption(selectbox, text, value) { + const optn = document.createElement("OPTION"); + optn.text = text; + optn.value = value; + selectbox.options.add(optn); + }, + +/* ------^------- + * /MISC + * ============== + */ +}; + +// Set up translations +const LINGUAS = ["af", "af_ZA", "am_ET", "am", "ar_AE", "ar_BH", "ar_DZ", "ar_EG", "ar_IN", "ar_IQ", "ar_JO", "ar_KW", "ar_LB", "ar_LY", "ar_MA", "ar_OM", "ar", "ar_QA", "ar_SA", "ar_SD", "ar_SY", "ar_TN", "ar_YE", "az_AZ", "az", "be_BY", "be", "bg_BG", "bg", "bn_BD", "bn_IN", "bn", "bs_BA", "bs", "ca_AD", "ca_ES", "ca_FR", "ca_IT", "ca", "cs_CZ", "cs", "cy_GB", "cy", "da_DK", "da", "de_AT", "de_BE", "de_CH", "de_DE", "de_LU", "de", "el", "es_AR", "es_BO", "es_CL", "es_CO", "es_CR", "es_CU", "es_DO", "es_EC", "es_ES", "es_GT", "es_HN", "es_MX", "es_NI", "es_PA", "es_PE", "es", "es_PR", "es_PY", "es_SV", "es_US", "es_UY", "es_VE", "et_EE", "et", "eu_ES", "eu", "fa_IR", "fa", "fi_FI", "fi", "fr_BE", "fr_CA", "fr_CH", "fr_FR", "fr_LU", "fr", "fy_DE", "fy_NL", "fy", "ga_IE", "ga", "gd_GB", "gd", "gl_ES", "gl", "gu_IN", "gu", "ha_NG", "ha", "he_IL", "he", "hi_IN", "hi", "hr_HR", "hr", "ht_HT", "ht", "hu_HU", "hu", "hy_AM", "hy", "id_ID", "id", "ig_NG", "ig", "is_IS", "is", "it_CH", "it_IT", "it", "ja_JP", "ja", "ka_GE", "ka", "kk_KZ", "kk", "km_KH", "km", "kn_IN", "kn", "ko_KR", "ko", "ku", "ku_TR", "ky_KG", "ky", "lb_LU", "lb", "lo_LA", "lo", "lt_LT", "lt", "lv_LV", "lv", "mg_MG", "mg", "mi_NZ", "mi", "mk_MK", "mk", "ml_IN", "ml", "mn_MN", "mn", "mr_IN", "mr", "ms_MY", "ms", "mt_MT", "mt", "my_MM", "my", "ne_NP", "ne", "nl_AW", "nl_BE", "nl_NL", "nl", "pa_IN", "pa_PK", "pa", "pl_PL", "pl", "ps_AF", "ps", "pt_BR", "pt", "pt_PT", "ro", "ro_RO", "ru", "ru_RU", "ru_UA", "sd_IN", "sd", "si_LK", "si", "sk", "sk_SK", "sl", "sl_SI", "so_DJ", "so_ET", "so_KE", "so", "so_SO", "sq_AL", "sq_MK", "sq", "st", "st_ZA", "sv_FI", "sv", "sv_SE", "sw_KE", "sw", "ta_IN", "ta_LK", "ta", "te_IN", "te", "tg", "tg_TJ", "th", "th_TH", "tl_PH", "tl", "tr_CY", "tr", "tr_TR", "tt", "tt_RU", "uk", "uk_UA", "ur_IN", "ur_PK", "ur", "uz", "uz_UZ", "vi", "vi_VN", "xh", "xh_ZA", "yi", "yi_US", "yo_NG", "yo", "zh_CN", "zh_TW", "zu", "zu_ZA"]; +l10n.setup(LINGUAS); +if (l10n.language === "en" || l10n.dictionary !== undefined) { + UI.prime(); +} else { + fetch('app/locale/' + l10n.language + '.json') + .then((response) => { + if (!response.ok) { + throw Error("" + response.status + " " + response.statusText); + } + return response.json(); + }) + .then((translations) => { l10n.dictionary = translations; }) + .catch(err => Log.Error("Failed to load translations: " + err)) + .then(UI.prime); +} + +export default UI; diff --git a/app/webutil.js b/app/webutil.js new file mode 100644 index 0000000..a673707 --- /dev/null +++ b/app/webutil.js @@ -0,0 +1,187 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +import { initLogging as mainInitLogging } from '../core/util/logging.js'; + +// init log level reading the logging HTTP param +export function initLogging(level) { + "use strict"; + if (typeof level !== "undefined") { + mainInitLogging(level); + } else { + const param = document.location.href.match(/logging=([A-Za-z0-9._-]*)/); + mainInitLogging(param || undefined); + } +} + +// Read a query string variable +export function getQueryVar(name, defVal) { + "use strict"; + const re = new RegExp('.*[?&]' + name + '=([^&#]*)'), + match = document.location.href.match(re); + if (typeof defVal === 'undefined') { defVal = null; } + + if (match) { + return decodeURIComponent(match[1]); + } + + return defVal; +} + +// Read a hash fragment variable +export function getHashVar(name, defVal) { + "use strict"; + const re = new RegExp('.*[&#]' + name + '=([^&]*)'), + match = document.location.hash.match(re); + if (typeof defVal === 'undefined') { defVal = null; } + + if (match) { + return decodeURIComponent(match[1]); + } + + return defVal; +} + +// Read a variable from the fragment or the query string +// Fragment takes precedence +export function getConfigVar(name, defVal) { + "use strict"; + const val = getHashVar(name); + + if (val === null) { + return getQueryVar(name, defVal); + } + + return val; +} + +/* + * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html + */ + +// No days means only for this browser session +export function createCookie(name, value, days) { + "use strict"; + let date, expires; + if (days) { + date = new Date(); + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + expires = "; expires=" + date.toGMTString(); + } else { + expires = ""; + } + + let secure; + if (document.location.protocol === "https:") { + secure = "; secure"; + } else { + secure = ""; + } + document.cookie = name + "=" + value + expires + "; path=/" + secure; +} + +export function readCookie(name, defaultValue) { + "use strict"; + const nameEQ = name + "="; + const ca = document.cookie.split(';'); + + for (let i = 0; i < ca.length; i += 1) { + let c = ca[i]; + while (c.charAt(0) === ' ') { + c = c.substring(1, c.length); + } + if (c.indexOf(nameEQ) === 0) { + return c.substring(nameEQ.length, c.length); + } + } + + return (typeof defaultValue !== 'undefined') ? defaultValue : null; +} + +export function eraseCookie(name) { + "use strict"; + createCookie(name, "", -1); +} + +/* + * Setting handling. + */ + +let settings = {}; + +export function initSettings() { + if (!window.chrome || !window.chrome.storage) { + settings = {}; + return Promise.resolve(); + } + + return new Promise(resolve => window.chrome.storage.sync.get(resolve)) + .then((cfg) => { settings = cfg; }); +} + +// Update the settings cache, but do not write to permanent storage +export function setSetting(name, value) { + settings[name] = value; +} + +// No days means only for this browser session +export function writeSetting(name, value) { + "use strict"; + if (settings[name] === value) return; + settings[name] = value; + if (window.chrome && window.chrome.storage) { + window.chrome.storage.sync.set(settings); + } else { + localStorage.setItem(name, value); + } +} + +export function readSetting(name, defaultValue) { + "use strict"; + let value; + if ((name in settings) || (window.chrome && window.chrome.storage)) { + value = settings[name]; + } else { + value = localStorage.getItem(name); + settings[name] = value; + } + if (typeof value === "undefined") { + value = null; + } + + if (value === null && typeof defaultValue !== "undefined") { + return defaultValue; + } + + return value; +} + +export function eraseSetting(name) { + "use strict"; + // Deleting here means that next time the setting is read when using local + // storage, it will be pulled from local storage again. + // If the setting in local storage is changed (e.g. in another tab) + // between this delete and the next read, it could lead to an unexpected + // value change. + delete settings[name]; + if (window.chrome && window.chrome.storage) { + window.chrome.storage.sync.remove(name); + } else { + localStorage.removeItem(name); + } +} + +//Are we running inside the Kasm VDI Framework +export function isInsideKasmVDI() { + //TODO: We should use a more explicit way to detect we are running inside KasmVDI + try { + return window.self !== window.top; + } catch (e) { + return true; + } +} \ No newline at end of file diff --git a/core/base64.js b/core/base64.js new file mode 100644 index 0000000..e4b6db7 --- /dev/null +++ b/core/base64.js @@ -0,0 +1,100 @@ +/* The decoder is the original MPL one from Mozilla. The encoder is a faster MIT one + from https://github.com/mitschabaude/fast-base64 */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtools/jint/sunspider/string-base64.js + +import * as Log from './util/logging.js'; + +const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; +const encodeLookup = Object.fromEntries(Array.from(alphabet).map((a, i) => [i, a.charCodeAt(0)])); +const decoder = new TextDecoder(); + +export default { + /* Convert data (an array of integers) to a Base64 string. */ + base64Pad: '=', + + encode(bytes) { + let m = bytes.length; + let k = m % 3; + let n = Math.floor(m / 3) * 4 + (k && k + 1); + let N = Math.ceil(m / 3) * 4; + let encoded = new Uint8Array(N); + + for (let i = 0, j = 0; j < m; i += 4, j += 3) { + let y = (bytes[j] << 16) + (bytes[j + 1] << 8) + (bytes[j + 2] | 0); + encoded[i] = encodeLookup[y >> 18]; + encoded[i + 1] = encodeLookup[(y >> 12) & 0x3f]; + encoded[i + 2] = encodeLookup[(y >> 6) & 0x3f]; + encoded[i + 3] = encodeLookup[y & 0x3f]; + } + + let base64 = decoder.decode(new Uint8Array(encoded.buffer, 0, n)); + if (k === 1) base64 += '=='; + if (k === 2) base64 += '='; + return base64; + }, + + /* Convert Base64 data to a string */ + /* eslint-disable comma-spacing */ + toBinaryTable: [ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 + ], + /* eslint-enable comma-spacing */ + + decode(data, offset = 0) { + let dataLength = data.indexOf('=') - offset; + if (dataLength < 0) { dataLength = data.length - offset; } + + /* Every four characters is 3 resulting numbers */ + const resultLength = (dataLength >> 2) * 3 + Math.floor((dataLength % 4) / 1.5); + const result = new Array(resultLength); + + // Convert one by one. + + let leftbits = 0; // number of bits decoded, but yet to be appended + let leftdata = 0; // bits decoded, but yet to be appended + for (let idx = 0, i = offset; i < data.length; i++) { + const c = this.toBinaryTable[data.charCodeAt(i) & 0x7f]; + const padding = (data.charAt(i) === this.base64Pad); + // Skip illegal characters and whitespace + if (c === -1) { + Log.Error("Illegal character code " + data.charCodeAt(i) + " at position " + i); + continue; + } + + // Collect data into leftdata, update bitcount + leftdata = (leftdata << 6) | c; + leftbits += 6; + + // If we have 8 or more bits, append 8 bits to the result + if (leftbits >= 8) { + leftbits -= 8; + // Append if not padding. + if (!padding) { + result[idx++] = (leftdata >> leftbits) & 0xff; + } + leftdata &= (1 << leftbits) - 1; + } + } + + // If there are any bits left, the base64 string was corrupted + if (leftbits) { + const err = new Error('Corrupted base64 string'); + err.name = 'Base64-Error'; + throw err; + } + + return result; + } +}; /* End of Base64 namespace */ diff --git a/core/decoders/copyrect.js b/core/decoders/copyrect.js new file mode 100644 index 0000000..55fd1b3 --- /dev/null +++ b/core/decoders/copyrect.js @@ -0,0 +1,28 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + * + */ + +export default class CopyRectDecoder { + + decodeRect(x, y, width, height, sock, display, depth, frame_id) { + if (sock.rQwait("COPYRECT", 4)) { + return false; + } + + let deltaX = sock.rQshift16(); + let deltaY = sock.rQshift16(); + + if ((width === 0) || (height === 0)) { + return true; + } + + display.copyImage(deltaX, deltaY, x, y, width, height, frame_id); + + return true; + } +} diff --git a/core/decoders/hextile.js b/core/decoders/hextile.js new file mode 100644 index 0000000..557e103 --- /dev/null +++ b/core/decoders/hextile.js @@ -0,0 +1,191 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + * + */ + +import * as Log from '../util/logging.js'; + +export default class HextileDecoder { + constructor() { + this._tiles = 0; + this._lastsubencoding = 0; + this._tileBuffer = new Uint8Array(16 * 16 * 4); + } + + decodeRect(x, y, width, height, sock, display, depth, frame_id) { + if (this._tiles === 0) { + this._tilesX = Math.ceil(width / 16); + this._tilesY = Math.ceil(height / 16); + this._totalTiles = this._tilesX * this._tilesY; + this._tiles = this._totalTiles; + } + + while (this._tiles > 0) { + let bytes = 1; + + if (sock.rQwait("HEXTILE", bytes)) { + return false; + } + + let rQ = sock.rQ; + let rQi = sock.rQi; + + let subencoding = rQ[rQi]; // Peek + if (subencoding > 30) { // Raw + throw new Error("Illegal hextile subencoding (subencoding: " + + subencoding + ")"); + } + + const currTile = this._totalTiles - this._tiles; + const tileX = currTile % this._tilesX; + const tileY = Math.floor(currTile / this._tilesX); + const tx = x + tileX * 16; + const ty = y + tileY * 16; + const tw = Math.min(16, (x + width) - tx); + const th = Math.min(16, (y + height) - ty); + + // Figure out how much we are expecting + if (subencoding & 0x01) { // Raw + bytes += tw * th * 4; + } else { + if (subencoding & 0x02) { // Background + bytes += 4; + } + if (subencoding & 0x04) { // Foreground + bytes += 4; + } + if (subencoding & 0x08) { // AnySubrects + bytes++; // Since we aren't shifting it off + + if (sock.rQwait("HEXTILE", bytes)) { + return false; + } + + let subrects = rQ[rQi + bytes - 1]; // Peek + if (subencoding & 0x10) { // SubrectsColoured + bytes += subrects * (4 + 2); + } else { + bytes += subrects * 2; + } + } + } + + if (sock.rQwait("HEXTILE", bytes)) { + return false; + } + + // We know the encoding and have a whole tile + rQi++; + if (subencoding === 0) { + if (this._lastsubencoding & 0x01) { + // Weird: ignore blanks are RAW + Log.Debug(" Ignoring blank after RAW"); + } else { + display.fillRect(tx, ty, tw, th, this._background, frame_id); + } + } else if (subencoding & 0x01) { // Raw + let pixels = tw * th; + // Max sure the image is fully opaque + for (let i = 0;i < pixels;i++) { + rQ[rQi + i * 4 + 3] = 255; + } + display.blitImage(tx, ty, tw, th, rQ, rQi, frame_id); + rQi += bytes - 1; + } else { + if (subencoding & 0x02) { // Background + this._background = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; + rQi += 4; + } + if (subencoding & 0x04) { // Foreground + this._foreground = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; + rQi += 4; + } + + this._startTile(tx, ty, tw, th, this._background); + if (subencoding & 0x08) { // AnySubrects + let subrects = rQ[rQi]; + rQi++; + + for (let s = 0; s < subrects; s++) { + let color; + if (subencoding & 0x10) { // SubrectsColoured + color = [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2], rQ[rQi + 3]]; + rQi += 4; + } else { + color = this._foreground; + } + const xy = rQ[rQi]; + rQi++; + const sx = (xy >> 4); + const sy = (xy & 0x0f); + + const wh = rQ[rQi]; + rQi++; + const sw = (wh >> 4) + 1; + const sh = (wh & 0x0f) + 1; + + this._subTile(sx, sy, sw, sh, color); + } + } + this._finishTile(display, frame_id); + } + sock.rQi = rQi; + this._lastsubencoding = subencoding; + this._tiles--; + } + + return true; + } + + // start updating a tile + _startTile(x, y, width, height, color) { + this._tileX = x; + this._tileY = y; + this._tileW = width; + this._tileH = height; + + const red = color[0]; + const green = color[1]; + const blue = color[2]; + + const data = this._tileBuffer; + for (let i = 0; i < width * height * 4; i += 4) { + data[i] = red; + data[i + 1] = green; + data[i + 2] = blue; + data[i + 3] = 255; + } + } + + // update sub-rectangle of the current tile + _subTile(x, y, w, h, color) { + const red = color[0]; + const green = color[1]; + const blue = color[2]; + const xend = x + w; + const yend = y + h; + + const data = this._tileBuffer; + const width = this._tileW; + for (let j = y; j < yend; j++) { + for (let i = x; i < xend; i++) { + const p = (i + (j * width)) * 4; + data[p] = red; + data[p + 1] = green; + data[p + 2] = blue; + data[p + 3] = 255; + } + } + } + + // draw the current tile to the screen + _finishTile(display, frame_id) { + display.blitImage(this._tileX, this._tileY, + this._tileW, this._tileH, + this._tileBuffer, 0, frame_id); + } +} diff --git a/core/decoders/qoi/decoder.js b/core/decoders/qoi/decoder.js new file mode 100644 index 0000000..45a509b --- /dev/null +++ b/core/decoders/qoi/decoder.js @@ -0,0 +1,345 @@ +let wasm; +const heap = new Array(32).fill(undefined); +heap.push(undefined, null, true, false); + +function getObject(idx) { + return heap[idx]; +} +let heap_next = heap.length; + +function dropObject(idx) { + if (idx < 36) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} +const cachedTextDecoder = new TextDecoder('utf-8', { + ignoreBOM: true, + fatal: true +}); +cachedTextDecoder.decode(); +let cachegetUint8Memory0 = null; + +function getUint8Memory0() { + if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) { + cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachegetUint8Memory0; +} + +function getStringFromWasm0(ptr, len) { + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); +} + +let cachegetInt32Memory0 = null; + +function getInt32Memory0() { + if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) { + cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachegetInt32Memory0; +} + +function getArrayU8FromWasm0(ptr, len) { + return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); +} + +let WASM_VECTOR_LEN = 0; + +function passArray8ToWasm0(arg, malloc) { + const ptr = malloc(arg.length * 1); + getUint8Memory0().set(arg, ptr / 1); + WASM_VECTOR_LEN = arg.length; + return ptr; +} +/** + * @param {Uint8Array} bytes + * @returns {ImageData} + */ +function decode_qoi(bytes) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArray8ToWasm0(bytes, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + wasm.decode_qoi(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + if (r2) { + throw takeObject(r1); + } + return takeObject(r0); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +const cachedTextEncoder = new TextEncoder('utf-8'); + +const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' ? + function(arg, view) { + return cachedTextEncoder.encodeInto(arg, view); + } : + function(arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; + }); + +function passStringToWasm0(arg, malloc, realloc) { + + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length); + getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len); + + const mem = getUint8Memory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3); + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +let cachegetUint8ClampedMemory0 = null; + +function getUint8ClampedMemory0() { + if (cachegetUint8ClampedMemory0 === null || cachegetUint8ClampedMemory0.buffer !== wasm.memory.buffer) { + cachegetUint8ClampedMemory0 = new Uint8ClampedArray(wasm.memory.buffer); + } + return cachegetUint8ClampedMemory0; +} + +function getClampedArrayU8FromWasm0(ptr, len) { + return getUint8ClampedMemory0().subarray(ptr / 1, ptr / 1 + len); +} + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_exn_store(addHeapObject(e)); + } +} +/** + */ +class QoiImage { + + static __wrap(ptr) { + const obj = Object.create(QoiImage.prototype); + obj.ptr = ptr; + + return obj; + } + + __destroy_into_raw() { + const ptr = this.ptr; + this.ptr = 0; + + return ptr; + } + + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_qoiimage_free(ptr); + } + /** + */ + constructor() { + const ret = wasm.qoiimage_new(); + return QoiImage.__wrap(ret); + } + /** + * @returns {number} + */ + get_width() { + const ret = wasm.qoiimage_get_width(this.ptr); + return ret >>> 0; + } + /** + * @returns {number} + */ + get_height() { + const ret = wasm.qoiimage_get_height(this.ptr); + return ret >>> 0; + } + /** + * @returns {number} + */ + get_channels() { + const ret = wasm.qoiimage_get_channels(this.ptr); + return ret; + } + /** + * @returns {Uint8Array} + */ + get_bytes() { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.qoiimage_get_bytes(retptr, this.ptr); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var v0 = getArrayU8FromWasm0(r0, r1).slice(); + wasm.__wbindgen_free(r0, r1 * 1); + return v0; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } +} + +async function load(module, imports) { + if (typeof Response === 'function' && module instanceof Response) { + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); + } else { + const instance = await WebAssembly.instantiate(module, imports); + + if (instance instanceof WebAssembly.Instance) { + return { + instance, + module + }; + + } else { + return instance; + } + } +} + +async function init(input) { + if (typeof input === 'undefined') { + input = path + 'core/decoders/qoi/qoi_viewer_bg.wasm'; + } + const imports = {}; + imports.wbg = {}; + imports.wbg.__wbg_new_693216e109162396 = function() { + const ret = new Error(); + return addHeapObject(ret); + }; + imports.wbg.__wbg_stack_0ddaca5d1abfb52f = function(arg0, arg1) { + const ret = getObject(arg1).stack; + const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }; + imports.wbg.__wbg_error_09919627ac0992f5 = function(arg0, arg1) { + try { + console.error(getStringFromWasm0(arg0, arg1)); + } finally { + wasm.__wbindgen_free(arg0, arg1); + } + }; + imports.wbg.__wbindgen_object_drop_ref = function(arg0) { + takeObject(arg0); + }; + imports.wbg.__wbg_newwithu8clampedarrayandsh_87d2f0a48030f922 = function() { + return handleError(function(arg0, arg1, arg2, arg3) { + const ret = new ImageData(getClampedArrayU8FromWasm0(arg0, arg1), arg2 >>> 0, arg3 >>> 0); + return addHeapObject(ret); + }, arguments) + }; + imports.wbg.__wbindgen_throw = function(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }; + if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { + input = fetch(input); + } + const { + instance, + module + } = await load(await input, imports); + wasm = instance.exports; + init.__wbindgen_wasm_module = module; + return wasm; +} + +var arr; +var path; + +async function run() { + self.addEventListener('message', async function(evt) { + if (evt.data.path) { + path = evt.data.path; + await init(); + //Send message that worker is ready + self.postMessage({ + result: 1 + }) + } else { + try { + let length = evt.data.length; + let data = new Uint8Array(evt.data.sab.slice(0, length)); + let resultData = decode_qoi(data); + if (!arr) { + arr = new Uint8Array(evt.data.sabR); + } + let lengthR = resultData.data.length; + arr.set(resultData.data); + let img = { + colorSpace: resultData.colorSpace, + width: resultData.width, + height: resultData.height + }; + self.postMessage({ + result: 0, + img: img, + length: lengthR, + width: evt.data.width, + height: evt.data.height, + x: evt.data.x, + y: evt.data.y, + frame_id: evt.data.frame_id + }); + } catch (err) { + self.postMessage({ + result: 2, + error: err + }); + } + } + }, false); +} + +run(); diff --git a/core/decoders/qoi/qoi_viewer_bg.wasm b/core/decoders/qoi/qoi_viewer_bg.wasm new file mode 100644 index 0000000..1447352 Binary files /dev/null and b/core/decoders/qoi/qoi_viewer_bg.wasm differ diff --git a/core/decoders/raw.js b/core/decoders/raw.js new file mode 100644 index 0000000..fd2a920 --- /dev/null +++ b/core/decoders/raw.js @@ -0,0 +1,66 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + * + */ + +export default class RawDecoder { + constructor() { + this._lines = 0; + } + + decodeRect(x, y, width, height, sock, display, depth, frame_id) { + if ((width === 0) || (height === 0)) { + return true; + } + + if (this._lines === 0) { + this._lines = height; + } + + const pixelSize = depth == 8 ? 1 : 4; + const bytesPerLine = width * pixelSize; + + if (sock.rQwait("RAW", bytesPerLine)) { + return false; + } + + const curY = y + (height - this._lines); + const currHeight = Math.min(this._lines, + Math.floor(sock.rQlen / bytesPerLine)); + const pixels = width * currHeight; + + let data = sock.rQ; + let index = sock.rQi; + + // Convert data if needed + if (depth == 8) { + const newdata = new Uint8Array(pixels * 4); + for (let i = 0; i < pixels; i++) { + newdata[i * 4 + 0] = ((data[index + i] >> 0) & 0x3) * 255 / 3; + newdata[i * 4 + 1] = ((data[index + i] >> 2) & 0x3) * 255 / 3; + newdata[i * 4 + 2] = ((data[index + i] >> 4) & 0x3) * 255 / 3; + newdata[i * 4 + 3] = 255; + } + data = newdata; + index = 0; + } + + // Max sure the image is fully opaque + for (let i = 0; i < pixels; i++) { + data[i * 4 + 3] = 255; + } + + display.blitImage(x, curY, width, currHeight, data, index, frame_id); + sock.rQskipBytes(currHeight * bytesPerLine); + this._lines -= currHeight; + if (this._lines > 0) { + return false; + } + + return true; + } +} diff --git a/core/decoders/rre.js b/core/decoders/rre.js new file mode 100644 index 0000000..0562fbc --- /dev/null +++ b/core/decoders/rre.js @@ -0,0 +1,44 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + * + */ + +export default class RREDecoder { + constructor() { + this._subrects = 0; + } + + decodeRect(x, y, width, height, sock, display, depth, frame_id) { + if (this._subrects === 0) { + if (sock.rQwait("RRE", 4 + 4)) { + return false; + } + + this._subrects = sock.rQshift32(); + + let color = sock.rQshiftBytes(4); // Background + display.fillRect(x, y, width, height, color); + } + + while (this._subrects > 0) { + if (sock.rQwait("RRE", 4 + 8)) { + return false; + } + + let color = sock.rQshiftBytes(4); + let sx = sock.rQshift16(); + let sy = sock.rQshift16(); + let swidth = sock.rQshift16(); + let sheight = sock.rQshift16(); + display.fillRect(x + sx, y + sy, swidth, sheight, color, frame_id); + + this._subrects--; + } + + return true; + } +} diff --git a/core/decoders/tight.js b/core/decoders/tight.js new file mode 100644 index 0000000..1532a88 --- /dev/null +++ b/core/decoders/tight.js @@ -0,0 +1,540 @@ +/* + * KasmVNC: HTML5 VNC client + * Copyright (C) 2020 Kasm Technologies + * Copyright (C) 2019 The noVNC Authors + * (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca) + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + * + */ + +import * as Log from '../util/logging.js'; +import Inflator from "../inflator.js"; + +export default class TightDecoder { + constructor(display) { + this._ctl = null; + this._filter = null; + this._numColors = 0; + this._palette = new Uint8Array(1024); // 256 * 4 (max palette size * max bytes-per-pixel) + this._len = 0; + this._enableQOI = false; + this._displayGlobal = display; + + this._zlibs = []; + for (let i = 0; i < 4; i++) { + this._zlibs[i] = new Inflator(); + } + this._itzlib = new Inflator(); + } + + // ===== PROPERTIES ===== + + get enableQOI() { return this._enableQOI; } + set enableQOI(enabled) { + if(this._enableQOI === enabled) { + return; + } + + if (enabled) { + this._enableQOI = this._enableQOIWorkers(); + } else { + this._enableQOI = false; + this._disableQOIWorkers(); + } + } + + // ===== Public Methods ===== + + decodeRect(x, y, width, height, sock, display, depth, frame_id) { + if (this._ctl === null) { + if (sock.rQwait("TIGHT compression-control", 1)) { + return false; + } + + this._ctl = sock.rQshift8(); + + // Reset streams if the server requests it + for (let i = 0; i < 4; i++) { + if ((this._ctl >> i) & 1) { + this._zlibs[i].reset(); + Log.Info("Reset zlib stream " + i); + } + } + + // Figure out filter + this._ctl = this._ctl >> 4; + } + + let ret; + + if (this._ctl === 0x08) { + ret = this._fillRect(x, y, width, height, + sock, display, depth, frame_id); + } else if (this._ctl === 0x09) { + ret = this._jpegRect(x, y, width, height, + sock, display, depth, frame_id); + } else if (this._ctl === 0x0A) { + ret = this._pngRect(x, y, width, height, + sock, display, depth, frame_id); + } else if ((this._ctl & 0x08) == 0) { + ret = this._basicRect(this._ctl, x, y, width, height, + sock, display, depth, frame_id); + } else if (this._ctl === 0x0B) { + ret = this._webpRect(x, y, width, height, + sock, display, depth, frame_id); + } else if (this._ctl === 0x0C) { + ret = this._qoiRect(x, y, width, height, + sock, display, depth, frame_id); + } else if (this._ctl === 0x0D) { + ret = this._itRect(x, y, width, height, + sock, display, depth, frame_id); + } else { + throw new Error("Illegal tight compression received (ctl: " + + this._ctl + ")"); + } + + if (ret) { + this._ctl = null; + } + + return ret; + } + + // ===== Private Methods ===== + + _fillRect(x, y, width, height, sock, display, depth, frame_id) { + if (sock.rQwait("TIGHT", 3)) { + return false; + } + + const rQi = sock.rQi; + const rQ = sock.rQ; + + display.fillRect(x, y, width, height, + [rQ[rQi], rQ[rQi + 1], rQ[rQi + 2]], frame_id, false); + sock.rQskipBytes(3); + + return true; + } + + _jpegRect(x, y, width, height, sock, display, depth, frame_id) { + let data = this._readData(sock); + if (data === null) { + return false; + } + + display.imageRect(x, y, width, height, "image/jpeg", data, frame_id); + + return true; + } + + _webpRect(x, y, width, height, sock, display, depth, frame_id) { + let data = this._readData(sock); + if (data === null) { + return false; + } + + display.imageRect(x, y, width, height, "image/webp", data, frame_id); + + return true; + } + + _processRectQ() { + while (this._availableWorkers.length > 0 && this._qoiRects.length > 0) { + let i = this._availableWorkers.pop(); + let worker = this._workers[i]; + let rect = this._qoiRects.shift(); + this._arrs[i].set(rect.data); + worker.postMessage({ + length: rect.data.length, + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height, + depth: rect.depth, + sab: this._sabs[i], + sabR: this._sabsR[i], + frame_id: rect.frame_id + }); + } + } + + _qoiRect(x, y, width, height, sock, display, depth, frame_id) { + let data = this._readData(sock); + if (data === null) { + return false; + } + + if (this._enableQOI) { + let dataClone = new Uint8Array(data); + let item = {x: x,y: y,width: width,height: height,data: dataClone,depth: depth, frame_id: frame_id}; + if (this._qoiRects.length < 1000) { + this._qoiRects.push(item); + this._processRectQ(); + } else { + Log.Warn("QOI queue exceeded limit."); + this._qoiRects.splice(0, 500); + } + + } + + return true; + } + + // intensity tinted + _itRect(x, y, width, height, sock, display, depth, frame_id) { + let data = this._readData(sock); + if (data === null) { + return false; + } + + const r = data[0]; + const g = data[1]; + const b = data[2]; + const a = data[3]; + + const uncompressedSize = width * height / 2 + 1; + + this._itzlib.reset(); + this._itzlib.setInput(data.slice(4)); + data = this._itzlib.inflate(uncompressedSize); + this._itzlib.setInput(null); + + // unpack + let rgba = new Uint8Array(width * height * 4 + 4); + for (let i = 0, d = 0; i < uncompressedSize; i++, d += 8) { + let p = data[i]; + + rgba[d + 0] = r; + rgba[d + 1] = g; + rgba[d + 2] = b; + rgba[d + 3] = a * ((p & 15) << 4) / 255; + + rgba[d + 4] = r; + rgba[d + 5] = g; + rgba[d + 6] = b; + rgba[d + 7] = a * (p & 240) / 255; + } + + let img = new ImageData(new Uint8ClampedArray(rgba.buffer, 0, width * height * 4), width, height); + display.transparentRect(x, y, width, height, img, frame_id); + + return true; + } + + _pngRect(x, y, width, height, sock, display, depth, frame_id) { + throw new Error("PNG received in standard Tight rect"); + } + + _basicRect(ctl, x, y, width, height, sock, display, depth, frame_id) { + if (this._filter === null) { + if (ctl & 0x4) { + if (sock.rQwait("TIGHT", 1)) { + return false; + } + + this._filter = sock.rQshift8(); + } else { + // Implicit CopyFilter + this._filter = 0; + } + } + + let streamId = ctl & 0x3; + + let ret; + + switch (this._filter) { + case 0: // CopyFilter + ret = this._copyFilter(streamId, x, y, width, height, + sock, display, depth, frame_id); + break; + case 1: // PaletteFilter + ret = this._paletteFilter(streamId, x, y, width, height, + sock, display, depth, frame_id); + break; + case 2: // GradientFilter + ret = this._gradientFilter(streamId, x, y, width, height, + sock, display, depth, frame_id); + break; + default: + throw new Error("Illegal tight filter received (ctl: " + + this._filter + ")"); + } + + if (ret) { + this._filter = null; + } + + return ret; + } + + _copyFilter(streamId, x, y, width, height, sock, display, depth, frame_id) { + const uncompressedSize = width * height * 3; + let data; + + if (uncompressedSize === 0) { + return true; + } + + if (uncompressedSize < 12) { + if (sock.rQwait("TIGHT", uncompressedSize)) { + return false; + } + + data = sock.rQshiftBytes(uncompressedSize); + } else { + data = this._readData(sock); + if (data === null) { + return false; + } + + this._zlibs[streamId].setInput(data); + data = this._zlibs[streamId].inflate(uncompressedSize); + this._zlibs[streamId].setInput(null); + } + + let rgbx = new Uint8Array(width * height * 4); + for (let i = 0, j = 0; i < width * height * 4; i += 4, j += 3) { + rgbx[i] = data[j]; + rgbx[i + 1] = data[j + 1]; + rgbx[i + 2] = data[j + 2]; + rgbx[i + 3] = 255; // Alpha + } + + display.blitImage(x, y, width, height, rgbx, 0, frame_id, false); + + return true; + } + + _paletteFilter(streamId, x, y, width, height, sock, display, depth, frame_id) { + if (this._numColors === 0) { + if (sock.rQwait("TIGHT palette", 1)) { + return false; + } + + const numColors = sock.rQpeek8() + 1; + const paletteSize = numColors * 3; + + if (sock.rQwait("TIGHT palette", 1 + paletteSize)) { + return false; + } + + this._numColors = numColors; + sock.rQskipBytes(1); + + sock.rQshiftTo(this._palette, paletteSize); + } + + const bpp = (this._numColors <= 2) ? 1 : 8; + const rowSize = Math.floor((width * bpp + 7) / 8); + const uncompressedSize = rowSize * height; + + let data; + + if (uncompressedSize === 0) { + return true; + } + + if (uncompressedSize < 12) { + if (sock.rQwait("TIGHT", uncompressedSize)) { + return false; + } + + data = sock.rQshiftBytes(uncompressedSize); + } else { + data = this._readData(sock); + if (data === null) { + return false; + } + + this._zlibs[streamId].setInput(data); + data = this._zlibs[streamId].inflate(uncompressedSize); + this._zlibs[streamId].setInput(null); + } + + // Convert indexed (palette based) image data to RGB + if (this._numColors == 2) { + this._monoRect(x, y, width, height, data, this._palette, display, frame_id); + } else { + this._paletteRect(x, y, width, height, data, this._palette, display, frame_id); + } + + this._numColors = 0; + + return true; + } + + _monoRect(x, y, width, height, data, palette, display, frame_id) { + // Convert indexed (palette based) image data to RGB + // TODO: reduce number of calculations inside loop + const dest = this._getScratchBuffer(width * height * 4); + const w = Math.floor((width + 7) / 8); + const w1 = Math.floor(width / 8); + + for (let y = 0; y < height; y++) { + let dp, sp, x; + for (x = 0; x < w1; x++) { + for (let b = 7; b >= 0; b--) { + dp = (y * width + x * 8 + 7 - b) * 4; + sp = (data[y * w + x] >> b & 1) * 3; + dest[dp] = palette[sp]; + dest[dp + 1] = palette[sp + 1]; + dest[dp + 2] = palette[sp + 2]; + dest[dp + 3] = 255; + } + } + + for (let b = 7; b >= 8 - width % 8; b--) { + dp = (y * width + x * 8 + 7 - b) * 4; + sp = (data[y * w + x] >> b & 1) * 3; + dest[dp] = palette[sp]; + dest[dp + 1] = palette[sp + 1]; + dest[dp + 2] = palette[sp + 2]; + dest[dp + 3] = 255; + } + } + + display.blitImage(x, y, width, height, dest, 0, frame_id, false); + } + + _paletteRect(x, y, width, height, data, palette, display, frame_id) { + // Convert indexed (palette based) image data to RGB + const dest = this._getScratchBuffer(width * height * 4); + const total = width * height * 4; + for (let i = 0, j = 0; i < total; i += 4, j++) { + const sp = data[j] * 3; + dest[i] = palette[sp]; + dest[i + 1] = palette[sp + 1]; + dest[i + 2] = palette[sp + 2]; + dest[i + 3] = 255; + } + + display.blitImage(x, y, width, height, dest, 0, frame_id, false); + } + + _gradientFilter(streamId, x, y, width, height, sock, display, depth, frame_id) { + throw new Error("Gradient filter not implemented"); + } + + _readData(sock) { + if (this._len === 0) { + if (sock.rQwait("TIGHT", 3)) { + return null; + } + + let byte; + + byte = sock.rQshift8(); + this._len = byte & 0x7f; + if (byte & 0x80) { + byte = sock.rQshift8(); + this._len |= (byte & 0x7f) << 7; + if (byte & 0x80) { + byte = sock.rQshift8(); + this._len |= byte << 14; + } + } + } + + if (sock.rQwait("TIGHT", this._len)) { + return null; + } + + let data = sock.rQshiftBytes(this._len); + this._len = 0; + + return data; + } + + _getScratchBuffer(size) { + if (!this._scratchBuffer || (this._scratchBuffer.length < size)) { + this._scratchBuffer = new Uint8Array(size); + } + return this._scratchBuffer; + } + + async _disableQOIWorkers() { + if (this._workers) { + this._enableQOI = false; + this._availableWorkers = null; + this._sabs = null; + this._sabsR = null; + this._arrs = null; + this._arrsR = null; + this._qoiRects = null; + this._rectQlooping = null; + for await (let i of Array.from(Array(this._threads).keys())) { + this._workers[i].terminate(); + delete this._workers[i]; + } + this._workers = null; + } + } + + _enableQOIWorkers() { + const supportsSharedArrayBuffers = typeof SharedArrayBuffer !== "undefined"; + if (!supportsSharedArrayBuffers) { + Log.Warn("Enabling QOI Failed, client not compatible."); + return false; + } + + let fullPath = window.location.pathname; + let path = fullPath.substring(0, fullPath.lastIndexOf('/')+1); + if ((window.navigator.hardwareConcurrency) && (window.navigator.hardwareConcurrency >= 4)) { + this._threads = 16; + } else { + this._threads = 8; + } + this._workers = []; + this._availableWorkers = []; + this._sabs = []; + this._sabsR = []; + this._arrs = []; + this._arrsR = []; + this._qoiRects = []; + this._rectQlooping = false; + for (let i = 0; i < this._threads; i++) { + this._workers.push(new Worker("core/decoders/qoi/decoder.js")); + this._sabs.push(new SharedArrayBuffer(300000)); + this._sabsR.push(new SharedArrayBuffer(400000)); + this._arrs.push(new Uint8Array(this._sabs[i])); + this._arrsR.push(new Uint8ClampedArray(this._sabsR[i])); + this._workers[i].onmessage = (evt) => { + this._availableWorkers.push(i); + switch(evt.data.result) { + case 0: + let data = new Uint8ClampedArray(evt.data.length); + data.set(this._arrsR[i].slice(0, evt.data.length)); + let img = new ImageData(data, evt.data.img.width, evt.data.img.height, {colorSpace: evt.data.img.colorSpace}); + + this._displayGlobal.blitQoi( + evt.data.x, + evt.data.y, + evt.data.width, + evt.data.height, + img, + 0, + evt.data.frame_id, + false + ); + this._processRectQ(); + break; + case 1: + Log.Info("QOI Worker is now available."); + break; + case 2: + Log.Info("Error on worker: " + evt.error); + break; + } + }; + } + for (let i = 0; i < this._threads; i++) { + this._workers[i].postMessage({path:path}); + } + + return true; + } +} diff --git a/core/decoders/tightpng.js b/core/decoders/tightpng.js new file mode 100644 index 0000000..9ed28b8 --- /dev/null +++ b/core/decoders/tightpng.js @@ -0,0 +1,27 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + * + */ + +import TightDecoder from './tight.js'; + +export default class TightPNGDecoder extends TightDecoder { + _pngRect(x, y, width, height, sock, display, depth, frame_id) { + let data = this._readData(sock); + if (data === null) { + return false; + } + + display.imageRect(x, y, width, height, "image/png", data, frame_id); + + return true; + } + + _basicRect(ctl, x, y, width, height, sock, display, depth) { + throw new Error("BasicCompression received in TightPNG rect"); + } +} diff --git a/core/decoders/udp.js b/core/decoders/udp.js new file mode 100644 index 0000000..f40e1c4 --- /dev/null +++ b/core/decoders/udp.js @@ -0,0 +1,283 @@ +/* + * KasmVNC: HTML5 VNC client + * Copyright (C) 2020 Kasm Technologies + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + * + */ + +import * as Log from '../util/logging.js'; +import Inflator from "../inflator.js"; + +export default class UDPDecoder { + constructor() { + this._filter = null; + this._palette = new Uint8Array(1024); // 256 * 4 (max palette size * max bytes-per-pixel) + this._directDraw = false; //Draw directly to the canvas without ordering + + this._zlibs = []; + for (let i = 0; i < 4; i++) { + this._zlibs[i] = new Inflator(); + } + } + + decodeRect(x, y, width, height, data, display, depth, frame_id) { + let ctl = data[12]; + ctl = ctl >> 4; + + let ret; + + if (ctl === 0x08) { + ret = this._fillRect(x, y, width, height, data, display, depth, frame_id); + } else if (ctl === 0x09) { + ret = this._jpegRect(x, y, width, height, data, display, depth, frame_id); + } else if (ctl === 0x0A) { + ret = this._pngRect(x, y, width, height, data, display, depth, frame_id); + } else if ((ctl & 0x08) == 0) { + ret = this._basicRect(ctl, x, y, width, height, data, display, depth, frame_id); + } else if (ctl === 0x0B) { + ret = this._webpRect(x, y, width, height, data, display, depth, frame_id); + } else { + throw new Error("Illegal udp compression received (ctl: " + + ctl + ")"); + } + + return ret; + } + + _fillRect(x, y, width, height, data, display, depth, frame_id) { + + display.fillRect(x, y, width, height, + [data[13], data[14], data[15]], frame_id, this._directDraw); + + return true; + } + + _jpegRect(x, y, width, height, data, display, depth, frame_id) { + let img = this._readData(data); + if (img === null) { + return false; + } + + display.imageRect(x, y, width, height, "image/jpeg", img, frame_id, this._directDraw); + + return true; + } + + _webpRect(x, y, width, height, data, display, depth, frame_id) { + let img = this._readData(data); + if (img === null) { + return false; + } + + display.imageRect(x, y, width, height, "image/webp", img, frame_id, this._directDraw); + + return true; + } + + _pngRect(x, y, width, height, data, display, depth, frame_id) { + //throw new Error("PNG received in UDP rect"); + Log.Error("PNG received in UDP rect"); + } + + _basicRect(ctl, x, y, width, height, data, display, depth, frame_id) { + let zlibs_flags = data[12]; + // Reset streams if the server requests it + for (let i = 0; i < 4; i++) { + if ((zlibs_flags >> i) & 1) { + this._zlibs[i].reset(); + //Log.Debug("Reset zlib stream " + i); + } + } + + let filter = data[13]; + let data_index = 14; + let streamId = ctl & 0x3; + if (!(ctl & 0x4)) { + // Implicit CopyFilter + filter = 0; + data_index = 13; + } + + let ret; + + switch (filter) { + case 0: // CopyFilter + ret = this._copyFilter(streamId, x, y, width, height, + data, display, depth, frame_id, data_index); + break; + case 1: // PaletteFilter + ret = this._paletteFilter(streamId, x, y, width, height, + data, display, depth, frame_id); + break; + case 2: // GradientFilter + ret = this._gradientFilter(streamId, x, y, width, height, + data, display, depth, frame_id); + break; + default: + throw new Error("Illegal tight filter received (ctl: " + + this._filter + ")"); + } + + return ret; + } + + _copyFilter(streamId, x, y, width, height, data, display, depth, frame_id, data_index=14) { + const uncompressedSize = width * height * 3; + + if (uncompressedSize === 0) { + return true; + } + + if (uncompressedSize < 12) { + data = data.slice(data_index, data_index + uncompressedSize); + } else { + data = this._readData(data, data_index); + if (data === null) { + return false; + } + + this._zlibs[streamId].setInput(data); + data = this._zlibs[streamId].inflate(uncompressedSize); + this._zlibs[streamId].setInput(null); + } + + let rgbx = new Uint8Array(width * height * 4); + for (let i = 0, j = 0; i < width * height * 4; i += 4, j += 3) { + rgbx[i] = data[j]; + rgbx[i + 1] = data[j + 1]; + rgbx[i + 2] = data[j + 2]; + rgbx[i + 3] = 255; // Alpha + } + + display.blitImage(x, y, width, height, rgbx, 0, frame_id, this._directDraw); + + return true; + } + + _paletteFilter(streamId, x, y, width, height, data, display, depth, frame_id) { + const numColors = data[14] + 1; + const paletteSize = numColors * 3; + let palette = data.slice(15, 15 + paletteSize); + + const bpp = (numColors <= 2) ? 1 : 8; + const rowSize = Math.floor((width * bpp + 7) / 8); + const uncompressedSize = rowSize * height; + let data_i = 15 + paletteSize; + + if (uncompressedSize === 0) { + return true; + } + + if (uncompressedSize < 12) { + data = data.slice(data_i, data_i + uncompressedSize); + } else { + data = this._readData(data, data_i); + if (data === null) { + return false; + } + + this._zlibs[streamId].setInput(data); + data = this._zlibs[streamId].inflate(uncompressedSize); + this._zlibs[streamId].setInput(null); + } + + // Convert indexed (palette based) image data to RGB + if (numColors == 2) { + this._monoRect(x, y, width, height, data, palette, display, frame_id); + } else { + this._paletteRect(x, y, width, height, data, palette, display, frame_id); + } + + return true; + } + + _monoRect(x, y, width, height, data, palette, display, frame_id) { + // Convert indexed (palette based) image data to RGB + // TODO: reduce number of calculations inside loop + const dest = this._getScratchBuffer(width * height * 4); + const w = Math.floor((width + 7) / 8); + const w1 = Math.floor(width / 8); + + for (let y = 0; y < height; y++) { + let dp, sp, x; + for (x = 0; x < w1; x++) { + for (let b = 7; b >= 0; b--) { + dp = (y * width + x * 8 + 7 - b) * 4; + sp = (data[y * w + x] >> b & 1) * 3; + dest[dp] = palette[sp]; + dest[dp + 1] = palette[sp + 1]; + dest[dp + 2] = palette[sp + 2]; + dest[dp + 3] = 255; + } + } + + for (let b = 7; b >= 8 - width % 8; b--) { + dp = (y * width + x * 8 + 7 - b) * 4; + sp = (data[y * w + x] >> b & 1) * 3; + dest[dp] = palette[sp]; + dest[dp + 1] = palette[sp + 1]; + dest[dp + 2] = palette[sp + 2]; + dest[dp + 3] = 255; + } + } + + display.blitImage(x, y, width, height, dest, 0, frame_id, this._directDraw); + } + + _paletteRect(x, y, width, height, data, palette, display, frame_id) { + // Convert indexed (palette based) image data to RGB + const dest = this._getScratchBuffer(width * height * 4); + const total = width * height * 4; + for (let i = 0, j = 0; i < total; i += 4, j++) { + const sp = data[j] * 3; + dest[i] = palette[sp]; + dest[i + 1] = palette[sp + 1]; + dest[i + 2] = palette[sp + 2]; + dest[i + 3] = 255; + } + + display.blitImage(x, y, width, height, dest, 0, frame_id, this._directDraw); + } + + _gradientFilter(streamId, x, y, width, height, data, display, depth, frame_id) { + throw new Error("Gradient filter not implemented"); + } + + _readData(data, len_index = 13) { + if (data.length < len_index + 2) { + Log.Error("UDP Decoder, readData, invalid data len") + return null; + } + + + let i = len_index; + let byte = data[i++]; + let len = byte & 0x7f; + // lenth field is variably sized 1 to 3 bytes long + if (byte & 0x80) { + byte = data[i++] + len |= (byte & 0x7f) << 7; + if (byte & 0x80) { + byte = data[i++]; + len |= byte << 14; + } + } + + //TODO: get rid of me + if (data.length !== len + i) { + console.log('Rect of size ' + len + ' with data size ' + data.length + ' index of ' + i); + } + + + return data.slice(i); + } + + _getScratchBuffer(size) { + if (!this._scratchBuffer || (this._scratchBuffer.length < size)) { + this._scratchBuffer = new Uint8Array(size); + } + return this._scratchBuffer; + } +} diff --git a/core/deflator.js b/core/deflator.js new file mode 100644 index 0000000..fe2a8f7 --- /dev/null +++ b/core/deflator.js @@ -0,0 +1,85 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2020 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +import { deflateInit, deflate } from "../vendor/pako/lib/zlib/deflate.js"; +import { Z_FULL_FLUSH } from "../vendor/pako/lib/zlib/deflate.js"; +import ZStream from "../vendor/pako/lib/zlib/zstream.js"; + +export default class Deflator { + constructor() { + this.strm = new ZStream(); + this.chunkSize = 1024 * 10 * 10; + this.outputBuffer = new Uint8Array(this.chunkSize); + this.windowBits = 5; + + deflateInit(this.strm, this.windowBits); + } + + deflate(inData) { + /* eslint-disable camelcase */ + this.strm.input = inData; + this.strm.avail_in = this.strm.input.length; + this.strm.next_in = 0; + this.strm.output = this.outputBuffer; + this.strm.avail_out = this.chunkSize; + this.strm.next_out = 0; + /* eslint-enable camelcase */ + + let lastRet = deflate(this.strm, Z_FULL_FLUSH); + let outData = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out); + + if (lastRet < 0) { + throw new Error("zlib deflate failed"); + } + + if (this.strm.avail_in > 0) { + // Read chunks until done + + let chunks = [outData]; + let totalLen = outData.length; + do { + /* eslint-disable camelcase */ + this.strm.output = new Uint8Array(this.chunkSize); + this.strm.next_out = 0; + this.strm.avail_out = this.chunkSize; + /* eslint-enable camelcase */ + + lastRet = deflate(this.strm, Z_FULL_FLUSH); + + if (lastRet < 0) { + throw new Error("zlib deflate failed"); + } + + let chunk = new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out); + totalLen += chunk.length; + chunks.push(chunk); + } while (this.strm.avail_in > 0); + + // Combine chunks into a single data + + let newData = new Uint8Array(totalLen); + let offset = 0; + + for (let i = 0; i < chunks.length; i++) { + newData.set(chunks[i], offset); + offset += chunks[i].length; + } + + outData = newData; + } + + /* eslint-disable camelcase */ + this.strm.input = null; + this.strm.avail_in = 0; + this.strm.next_in = 0; + /* eslint-enable camelcase */ + + return outData; + } + +} diff --git a/core/des.js b/core/des.js new file mode 100644 index 0000000..d2f807b --- /dev/null +++ b/core/des.js @@ -0,0 +1,266 @@ +/* + * Ported from Flashlight VNC ActionScript implementation: + * http://www.wizhelp.com/flashlight-vnc/ + * + * Full attribution follows: + * + * ------------------------------------------------------------------------- + * + * This DES class has been extracted from package Acme.Crypto for use in VNC. + * The unnecessary odd parity code has been removed. + * + * These changes are: + * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + + * DesCipher - the DES encryption method + * + * The meat of this code is by Dave Zimmerman , and is: + * + * Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software + * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and + * without fee is hereby granted, provided that this copyright notice is kept + * intact. + * + * WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY + * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE + * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. + * + * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE + * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE + * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT + * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE + * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE + * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE + * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP + * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR + * HIGH RISK ACTIVITIES. + * + * + * The rest is: + * + * Copyright (C) 1996 by Jef Poskanzer . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Visit the ACME Labs Java page for up-to-date versions of this and other + * fine Java utilities: http://www.acme.com/java/ + */ + +/* eslint-disable comma-spacing */ + +// Tables, permutations, S-boxes, etc. +const PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3, + 25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39, + 50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ], + totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28]; + +const z = 0x0; +let a,b,c,d,e,f; +a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e; +const SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d, + z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z, + a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f, + c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d]; +a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e; +const SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d, + a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f, + z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z, + z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e]; +a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e; +const SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f, + b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z, + c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d, + b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e]; +a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e; +const SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d, + z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f, + b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e, + c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e]; +a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e; +const SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z, + a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f, + z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e, + c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d]; +a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e; +const SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f, + z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z, + b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z, + a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f]; +a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e; +const SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f, + b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e, + b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e, + z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d]; +a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e; +const SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d, + c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z, + a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f, + z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e]; + +/* eslint-enable comma-spacing */ + +export default class DES { + constructor(password) { + this.keys = []; + + // Set the key. + const pc1m = [], pcr = [], kn = []; + + for (let j = 0, l = 56; j < 56; ++j, l -= 8) { + l += l < -5 ? 65 : l < -3 ? 31 : l < -1 ? 63 : l === 27 ? 35 : 0; // PC1 + const m = l & 0x7; + pc1m[j] = ((password[l >>> 3] & (1<>> 10; + this.keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6; + ++KnLi; + this.keys[KnLi] = (raw0 & 0x0003f000) << 12; + this.keys[KnLi] |= (raw0 & 0x0000003f) << 16; + this.keys[KnLi] |= (raw1 & 0x0003f000) >>> 4; + this.keys[KnLi] |= (raw1 & 0x0000003f); + ++KnLi; + } + } + + // Encrypt 8 bytes of text + enc8(text) { + const b = text.slice(); + let i = 0, l, r, x; // left, right, accumulator + + // Squash 8 bytes to 2 ints + l = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++]; + r = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++]; + + x = ((l >>> 4) ^ r) & 0x0f0f0f0f; + r ^= x; + l ^= (x << 4); + x = ((l >>> 16) ^ r) & 0x0000ffff; + r ^= x; + l ^= (x << 16); + x = ((r >>> 2) ^ l) & 0x33333333; + l ^= x; + r ^= (x << 2); + x = ((r >>> 8) ^ l) & 0x00ff00ff; + l ^= x; + r ^= (x << 8); + r = (r << 1) | ((r >>> 31) & 1); + x = (l ^ r) & 0xaaaaaaaa; + l ^= x; + r ^= x; + l = (l << 1) | ((l >>> 31) & 1); + + for (let i = 0, keysi = 0; i < 8; ++i) { + x = (r << 28) | (r >>> 4); + x ^= this.keys[keysi++]; + let fval = SP7[x & 0x3f]; + fval |= SP5[(x >>> 8) & 0x3f]; + fval |= SP3[(x >>> 16) & 0x3f]; + fval |= SP1[(x >>> 24) & 0x3f]; + x = r ^ this.keys[keysi++]; + fval |= SP8[x & 0x3f]; + fval |= SP6[(x >>> 8) & 0x3f]; + fval |= SP4[(x >>> 16) & 0x3f]; + fval |= SP2[(x >>> 24) & 0x3f]; + l ^= fval; + x = (l << 28) | (l >>> 4); + x ^= this.keys[keysi++]; + fval = SP7[x & 0x3f]; + fval |= SP5[(x >>> 8) & 0x3f]; + fval |= SP3[(x >>> 16) & 0x3f]; + fval |= SP1[(x >>> 24) & 0x3f]; + x = l ^ this.keys[keysi++]; + fval |= SP8[x & 0x0000003f]; + fval |= SP6[(x >>> 8) & 0x3f]; + fval |= SP4[(x >>> 16) & 0x3f]; + fval |= SP2[(x >>> 24) & 0x3f]; + r ^= fval; + } + + r = (r << 31) | (r >>> 1); + x = (l ^ r) & 0xaaaaaaaa; + l ^= x; + r ^= x; + l = (l << 31) | (l >>> 1); + x = ((l >>> 8) ^ r) & 0x00ff00ff; + r ^= x; + l ^= (x << 8); + x = ((l >>> 2) ^ r) & 0x33333333; + r ^= x; + l ^= (x << 2); + x = ((r >>> 16) ^ l) & 0x0000ffff; + l ^= x; + r ^= (x << 16); + x = ((r >>> 4) ^ l) & 0x0f0f0f0f; + l ^= x; + r ^= (x << 4); + + // Spread ints to bytes + x = [r, l]; + for (i = 0; i < 8; i++) { + b[i] = (x[i>>>2] >>> (8 * (3 - (i % 4)))) % 256; + if (b[i] < 0) { b[i] += 256; } // unsigned + } + return b; + } + + // Encrypt 16 bytes of text using passwd as key + encrypt(t) { + return this.enc8(t.slice(0, 8)).concat(this.enc8(t.slice(8, 16))); + } +} diff --git a/core/display.js b/core/display.js new file mode 100644 index 0000000..1713314 --- /dev/null +++ b/core/display.js @@ -0,0 +1,697 @@ +/* + * KasmVNC: HTML5 VNC client + * Copyright (C) 2020 Kasm Technologies + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +import * as Log from './util/logging.js'; +import Base64 from "./base64.js"; +import { toSigned32bit } from './util/int.js'; +import { isWindows } from './util/browser.js'; + +export default class Display { + constructor(target) { + Log.Debug(">> Display.constructor"); + + /* + For performance reasons we use a multi dimensional array + 1st Dimension of Array Represents Frames, each element is a Frame + 2nd Dimension is the contents of a frame and meta data, contains 4 elements + 0 - int, FrameID + 1 - int, Rect Count + 2 - Array of Rect objects + 3 - bool, is the frame complete + 4 - int, index of current rect (post-processing) + 5 - int, number of times requestAnimationFrame called _pushAsyncFrame and the frame had all rects, however, the frame was not marked complete + */ + this._asyncFrameQueue = []; + this._maxAsyncFrameQueue = 3; + this._clearAsyncQueue(); + + this._flushing = false; + + // the full frame buffer (logical canvas) size + this._fbWidth = 0; + this._fbHeight = 0; + + this._renderMs = 0; + this._prevDrawStyle = ""; + this._target = target; + + if (!this._target) { + throw new Error("Target must be set"); + } + + if (typeof this._target === 'string') { + throw new Error('target must be a DOM element'); + } + + if (!this._target.getContext) { + throw new Error("no getContext method"); + } + + this._targetCtx = this._target.getContext('2d'); + + // the visible canvas viewport (i.e. what actually gets seen) + this._viewportLoc = { 'x': 0, 'y': 0, 'w': this._target.width, 'h': this._target.height }; + + Log.Debug("User Agent: " + navigator.userAgent); + + // performance metrics + this._flipCnt = 0; + this._lastFlip = Date.now(); + this._droppedFrames = 0; + this._droppedRects = 0; + this._forcedFrameCnt = 0; + this._missingFlipRect = 0; + this._lateFlipRect = 0; + this._frameStatsInterval = setInterval(function() { + let delta = Date.now() - this._lastFlip; + if (delta > 0) { + this._fps = (this._flipCnt / (delta / 1000)).toFixed(2); + } + Log.Info('Dropped Frames: ' + this._droppedFrames + ' Dropped Rects: ' + this._droppedRects + ' Forced Frames: ' + this._forcedFrameCnt + ' Missing Flips: ' + this._missingFlipRect + ' Late Flips: ' + this._lateFlipRect); + this._flipCnt = 0; + this._lastFlip = Date.now(); + }.bind(this), 5000); + + // ===== PROPERTIES ===== + + this._scale = 1.0; + this._clipViewport = false; + this._antiAliasing = 0; + this._fps = 0; + + // ===== EVENT HANDLERS ===== + + this.onflush = () => { }; // A flush request has finished + + // Use requestAnimationFrame to write to canvas, to match display refresh rate + this._animationFrameID = window.requestAnimationFrame( () => { this._pushAsyncFrame(); }); + + Log.Debug("<< Display.constructor"); + } + + // ===== PROPERTIES ===== + + get antiAliasing() { return this._antiAliasing; } + set antiAliasing(value) { + this._antiAliasing = value; + this._rescale(this._scale); + } + + get scale() { return this._scale; } + set scale(scale) { + this._rescale(scale); + } + + get clipViewport() { return this._clipViewport; } + set clipViewport(viewport) { + this._clipViewport = viewport; + // May need to readjust the viewport dimensions + const vp = this._viewportLoc; + this.viewportChangeSize(vp.w, vp.h); + this.viewportChangePos(0, 0); + } + + get width() { + return this._fbWidth; + } + + get height() { + return this._fbHeight; + } + + get renderMs() { + return this._renderMs; + } + set renderMs(val) { + this._renderMs = val; + } + + get fps() { return this._fps; } + + // ===== PUBLIC METHODS ===== + + viewportChangePos(deltaX, deltaY) { + const vp = this._viewportLoc; + deltaX = Math.floor(deltaX); + deltaY = Math.floor(deltaY); + + if (!this._clipViewport) { + deltaX = -vp.w; // clamped later of out of bounds + deltaY = -vp.h; + } + + const vx2 = vp.x + vp.w - 1; + const vy2 = vp.y + vp.h - 1; + + // Position change + + if (deltaX < 0 && vp.x + deltaX < 0) { + deltaX = -vp.x; + } + if (vx2 + deltaX >= this._fbWidth) { + deltaX -= vx2 + deltaX - this._fbWidth + 1; + } + + if (vp.y + deltaY < 0) { + deltaY = -vp.y; + } + if (vy2 + deltaY >= this._fbHeight) { + deltaY -= (vy2 + deltaY - this._fbHeight + 1); + } + + if (deltaX === 0 && deltaY === 0) { + return; + } + Log.Debug("viewportChange deltaX: " + deltaX + ", deltaY: " + deltaY); + } + + viewportChangeSize(width, height) { + + if (!this._clipViewport || + typeof(width) === "undefined" || + typeof(height) === "undefined") { + + Log.Debug("Setting viewport to full display region"); + width = this._fbWidth; + height = this._fbHeight; + } + + width = Math.floor(width); + height = Math.floor(height); + + if (width > this._fbWidth) { + width = this._fbWidth; + } + if (height > this._fbHeight) { + height = this._fbHeight; + } + + const vp = this._viewportLoc; + if (vp.w !== width || vp.h !== height) { + vp.w = width; + vp.h = height; + + const canvas = this._target; + canvas.width = width; + canvas.height = height; + + // The position might need to be updated if we've grown + this.viewportChangePos(0, 0); + + // Update the visible size of the target canvas + this._rescale(this._scale); + } + } + + absX(x) { + if (this._scale === 0) { + return 0; + } + return toSigned32bit(x / this._scale + this._viewportLoc.x); + } + + absY(y) { + if (this._scale === 0) { + return 0; + } + return toSigned32bit(y / this._scale + this._viewportLoc.y); + } + + resize(width, height) { + this._prevDrawStyle = ""; + + this._fbWidth = width; + this._fbHeight = height; + + const canvas = this._target; + if (canvas == undefined) { return; } + if (canvas.width !== width || canvas.height !== height) { + + // We have to save the canvas data since changing the size will clear it + let saveImg = null; + if (canvas.width > 0 && canvas.height > 0) { + saveImg = this._targetCtx.getImageData(0, 0, canvas.width, canvas.height); + } + + if (canvas.width !== width) { + canvas.width = width; + } + if (canvas.height !== height) { + canvas.height = height; + } + + if (saveImg) { + this._targetCtx.putImageData(saveImg, 0, 0); + } + } + + // Readjust the viewport as it may be incorrectly sized + // and positioned + const vp = this._viewportLoc; + this.viewportChangeSize(vp.w, vp.h); + this.viewportChangePos(0, 0); + } + + /* + * Mark the specified frame with a rect count + * @param {number} frame_id - The frame ID of the target frame + * @param {number} rect_cnt - The number of rects in the target frame + */ + flip(frame_id, rect_cnt) { + this._asyncRenderQPush({ + 'type': 'flip', + 'frame_id': frame_id, + 'rect_cnt': rect_cnt + }); + } + + /* + * Is the frame queue full + * @returns {bool} is the queue full + */ + pending() { + //is the slot in the queue for the newest frame in use + return this._asyncFrameQueue[this._maxAsyncFrameQueue - 1][0] > 0; + } + + /* + * Force the oldest frame in the queue to render, whether ready or not. + * @param {bool} onflush_message - The caller wants an onflush event triggered once complete. This is + * useful for TCP, allowing the websocket to block until we are ready to process the next frame. + * UDP cannot block and thus no need to notify the caller when complete. + */ + flush(onflush_message=true) { + //force oldest frame to render + this._asyncFrameComplete(0, true); + + if (onflush_message) + this._flushing = true; + } + + /* + * Clears the buffer of anything that has not yet been displayed. + * This must be called when switching between transit modes tcp/udp + */ + clear() { + this._clearAsyncQueue(); + } + + /* + * Cleans up resources, should be called on a disconnect + */ + dispose() { + clearInterval(this._frameStatsInterval); + cancelAnimationFrame(this._animationFrameID); + this.clear(); + } + + fillRect(x, y, width, height, color, frame_id, fromQueue) { + if (!fromQueue) { + this._asyncRenderQPush({ + 'type': 'fill', + 'x': x, + 'y': y, + 'width': width, + 'height': height, + 'color': color, + 'frame_id': frame_id + }); + } else { + this._setFillColor(color); + this._targetCtx.fillRect(x, y, width, height); + } + } + + copyImage(oldX, oldY, newX, newY, w, h, frame_id, fromQueue) { + if (!fromQueue) { + this._asyncRenderQPush({ + 'type': 'copy', + 'oldX': oldX, + 'oldY': oldY, + 'x': newX, + 'y': newY, + 'width': w, + 'height': h, + 'frame_id': frame_id + }); + } else { + // Due to this bug among others [1] we need to disable the image-smoothing to + // avoid getting a blur effect when copying data. + // + // 1. https://bugzilla.mozilla.org/show_bug.cgi?id=1194719 + // + // We need to set these every time since all properties are reset + // when the the size is changed + this._targetCtx.mozImageSmoothingEnabled = false; + this._targetCtx.webkitImageSmoothingEnabled = false; + this._targetCtx.msImageSmoothingEnabled = false; + this._targetCtx.imageSmoothingEnabled = false; + + this._targetCtx.drawImage(this._target, + oldX, oldY, w, h, + newX, newY, w, h); + } + } + + imageRect(x, y, width, height, mime, arr, frame_id) { + /* The internal logic cannot handle empty images, so bail early */ + if ((width === 0) || (height === 0)) { + return; + } + const img = new Image(); + img.src = "data: " + mime + ";base64," + Base64.encode(arr); + + this._asyncRenderQPush({ + 'type': 'img', + 'img': img, + 'x': x, + 'y': y, + 'width': width, + 'height': height, + 'frame_id': frame_id + }); + } + + transparentRect(x, y, width, height, img, frame_id) { + /* The internal logic cannot handle empty images, so bail early */ + if ((width === 0) || (height === 0)) { + return; + } + + var rect = { + 'type': 'transparent', + 'img': null, + 'x': x, + 'y': y, + 'width': width, + 'height': height, + 'frame_id': frame_id + } + + let imageBmpPromise = createImageBitmap(img); + imageBmpPromise.then( function(img) { + rect.img = img; + rect.img.complete = true; + }.bind(rect) ); + + this._asyncRenderQPush(rect); + } + + blitImage(x, y, width, height, arr, offset, frame_id, fromQueue) { + if (!fromQueue) { + // NB(directxman12): it's technically more performant here to use preallocated arrays, + // but it's a lot of extra work for not a lot of payoff -- if we're using the render queue, + // this probably isn't getting called *nearly* as much + const newArr = new Uint8Array(width * height * 4); + newArr.set(new Uint8Array(arr.buffer, 0, newArr.length)); + this._asyncRenderQPush({ + 'type': 'blit', + 'data': newArr, + 'x': x, + 'y': y, + 'width': width, + 'height': height, + 'frame_id': frame_id + }); + } else { + // NB(directxman12): arr must be an Type Array view + let data = new Uint8ClampedArray(arr.buffer, + arr.byteOffset + offset, + width * height * 4); + let img = new ImageData(data, width, height); + this._targetCtx.putImageData(img, x, y); + } + } + + blitQoi(x, y, width, height, arr, offset, frame_id, fromQueue) { + if (!fromQueue) { + this._asyncRenderQPush({ + 'type': 'blitQ', + 'data': arr, + 'x': x, + 'y': y, + 'width': width, + 'height': height, + 'frame_id': frame_id + }); + } else { + this._targetCtx.putImageData(arr, x, y); + } + } + + drawImage(img, x, y, w, h) { + try { + if (img.width != w || img.height != h) { + this._targetCtx.drawImage(img, x, y, w, h); + } else { + this._targetCtx.drawImage(img, x, y); + } + } catch (error) { + Log.Error('Invalid image recieved.'); //KASM-2090 + } + } + + autoscale(containerWidth, containerHeight, scaleRatio=0) { + + if (containerWidth === 0 || containerHeight === 0) { + scaleRatio = 0; + + } else if (scaleRatio === 0) { + + const vp = this._viewportLoc; + const targetAspectRatio = containerWidth / containerHeight; + const fbAspectRatio = vp.w / vp.h; + + if (fbAspectRatio >= targetAspectRatio) { + scaleRatio = containerWidth / vp.w; + } else { + scaleRatio = containerHeight / vp.h; + } + } + + this._rescale(scaleRatio); + } + + // ===== PRIVATE METHODS ===== + + /* + Process incoming rects into a frame buffer, assume rects are out of order due to either UDP or parallel processing of decoding + */ + _asyncRenderQPush(rect) { + let frameIx = -1; + let oldestFrameID = Number.MAX_SAFE_INTEGER; + let newestFrameID = 0; + for (let i=0; i= 0) { + if (rect.type == "flip") { + //flip rect contains the rect count for the frame + if (this._asyncFrameQueue[frameIx][1] !== 0) { + Log.Warn("Redundant flip rect, current rect_cnt: " + this._asyncFrameQueue[frameIx][1] + ", new rect_cnt: " + rect.rect_cnt ); + } + this._asyncFrameQueue[frameIx][1] = rect.rect_cnt; + if (rect.rect_cnt == 0) { + Log.Warn("Invalid rect count"); + } + } + + if (this._asyncFrameQueue[frameIx][1] == this._asyncFrameQueue[frameIx][2].length) { + //frame is complete + this._asyncFrameComplete(frameIx); + } + } else { + if (rect.frame_id < oldestFrameID) { + //rect is older than any frame in the queue, drop it + this._droppedRects++; + if (rect.type == "flip") { this._lateFlipRect++; } + return; + } else if (rect.frame_id > newestFrameID) { + //frame is newer than any frame in the queue, drop old frames + this._asyncFrameQueue.shift(); + let rect_cnt = ((rect.type == "flip") ? rect.rect_cnt : 0); + this._asyncFrameQueue.push([ rect.frame_id, rect_cnt, [ rect ], (rect_cnt == 1), 0, 0 ]); + this._droppedFrames++; + } + } + + } + + /* + Clear the async frame buffer + */ + _clearAsyncQueue() { + this._droppedFrames += this._asyncFrameQueue.length; + + this._asyncFrameQueue = []; + for (let i=0; i this._asyncFrameQueue[frameIx][1]) { + Log.Warn("Frame has more rects than the reported rect_cnt."); + } + } + while (currentFrameRectIx < this._asyncFrameQueue[frameIx][2].length) { + if (this._asyncFrameQueue[frameIx][2][currentFrameRectIx].type == 'img' && !this._asyncFrameQueue[frameIx][2][currentFrameRectIx].img.complete) { + this._asyncFrameQueue[frameIx][2][currentFrameRectIx].type = 'skip'; + this._droppedRects++; + } + currentFrameRectIx++; + } + } else { + while (currentFrameRectIx < this._asyncFrameQueue[frameIx][2].length) { + if (this._asyncFrameQueue[frameIx][2][currentFrameRectIx].type == 'img' && !this._asyncFrameQueue[frameIx][2][currentFrameRectIx].img.complete) { + this._asyncFrameQueue[frameIx][2][currentFrameRectIx].img.addEventListener('load', () => { this._asyncFrameComplete(frameIx); }); + this._asyncFrameQueue[frameIx][4] = currentFrameRectIx; + return; + } else if (this._asyncFrameQueue[frameIx][2][currentFrameRectIx].type == 'transparent' && !this._asyncFrameQueue[frameIx][2][currentFrameRectIx].img) { + return; + } + + currentFrameRectIx++; + } + } + this._asyncFrameQueue[frameIx][4] = currentFrameRectIx; + this._asyncFrameQueue[frameIx][3] = true; + } + + /* + Push the oldest frame in the buffer to the canvas if it is marked ready + */ + _pushAsyncFrame(force=false) { + if (this._asyncFrameQueue[0][3] || force) { + let frame = this._asyncFrameQueue.shift()[2]; + if (this._asyncFrameQueue.length < this._maxAsyncFrameQueue) { + this._asyncFrameQueue.push([ 0, 0, [], false, 0, 0 ]); + } + + let transparent_rects = []; + + //render the selected frame + for (let i = 0; i < frame.length; i++) { + + const a = frame[i]; + switch (a.type) { + case 'copy': + this.copyImage(a.oldX, a.oldY, a.x, a.y, a.width, a.height, a.frame_id, true); + break; + case 'fill': + this.fillRect(a.x, a.y, a.width, a.height, a.color, a.frame_id, true); + break; + case 'blit': + this.blitImage(a.x, a.y, a.width, a.height, a.data, 0, a.frame_id, true); + break; + case 'blitQ': + this.blitQoi(a.x, a.y, a.width, a.height, a.data, 0, a.frame_id, true); + break; + case 'img': + this.drawImage(a.img, a.x, a.y, a.width, a.height); + break; + case 'transparent': + transparent_rects.push(a); + break; + } + } + + //rects with transparency get applied last + for (let i = 0; i < transparent_rects.length; i++) { + const a = transparent_rects[i]; + + if (a.img) { + this.drawImage(a.img, a.x, a.y, a.width, a.height); + } + } + + this._flipCnt += 1; + + if (this._flushing) { + this._flushing = false; + this.onflush(); + } + } else if (this._asyncFrameQueue[0][1] > 0 && this._asyncFrameQueue[0][1] == this._asyncFrameQueue[0][2].length) { + //how many times has _pushAsyncFrame been called when the frame had all rects but has not been drawn + this._asyncFrameQueue[0][5] += 1; + //force the frame to be drawn if it has been here too long + if (this._asyncFrameQueue[0][5] > 5) { + this._pushAsyncFrame(true); + } + } + + if (!force) { + window.requestAnimationFrame( () => { this._pushAsyncFrame(); }); + } + } + + _rescale(factor) { + this._scale = factor; + const vp = this._viewportLoc; + + // NB(directxman12): If you set the width directly, or set the + // style width to a number, the canvas is cleared. + // However, if you set the style width to a string + // ('NNNpx'), the canvas is scaled without clearing. + const width = factor * vp.w + 'px'; + const height = factor * vp.h + 'px'; + + if ((this._target.style.width !== width) || + (this._target.style.height !== height)) { + this._target.style.width = width; + this._target.style.height = height; + } + + Log.Info('Pixel Ratio: ' + window.devicePixelRatio + ', VNC Scale: ' + factor + 'VNC Res: ' + vp.w + 'x' + vp.h); + + var pixR = Math.abs(Math.ceil(window.devicePixelRatio)); + var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; + + if (this.antiAliasing === 2 || (this.antiAliasing === 0 && factor === 1 && this._target.style.imageRendering !== 'pixelated' && pixR === window.devicePixelRatio && vp.w > 0)) { + this._target.style.imageRendering = ((!isFirefox) ? 'pixelated' : 'crisp-edges' ); + Log.Debug('Smoothing disabled'); + } else if (this.antiAliasing === 1 || (this.antiAliasing === 0 && factor !== 1 && this._target.style.imageRendering !== 'auto')) { + this._target.style.imageRendering = 'auto'; //auto is really smooth (blurry) using trilinear of linear + Log.Debug('Smoothing enabled'); + } + } + + _setFillColor(color) { + const newStyle = 'rgb(' + color[0] + ',' + color[1] + ',' + color[2] + ')'; + if (newStyle !== this._prevDrawStyle) { + this._targetCtx.fillStyle = newStyle; + this._prevDrawStyle = newStyle; + } + } +} diff --git a/core/encodings.js b/core/encodings.js new file mode 100644 index 0000000..af2f449 --- /dev/null +++ b/core/encodings.js @@ -0,0 +1,73 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +export const encodings = { + encodingRaw: 0, + encodingCopyRect: 1, + encodingRRE: 2, + encodingHextile: 5, + encodingTight: 7, + encodingTightPNG: -260, + encodingUDP: -261, + + pseudoEncodingQualityLevel9: -23, + pseudoEncodingQualityLevel0: -32, + pseudoEncodingDesktopSize: -223, + pseudoEncodingLastRect: -224, + pseudoEncodingCursor: -239, + pseudoEncodingQEMUExtendedKeyEvent: -258, + pseudoEncodingDesktopName: -307, + pseudoEncodingExtendedDesktopSize: -308, + pseudoEncodingXvp: -309, + pseudoEncodingFence: -312, + pseudoEncodingContinuousUpdates: -313, + pseudoEncodingCompressLevel9: -247, + pseudoEncodingCompressLevel0: -256, + + pseudoEncodingWEBP: -1024, + pseudoEncodingJpegVideoQualityLevel0: -1023, + pseudoEncodingJpegVideoQualityLevel9: -1014, + pseudoEncodingWebpVideoQualityLevel0: -1013, + pseudoEncodingWebpVideoQualityLevel9: -1004, + pseudoEncodingTreatLosslessLevel0: -1003, + pseudoEncodingTreatLosslessLevel10: -993, + pseudoEncodingPreferBandwidth: -992, + pseudoEncodingDynamicQualityMinLevel0: -991, + pseudoEncodingDynamicQualityMinLevel9: -982, + pseudoEncodingDynamicQualityMaxLevel0: -981, + pseudoEncodingDynamicQualityMaxLevel9: -972, + pseudoEncodingVideoAreaLevel1: -971, + pseudoEncodingVideoAreaLevel100: -871, + pseudoEncodingVideoTimeLevel0: -870, + pseudoEncodingVideoTimeLevel100: -770, + + pseudoEncodingFrameRateLevel10: -2048, + pseudoEncodingFrameRateLevel60: -1998, + pseudoEncodingMaxVideoResolution: -1997, + pseudoEncodingVideoScalingLevel0: -1996, + pseudoEncodingVideoScalingLevel9: -1987, + pseudoEncodingVideoOutTimeLevel1: -1986, + pseudoEncodingVideoOutTimeLevel100: -1887, + pseudoEncodingQOI: -1886, + + pseudoEncodingVMwareCursor: 0x574d5664, + pseudoEncodingVMwareCursorPosition: 0x574d5666, + pseudoEncodingExtendedClipboard: 0xc0a1e5ce +}; + +export function encodingName(num) { + switch (num) { + case encodings.encodingRaw: return "Raw"; + case encodings.encodingCopyRect: return "CopyRect"; + case encodings.encodingRRE: return "RRE"; + case encodings.encodingHextile: return "Hextile"; + case encodings.encodingTight: return "Tight"; + case encodings.encodingTightPNG: return "TightPNG"; + default: return "[unknown encoding " + num + "]"; + } +} diff --git a/core/inflator.js b/core/inflator.js new file mode 100644 index 0000000..4b33760 --- /dev/null +++ b/core/inflator.js @@ -0,0 +1,66 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2020 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +import { inflateInit, inflate, inflateReset } from "../vendor/pako/lib/zlib/inflate.js"; +import ZStream from "../vendor/pako/lib/zlib/zstream.js"; + +export default class Inflate { + constructor() { + this.strm = new ZStream(); + this.chunkSize = 1024 * 10 * 10; + this.strm.output = new Uint8Array(this.chunkSize); + this.windowBits = 5; + + inflateInit(this.strm, this.windowBits); + } + + setInput(data) { + if (!data) { + //FIXME: flush remaining data. + /* eslint-disable camelcase */ + this.strm.input = null; + this.strm.avail_in = 0; + this.strm.next_in = 0; + } else { + this.strm.input = data; + this.strm.avail_in = this.strm.input.length; + this.strm.next_in = 0; + /* eslint-enable camelcase */ + } + } + + inflate(expected) { + // resize our output buffer if it's too small + // (we could just use multiple chunks, but that would cause an extra + // allocation each time to flatten the chunks) + if (expected > this.chunkSize) { + this.chunkSize = expected; + this.strm.output = new Uint8Array(this.chunkSize); + } + + /* eslint-disable camelcase */ + this.strm.next_out = 0; + this.strm.avail_out = expected; + /* eslint-enable camelcase */ + + let ret = inflate(this.strm, 0); // Flush argument not used. + if (ret < 0) { + throw new Error("zlib inflate failed"); + } + + if (this.strm.next_out != expected) { + throw new Error("Incomplete zlib block"); + } + + return new Uint8Array(this.strm.output.buffer, 0, this.strm.next_out); + } + + reset() { + inflateReset(this.strm); + } +} diff --git a/core/input/domkeytable.js b/core/input/domkeytable.js new file mode 100644 index 0000000..f79aead --- /dev/null +++ b/core/input/domkeytable.js @@ -0,0 +1,311 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2018 The noVNC Authors + * Licensed under MPL 2.0 or any later version (see LICENSE.txt) + */ + +import KeyTable from "./keysym.js"; + +/* + * Mapping between HTML key values and VNC/X11 keysyms for "special" + * keys that cannot be handled via their Unicode codepoint. + * + * See https://www.w3.org/TR/uievents-key/ for possible values. + */ + +const DOMKeyTable = {}; + +function addStandard(key, standard) { + if (standard === undefined) throw new Error("Undefined keysym for key \"" + key + "\""); + if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\""); + DOMKeyTable[key] = [standard, standard, standard, standard]; +} + +function addLeftRight(key, left, right) { + if (left === undefined) throw new Error("Undefined keysym for key \"" + key + "\""); + if (right === undefined) throw new Error("Undefined keysym for key \"" + key + "\""); + if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\""); + DOMKeyTable[key] = [left, left, right, left]; +} + +function addNumpad(key, standard, numpad) { + if (standard === undefined) throw new Error("Undefined keysym for key \"" + key + "\""); + if (numpad === undefined) throw new Error("Undefined keysym for key \"" + key + "\""); + if (key in DOMKeyTable) throw new Error("Duplicate entry for key \"" + key + "\""); + DOMKeyTable[key] = [standard, standard, standard, numpad]; +} + +// 3.2. Modifier Keys + +addLeftRight("Alt", KeyTable.XK_Alt_L, KeyTable.XK_Alt_R); +addStandard("AltGraph", KeyTable.XK_ISO_Level3_Shift); +addStandard("CapsLock", KeyTable.XK_Caps_Lock); +addLeftRight("Control", KeyTable.XK_Control_L, KeyTable.XK_Control_R); +// - Fn +// - FnLock +addLeftRight("Meta", KeyTable.XK_Super_L, KeyTable.XK_Super_R); +addStandard("NumLock", KeyTable.XK_Num_Lock); +addStandard("ScrollLock", KeyTable.XK_Scroll_Lock); +addLeftRight("Shift", KeyTable.XK_Shift_L, KeyTable.XK_Shift_R); +// - Symbol +// - SymbolLock +// - Hyper +// - Super + +// 3.3. Whitespace Keys + +addNumpad("Enter", KeyTable.XK_Return, KeyTable.XK_KP_Enter); +addStandard("Tab", KeyTable.XK_Tab); +addNumpad(" ", KeyTable.XK_space, KeyTable.XK_KP_Space); + +// 3.4. Navigation Keys + +addNumpad("ArrowDown", KeyTable.XK_Down, KeyTable.XK_KP_Down); +addNumpad("ArrowLeft", KeyTable.XK_Left, KeyTable.XK_KP_Left); +addNumpad("ArrowRight", KeyTable.XK_Right, KeyTable.XK_KP_Right); +addNumpad("ArrowUp", KeyTable.XK_Up, KeyTable.XK_KP_Up); +addNumpad("End", KeyTable.XK_End, KeyTable.XK_KP_End); +addNumpad("Home", KeyTable.XK_Home, KeyTable.XK_KP_Home); +addNumpad("PageDown", KeyTable.XK_Next, KeyTable.XK_KP_Next); +addNumpad("PageUp", KeyTable.XK_Prior, KeyTable.XK_KP_Prior); + +// 3.5. Editing Keys + +addStandard("Backspace", KeyTable.XK_BackSpace); +// Browsers send "Clear" for the numpad 5 without NumLock because +// Windows uses VK_Clear for that key. But Unix expects KP_Begin for +// that scenario. +addNumpad("Clear", KeyTable.XK_Clear, KeyTable.XK_KP_Begin); +addStandard("Copy", KeyTable.XF86XK_Copy); +// - CrSel +addStandard("Cut", KeyTable.XF86XK_Cut); +addNumpad("Delete", KeyTable.XK_Delete, KeyTable.XK_KP_Delete); +// - EraseEof +// - ExSel +addNumpad("Insert", KeyTable.XK_Insert, KeyTable.XK_KP_Insert); +addStandard("Paste", KeyTable.XF86XK_Paste); +addStandard("Redo", KeyTable.XK_Redo); +addStandard("Undo", KeyTable.XK_Undo); + +// 3.6. UI Keys + +// - Accept +// - Again (could just be XK_Redo) +// - Attn +addStandard("Cancel", KeyTable.XK_Cancel); +addStandard("ContextMenu", KeyTable.XK_Menu); +addStandard("Escape", KeyTable.XK_Escape); +addStandard("Execute", KeyTable.XK_Execute); +addStandard("Find", KeyTable.XK_Find); +addStandard("Help", KeyTable.XK_Help); +addStandard("Pause", KeyTable.XK_Pause); +// - Play +// - Props +addStandard("Select", KeyTable.XK_Select); +addStandard("ZoomIn", KeyTable.XF86XK_ZoomIn); +addStandard("ZoomOut", KeyTable.XF86XK_ZoomOut); + +// 3.7. Device Keys + +addStandard("BrightnessDown", KeyTable.XF86XK_MonBrightnessDown); +addStandard("BrightnessUp", KeyTable.XF86XK_MonBrightnessUp); +addStandard("Eject", KeyTable.XF86XK_Eject); +addStandard("LogOff", KeyTable.XF86XK_LogOff); +addStandard("Power", KeyTable.XF86XK_PowerOff); +addStandard("PowerOff", KeyTable.XF86XK_PowerDown); +addStandard("PrintScreen", KeyTable.XK_Print); +addStandard("Hibernate", KeyTable.XF86XK_Hibernate); +addStandard("Standby", KeyTable.XF86XK_Standby); +addStandard("WakeUp", KeyTable.XF86XK_WakeUp); + +// 3.8. IME and Composition Keys + +addStandard("AllCandidates", KeyTable.XK_MultipleCandidate); +addStandard("Alphanumeric", KeyTable.XK_Eisu_toggle); +addStandard("CodeInput", KeyTable.XK_Codeinput); +addStandard("Compose", KeyTable.XK_Multi_key); +addStandard("Convert", KeyTable.XK_Henkan); +// - Dead +// - FinalMode +addStandard("GroupFirst", KeyTable.XK_ISO_First_Group); +addStandard("GroupLast", KeyTable.XK_ISO_Last_Group); +addStandard("GroupNext", KeyTable.XK_ISO_Next_Group); +addStandard("GroupPrevious", KeyTable.XK_ISO_Prev_Group); +// - ModeChange (XK_Mode_switch is often used for AltGr) +// - NextCandidate +addStandard("NonConvert", KeyTable.XK_Muhenkan); +addStandard("PreviousCandidate", KeyTable.XK_PreviousCandidate); +// - Process +addStandard("SingleCandidate", KeyTable.XK_SingleCandidate); +addStandard("HangulMode", KeyTable.XK_Hangul); +addStandard("HanjaMode", KeyTable.XK_Hangul_Hanja); +addStandard("JunjaMode", KeyTable.XK_Hangul_Jeonja); +addStandard("Eisu", KeyTable.XK_Eisu_toggle); +addStandard("Hankaku", KeyTable.XK_Hankaku); +addStandard("Hiragana", KeyTable.XK_Hiragana); +addStandard("HiraganaKatakana", KeyTable.XK_Hiragana_Katakana); +addStandard("KanaMode", KeyTable.XK_Kana_Shift); // could also be _Kana_Lock +addStandard("KanjiMode", KeyTable.XK_Kanji); +addStandard("Katakana", KeyTable.XK_Katakana); +addStandard("Romaji", KeyTable.XK_Romaji); +addStandard("Zenkaku", KeyTable.XK_Zenkaku); +addStandard("ZenkakuHankaku", KeyTable.XK_Zenkaku_Hankaku); + +// 3.9. General-Purpose Function Keys + +addStandard("F1", KeyTable.XK_F1); +addStandard("F2", KeyTable.XK_F2); +addStandard("F3", KeyTable.XK_F3); +addStandard("F4", KeyTable.XK_F4); +addStandard("F5", KeyTable.XK_F5); +addStandard("F6", KeyTable.XK_F6); +addStandard("F7", KeyTable.XK_F7); +addStandard("F8", KeyTable.XK_F8); +addStandard("F9", KeyTable.XK_F9); +addStandard("F10", KeyTable.XK_F10); +addStandard("F11", KeyTable.XK_F11); +addStandard("F12", KeyTable.XK_F12); +addStandard("F13", KeyTable.XK_F13); +addStandard("F14", KeyTable.XK_F14); +addStandard("F15", KeyTable.XK_F15); +addStandard("F16", KeyTable.XK_F16); +addStandard("F17", KeyTable.XK_F17); +addStandard("F18", KeyTable.XK_F18); +addStandard("F19", KeyTable.XK_F19); +addStandard("F20", KeyTable.XK_F20); +addStandard("F21", KeyTable.XK_F21); +addStandard("F22", KeyTable.XK_F22); +addStandard("F23", KeyTable.XK_F23); +addStandard("F24", KeyTable.XK_F24); +addStandard("F25", KeyTable.XK_F25); +addStandard("F26", KeyTable.XK_F26); +addStandard("F27", KeyTable.XK_F27); +addStandard("F28", KeyTable.XK_F28); +addStandard("F29", KeyTable.XK_F29); +addStandard("F30", KeyTable.XK_F30); +addStandard("F31", KeyTable.XK_F31); +addStandard("F32", KeyTable.XK_F32); +addStandard("F33", KeyTable.XK_F33); +addStandard("F34", KeyTable.XK_F34); +addStandard("F35", KeyTable.XK_F35); +// - Soft1... + +// 3.10. Multimedia Keys + +// - ChannelDown +// - ChannelUp +addStandard("Close", KeyTable.XF86XK_Close); +addStandard("MailForward", KeyTable.XF86XK_MailForward); +addStandard("MailReply", KeyTable.XF86XK_Reply); +addStandard("MailSend", KeyTable.XF86XK_Send); +// - MediaClose +addStandard("MediaFastForward", KeyTable.XF86XK_AudioForward); +addStandard("MediaPause", KeyTable.XF86XK_AudioPause); +addStandard("MediaPlay", KeyTable.XF86XK_AudioPlay); +// - MediaPlayPause +addStandard("MediaRecord", KeyTable.XF86XK_AudioRecord); +addStandard("MediaRewind", KeyTable.XF86XK_AudioRewind); +addStandard("MediaStop", KeyTable.XF86XK_AudioStop); +addStandard("MediaTrackNext", KeyTable.XF86XK_AudioNext); +addStandard("MediaTrackPrevious", KeyTable.XF86XK_AudioPrev); +addStandard("New", KeyTable.XF86XK_New); +addStandard("Open", KeyTable.XF86XK_Open); +addStandard("Print", KeyTable.XK_Print); +addStandard("Save", KeyTable.XF86XK_Save); +addStandard("SpellCheck", KeyTable.XF86XK_Spell); + +// 3.11. Multimedia Numpad Keys + +// - Key11 +// - Key12 + +// 3.12. Audio Keys + +// - AudioBalanceLeft +// - AudioBalanceRight +// - AudioBassBoostDown +// - AudioBassBoostToggle +// - AudioBassBoostUp +// - AudioFaderFront +// - AudioFaderRear +// - AudioSurroundModeNext +// - AudioTrebleDown +// - AudioTrebleUp +addStandard("AudioVolumeDown", KeyTable.XF86XK_AudioLowerVolume); +addStandard("AudioVolumeUp", KeyTable.XF86XK_AudioRaiseVolume); +addStandard("AudioVolumeMute", KeyTable.XF86XK_AudioMute); +// - MicrophoneToggle +// - MicrophoneVolumeDown +// - MicrophoneVolumeUp +addStandard("MicrophoneVolumeMute", KeyTable.XF86XK_AudioMicMute); + +// 3.13. Speech Keys + +// - SpeechCorrectionList +// - SpeechInputToggle + +// 3.14. Application Keys + +addStandard("LaunchApplication1", KeyTable.XF86XK_MyComputer); +addStandard("LaunchApplication2", KeyTable.XF86XK_Calculator); +addStandard("LaunchCalendar", KeyTable.XF86XK_Calendar); +// - LaunchContacts +addStandard("LaunchMail", KeyTable.XF86XK_Mail); +addStandard("LaunchMediaPlayer", KeyTable.XF86XK_AudioMedia); +addStandard("LaunchMusicPlayer", KeyTable.XF86XK_Music); +addStandard("LaunchPhone", KeyTable.XF86XK_Phone); +addStandard("LaunchScreenSaver", KeyTable.XF86XK_ScreenSaver); +addStandard("LaunchSpreadsheet", KeyTable.XF86XK_Excel); +addStandard("LaunchWebBrowser", KeyTable.XF86XK_WWW); +addStandard("LaunchWebCam", KeyTable.XF86XK_WebCam); +addStandard("LaunchWordProcessor", KeyTable.XF86XK_Word); + +// 3.15. Browser Keys + +addStandard("BrowserBack", KeyTable.XF86XK_Back); +addStandard("BrowserFavorites", KeyTable.XF86XK_Favorites); +addStandard("BrowserForward", KeyTable.XF86XK_Forward); +addStandard("BrowserHome", KeyTable.XF86XK_HomePage); +addStandard("BrowserRefresh", KeyTable.XF86XK_Refresh); +addStandard("BrowserSearch", KeyTable.XF86XK_Search); +addStandard("BrowserStop", KeyTable.XF86XK_Stop); + +// 3.16. Mobile Phone Keys + +// - A whole bunch... + +// 3.17. TV Keys + +// - A whole bunch... + +// 3.18. Media Controller Keys + +// - A whole bunch... +addStandard("Dimmer", KeyTable.XF86XK_BrightnessAdjust); +addStandard("MediaAudioTrack", KeyTable.XF86XK_AudioCycleTrack); +addStandard("RandomToggle", KeyTable.XF86XK_AudioRandomPlay); +addStandard("SplitScreenToggle", KeyTable.XF86XK_SplitScreen); +addStandard("Subtitle", KeyTable.XF86XK_Subtitle); +addStandard("VideoModeNext", KeyTable.XF86XK_Next_VMode); + +// Extra: Numpad + +addNumpad("=", KeyTable.XK_equal, KeyTable.XK_KP_Equal); +addNumpad("+", KeyTable.XK_plus, KeyTable.XK_KP_Add); +addNumpad("-", KeyTable.XK_minus, KeyTable.XK_KP_Subtract); +addNumpad("*", KeyTable.XK_asterisk, KeyTable.XK_KP_Multiply); +addNumpad("/", KeyTable.XK_slash, KeyTable.XK_KP_Divide); +addNumpad(".", KeyTable.XK_period, KeyTable.XK_KP_Decimal); +addNumpad(",", KeyTable.XK_comma, KeyTable.XK_KP_Separator); +addNumpad("0", KeyTable.XK_0, KeyTable.XK_KP_0); +addNumpad("1", KeyTable.XK_1, KeyTable.XK_KP_1); +addNumpad("2", KeyTable.XK_2, KeyTable.XK_KP_2); +addNumpad("3", KeyTable.XK_3, KeyTable.XK_KP_3); +addNumpad("4", KeyTable.XK_4, KeyTable.XK_KP_4); +addNumpad("5", KeyTable.XK_5, KeyTable.XK_KP_5); +addNumpad("6", KeyTable.XK_6, KeyTable.XK_KP_6); +addNumpad("7", KeyTable.XK_7, KeyTable.XK_KP_7); +addNumpad("8", KeyTable.XK_8, KeyTable.XK_KP_8); +addNumpad("9", KeyTable.XK_9, KeyTable.XK_KP_9); + +export default DOMKeyTable; diff --git a/core/input/fixedkeys.js b/core/input/fixedkeys.js new file mode 100644 index 0000000..4d09f2f --- /dev/null +++ b/core/input/fixedkeys.js @@ -0,0 +1,129 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2018 The noVNC Authors + * Licensed under MPL 2.0 or any later version (see LICENSE.txt) + */ + +/* + * Fallback mapping between HTML key codes (physical keys) and + * HTML key values. This only works for keys that don't vary + * between layouts. We also omit those who manage fine by mapping the + * Unicode representation. + * + * See https://www.w3.org/TR/uievents-code/ for possible codes. + * See https://www.w3.org/TR/uievents-key/ for possible values. + */ + +/* eslint-disable key-spacing */ + +export default { + +// 3.1.1.1. Writing System Keys + + 'Backspace': 'Backspace', + +// 3.1.1.2. Functional Keys + + 'AltLeft': 'Alt', + 'AltRight': 'Alt', // This could also be 'AltGraph' + 'CapsLock': 'CapsLock', + 'ContextMenu': 'ContextMenu', + 'ControlLeft': 'Control', + 'ControlRight': 'Control', + 'Enter': 'Enter', + 'MetaLeft': 'Meta', + 'MetaRight': 'Meta', + 'ShiftLeft': 'Shift', + 'ShiftRight': 'Shift', + 'Tab': 'Tab', + // FIXME: Japanese/Korean keys + +// 3.1.2. Control Pad Section + + 'Delete': 'Delete', + 'End': 'End', + 'Help': 'Help', + 'Home': 'Home', + 'Insert': 'Insert', + 'PageDown': 'PageDown', + 'PageUp': 'PageUp', + +// 3.1.3. Arrow Pad Section + + 'ArrowDown': 'ArrowDown', + 'ArrowLeft': 'ArrowLeft', + 'ArrowRight': 'ArrowRight', + 'ArrowUp': 'ArrowUp', + +// 3.1.4. Numpad Section + + 'NumLock': 'NumLock', + 'NumpadBackspace': 'Backspace', + 'NumpadClear': 'Clear', + +// 3.1.5. Function Section + + 'Escape': 'Escape', + 'F1': 'F1', + 'F2': 'F2', + 'F3': 'F3', + 'F4': 'F4', + 'F5': 'F5', + 'F6': 'F6', + 'F7': 'F7', + 'F8': 'F8', + 'F9': 'F9', + 'F10': 'F10', + 'F11': 'F11', + 'F12': 'F12', + 'F13': 'F13', + 'F14': 'F14', + 'F15': 'F15', + 'F16': 'F16', + 'F17': 'F17', + 'F18': 'F18', + 'F19': 'F19', + 'F20': 'F20', + 'F21': 'F21', + 'F22': 'F22', + 'F23': 'F23', + 'F24': 'F24', + 'F25': 'F25', + 'F26': 'F26', + 'F27': 'F27', + 'F28': 'F28', + 'F29': 'F29', + 'F30': 'F30', + 'F31': 'F31', + 'F32': 'F32', + 'F33': 'F33', + 'F34': 'F34', + 'F35': 'F35', + 'PrintScreen': 'PrintScreen', + 'ScrollLock': 'ScrollLock', + 'Pause': 'Pause', + +// 3.1.6. Media Keys + + 'BrowserBack': 'BrowserBack', + 'BrowserFavorites': 'BrowserFavorites', + 'BrowserForward': 'BrowserForward', + 'BrowserHome': 'BrowserHome', + 'BrowserRefresh': 'BrowserRefresh', + 'BrowserSearch': 'BrowserSearch', + 'BrowserStop': 'BrowserStop', + 'Eject': 'Eject', + 'LaunchApp1': 'LaunchMyComputer', + 'LaunchApp2': 'LaunchCalendar', + 'LaunchMail': 'LaunchMail', + 'MediaPlayPause': 'MediaPlay', + 'MediaStop': 'MediaStop', + 'MediaTrackNext': 'MediaTrackNext', + 'MediaTrackPrevious': 'MediaTrackPrevious', + 'Power': 'Power', + 'Sleep': 'Sleep', + 'AudioVolumeDown': 'AudioVolumeDown', + 'AudioVolumeMute': 'AudioVolumeMute', + 'AudioVolumeUp': 'AudioVolumeUp', + 'WakeUp': 'WakeUp', +}; diff --git a/core/input/gesturehandler.js b/core/input/gesturehandler.js new file mode 100644 index 0000000..6fa72d2 --- /dev/null +++ b/core/input/gesturehandler.js @@ -0,0 +1,567 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2020 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + * + */ + +const GH_NOGESTURE = 0; +const GH_ONETAP = 1; +const GH_TWOTAP = 2; +const GH_THREETAP = 4; +const GH_DRAG = 8; +const GH_LONGPRESS = 16; +const GH_TWODRAG = 32; +const GH_PINCH = 64; + +const GH_INITSTATE = 127; + +const GH_MOVE_THRESHOLD = 50; +const GH_ANGLE_THRESHOLD = 90; // Degrees + +// Timeout when waiting for gestures (ms) +const GH_MULTITOUCH_TIMEOUT = 250; + +// Maximum time between press and release for a tap (ms) +const GH_TAP_TIMEOUT = 1000; + +// Timeout when waiting for longpress (ms) +const GH_LONGPRESS_TIMEOUT = 1000; + +// Timeout when waiting to decide between PINCH and TWODRAG (ms) +const GH_TWOTOUCH_TIMEOUT = 50; + +export default class GestureHandler { + constructor() { + this._target = null; + + this._state = GH_INITSTATE; + + this._tracked = []; + this._ignored = []; + + this._waitingRelease = false; + this._releaseStart = 0.0; + + this._longpressTimeoutId = null; + this._twoTouchTimeoutId = null; + + this._boundEventHandler = this._eventHandler.bind(this); + } + + attach(target) { + this.detach(); + + this._target = target; + this._target.addEventListener('touchstart', + this._boundEventHandler); + this._target.addEventListener('touchmove', + this._boundEventHandler); + this._target.addEventListener('touchend', + this._boundEventHandler); + this._target.addEventListener('touchcancel', + this._boundEventHandler); + } + + detach() { + if (!this._target) { + return; + } + + this._stopLongpressTimeout(); + this._stopTwoTouchTimeout(); + + this._target.removeEventListener('touchstart', + this._boundEventHandler); + this._target.removeEventListener('touchmove', + this._boundEventHandler); + this._target.removeEventListener('touchend', + this._boundEventHandler); + this._target.removeEventListener('touchcancel', + this._boundEventHandler); + this._target = null; + } + + _eventHandler(e) { + let fn; + + e.stopPropagation(); + e.preventDefault(); + + switch (e.type) { + case 'touchstart': + fn = this._touchStart; + break; + case 'touchmove': + fn = this._touchMove; + break; + case 'touchend': + case 'touchcancel': + fn = this._touchEnd; + break; + } + + for (let i = 0; i < e.changedTouches.length; i++) { + let touch = e.changedTouches[i]; + fn.call(this, touch.identifier, touch.clientX, touch.clientY); + } + } + + _touchStart(id, x, y) { + // Ignore any new touches if there is already an active gesture, + // or we're in a cleanup state + if (this._hasDetectedGesture() || (this._state === GH_NOGESTURE)) { + this._ignored.push(id); + return; + } + + // Did it take too long between touches that we should no longer + // consider this a single gesture? + if ((this._tracked.length > 0) && + ((Date.now() - this._tracked[0].started) > GH_MULTITOUCH_TIMEOUT)) { + this._state = GH_NOGESTURE; + this._ignored.push(id); + return; + } + + // If we're waiting for fingers to release then we should no longer + // recognize new touches + if (this._waitingRelease) { + this._state = GH_NOGESTURE; + this._ignored.push(id); + return; + } + + this._tracked.push({ + id: id, + started: Date.now(), + active: true, + firstX: x, + firstY: y, + lastX: x, + lastY: y, + angle: 0 + }); + + switch (this._tracked.length) { + case 1: + this._startLongpressTimeout(); + break; + + case 2: + this._state &= ~(GH_ONETAP | GH_DRAG | GH_LONGPRESS); + this._stopLongpressTimeout(); + break; + + case 3: + this._state &= ~(GH_TWOTAP | GH_TWODRAG | GH_PINCH); + break; + + default: + this._state = GH_NOGESTURE; + } + } + + _touchMove(id, x, y) { + let touch = this._tracked.find(t => t.id === id); + + // If this is an update for a touch we're not tracking, ignore it + if (touch === undefined) { + return; + } + + // Update the touches last position with the event coordinates + touch.lastX = x; + touch.lastY = y; + + let deltaX = x - touch.firstX; + let deltaY = y - touch.firstY; + + // Update angle when the touch has moved + if ((touch.firstX !== touch.lastX) || + (touch.firstY !== touch.lastY)) { + touch.angle = Math.atan2(deltaY, deltaX) * 180 / Math.PI; + } + + if (!this._hasDetectedGesture()) { + // Ignore moves smaller than the minimum threshold + if (Math.hypot(deltaX, deltaY) < GH_MOVE_THRESHOLD) { + return; + } + + // Can't be a tap or long press as we've seen movement + this._state &= ~(GH_ONETAP | GH_TWOTAP | GH_THREETAP | GH_LONGPRESS); + this._stopLongpressTimeout(); + + if (this._tracked.length !== 1) { + this._state &= ~(GH_DRAG); + } + if (this._tracked.length !== 2) { + this._state &= ~(GH_TWODRAG | GH_PINCH); + } + + // We need to figure out which of our different two touch gestures + // this might be + if (this._tracked.length === 2) { + + // The other touch is the one where the id doesn't match + let prevTouch = this._tracked.find(t => t.id !== id); + + // How far the previous touch point has moved since start + let prevDeltaMove = Math.hypot(prevTouch.firstX - prevTouch.lastX, + prevTouch.firstY - prevTouch.lastY); + + // We know that the current touch moved far enough, + // but unless both touches moved further than their + // threshold we don't want to disqualify any gestures + if (prevDeltaMove > GH_MOVE_THRESHOLD) { + + // The angle difference between the direction of the touch points + let deltaAngle = Math.abs(touch.angle - prevTouch.angle); + deltaAngle = Math.abs(((deltaAngle + 180) % 360) - 180); + + // PINCH or TWODRAG can be eliminated depending on the angle + if (deltaAngle > GH_ANGLE_THRESHOLD) { + this._state &= ~GH_TWODRAG; + } else { + this._state &= ~GH_PINCH; + } + + if (this._isTwoTouchTimeoutRunning()) { + this._stopTwoTouchTimeout(); + } + } else if (!this._isTwoTouchTimeoutRunning()) { + // We can't determine the gesture right now, let's + // wait and see if more events are on their way + this._startTwoTouchTimeout(); + } + } + + if (!this._hasDetectedGesture()) { + return; + } + + this._pushEvent('gesturestart'); + } + + this._pushEvent('gesturemove'); + } + + _touchEnd(id, x, y) { + // Check if this is an ignored touch + if (this._ignored.indexOf(id) !== -1) { + // Remove this touch from ignored + this._ignored.splice(this._ignored.indexOf(id), 1); + + // And reset the state if there are no more touches + if ((this._ignored.length === 0) && + (this._tracked.length === 0)) { + this._state = GH_INITSTATE; + this._waitingRelease = false; + } + return; + } + + // We got a touchend before the timer triggered, + // this cannot result in a gesture anymore. + if (!this._hasDetectedGesture() && + this._isTwoTouchTimeoutRunning()) { + this._stopTwoTouchTimeout(); + this._state = GH_NOGESTURE; + } + + // Some gestures don't trigger until a touch is released + if (!this._hasDetectedGesture()) { + // Can't be a gesture that relies on movement + this._state &= ~(GH_DRAG | GH_TWODRAG | GH_PINCH); + // Or something that relies on more time + this._state &= ~GH_LONGPRESS; + this._stopLongpressTimeout(); + + if (!this._waitingRelease) { + this._releaseStart = Date.now(); + this._waitingRelease = true; + + // Can't be a tap that requires more touches than we current have + switch (this._tracked.length) { + case 1: + this._state &= ~(GH_TWOTAP | GH_THREETAP); + break; + + case 2: + this._state &= ~(GH_ONETAP | GH_THREETAP); + break; + } + } + } + + // Waiting for all touches to release? (i.e. some tap) + if (this._waitingRelease) { + // Were all touches released at roughly the same time? + if ((Date.now() - this._releaseStart) > GH_MULTITOUCH_TIMEOUT) { + this._state = GH_NOGESTURE; + } + + // Did too long time pass between press and release? + if (this._tracked.some(t => (Date.now() - t.started) > GH_TAP_TIMEOUT)) { + this._state = GH_NOGESTURE; + } + + let touch = this._tracked.find(t => t.id === id); + touch.active = false; + + // Are we still waiting for more releases? + if (this._hasDetectedGesture()) { + this._pushEvent('gesturestart'); + } else { + // Have we reached a dead end? + if (this._state !== GH_NOGESTURE) { + return; + } + } + } + + if (this._hasDetectedGesture()) { + this._pushEvent('gestureend'); + } + + // Ignore any remaining touches until they are ended + for (let i = 0; i < this._tracked.length; i++) { + if (this._tracked[i].active) { + this._ignored.push(this._tracked[i].id); + } + } + this._tracked = []; + + this._state = GH_NOGESTURE; + + // Remove this touch from ignored if it's in there + if (this._ignored.indexOf(id) !== -1) { + this._ignored.splice(this._ignored.indexOf(id), 1); + } + + // We reset the state if ignored is empty + if ((this._ignored.length === 0)) { + this._state = GH_INITSTATE; + this._waitingRelease = false; + } + } + + _hasDetectedGesture() { + if (this._state === GH_NOGESTURE) { + return false; + } + // Check to see if the bitmask value is a power of 2 + // (i.e. only one bit set). If it is, we have a state. + if (this._state & (this._state - 1)) { + return false; + } + + // For taps we also need to have all touches released + // before we've fully detected the gesture + if (this._state & (GH_ONETAP | GH_TWOTAP | GH_THREETAP)) { + if (this._tracked.some(t => t.active)) { + return false; + } + } + + return true; + } + + _startLongpressTimeout() { + this._stopLongpressTimeout(); + this._longpressTimeoutId = setTimeout(() => this._longpressTimeout(), + GH_LONGPRESS_TIMEOUT); + } + + _stopLongpressTimeout() { + clearTimeout(this._longpressTimeoutId); + this._longpressTimeoutId = null; + } + + _longpressTimeout() { + if (this._hasDetectedGesture()) { + throw new Error("A longpress gesture failed, conflict with a different gesture"); + } + + this._state = GH_LONGPRESS; + this._pushEvent('gesturestart'); + } + + _startTwoTouchTimeout() { + this._stopTwoTouchTimeout(); + this._twoTouchTimeoutId = setTimeout(() => this._twoTouchTimeout(), + GH_TWOTOUCH_TIMEOUT); + } + + _stopTwoTouchTimeout() { + clearTimeout(this._twoTouchTimeoutId); + this._twoTouchTimeoutId = null; + } + + _isTwoTouchTimeoutRunning() { + return this._twoTouchTimeoutId !== null; + } + + _twoTouchTimeout() { + if (this._tracked.length === 0) { + throw new Error("A pinch or two drag gesture failed, no tracked touches"); + } + + // How far each touch point has moved since start + let avgM = this._getAverageMovement(); + let avgMoveH = Math.abs(avgM.x); + let avgMoveV = Math.abs(avgM.y); + + // The difference in the distance between where + // the touch points started and where they are now + let avgD = this._getAverageDistance(); + let deltaTouchDistance = Math.abs(Math.hypot(avgD.first.x, avgD.first.y) - + Math.hypot(avgD.last.x, avgD.last.y)); + + if ((avgMoveV < deltaTouchDistance) && + (avgMoveH < deltaTouchDistance)) { + this._state = GH_PINCH; + } else { + this._state = GH_TWODRAG; + } + + this._pushEvent('gesturestart'); + this._pushEvent('gesturemove'); + } + + _pushEvent(type) { + let detail = { type: this._stateToGesture(this._state) }; + + // For most gesture events the current (average) position is the + // most useful + let avg = this._getPosition(); + let pos = avg.last; + + // However we have a slight distance to detect gestures, so for the + // first gesture event we want to use the first positions we saw + if (type === 'gesturestart') { + pos = avg.first; + } + + // For these gestures, we always want the event coordinates + // to be where the gesture began, not the current touch location. + switch (this._state) { + case GH_TWODRAG: + case GH_PINCH: + pos = avg.first; + break; + } + + detail['clientX'] = pos.x; + detail['clientY'] = pos.y; + + // FIXME: other coordinates? + + // Some gestures also have a magnitude + if (this._state === GH_PINCH) { + let distance = this._getAverageDistance(); + if (type === 'gesturestart') { + detail['magnitudeX'] = distance.first.x; + detail['magnitudeY'] = distance.first.y; + } else { + detail['magnitudeX'] = distance.last.x; + detail['magnitudeY'] = distance.last.y; + } + } else if (this._state === GH_TWODRAG) { + if (type === 'gesturestart') { + detail['magnitudeX'] = 0.0; + detail['magnitudeY'] = 0.0; + } else { + let movement = this._getAverageMovement(); + detail['magnitudeX'] = movement.x; + detail['magnitudeY'] = movement.y; + } + } + + let gev = new CustomEvent(type, { detail: detail }); + this._target.dispatchEvent(gev); + } + + _stateToGesture(state) { + switch (state) { + case GH_ONETAP: + return 'onetap'; + case GH_TWOTAP: + return 'twotap'; + case GH_THREETAP: + return 'threetap'; + case GH_DRAG: + return 'drag'; + case GH_LONGPRESS: + return 'longpress'; + case GH_TWODRAG: + return 'twodrag'; + case GH_PINCH: + return 'pinch'; + } + + throw new Error("Unknown gesture state: " + state); + } + + _getPosition() { + if (this._tracked.length === 0) { + throw new Error("Failed to get gesture position, no tracked touches"); + } + + let size = this._tracked.length; + let fx = 0, fy = 0, lx = 0, ly = 0; + + for (let i = 0; i < this._tracked.length; i++) { + fx += this._tracked[i].firstX; + fy += this._tracked[i].firstY; + lx += this._tracked[i].lastX; + ly += this._tracked[i].lastY; + } + + return { first: { x: fx / size, + y: fy / size }, + last: { x: lx / size, + y: ly / size } }; + } + + _getAverageMovement() { + if (this._tracked.length === 0) { + throw new Error("Failed to get gesture movement, no tracked touches"); + } + + let totalH, totalV; + totalH = totalV = 0; + let size = this._tracked.length; + + for (let i = 0; i < this._tracked.length; i++) { + totalH += this._tracked[i].lastX - this._tracked[i].firstX; + totalV += this._tracked[i].lastY - this._tracked[i].firstY; + } + + return { x: totalH / size, + y: totalV / size }; + } + + _getAverageDistance() { + if (this._tracked.length === 0) { + throw new Error("Failed to get gesture distance, no tracked touches"); + } + + // Distance between the first and last tracked touches + + let first = this._tracked[0]; + let last = this._tracked[this._tracked.length - 1]; + + let fdx = Math.abs(last.firstX - first.firstX); + let fdy = Math.abs(last.firstY - first.firstY); + + let ldx = Math.abs(last.lastX - first.lastX); + let ldy = Math.abs(last.lastY - first.lastY); + + return { first: { x: fdx, y: fdy }, + last: { x: ldx, y: ldy } }; + } +} diff --git a/core/input/imekeys.js b/core/input/imekeys.js new file mode 100644 index 0000000..219e238 --- /dev/null +++ b/core/input/imekeys.js @@ -0,0 +1,32 @@ +/* + * KasmVNC: HTML5 VNC client + * Copyright (C) 2022 Kasm Technologies Inc + * Licensed under MPL 2.0 or any later version (see LICENSE.txt) + */ + +/* + * Keys that could be interaction with IME input + */ + +export default { + 0x30: 'Digit0', + 0x31: 'Digit1', + 0x32: 'Digit2', + 0x33: 'Digit3', + 0x34: 'Digit4', + 0x35: 'Digit5', + 0x36: 'Digit6', + 0x37: 'Digit7', + 0x38: 'Digit8', + 0x39: 'Digit9', + 0x60: 'Numpad0', + 0x61: 'Numpad1', + 0x62: 'Numpad2', + 0x63: 'Numpad3', + 0x64: 'Numpad4', + 0x65: 'Numpad5', + 0x66: 'Numpad6', + 0x67: 'Numpad7', + 0x68: 'Numpad8', + 0x69: 'Numpad9' +}; \ No newline at end of file diff --git a/core/input/keyboard.js b/core/input/keyboard.js new file mode 100644 index 0000000..e551c6f --- /dev/null +++ b/core/input/keyboard.js @@ -0,0 +1,533 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 or any later version (see LICENSE.txt) + */ + +import * as Log from '../util/logging.js'; +import { stopEvent } from '../util/events.js'; +import * as KeyboardUtil from "./util.js"; +import KeyTable from "./keysym.js"; +import keysyms from "./keysymdef.js"; +import imekeys from "./imekeys.js"; +import * as browser from "../util/browser.js"; +import UI from '../../app/ui.js'; +import { isChromiumBased } from '../util/browser.js'; + +// +// Keyboard event handler +// + +export default class Keyboard { + constructor(screenInput, touchInput) { + this._screenInput = screenInput; + this._touchInput = touchInput; + + this._keyDownList = {}; // List of depressed keys + // (even if they are happy) + this._altGrArmed = false; // Windows AltGr detection + + // keep these here so we can refer to them later + this._eventHandlers = { + 'keyup': this._handleKeyUp.bind(this), + 'keydown': this._handleKeyDown.bind(this), + 'blur': this._allKeysUp.bind(this), + 'compositionstart' : this._handleCompositionStart.bind(this), + 'compositionend' : this._handleCompositionEnd.bind(this), + 'input' : this._handleInput.bind(this) + }; + + // ===== EVENT HANDLERS ===== + this.onkeyevent = () => {}; // Handler for key press/release + + this._enableIME = false; + this._imeHold = false; + this._imeInProgress = false; + this._lastKeyboardInput = null; + this._defaultKeyboardInputLen = 100; + this._keyboardInputReset(); + } + + // ===== PUBLIC METHODS ===== + + get enableIME() { return this._enableIME; } + set enableIME(val) { + this._enableIME = val; + this.focus(); + } + + // ===== PRIVATE METHODS ===== + + _clearKeysDown(event) { + // On some Operating systems, the browser will lose key up events when a shortcut key combination triggers something + // on the OS that is outside the scope of the browser. For example, MacOS Cmd+Shift+Ctrl+4 brings up a screen capture + // tool and the browser only recieves some of the key down events, but not the key up events. This leaves the server + // out of sync, with cetain keys stuck down. This attempts to discover and fix these occurances in a OS nuetral way + if (event) { + + for (const [key, value] of Object.entries(this._keyDownList)) { + switch(key) { + case "ControlLeft": + case "ControlRight": + if (!event.ctrlKey) { + Log.Error("A control key is stuck down, sending up."); + this._sendKeyEvent(value, key, false); + } + break; + case "MetaLeft": + case "MetaRight": + if (!event.metaKey) { + Log.Error("A meta key is stuck down, sending up."); + this._sendKeyEvent(value, key, false); + } + break; + case "AltLeft": + case "AltRight": + if (!event.altKey) { + Log.Error("A alt key is stuck down, sending up. "); + this._sendKeyEvent(value, key, false); + } + break; + case "ShiftRight": + case "ShiftLeft": + if (!event.shiftKey) { + Log.Error("A shift key is stuck down, sending up."); + this._sendKeyEvent(value, key, false); + } + break; + } + } + } + } + + _sendKeyEvent(keysym, code, down) { + if (down) { + this._keyDownList[code] = keysym; + } else { + // Do we really think this key is down? + if (!(code in this._keyDownList)) { + return; + } + delete this._keyDownList[code]; + } + + Log.Debug("onkeyevent " + (down ? "down" : "up") + + ", keysym: " + keysym, ", code: " + code); + this.onkeyevent(keysym, code, down); + } + + _getKeyCode(e) { + const code = KeyboardUtil.getKeycode(e); + if (code !== 'Unidentified') { + return code; + } + + // Unstable, but we don't have anything else to go on + if (e.keyCode) { + // 229 is used for composition events + if (e.keyCode !== 229) { + return 'Platform' + e.keyCode; + } + } + + // A precursor to the final DOM3 standard. Unfortunately it + // is not layout independent, so it is as bad as using keyCode + if (e.keyIdentifier) { + // Non-character key? + if (e.keyIdentifier.substr(0, 2) !== 'U+') { + return e.keyIdentifier; + } + + const codepoint = parseInt(e.keyIdentifier.substr(2), 16); + const char = String.fromCharCode(codepoint).toUpperCase(); + + return 'Platform' + char.charCodeAt(); + } + + return 'Unidentified'; + } + + _handleCompositionStart(e) { + Log.Debug("composition started"); + if (this._enableIME) { + this._imeHold = true; + this._imeInProgress = true; + } + } + + _handleCompositionEnd(e) { + Log.Debug("Composition ended"); + if (this._enableIME) { this._imeInProgress = false; } + if (isChromiumBased()) { + this._imeHold = false; + } + } + + _handleInput(e) { + //input event occurs only when keyup keydown events don't prevent default + //IME events will make this happen, for example + //IME changes can back out old characters and replace, thus send differential if IME + //otherwise send new characters + if (this._enableIME && this._imeHold) { + Log.Debug("IME input change, sending differential"); + if (!this._imeInProgress) { + this._imeHold = false; //Firefox fires compisitionend before last input change + } + + const oldValue = this._lastKeyboardInput; + const newValue = e.target.value; + let diff_start = 0; + + //find position where difference starts + for (let i = 0; i < Math.min(oldValue.length, newValue.length); i++) { + if (newValue.charAt(i) != oldValue.charAt(i)) { + break; + } + diff_start++; + } + + //send backspaces if needed + for (let bs = oldValue.length - diff_start; bs > 0; bs--) { + this._sendKeyEvent(KeyTable.XK_BackSpace, "Backspace", true); + this._sendKeyEvent(KeyTable.XK_BackSpace, "Backspace", false); + } + + //send new keys + for (let i = diff_start; i < newValue.length; i++) { + this._sendKeyEvent(keysyms.lookup(newValue.charCodeAt(i)), 'Unidentified', true); + this._sendKeyEvent(keysyms.lookup(newValue.charCodeAt(i)), 'Unidentified', false); + } + this._lastKeyboardInput = newValue; + } else { + Log.Debug("Non-IME input change, sending new characters"); + const newValue = e.target.value; + + if (!this._lastKeyboardInput) { + this._keyboardInputReset(); + } + + const oldValue = this._lastKeyboardInput; + let newLen; + + try { + // Try to check caret position since whitespace at the end + // will not be considered by value.length in some browsers + newLen = Math.max(e.target.selectionStart, newValue.length); + } catch (err) { + // selectionStart is undefined in Google Chrome + newLen = newValue.length; + } + const oldLen = oldValue.length; + + let inputs = newLen - oldLen; + let backspaces = inputs < 0 ? -inputs : 0; + + // Compare the old string with the new to account for + // text-corrections or other input that modify existing text + for (let i = 0; i < Math.min(oldLen, newLen); i++) { + if (newValue.charAt(i) != oldValue.charAt(i)) { + inputs = newLen - i; + backspaces = oldLen - i; + break; + } + } + + // Send the key events + for (let i = 0; i < backspaces; i++) { + this._sendKeyEvent(KeyTable.XK_BackSpace, "Backspace", true); + this._sendKeyEvent(KeyTable.XK_BackSpace, "Backspace", false); + } + for (let i = newLen - inputs; i < newLen; i++) { + this._sendKeyEvent(keysyms.lookup(newValue.charCodeAt(i)), 'Unidentified', true); + this._sendKeyEvent(keysyms.lookup(newValue.charCodeAt(i)), 'Unidentified', false); + } + + // Control the text content length in the keyboardinput element + if (newLen > 2 * this._defaultKeyboardInputLen) { + this._keyboardInputReset(); + } else if (newLen < 1) { + // There always have to be some text in the keyboardinput + // element with which backspace can interact. + this._keyboardInputReset(); + // This sometimes causes the keyboard to disappear for a second + // but it is required for the android keyboard to recognize that + // text has been added to the field + e.target.blur(); + // This has to be ran outside of the input handler in order to work + setTimeout(e.target.focus.bind(e.target), 0); + } else { + this._lastKeyboardInput = newValue; + } + } + } + + _keyboardInputReset() { + this._touchInput.value = new Array(this._defaultKeyboardInputLen).join("_"); + this._lastKeyboardInput = this._touchInput.value; + } + + _handleKeyDown(e) { + const code = this._getKeyCode(e); + let keysym = KeyboardUtil.getKeysym(e); + this._clearKeysDown(e); + + if (this._isIMEInteraction(e)) { + //skip event if IME related + Log.Debug("Skipping keydown, IME interaction, code: " + code + " keysym: " + keysym + " keycode: " + e.keyCode); + return; + } + + // Windows doesn't have a proper AltGr, but handles it using + // fake Ctrl+Alt. However the remote end might not be Windows, + // so we need to merge those in to a single AltGr event. We + // detect this case by seeing the two key events directly after + // each other with a very short time between them (<50ms). + if (this._altGrArmed) { + this._altGrArmed = false; + clearTimeout(this._altGrTimeout); + + if ((code === "AltRight") && + ((e.timeStamp - this._altGrCtrlTime) < 50)) { + // FIXME: We fail to detect this if either Ctrl key is + // first manually pressed as Windows then no + // longer sends the fake Ctrl down event. It + // does however happily send real Ctrl events + // even when AltGr is already down. Some + // browsers detect this for us though and set the + // key to "AltGraph". + keysym = KeyTable.XK_ISO_Level3_Shift; + } else { + this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); + } + } + + // We cannot handle keys we cannot track, but we also need + // to deal with virtual keyboards which omit key info + if (code === 'Unidentified') { + if (keysym) { + // If it's a virtual keyboard then it should be + // sufficient to just send press and release right + // after each other + this._sendKeyEvent(keysym, code, true); + this._sendKeyEvent(keysym, code, false); + } + + stopEvent(e); + return; + } + + // Translate MacOs CMD based shortcuts to their CTRL based counterpart + if ( + browser.isMac() && + UI.rfb && UI.rfb.translateShortcuts && + code !== "MetaLeft" && code !== "MetaRight" && + e.metaKey && !e.ctrlKey && !e.altKey + ) { + this._sendKeyEvent(this._keyDownList["MetaLeft"], "MetaLeft", false); + this._sendKeyEvent(this._keyDownList["MetaRight"], "MetaRight", false); + this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); + this._sendKeyEvent(keysym, code, true); + stopEvent(e); + return; + } + + // Alt behaves more like AltGraph on macOS, so shuffle the + // keys around a bit to make things more sane for the remote + // server. This method is used by RealVNC and TigerVNC (and + // possibly others). + if (browser.isMac() || browser.isIOS()) { + switch (keysym) { + case KeyTable.XK_Super_L: + keysym = KeyTable.XK_Alt_L; + break; + case KeyTable.XK_Super_R: + keysym = KeyTable.XK_Super_L; + break; + case KeyTable.XK_Alt_L: + keysym = KeyTable.XK_Mode_switch; + break; + case KeyTable.XK_Alt_R: + keysym = KeyTable.XK_ISO_Level3_Shift; + break; + } + } + + // Is this key already pressed? If so, then we must use the + // same keysym or we'll confuse the server + if (code in this._keyDownList) { + keysym = this._keyDownList[code]; + } + + // macOS doesn't send proper key events for modifiers, only + // state change events. That gets extra confusing for CapsLock + // which toggles on each press, but not on release. So pretend + // it was a quick press and release of the button. + if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) { + this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true); + this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false); + stopEvent(e); + return; + } + + // Windows doesn't send proper key releases for a bunch of + // Japanese IM keys so we have to fake the release right away + const jpBadKeys = [ KeyTable.XK_Zenkaku_Hankaku, + KeyTable.XK_Eisu_toggle, + KeyTable.XK_Katakana, + KeyTable.XK_Hiragana, + KeyTable.XK_Romaji ]; + if (browser.isWindows() && jpBadKeys.includes(keysym)) { + this._sendKeyEvent(keysym, code, true); + this._sendKeyEvent(keysym, code, false); + stopEvent(e); + return; + } + + stopEvent(e); + + // Possible start of AltGr sequence? (see above) + if ((code === "ControlLeft") && browser.isWindows() && + !("ControlLeft" in this._keyDownList)) { + this._altGrArmed = true; + this._altGrTimeout = setTimeout(this._handleAltGrTimeout.bind(this), 100); + this._altGrCtrlTime = e.timeStamp; + return; + } + + this._sendKeyEvent(keysym, code, true); + } + + _handleKeyUp(e) { + const code = this._getKeyCode(e); + + if (this._isIMEInteraction(e)) { + //skip IME related events + Log.Debug("Skipping keyup, IME interaction, code: " + code + " keycode: " + e.keyCode); + return; + } + stopEvent(e); + + // We can't get a release in the middle of an AltGr sequence, so + // abort that detection + if (this._altGrArmed) { + this._altGrArmed = false; + clearTimeout(this._altGrTimeout); + this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); + } + + // See comment in _handleKeyDown() + if ((browser.isMac() || browser.isIOS()) && (code === 'CapsLock')) { + this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', true); + this._sendKeyEvent(KeyTable.XK_Caps_Lock, 'CapsLock', false); + return; + } + + this._sendKeyEvent(this._keyDownList[code], code, false); + + // Windows has a rather nasty bug where it won't send key + // release events for a Shift button if the other Shift is still + // pressed + if (browser.isWindows() && ((code === 'ShiftLeft') || + (code === 'ShiftRight'))) { + if ('ShiftRight' in this._keyDownList) { + this._sendKeyEvent(this._keyDownList['ShiftRight'], + 'ShiftRight', false); + } + if ('ShiftLeft' in this._keyDownList) { + this._sendKeyEvent(this._keyDownList['ShiftLeft'], + 'ShiftLeft', false); + } + } + } + + _handleAltGrTimeout() { + this._altGrArmed = false; + clearTimeout(this._altGrTimeout); + this._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); + } + + _allKeysUp() { + Log.Debug(">> Keyboard.allKeysUp"); + for (let code in this._keyDownList) { + this._sendKeyEvent(this._keyDownList[code], code, false); + } + Log.Debug("<< Keyboard.allKeysUp"); + } + + _isIMEInteraction(e) { + //input must come from touchinput (textarea) and ime must be enabled + if (e.target != this._touchInput || !this._enableIME) { return false; } + + //keyCode of 229 is IME composition + if (e.keyCode == 229) { + return true; + } + + //unfortunately, IME interactions can come through as events + //generally safe to ignore and let them come in as "input" events instead + //we can't do that with none character keys though + //Firefox does not seem to fire key events for IME interaction but Chrome does + //TODO: potentially skip this for Firefox browsers, needs more testing with different IME types + if (e.keyCode in imekeys) { + return true; + } + + return false; + } + + // ===== PUBLIC METHODS ===== + + focus() { + if (this._enableIME) { + this._touchInput.focus(); + } else { + this._screenInput.focus(); + } + } + + blur() { + if (this._enableIME) { + this._touchInput.blur(); + } else { + this._screenInput.blur(); + } + } + + grab() { + //Log.Debug(">> Keyboard.grab"); + + this._screenInput.addEventListener('keydown', this._eventHandlers.keydown); + this._screenInput.addEventListener('keyup', this._eventHandlers.keyup); + + this._touchInput.addEventListener('keydown', this._eventHandlers.keydown); + this._touchInput.addEventListener('keyup', this._eventHandlers.keyup); + this._touchInput.addEventListener('compositionstart', this._eventHandlers.compositionstart); + this._touchInput.addEventListener('compositionend', this._eventHandlers.compositionend); + this._touchInput.addEventListener('input', this._eventHandlers.input); + + // Release (key up) if window loses focus + window.addEventListener('blur', this._eventHandlers.blur); + + //Log.Debug("<< Keyboard.grab"); + } + + ungrab() { + //Log.Debug(">> Keyboard.ungrab"); + + this._screenInput.removeEventListener('keydown', this._eventHandlers.keydown); + this._screenInput.removeEventListener('keyup', this._eventHandlers.keyup); + + this._touchInput.removeEventListener('keydown', this._eventHandlers.keydown); + this._touchInput.removeEventListener('keyup', this._eventHandlers.keyup); + this._touchInput.removeEventListener('compositionstart', this._eventHandlers.compositionstart); + this._touchInput.removeEventListener('compositionend', this._eventHandlers.compositionend); + this._touchInput.removeEventListener('input', this._eventHandlers.input); + + window.removeEventListener('blur', this._eventHandlers.blur); + + // Release (key up) all keys that are in a down state + this._allKeysUp(); + + //Log.Debug(">> Keyboard.ungrab"); + } +} diff --git a/core/input/keysym.js b/core/input/keysym.js new file mode 100644 index 0000000..22ba058 --- /dev/null +++ b/core/input/keysym.js @@ -0,0 +1,616 @@ +/* eslint-disable key-spacing */ + +export default { + XK_VoidSymbol: 0xffffff, /* Void symbol */ + + XK_BackSpace: 0xff08, /* Back space, back char */ + XK_Tab: 0xff09, + XK_Linefeed: 0xff0a, /* Linefeed, LF */ + XK_Clear: 0xff0b, + XK_Return: 0xff0d, /* Return, enter */ + XK_Pause: 0xff13, /* Pause, hold */ + XK_Scroll_Lock: 0xff14, + XK_Sys_Req: 0xff15, + XK_Escape: 0xff1b, + XK_Delete: 0xffff, /* Delete, rubout */ + + /* International & multi-key character composition */ + + XK_Multi_key: 0xff20, /* Multi-key character compose */ + XK_Codeinput: 0xff37, + XK_SingleCandidate: 0xff3c, + XK_MultipleCandidate: 0xff3d, + XK_PreviousCandidate: 0xff3e, + + /* Japanese keyboard support */ + + XK_Kanji: 0xff21, /* Kanji, Kanji convert */ + XK_Muhenkan: 0xff22, /* Cancel Conversion */ + XK_Henkan_Mode: 0xff23, /* Start/Stop Conversion */ + XK_Henkan: 0xff23, /* Alias for Henkan_Mode */ + XK_Romaji: 0xff24, /* to Romaji */ + XK_Hiragana: 0xff25, /* to Hiragana */ + XK_Katakana: 0xff26, /* to Katakana */ + XK_Hiragana_Katakana: 0xff27, /* Hiragana/Katakana toggle */ + XK_Zenkaku: 0xff28, /* to Zenkaku */ + XK_Hankaku: 0xff29, /* to Hankaku */ + XK_Zenkaku_Hankaku: 0xff2a, /* Zenkaku/Hankaku toggle */ + XK_Touroku: 0xff2b, /* Add to Dictionary */ + XK_Massyo: 0xff2c, /* Delete from Dictionary */ + XK_Kana_Lock: 0xff2d, /* Kana Lock */ + XK_Kana_Shift: 0xff2e, /* Kana Shift */ + XK_Eisu_Shift: 0xff2f, /* Alphanumeric Shift */ + XK_Eisu_toggle: 0xff30, /* Alphanumeric toggle */ + XK_Kanji_Bangou: 0xff37, /* Codeinput */ + XK_Zen_Koho: 0xff3d, /* Multiple/All Candidate(s) */ + XK_Mae_Koho: 0xff3e, /* Previous Candidate */ + + /* Cursor control & motion */ + + XK_Home: 0xff50, + XK_Left: 0xff51, /* Move left, left arrow */ + XK_Up: 0xff52, /* Move up, up arrow */ + XK_Right: 0xff53, /* Move right, right arrow */ + XK_Down: 0xff54, /* Move down, down arrow */ + XK_Prior: 0xff55, /* Prior, previous */ + XK_Page_Up: 0xff55, + XK_Next: 0xff56, /* Next */ + XK_Page_Down: 0xff56, + XK_End: 0xff57, /* EOL */ + XK_Begin: 0xff58, /* BOL */ + + + /* Misc functions */ + + XK_Select: 0xff60, /* Select, mark */ + XK_Print: 0xff61, + XK_Execute: 0xff62, /* Execute, run, do */ + XK_Insert: 0xff63, /* Insert, insert here */ + XK_Undo: 0xff65, + XK_Redo: 0xff66, /* Redo, again */ + XK_Menu: 0xff67, + XK_Find: 0xff68, /* Find, search */ + XK_Cancel: 0xff69, /* Cancel, stop, abort, exit */ + XK_Help: 0xff6a, /* Help */ + XK_Break: 0xff6b, + XK_Mode_switch: 0xff7e, /* Character set switch */ + XK_script_switch: 0xff7e, /* Alias for mode_switch */ + XK_Num_Lock: 0xff7f, + + /* Keypad functions, keypad numbers cleverly chosen to map to ASCII */ + + XK_KP_Space: 0xff80, /* Space */ + XK_KP_Tab: 0xff89, + XK_KP_Enter: 0xff8d, /* Enter */ + XK_KP_F1: 0xff91, /* PF1, KP_A, ... */ + XK_KP_F2: 0xff92, + XK_KP_F3: 0xff93, + XK_KP_F4: 0xff94, + XK_KP_Home: 0xff95, + XK_KP_Left: 0xff96, + XK_KP_Up: 0xff97, + XK_KP_Right: 0xff98, + XK_KP_Down: 0xff99, + XK_KP_Prior: 0xff9a, + XK_KP_Page_Up: 0xff9a, + XK_KP_Next: 0xff9b, + XK_KP_Page_Down: 0xff9b, + XK_KP_End: 0xff9c, + XK_KP_Begin: 0xff9d, + XK_KP_Insert: 0xff9e, + XK_KP_Delete: 0xff9f, + XK_KP_Equal: 0xffbd, /* Equals */ + XK_KP_Multiply: 0xffaa, + XK_KP_Add: 0xffab, + XK_KP_Separator: 0xffac, /* Separator, often comma */ + XK_KP_Subtract: 0xffad, + XK_KP_Decimal: 0xffae, + XK_KP_Divide: 0xffaf, + + XK_KP_0: 0xffb0, + XK_KP_1: 0xffb1, + XK_KP_2: 0xffb2, + XK_KP_3: 0xffb3, + XK_KP_4: 0xffb4, + XK_KP_5: 0xffb5, + XK_KP_6: 0xffb6, + XK_KP_7: 0xffb7, + XK_KP_8: 0xffb8, + XK_KP_9: 0xffb9, + + /* + * Auxiliary functions; note the duplicate definitions for left and right + * function keys; Sun keyboards and a few other manufacturers have such + * function key groups on the left and/or right sides of the keyboard. + * We've not found a keyboard with more than 35 function keys total. + */ + + XK_F1: 0xffbe, + XK_F2: 0xffbf, + XK_F3: 0xffc0, + XK_F4: 0xffc1, + XK_F5: 0xffc2, + XK_F6: 0xffc3, + XK_F7: 0xffc4, + XK_F8: 0xffc5, + XK_F9: 0xffc6, + XK_F10: 0xffc7, + XK_F11: 0xffc8, + XK_L1: 0xffc8, + XK_F12: 0xffc9, + XK_L2: 0xffc9, + XK_F13: 0xffca, + XK_L3: 0xffca, + XK_F14: 0xffcb, + XK_L4: 0xffcb, + XK_F15: 0xffcc, + XK_L5: 0xffcc, + XK_F16: 0xffcd, + XK_L6: 0xffcd, + XK_F17: 0xffce, + XK_L7: 0xffce, + XK_F18: 0xffcf, + XK_L8: 0xffcf, + XK_F19: 0xffd0, + XK_L9: 0xffd0, + XK_F20: 0xffd1, + XK_L10: 0xffd1, + XK_F21: 0xffd2, + XK_R1: 0xffd2, + XK_F22: 0xffd3, + XK_R2: 0xffd3, + XK_F23: 0xffd4, + XK_R3: 0xffd4, + XK_F24: 0xffd5, + XK_R4: 0xffd5, + XK_F25: 0xffd6, + XK_R5: 0xffd6, + XK_F26: 0xffd7, + XK_R6: 0xffd7, + XK_F27: 0xffd8, + XK_R7: 0xffd8, + XK_F28: 0xffd9, + XK_R8: 0xffd9, + XK_F29: 0xffda, + XK_R9: 0xffda, + XK_F30: 0xffdb, + XK_R10: 0xffdb, + XK_F31: 0xffdc, + XK_R11: 0xffdc, + XK_F32: 0xffdd, + XK_R12: 0xffdd, + XK_F33: 0xffde, + XK_R13: 0xffde, + XK_F34: 0xffdf, + XK_R14: 0xffdf, + XK_F35: 0xffe0, + XK_R15: 0xffe0, + + /* Modifiers */ + + XK_Shift_L: 0xffe1, /* Left shift */ + XK_Shift_R: 0xffe2, /* Right shift */ + XK_Control_L: 0xffe3, /* Left control */ + XK_Control_R: 0xffe4, /* Right control */ + XK_Caps_Lock: 0xffe5, /* Caps lock */ + XK_Shift_Lock: 0xffe6, /* Shift lock */ + + XK_Meta_L: 0xffe7, /* Left meta */ + XK_Meta_R: 0xffe8, /* Right meta */ + XK_Alt_L: 0xffe9, /* Left alt */ + XK_Alt_R: 0xffea, /* Right alt */ + XK_Super_L: 0xffeb, /* Left super */ + XK_Super_R: 0xffec, /* Right super */ + XK_Hyper_L: 0xffed, /* Left hyper */ + XK_Hyper_R: 0xffee, /* Right hyper */ + + /* + * Keyboard (XKB) Extension function and modifier keys + * (from Appendix C of "The X Keyboard Extension: Protocol Specification") + * Byte 3 = 0xfe + */ + + XK_ISO_Level3_Shift: 0xfe03, /* AltGr */ + XK_ISO_Next_Group: 0xfe08, + XK_ISO_Prev_Group: 0xfe0a, + XK_ISO_First_Group: 0xfe0c, + XK_ISO_Last_Group: 0xfe0e, + + /* + * Latin 1 + * (ISO/IEC 8859-1: Unicode U+0020..U+00FF) + * Byte 3: 0 + */ + + XK_space: 0x0020, /* U+0020 SPACE */ + XK_exclam: 0x0021, /* U+0021 EXCLAMATION MARK */ + XK_quotedbl: 0x0022, /* U+0022 QUOTATION MARK */ + XK_numbersign: 0x0023, /* U+0023 NUMBER SIGN */ + XK_dollar: 0x0024, /* U+0024 DOLLAR SIGN */ + XK_percent: 0x0025, /* U+0025 PERCENT SIGN */ + XK_ampersand: 0x0026, /* U+0026 AMPERSAND */ + XK_apostrophe: 0x0027, /* U+0027 APOSTROPHE */ + XK_quoteright: 0x0027, /* deprecated */ + XK_parenleft: 0x0028, /* U+0028 LEFT PARENTHESIS */ + XK_parenright: 0x0029, /* U+0029 RIGHT PARENTHESIS */ + XK_asterisk: 0x002a, /* U+002A ASTERISK */ + XK_plus: 0x002b, /* U+002B PLUS SIGN */ + XK_comma: 0x002c, /* U+002C COMMA */ + XK_minus: 0x002d, /* U+002D HYPHEN-MINUS */ + XK_period: 0x002e, /* U+002E FULL STOP */ + XK_slash: 0x002f, /* U+002F SOLIDUS */ + XK_0: 0x0030, /* U+0030 DIGIT ZERO */ + XK_1: 0x0031, /* U+0031 DIGIT ONE */ + XK_2: 0x0032, /* U+0032 DIGIT TWO */ + XK_3: 0x0033, /* U+0033 DIGIT THREE */ + XK_4: 0x0034, /* U+0034 DIGIT FOUR */ + XK_5: 0x0035, /* U+0035 DIGIT FIVE */ + XK_6: 0x0036, /* U+0036 DIGIT SIX */ + XK_7: 0x0037, /* U+0037 DIGIT SEVEN */ + XK_8: 0x0038, /* U+0038 DIGIT EIGHT */ + XK_9: 0x0039, /* U+0039 DIGIT NINE */ + XK_colon: 0x003a, /* U+003A COLON */ + XK_semicolon: 0x003b, /* U+003B SEMICOLON */ + XK_less: 0x003c, /* U+003C LESS-THAN SIGN */ + XK_equal: 0x003d, /* U+003D EQUALS SIGN */ + XK_greater: 0x003e, /* U+003E GREATER-THAN SIGN */ + XK_question: 0x003f, /* U+003F QUESTION MARK */ + XK_at: 0x0040, /* U+0040 COMMERCIAL AT */ + XK_A: 0x0041, /* U+0041 LATIN CAPITAL LETTER A */ + XK_B: 0x0042, /* U+0042 LATIN CAPITAL LETTER B */ + XK_C: 0x0043, /* U+0043 LATIN CAPITAL LETTER C */ + XK_D: 0x0044, /* U+0044 LATIN CAPITAL LETTER D */ + XK_E: 0x0045, /* U+0045 LATIN CAPITAL LETTER E */ + XK_F: 0x0046, /* U+0046 LATIN CAPITAL LETTER F */ + XK_G: 0x0047, /* U+0047 LATIN CAPITAL LETTER G */ + XK_H: 0x0048, /* U+0048 LATIN CAPITAL LETTER H */ + XK_I: 0x0049, /* U+0049 LATIN CAPITAL LETTER I */ + XK_J: 0x004a, /* U+004A LATIN CAPITAL LETTER J */ + XK_K: 0x004b, /* U+004B LATIN CAPITAL LETTER K */ + XK_L: 0x004c, /* U+004C LATIN CAPITAL LETTER L */ + XK_M: 0x004d, /* U+004D LATIN CAPITAL LETTER M */ + XK_N: 0x004e, /* U+004E LATIN CAPITAL LETTER N */ + XK_O: 0x004f, /* U+004F LATIN CAPITAL LETTER O */ + XK_P: 0x0050, /* U+0050 LATIN CAPITAL LETTER P */ + XK_Q: 0x0051, /* U+0051 LATIN CAPITAL LETTER Q */ + XK_R: 0x0052, /* U+0052 LATIN CAPITAL LETTER R */ + XK_S: 0x0053, /* U+0053 LATIN CAPITAL LETTER S */ + XK_T: 0x0054, /* U+0054 LATIN CAPITAL LETTER T */ + XK_U: 0x0055, /* U+0055 LATIN CAPITAL LETTER U */ + XK_V: 0x0056, /* U+0056 LATIN CAPITAL LETTER V */ + XK_W: 0x0057, /* U+0057 LATIN CAPITAL LETTER W */ + XK_X: 0x0058, /* U+0058 LATIN CAPITAL LETTER X */ + XK_Y: 0x0059, /* U+0059 LATIN CAPITAL LETTER Y */ + XK_Z: 0x005a, /* U+005A LATIN CAPITAL LETTER Z */ + XK_bracketleft: 0x005b, /* U+005B LEFT SQUARE BRACKET */ + XK_backslash: 0x005c, /* U+005C REVERSE SOLIDUS */ + XK_bracketright: 0x005d, /* U+005D RIGHT SQUARE BRACKET */ + XK_asciicircum: 0x005e, /* U+005E CIRCUMFLEX ACCENT */ + XK_underscore: 0x005f, /* U+005F LOW LINE */ + XK_grave: 0x0060, /* U+0060 GRAVE ACCENT */ + XK_quoteleft: 0x0060, /* deprecated */ + XK_a: 0x0061, /* U+0061 LATIN SMALL LETTER A */ + XK_b: 0x0062, /* U+0062 LATIN SMALL LETTER B */ + XK_c: 0x0063, /* U+0063 LATIN SMALL LETTER C */ + XK_d: 0x0064, /* U+0064 LATIN SMALL LETTER D */ + XK_e: 0x0065, /* U+0065 LATIN SMALL LETTER E */ + XK_f: 0x0066, /* U+0066 LATIN SMALL LETTER F */ + XK_g: 0x0067, /* U+0067 LATIN SMALL LETTER G */ + XK_h: 0x0068, /* U+0068 LATIN SMALL LETTER H */ + XK_i: 0x0069, /* U+0069 LATIN SMALL LETTER I */ + XK_j: 0x006a, /* U+006A LATIN SMALL LETTER J */ + XK_k: 0x006b, /* U+006B LATIN SMALL LETTER K */ + XK_l: 0x006c, /* U+006C LATIN SMALL LETTER L */ + XK_m: 0x006d, /* U+006D LATIN SMALL LETTER M */ + XK_n: 0x006e, /* U+006E LATIN SMALL LETTER N */ + XK_o: 0x006f, /* U+006F LATIN SMALL LETTER O */ + XK_p: 0x0070, /* U+0070 LATIN SMALL LETTER P */ + XK_q: 0x0071, /* U+0071 LATIN SMALL LETTER Q */ + XK_r: 0x0072, /* U+0072 LATIN SMALL LETTER R */ + XK_s: 0x0073, /* U+0073 LATIN SMALL LETTER S */ + XK_t: 0x0074, /* U+0074 LATIN SMALL LETTER T */ + XK_u: 0x0075, /* U+0075 LATIN SMALL LETTER U */ + XK_v: 0x0076, /* U+0076 LATIN SMALL LETTER V */ + XK_w: 0x0077, /* U+0077 LATIN SMALL LETTER W */ + XK_x: 0x0078, /* U+0078 LATIN SMALL LETTER X */ + XK_y: 0x0079, /* U+0079 LATIN SMALL LETTER Y */ + XK_z: 0x007a, /* U+007A LATIN SMALL LETTER Z */ + XK_braceleft: 0x007b, /* U+007B LEFT CURLY BRACKET */ + XK_bar: 0x007c, /* U+007C VERTICAL LINE */ + XK_braceright: 0x007d, /* U+007D RIGHT CURLY BRACKET */ + XK_asciitilde: 0x007e, /* U+007E TILDE */ + + XK_nobreakspace: 0x00a0, /* U+00A0 NO-BREAK SPACE */ + XK_exclamdown: 0x00a1, /* U+00A1 INVERTED EXCLAMATION MARK */ + XK_cent: 0x00a2, /* U+00A2 CENT SIGN */ + XK_sterling: 0x00a3, /* U+00A3 POUND SIGN */ + XK_currency: 0x00a4, /* U+00A4 CURRENCY SIGN */ + XK_yen: 0x00a5, /* U+00A5 YEN SIGN */ + XK_brokenbar: 0x00a6, /* U+00A6 BROKEN BAR */ + XK_section: 0x00a7, /* U+00A7 SECTION SIGN */ + XK_diaeresis: 0x00a8, /* U+00A8 DIAERESIS */ + XK_copyright: 0x00a9, /* U+00A9 COPYRIGHT SIGN */ + XK_ordfeminine: 0x00aa, /* U+00AA FEMININE ORDINAL INDICATOR */ + XK_guillemotleft: 0x00ab, /* U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */ + XK_notsign: 0x00ac, /* U+00AC NOT SIGN */ + XK_hyphen: 0x00ad, /* U+00AD SOFT HYPHEN */ + XK_registered: 0x00ae, /* U+00AE REGISTERED SIGN */ + XK_macron: 0x00af, /* U+00AF MACRON */ + XK_degree: 0x00b0, /* U+00B0 DEGREE SIGN */ + XK_plusminus: 0x00b1, /* U+00B1 PLUS-MINUS SIGN */ + XK_twosuperior: 0x00b2, /* U+00B2 SUPERSCRIPT TWO */ + XK_threesuperior: 0x00b3, /* U+00B3 SUPERSCRIPT THREE */ + XK_acute: 0x00b4, /* U+00B4 ACUTE ACCENT */ + XK_mu: 0x00b5, /* U+00B5 MICRO SIGN */ + XK_paragraph: 0x00b6, /* U+00B6 PILCROW SIGN */ + XK_periodcentered: 0x00b7, /* U+00B7 MIDDLE DOT */ + XK_cedilla: 0x00b8, /* U+00B8 CEDILLA */ + XK_onesuperior: 0x00b9, /* U+00B9 SUPERSCRIPT ONE */ + XK_masculine: 0x00ba, /* U+00BA MASCULINE ORDINAL INDICATOR */ + XK_guillemotright: 0x00bb, /* U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */ + XK_onequarter: 0x00bc, /* U+00BC VULGAR FRACTION ONE QUARTER */ + XK_onehalf: 0x00bd, /* U+00BD VULGAR FRACTION ONE HALF */ + XK_threequarters: 0x00be, /* U+00BE VULGAR FRACTION THREE QUARTERS */ + XK_questiondown: 0x00bf, /* U+00BF INVERTED QUESTION MARK */ + XK_Agrave: 0x00c0, /* U+00C0 LATIN CAPITAL LETTER A WITH GRAVE */ + XK_Aacute: 0x00c1, /* U+00C1 LATIN CAPITAL LETTER A WITH ACUTE */ + XK_Acircumflex: 0x00c2, /* U+00C2 LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ + XK_Atilde: 0x00c3, /* U+00C3 LATIN CAPITAL LETTER A WITH TILDE */ + XK_Adiaeresis: 0x00c4, /* U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS */ + XK_Aring: 0x00c5, /* U+00C5 LATIN CAPITAL LETTER A WITH RING ABOVE */ + XK_AE: 0x00c6, /* U+00C6 LATIN CAPITAL LETTER AE */ + XK_Ccedilla: 0x00c7, /* U+00C7 LATIN CAPITAL LETTER C WITH CEDILLA */ + XK_Egrave: 0x00c8, /* U+00C8 LATIN CAPITAL LETTER E WITH GRAVE */ + XK_Eacute: 0x00c9, /* U+00C9 LATIN CAPITAL LETTER E WITH ACUTE */ + XK_Ecircumflex: 0x00ca, /* U+00CA LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ + XK_Ediaeresis: 0x00cb, /* U+00CB LATIN CAPITAL LETTER E WITH DIAERESIS */ + XK_Igrave: 0x00cc, /* U+00CC LATIN CAPITAL LETTER I WITH GRAVE */ + XK_Iacute: 0x00cd, /* U+00CD LATIN CAPITAL LETTER I WITH ACUTE */ + XK_Icircumflex: 0x00ce, /* U+00CE LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ + XK_Idiaeresis: 0x00cf, /* U+00CF LATIN CAPITAL LETTER I WITH DIAERESIS */ + XK_ETH: 0x00d0, /* U+00D0 LATIN CAPITAL LETTER ETH */ + XK_Eth: 0x00d0, /* deprecated */ + XK_Ntilde: 0x00d1, /* U+00D1 LATIN CAPITAL LETTER N WITH TILDE */ + XK_Ograve: 0x00d2, /* U+00D2 LATIN CAPITAL LETTER O WITH GRAVE */ + XK_Oacute: 0x00d3, /* U+00D3 LATIN CAPITAL LETTER O WITH ACUTE */ + XK_Ocircumflex: 0x00d4, /* U+00D4 LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ + XK_Otilde: 0x00d5, /* U+00D5 LATIN CAPITAL LETTER O WITH TILDE */ + XK_Odiaeresis: 0x00d6, /* U+00D6 LATIN CAPITAL LETTER O WITH DIAERESIS */ + XK_multiply: 0x00d7, /* U+00D7 MULTIPLICATION SIGN */ + XK_Oslash: 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */ + XK_Ooblique: 0x00d8, /* U+00D8 LATIN CAPITAL LETTER O WITH STROKE */ + XK_Ugrave: 0x00d9, /* U+00D9 LATIN CAPITAL LETTER U WITH GRAVE */ + XK_Uacute: 0x00da, /* U+00DA LATIN CAPITAL LETTER U WITH ACUTE */ + XK_Ucircumflex: 0x00db, /* U+00DB LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ + XK_Udiaeresis: 0x00dc, /* U+00DC LATIN CAPITAL LETTER U WITH DIAERESIS */ + XK_Yacute: 0x00dd, /* U+00DD LATIN CAPITAL LETTER Y WITH ACUTE */ + XK_THORN: 0x00de, /* U+00DE LATIN CAPITAL LETTER THORN */ + XK_Thorn: 0x00de, /* deprecated */ + XK_ssharp: 0x00df, /* U+00DF LATIN SMALL LETTER SHARP S */ + XK_agrave: 0x00e0, /* U+00E0 LATIN SMALL LETTER A WITH GRAVE */ + XK_aacute: 0x00e1, /* U+00E1 LATIN SMALL LETTER A WITH ACUTE */ + XK_acircumflex: 0x00e2, /* U+00E2 LATIN SMALL LETTER A WITH CIRCUMFLEX */ + XK_atilde: 0x00e3, /* U+00E3 LATIN SMALL LETTER A WITH TILDE */ + XK_adiaeresis: 0x00e4, /* U+00E4 LATIN SMALL LETTER A WITH DIAERESIS */ + XK_aring: 0x00e5, /* U+00E5 LATIN SMALL LETTER A WITH RING ABOVE */ + XK_ae: 0x00e6, /* U+00E6 LATIN SMALL LETTER AE */ + XK_ccedilla: 0x00e7, /* U+00E7 LATIN SMALL LETTER C WITH CEDILLA */ + XK_egrave: 0x00e8, /* U+00E8 LATIN SMALL LETTER E WITH GRAVE */ + XK_eacute: 0x00e9, /* U+00E9 LATIN SMALL LETTER E WITH ACUTE */ + XK_ecircumflex: 0x00ea, /* U+00EA LATIN SMALL LETTER E WITH CIRCUMFLEX */ + XK_ediaeresis: 0x00eb, /* U+00EB LATIN SMALL LETTER E WITH DIAERESIS */ + XK_igrave: 0x00ec, /* U+00EC LATIN SMALL LETTER I WITH GRAVE */ + XK_iacute: 0x00ed, /* U+00ED LATIN SMALL LETTER I WITH ACUTE */ + XK_icircumflex: 0x00ee, /* U+00EE LATIN SMALL LETTER I WITH CIRCUMFLEX */ + XK_idiaeresis: 0x00ef, /* U+00EF LATIN SMALL LETTER I WITH DIAERESIS */ + XK_eth: 0x00f0, /* U+00F0 LATIN SMALL LETTER ETH */ + XK_ntilde: 0x00f1, /* U+00F1 LATIN SMALL LETTER N WITH TILDE */ + XK_ograve: 0x00f2, /* U+00F2 LATIN SMALL LETTER O WITH GRAVE */ + XK_oacute: 0x00f3, /* U+00F3 LATIN SMALL LETTER O WITH ACUTE */ + XK_ocircumflex: 0x00f4, /* U+00F4 LATIN SMALL LETTER O WITH CIRCUMFLEX */ + XK_otilde: 0x00f5, /* U+00F5 LATIN SMALL LETTER O WITH TILDE */ + XK_odiaeresis: 0x00f6, /* U+00F6 LATIN SMALL LETTER O WITH DIAERESIS */ + XK_division: 0x00f7, /* U+00F7 DIVISION SIGN */ + XK_oslash: 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */ + XK_ooblique: 0x00f8, /* U+00F8 LATIN SMALL LETTER O WITH STROKE */ + XK_ugrave: 0x00f9, /* U+00F9 LATIN SMALL LETTER U WITH GRAVE */ + XK_uacute: 0x00fa, /* U+00FA LATIN SMALL LETTER U WITH ACUTE */ + XK_ucircumflex: 0x00fb, /* U+00FB LATIN SMALL LETTER U WITH CIRCUMFLEX */ + XK_udiaeresis: 0x00fc, /* U+00FC LATIN SMALL LETTER U WITH DIAERESIS */ + XK_yacute: 0x00fd, /* U+00FD LATIN SMALL LETTER Y WITH ACUTE */ + XK_thorn: 0x00fe, /* U+00FE LATIN SMALL LETTER THORN */ + XK_ydiaeresis: 0x00ff, /* U+00FF LATIN SMALL LETTER Y WITH DIAERESIS */ + + /* + * Korean + * Byte 3 = 0x0e + */ + + XK_Hangul: 0xff31, /* Hangul start/stop(toggle) */ + XK_Hangul_Hanja: 0xff34, /* Start Hangul->Hanja Conversion */ + XK_Hangul_Jeonja: 0xff38, /* Jeonja mode */ + + /* + * XFree86 vendor specific keysyms. + * + * The XFree86 keysym range is 0x10080001 - 0x1008FFFF. + */ + + XF86XK_ModeLock: 0x1008FF01, + XF86XK_MonBrightnessUp: 0x1008FF02, + XF86XK_MonBrightnessDown: 0x1008FF03, + XF86XK_KbdLightOnOff: 0x1008FF04, + XF86XK_KbdBrightnessUp: 0x1008FF05, + XF86XK_KbdBrightnessDown: 0x1008FF06, + XF86XK_Standby: 0x1008FF10, + XF86XK_AudioLowerVolume: 0x1008FF11, + XF86XK_AudioMute: 0x1008FF12, + XF86XK_AudioRaiseVolume: 0x1008FF13, + XF86XK_AudioPlay: 0x1008FF14, + XF86XK_AudioStop: 0x1008FF15, + XF86XK_AudioPrev: 0x1008FF16, + XF86XK_AudioNext: 0x1008FF17, + XF86XK_HomePage: 0x1008FF18, + XF86XK_Mail: 0x1008FF19, + XF86XK_Start: 0x1008FF1A, + XF86XK_Search: 0x1008FF1B, + XF86XK_AudioRecord: 0x1008FF1C, + XF86XK_Calculator: 0x1008FF1D, + XF86XK_Memo: 0x1008FF1E, + XF86XK_ToDoList: 0x1008FF1F, + XF86XK_Calendar: 0x1008FF20, + XF86XK_PowerDown: 0x1008FF21, + XF86XK_ContrastAdjust: 0x1008FF22, + XF86XK_RockerUp: 0x1008FF23, + XF86XK_RockerDown: 0x1008FF24, + XF86XK_RockerEnter: 0x1008FF25, + XF86XK_Back: 0x1008FF26, + XF86XK_Forward: 0x1008FF27, + XF86XK_Stop: 0x1008FF28, + XF86XK_Refresh: 0x1008FF29, + XF86XK_PowerOff: 0x1008FF2A, + XF86XK_WakeUp: 0x1008FF2B, + XF86XK_Eject: 0x1008FF2C, + XF86XK_ScreenSaver: 0x1008FF2D, + XF86XK_WWW: 0x1008FF2E, + XF86XK_Sleep: 0x1008FF2F, + XF86XK_Favorites: 0x1008FF30, + XF86XK_AudioPause: 0x1008FF31, + XF86XK_AudioMedia: 0x1008FF32, + XF86XK_MyComputer: 0x1008FF33, + XF86XK_VendorHome: 0x1008FF34, + XF86XK_LightBulb: 0x1008FF35, + XF86XK_Shop: 0x1008FF36, + XF86XK_History: 0x1008FF37, + XF86XK_OpenURL: 0x1008FF38, + XF86XK_AddFavorite: 0x1008FF39, + XF86XK_HotLinks: 0x1008FF3A, + XF86XK_BrightnessAdjust: 0x1008FF3B, + XF86XK_Finance: 0x1008FF3C, + XF86XK_Community: 0x1008FF3D, + XF86XK_AudioRewind: 0x1008FF3E, + XF86XK_BackForward: 0x1008FF3F, + XF86XK_Launch0: 0x1008FF40, + XF86XK_Launch1: 0x1008FF41, + XF86XK_Launch2: 0x1008FF42, + XF86XK_Launch3: 0x1008FF43, + XF86XK_Launch4: 0x1008FF44, + XF86XK_Launch5: 0x1008FF45, + XF86XK_Launch6: 0x1008FF46, + XF86XK_Launch7: 0x1008FF47, + XF86XK_Launch8: 0x1008FF48, + XF86XK_Launch9: 0x1008FF49, + XF86XK_LaunchA: 0x1008FF4A, + XF86XK_LaunchB: 0x1008FF4B, + XF86XK_LaunchC: 0x1008FF4C, + XF86XK_LaunchD: 0x1008FF4D, + XF86XK_LaunchE: 0x1008FF4E, + XF86XK_LaunchF: 0x1008FF4F, + XF86XK_ApplicationLeft: 0x1008FF50, + XF86XK_ApplicationRight: 0x1008FF51, + XF86XK_Book: 0x1008FF52, + XF86XK_CD: 0x1008FF53, + XF86XK_Calculater: 0x1008FF54, + XF86XK_Clear: 0x1008FF55, + XF86XK_Close: 0x1008FF56, + XF86XK_Copy: 0x1008FF57, + XF86XK_Cut: 0x1008FF58, + XF86XK_Display: 0x1008FF59, + XF86XK_DOS: 0x1008FF5A, + XF86XK_Documents: 0x1008FF5B, + XF86XK_Excel: 0x1008FF5C, + XF86XK_Explorer: 0x1008FF5D, + XF86XK_Game: 0x1008FF5E, + XF86XK_Go: 0x1008FF5F, + XF86XK_iTouch: 0x1008FF60, + XF86XK_LogOff: 0x1008FF61, + XF86XK_Market: 0x1008FF62, + XF86XK_Meeting: 0x1008FF63, + XF86XK_MenuKB: 0x1008FF65, + XF86XK_MenuPB: 0x1008FF66, + XF86XK_MySites: 0x1008FF67, + XF86XK_New: 0x1008FF68, + XF86XK_News: 0x1008FF69, + XF86XK_OfficeHome: 0x1008FF6A, + XF86XK_Open: 0x1008FF6B, + XF86XK_Option: 0x1008FF6C, + XF86XK_Paste: 0x1008FF6D, + XF86XK_Phone: 0x1008FF6E, + XF86XK_Q: 0x1008FF70, + XF86XK_Reply: 0x1008FF72, + XF86XK_Reload: 0x1008FF73, + XF86XK_RotateWindows: 0x1008FF74, + XF86XK_RotationPB: 0x1008FF75, + XF86XK_RotationKB: 0x1008FF76, + XF86XK_Save: 0x1008FF77, + XF86XK_ScrollUp: 0x1008FF78, + XF86XK_ScrollDown: 0x1008FF79, + XF86XK_ScrollClick: 0x1008FF7A, + XF86XK_Send: 0x1008FF7B, + XF86XK_Spell: 0x1008FF7C, + XF86XK_SplitScreen: 0x1008FF7D, + XF86XK_Support: 0x1008FF7E, + XF86XK_TaskPane: 0x1008FF7F, + XF86XK_Terminal: 0x1008FF80, + XF86XK_Tools: 0x1008FF81, + XF86XK_Travel: 0x1008FF82, + XF86XK_UserPB: 0x1008FF84, + XF86XK_User1KB: 0x1008FF85, + XF86XK_User2KB: 0x1008FF86, + XF86XK_Video: 0x1008FF87, + XF86XK_WheelButton: 0x1008FF88, + XF86XK_Word: 0x1008FF89, + XF86XK_Xfer: 0x1008FF8A, + XF86XK_ZoomIn: 0x1008FF8B, + XF86XK_ZoomOut: 0x1008FF8C, + XF86XK_Away: 0x1008FF8D, + XF86XK_Messenger: 0x1008FF8E, + XF86XK_WebCam: 0x1008FF8F, + XF86XK_MailForward: 0x1008FF90, + XF86XK_Pictures: 0x1008FF91, + XF86XK_Music: 0x1008FF92, + XF86XK_Battery: 0x1008FF93, + XF86XK_Bluetooth: 0x1008FF94, + XF86XK_WLAN: 0x1008FF95, + XF86XK_UWB: 0x1008FF96, + XF86XK_AudioForward: 0x1008FF97, + XF86XK_AudioRepeat: 0x1008FF98, + XF86XK_AudioRandomPlay: 0x1008FF99, + XF86XK_Subtitle: 0x1008FF9A, + XF86XK_AudioCycleTrack: 0x1008FF9B, + XF86XK_CycleAngle: 0x1008FF9C, + XF86XK_FrameBack: 0x1008FF9D, + XF86XK_FrameForward: 0x1008FF9E, + XF86XK_Time: 0x1008FF9F, + XF86XK_Select: 0x1008FFA0, + XF86XK_View: 0x1008FFA1, + XF86XK_TopMenu: 0x1008FFA2, + XF86XK_Red: 0x1008FFA3, + XF86XK_Green: 0x1008FFA4, + XF86XK_Yellow: 0x1008FFA5, + XF86XK_Blue: 0x1008FFA6, + XF86XK_Suspend: 0x1008FFA7, + XF86XK_Hibernate: 0x1008FFA8, + XF86XK_TouchpadToggle: 0x1008FFA9, + XF86XK_TouchpadOn: 0x1008FFB0, + XF86XK_TouchpadOff: 0x1008FFB1, + XF86XK_AudioMicMute: 0x1008FFB2, + XF86XK_Switch_VT_1: 0x1008FE01, + XF86XK_Switch_VT_2: 0x1008FE02, + XF86XK_Switch_VT_3: 0x1008FE03, + XF86XK_Switch_VT_4: 0x1008FE04, + XF86XK_Switch_VT_5: 0x1008FE05, + XF86XK_Switch_VT_6: 0x1008FE06, + XF86XK_Switch_VT_7: 0x1008FE07, + XF86XK_Switch_VT_8: 0x1008FE08, + XF86XK_Switch_VT_9: 0x1008FE09, + XF86XK_Switch_VT_10: 0x1008FE0A, + XF86XK_Switch_VT_11: 0x1008FE0B, + XF86XK_Switch_VT_12: 0x1008FE0C, + XF86XK_Ungrab: 0x1008FE20, + XF86XK_ClearGrab: 0x1008FE21, + XF86XK_Next_VMode: 0x1008FE22, + XF86XK_Prev_VMode: 0x1008FE23, + XF86XK_LogWindowTree: 0x1008FE24, + XF86XK_LogGrabInfo: 0x1008FE25, +}; diff --git a/core/input/keysymdef.js b/core/input/keysymdef.js new file mode 100644 index 0000000..951caca --- /dev/null +++ b/core/input/keysymdef.js @@ -0,0 +1,688 @@ +/* + * Mapping from Unicode codepoints to X11/RFB keysyms + * + * This file was automatically generated from keysymdef.h + * DO NOT EDIT! + */ + +/* Functions at the bottom */ + +const codepoints = { + 0x0100: 0x03c0, // XK_Amacron + 0x0101: 0x03e0, // XK_amacron + 0x0102: 0x01c3, // XK_Abreve + 0x0103: 0x01e3, // XK_abreve + 0x0104: 0x01a1, // XK_Aogonek + 0x0105: 0x01b1, // XK_aogonek + 0x0106: 0x01c6, // XK_Cacute + 0x0107: 0x01e6, // XK_cacute + 0x0108: 0x02c6, // XK_Ccircumflex + 0x0109: 0x02e6, // XK_ccircumflex + 0x010a: 0x02c5, // XK_Cabovedot + 0x010b: 0x02e5, // XK_cabovedot + 0x010c: 0x01c8, // XK_Ccaron + 0x010d: 0x01e8, // XK_ccaron + 0x010e: 0x01cf, // XK_Dcaron + 0x010f: 0x01ef, // XK_dcaron + 0x0110: 0x01d0, // XK_Dstroke + 0x0111: 0x01f0, // XK_dstroke + 0x0112: 0x03aa, // XK_Emacron + 0x0113: 0x03ba, // XK_emacron + 0x0116: 0x03cc, // XK_Eabovedot + 0x0117: 0x03ec, // XK_eabovedot + 0x0118: 0x01ca, // XK_Eogonek + 0x0119: 0x01ea, // XK_eogonek + 0x011a: 0x01cc, // XK_Ecaron + 0x011b: 0x01ec, // XK_ecaron + 0x011c: 0x02d8, // XK_Gcircumflex + 0x011d: 0x02f8, // XK_gcircumflex + 0x011e: 0x02ab, // XK_Gbreve + 0x011f: 0x02bb, // XK_gbreve + 0x0120: 0x02d5, // XK_Gabovedot + 0x0121: 0x02f5, // XK_gabovedot + 0x0122: 0x03ab, // XK_Gcedilla + 0x0123: 0x03bb, // XK_gcedilla + 0x0124: 0x02a6, // XK_Hcircumflex + 0x0125: 0x02b6, // XK_hcircumflex + 0x0126: 0x02a1, // XK_Hstroke + 0x0127: 0x02b1, // XK_hstroke + 0x0128: 0x03a5, // XK_Itilde + 0x0129: 0x03b5, // XK_itilde + 0x012a: 0x03cf, // XK_Imacron + 0x012b: 0x03ef, // XK_imacron + 0x012e: 0x03c7, // XK_Iogonek + 0x012f: 0x03e7, // XK_iogonek + 0x0130: 0x02a9, // XK_Iabovedot + 0x0131: 0x02b9, // XK_idotless + 0x0134: 0x02ac, // XK_Jcircumflex + 0x0135: 0x02bc, // XK_jcircumflex + 0x0136: 0x03d3, // XK_Kcedilla + 0x0137: 0x03f3, // XK_kcedilla + 0x0138: 0x03a2, // XK_kra + 0x0139: 0x01c5, // XK_Lacute + 0x013a: 0x01e5, // XK_lacute + 0x013b: 0x03a6, // XK_Lcedilla + 0x013c: 0x03b6, // XK_lcedilla + 0x013d: 0x01a5, // XK_Lcaron + 0x013e: 0x01b5, // XK_lcaron + 0x0141: 0x01a3, // XK_Lstroke + 0x0142: 0x01b3, // XK_lstroke + 0x0143: 0x01d1, // XK_Nacute + 0x0144: 0x01f1, // XK_nacute + 0x0145: 0x03d1, // XK_Ncedilla + 0x0146: 0x03f1, // XK_ncedilla + 0x0147: 0x01d2, // XK_Ncaron + 0x0148: 0x01f2, // XK_ncaron + 0x014a: 0x03bd, // XK_ENG + 0x014b: 0x03bf, // XK_eng + 0x014c: 0x03d2, // XK_Omacron + 0x014d: 0x03f2, // XK_omacron + 0x0150: 0x01d5, // XK_Odoubleacute + 0x0151: 0x01f5, // XK_odoubleacute + 0x0152: 0x13bc, // XK_OE + 0x0153: 0x13bd, // XK_oe + 0x0154: 0x01c0, // XK_Racute + 0x0155: 0x01e0, // XK_racute + 0x0156: 0x03a3, // XK_Rcedilla + 0x0157: 0x03b3, // XK_rcedilla + 0x0158: 0x01d8, // XK_Rcaron + 0x0159: 0x01f8, // XK_rcaron + 0x015a: 0x01a6, // XK_Sacute + 0x015b: 0x01b6, // XK_sacute + 0x015c: 0x02de, // XK_Scircumflex + 0x015d: 0x02fe, // XK_scircumflex + 0x015e: 0x01aa, // XK_Scedilla + 0x015f: 0x01ba, // XK_scedilla + 0x0160: 0x01a9, // XK_Scaron + 0x0161: 0x01b9, // XK_scaron + 0x0162: 0x01de, // XK_Tcedilla + 0x0163: 0x01fe, // XK_tcedilla + 0x0164: 0x01ab, // XK_Tcaron + 0x0165: 0x01bb, // XK_tcaron + 0x0166: 0x03ac, // XK_Tslash + 0x0167: 0x03bc, // XK_tslash + 0x0168: 0x03dd, // XK_Utilde + 0x0169: 0x03fd, // XK_utilde + 0x016a: 0x03de, // XK_Umacron + 0x016b: 0x03fe, // XK_umacron + 0x016c: 0x02dd, // XK_Ubreve + 0x016d: 0x02fd, // XK_ubreve + 0x016e: 0x01d9, // XK_Uring + 0x016f: 0x01f9, // XK_uring + 0x0170: 0x01db, // XK_Udoubleacute + 0x0171: 0x01fb, // XK_udoubleacute + 0x0172: 0x03d9, // XK_Uogonek + 0x0173: 0x03f9, // XK_uogonek + 0x0178: 0x13be, // XK_Ydiaeresis + 0x0179: 0x01ac, // XK_Zacute + 0x017a: 0x01bc, // XK_zacute + 0x017b: 0x01af, // XK_Zabovedot + 0x017c: 0x01bf, // XK_zabovedot + 0x017d: 0x01ae, // XK_Zcaron + 0x017e: 0x01be, // XK_zcaron + 0x0192: 0x08f6, // XK_function + 0x01d2: 0x10001d1, // XK_Ocaron + 0x02c7: 0x01b7, // XK_caron + 0x02d8: 0x01a2, // XK_breve + 0x02d9: 0x01ff, // XK_abovedot + 0x02db: 0x01b2, // XK_ogonek + 0x02dd: 0x01bd, // XK_doubleacute + 0x0385: 0x07ae, // XK_Greek_accentdieresis + 0x0386: 0x07a1, // XK_Greek_ALPHAaccent + 0x0388: 0x07a2, // XK_Greek_EPSILONaccent + 0x0389: 0x07a3, // XK_Greek_ETAaccent + 0x038a: 0x07a4, // XK_Greek_IOTAaccent + 0x038c: 0x07a7, // XK_Greek_OMICRONaccent + 0x038e: 0x07a8, // XK_Greek_UPSILONaccent + 0x038f: 0x07ab, // XK_Greek_OMEGAaccent + 0x0390: 0x07b6, // XK_Greek_iotaaccentdieresis + 0x0391: 0x07c1, // XK_Greek_ALPHA + 0x0392: 0x07c2, // XK_Greek_BETA + 0x0393: 0x07c3, // XK_Greek_GAMMA + 0x0394: 0x07c4, // XK_Greek_DELTA + 0x0395: 0x07c5, // XK_Greek_EPSILON + 0x0396: 0x07c6, // XK_Greek_ZETA + 0x0397: 0x07c7, // XK_Greek_ETA + 0x0398: 0x07c8, // XK_Greek_THETA + 0x0399: 0x07c9, // XK_Greek_IOTA + 0x039a: 0x07ca, // XK_Greek_KAPPA + 0x039b: 0x07cb, // XK_Greek_LAMDA + 0x039c: 0x07cc, // XK_Greek_MU + 0x039d: 0x07cd, // XK_Greek_NU + 0x039e: 0x07ce, // XK_Greek_XI + 0x039f: 0x07cf, // XK_Greek_OMICRON + 0x03a0: 0x07d0, // XK_Greek_PI + 0x03a1: 0x07d1, // XK_Greek_RHO + 0x03a3: 0x07d2, // XK_Greek_SIGMA + 0x03a4: 0x07d4, // XK_Greek_TAU + 0x03a5: 0x07d5, // XK_Greek_UPSILON + 0x03a6: 0x07d6, // XK_Greek_PHI + 0x03a7: 0x07d7, // XK_Greek_CHI + 0x03a8: 0x07d8, // XK_Greek_PSI + 0x03a9: 0x07d9, // XK_Greek_OMEGA + 0x03aa: 0x07a5, // XK_Greek_IOTAdieresis + 0x03ab: 0x07a9, // XK_Greek_UPSILONdieresis + 0x03ac: 0x07b1, // XK_Greek_alphaaccent + 0x03ad: 0x07b2, // XK_Greek_epsilonaccent + 0x03ae: 0x07b3, // XK_Greek_etaaccent + 0x03af: 0x07b4, // XK_Greek_iotaaccent + 0x03b0: 0x07ba, // XK_Greek_upsilonaccentdieresis + 0x03b1: 0x07e1, // XK_Greek_alpha + 0x03b2: 0x07e2, // XK_Greek_beta + 0x03b3: 0x07e3, // XK_Greek_gamma + 0x03b4: 0x07e4, // XK_Greek_delta + 0x03b5: 0x07e5, // XK_Greek_epsilon + 0x03b6: 0x07e6, // XK_Greek_zeta + 0x03b7: 0x07e7, // XK_Greek_eta + 0x03b8: 0x07e8, // XK_Greek_theta + 0x03b9: 0x07e9, // XK_Greek_iota + 0x03ba: 0x07ea, // XK_Greek_kappa + 0x03bb: 0x07eb, // XK_Greek_lamda + 0x03bc: 0x07ec, // XK_Greek_mu + 0x03bd: 0x07ed, // XK_Greek_nu + 0x03be: 0x07ee, // XK_Greek_xi + 0x03bf: 0x07ef, // XK_Greek_omicron + 0x03c0: 0x07f0, // XK_Greek_pi + 0x03c1: 0x07f1, // XK_Greek_rho + 0x03c2: 0x07f3, // XK_Greek_finalsmallsigma + 0x03c3: 0x07f2, // XK_Greek_sigma + 0x03c4: 0x07f4, // XK_Greek_tau + 0x03c5: 0x07f5, // XK_Greek_upsilon + 0x03c6: 0x07f6, // XK_Greek_phi + 0x03c7: 0x07f7, // XK_Greek_chi + 0x03c8: 0x07f8, // XK_Greek_psi + 0x03c9: 0x07f9, // XK_Greek_omega + 0x03ca: 0x07b5, // XK_Greek_iotadieresis + 0x03cb: 0x07b9, // XK_Greek_upsilondieresis + 0x03cc: 0x07b7, // XK_Greek_omicronaccent + 0x03cd: 0x07b8, // XK_Greek_upsilonaccent + 0x03ce: 0x07bb, // XK_Greek_omegaaccent + 0x0401: 0x06b3, // XK_Cyrillic_IO + 0x0402: 0x06b1, // XK_Serbian_DJE + 0x0403: 0x06b2, // XK_Macedonia_GJE + 0x0404: 0x06b4, // XK_Ukrainian_IE + 0x0405: 0x06b5, // XK_Macedonia_DSE + 0x0406: 0x06b6, // XK_Ukrainian_I + 0x0407: 0x06b7, // XK_Ukrainian_YI + 0x0408: 0x06b8, // XK_Cyrillic_JE + 0x0409: 0x06b9, // XK_Cyrillic_LJE + 0x040a: 0x06ba, // XK_Cyrillic_NJE + 0x040b: 0x06bb, // XK_Serbian_TSHE + 0x040c: 0x06bc, // XK_Macedonia_KJE + 0x040e: 0x06be, // XK_Byelorussian_SHORTU + 0x040f: 0x06bf, // XK_Cyrillic_DZHE + 0x0410: 0x06e1, // XK_Cyrillic_A + 0x0411: 0x06e2, // XK_Cyrillic_BE + 0x0412: 0x06f7, // XK_Cyrillic_VE + 0x0413: 0x06e7, // XK_Cyrillic_GHE + 0x0414: 0x06e4, // XK_Cyrillic_DE + 0x0415: 0x06e5, // XK_Cyrillic_IE + 0x0416: 0x06f6, // XK_Cyrillic_ZHE + 0x0417: 0x06fa, // XK_Cyrillic_ZE + 0x0418: 0x06e9, // XK_Cyrillic_I + 0x0419: 0x06ea, // XK_Cyrillic_SHORTI + 0x041a: 0x06eb, // XK_Cyrillic_KA + 0x041b: 0x06ec, // XK_Cyrillic_EL + 0x041c: 0x06ed, // XK_Cyrillic_EM + 0x041d: 0x06ee, // XK_Cyrillic_EN + 0x041e: 0x06ef, // XK_Cyrillic_O + 0x041f: 0x06f0, // XK_Cyrillic_PE + 0x0420: 0x06f2, // XK_Cyrillic_ER + 0x0421: 0x06f3, // XK_Cyrillic_ES + 0x0422: 0x06f4, // XK_Cyrillic_TE + 0x0423: 0x06f5, // XK_Cyrillic_U + 0x0424: 0x06e6, // XK_Cyrillic_EF + 0x0425: 0x06e8, // XK_Cyrillic_HA + 0x0426: 0x06e3, // XK_Cyrillic_TSE + 0x0427: 0x06fe, // XK_Cyrillic_CHE + 0x0428: 0x06fb, // XK_Cyrillic_SHA + 0x0429: 0x06fd, // XK_Cyrillic_SHCHA + 0x042a: 0x06ff, // XK_Cyrillic_HARDSIGN + 0x042b: 0x06f9, // XK_Cyrillic_YERU + 0x042c: 0x06f8, // XK_Cyrillic_SOFTSIGN + 0x042d: 0x06fc, // XK_Cyrillic_E + 0x042e: 0x06e0, // XK_Cyrillic_YU + 0x042f: 0x06f1, // XK_Cyrillic_YA + 0x0430: 0x06c1, // XK_Cyrillic_a + 0x0431: 0x06c2, // XK_Cyrillic_be + 0x0432: 0x06d7, // XK_Cyrillic_ve + 0x0433: 0x06c7, // XK_Cyrillic_ghe + 0x0434: 0x06c4, // XK_Cyrillic_de + 0x0435: 0x06c5, // XK_Cyrillic_ie + 0x0436: 0x06d6, // XK_Cyrillic_zhe + 0x0437: 0x06da, // XK_Cyrillic_ze + 0x0438: 0x06c9, // XK_Cyrillic_i + 0x0439: 0x06ca, // XK_Cyrillic_shorti + 0x043a: 0x06cb, // XK_Cyrillic_ka + 0x043b: 0x06cc, // XK_Cyrillic_el + 0x043c: 0x06cd, // XK_Cyrillic_em + 0x043d: 0x06ce, // XK_Cyrillic_en + 0x043e: 0x06cf, // XK_Cyrillic_o + 0x043f: 0x06d0, // XK_Cyrillic_pe + 0x0440: 0x06d2, // XK_Cyrillic_er + 0x0441: 0x06d3, // XK_Cyrillic_es + 0x0442: 0x06d4, // XK_Cyrillic_te + 0x0443: 0x06d5, // XK_Cyrillic_u + 0x0444: 0x06c6, // XK_Cyrillic_ef + 0x0445: 0x06c8, // XK_Cyrillic_ha + 0x0446: 0x06c3, // XK_Cyrillic_tse + 0x0447: 0x06de, // XK_Cyrillic_che + 0x0448: 0x06db, // XK_Cyrillic_sha + 0x0449: 0x06dd, // XK_Cyrillic_shcha + 0x044a: 0x06df, // XK_Cyrillic_hardsign + 0x044b: 0x06d9, // XK_Cyrillic_yeru + 0x044c: 0x06d8, // XK_Cyrillic_softsign + 0x044d: 0x06dc, // XK_Cyrillic_e + 0x044e: 0x06c0, // XK_Cyrillic_yu + 0x044f: 0x06d1, // XK_Cyrillic_ya + 0x0451: 0x06a3, // XK_Cyrillic_io + 0x0452: 0x06a1, // XK_Serbian_dje + 0x0453: 0x06a2, // XK_Macedonia_gje + 0x0454: 0x06a4, // XK_Ukrainian_ie + 0x0455: 0x06a5, // XK_Macedonia_dse + 0x0456: 0x06a6, // XK_Ukrainian_i + 0x0457: 0x06a7, // XK_Ukrainian_yi + 0x0458: 0x06a8, // XK_Cyrillic_je + 0x0459: 0x06a9, // XK_Cyrillic_lje + 0x045a: 0x06aa, // XK_Cyrillic_nje + 0x045b: 0x06ab, // XK_Serbian_tshe + 0x045c: 0x06ac, // XK_Macedonia_kje + 0x045e: 0x06ae, // XK_Byelorussian_shortu + 0x045f: 0x06af, // XK_Cyrillic_dzhe + 0x0490: 0x06bd, // XK_Ukrainian_GHE_WITH_UPTURN + 0x0491: 0x06ad, // XK_Ukrainian_ghe_with_upturn + 0x05d0: 0x0ce0, // XK_hebrew_aleph + 0x05d1: 0x0ce1, // XK_hebrew_bet + 0x05d2: 0x0ce2, // XK_hebrew_gimel + 0x05d3: 0x0ce3, // XK_hebrew_dalet + 0x05d4: 0x0ce4, // XK_hebrew_he + 0x05d5: 0x0ce5, // XK_hebrew_waw + 0x05d6: 0x0ce6, // XK_hebrew_zain + 0x05d7: 0x0ce7, // XK_hebrew_chet + 0x05d8: 0x0ce8, // XK_hebrew_tet + 0x05d9: 0x0ce9, // XK_hebrew_yod + 0x05da: 0x0cea, // XK_hebrew_finalkaph + 0x05db: 0x0ceb, // XK_hebrew_kaph + 0x05dc: 0x0cec, // XK_hebrew_lamed + 0x05dd: 0x0ced, // XK_hebrew_finalmem + 0x05de: 0x0cee, // XK_hebrew_mem + 0x05df: 0x0cef, // XK_hebrew_finalnun + 0x05e0: 0x0cf0, // XK_hebrew_nun + 0x05e1: 0x0cf1, // XK_hebrew_samech + 0x05e2: 0x0cf2, // XK_hebrew_ayin + 0x05e3: 0x0cf3, // XK_hebrew_finalpe + 0x05e4: 0x0cf4, // XK_hebrew_pe + 0x05e5: 0x0cf5, // XK_hebrew_finalzade + 0x05e6: 0x0cf6, // XK_hebrew_zade + 0x05e7: 0x0cf7, // XK_hebrew_qoph + 0x05e8: 0x0cf8, // XK_hebrew_resh + 0x05e9: 0x0cf9, // XK_hebrew_shin + 0x05ea: 0x0cfa, // XK_hebrew_taw + 0x060c: 0x05ac, // XK_Arabic_comma + 0x061b: 0x05bb, // XK_Arabic_semicolon + 0x061f: 0x05bf, // XK_Arabic_question_mark + 0x0621: 0x05c1, // XK_Arabic_hamza + 0x0622: 0x05c2, // XK_Arabic_maddaonalef + 0x0623: 0x05c3, // XK_Arabic_hamzaonalef + 0x0624: 0x05c4, // XK_Arabic_hamzaonwaw + 0x0625: 0x05c5, // XK_Arabic_hamzaunderalef + 0x0626: 0x05c6, // XK_Arabic_hamzaonyeh + 0x0627: 0x05c7, // XK_Arabic_alef + 0x0628: 0x05c8, // XK_Arabic_beh + 0x0629: 0x05c9, // XK_Arabic_tehmarbuta + 0x062a: 0x05ca, // XK_Arabic_teh + 0x062b: 0x05cb, // XK_Arabic_theh + 0x062c: 0x05cc, // XK_Arabic_jeem + 0x062d: 0x05cd, // XK_Arabic_hah + 0x062e: 0x05ce, // XK_Arabic_khah + 0x062f: 0x05cf, // XK_Arabic_dal + 0x0630: 0x05d0, // XK_Arabic_thal + 0x0631: 0x05d1, // XK_Arabic_ra + 0x0632: 0x05d2, // XK_Arabic_zain + 0x0633: 0x05d3, // XK_Arabic_seen + 0x0634: 0x05d4, // XK_Arabic_sheen + 0x0635: 0x05d5, // XK_Arabic_sad + 0x0636: 0x05d6, // XK_Arabic_dad + 0x0637: 0x05d7, // XK_Arabic_tah + 0x0638: 0x05d8, // XK_Arabic_zah + 0x0639: 0x05d9, // XK_Arabic_ain + 0x063a: 0x05da, // XK_Arabic_ghain + 0x0640: 0x05e0, // XK_Arabic_tatweel + 0x0641: 0x05e1, // XK_Arabic_feh + 0x0642: 0x05e2, // XK_Arabic_qaf + 0x0643: 0x05e3, // XK_Arabic_kaf + 0x0644: 0x05e4, // XK_Arabic_lam + 0x0645: 0x05e5, // XK_Arabic_meem + 0x0646: 0x05e6, // XK_Arabic_noon + 0x0647: 0x05e7, // XK_Arabic_ha + 0x0648: 0x05e8, // XK_Arabic_waw + 0x0649: 0x05e9, // XK_Arabic_alefmaksura + 0x064a: 0x05ea, // XK_Arabic_yeh + 0x064b: 0x05eb, // XK_Arabic_fathatan + 0x064c: 0x05ec, // XK_Arabic_dammatan + 0x064d: 0x05ed, // XK_Arabic_kasratan + 0x064e: 0x05ee, // XK_Arabic_fatha + 0x064f: 0x05ef, // XK_Arabic_damma + 0x0650: 0x05f0, // XK_Arabic_kasra + 0x0651: 0x05f1, // XK_Arabic_shadda + 0x0652: 0x05f2, // XK_Arabic_sukun + 0x0e01: 0x0da1, // XK_Thai_kokai + 0x0e02: 0x0da2, // XK_Thai_khokhai + 0x0e03: 0x0da3, // XK_Thai_khokhuat + 0x0e04: 0x0da4, // XK_Thai_khokhwai + 0x0e05: 0x0da5, // XK_Thai_khokhon + 0x0e06: 0x0da6, // XK_Thai_khorakhang + 0x0e07: 0x0da7, // XK_Thai_ngongu + 0x0e08: 0x0da8, // XK_Thai_chochan + 0x0e09: 0x0da9, // XK_Thai_choching + 0x0e0a: 0x0daa, // XK_Thai_chochang + 0x0e0b: 0x0dab, // XK_Thai_soso + 0x0e0c: 0x0dac, // XK_Thai_chochoe + 0x0e0d: 0x0dad, // XK_Thai_yoying + 0x0e0e: 0x0dae, // XK_Thai_dochada + 0x0e0f: 0x0daf, // XK_Thai_topatak + 0x0e10: 0x0db0, // XK_Thai_thothan + 0x0e11: 0x0db1, // XK_Thai_thonangmontho + 0x0e12: 0x0db2, // XK_Thai_thophuthao + 0x0e13: 0x0db3, // XK_Thai_nonen + 0x0e14: 0x0db4, // XK_Thai_dodek + 0x0e15: 0x0db5, // XK_Thai_totao + 0x0e16: 0x0db6, // XK_Thai_thothung + 0x0e17: 0x0db7, // XK_Thai_thothahan + 0x0e18: 0x0db8, // XK_Thai_thothong + 0x0e19: 0x0db9, // XK_Thai_nonu + 0x0e1a: 0x0dba, // XK_Thai_bobaimai + 0x0e1b: 0x0dbb, // XK_Thai_popla + 0x0e1c: 0x0dbc, // XK_Thai_phophung + 0x0e1d: 0x0dbd, // XK_Thai_fofa + 0x0e1e: 0x0dbe, // XK_Thai_phophan + 0x0e1f: 0x0dbf, // XK_Thai_fofan + 0x0e20: 0x0dc0, // XK_Thai_phosamphao + 0x0e21: 0x0dc1, // XK_Thai_moma + 0x0e22: 0x0dc2, // XK_Thai_yoyak + 0x0e23: 0x0dc3, // XK_Thai_rorua + 0x0e24: 0x0dc4, // XK_Thai_ru + 0x0e25: 0x0dc5, // XK_Thai_loling + 0x0e26: 0x0dc6, // XK_Thai_lu + 0x0e27: 0x0dc7, // XK_Thai_wowaen + 0x0e28: 0x0dc8, // XK_Thai_sosala + 0x0e29: 0x0dc9, // XK_Thai_sorusi + 0x0e2a: 0x0dca, // XK_Thai_sosua + 0x0e2b: 0x0dcb, // XK_Thai_hohip + 0x0e2c: 0x0dcc, // XK_Thai_lochula + 0x0e2d: 0x0dcd, // XK_Thai_oang + 0x0e2e: 0x0dce, // XK_Thai_honokhuk + 0x0e2f: 0x0dcf, // XK_Thai_paiyannoi + 0x0e30: 0x0dd0, // XK_Thai_saraa + 0x0e31: 0x0dd1, // XK_Thai_maihanakat + 0x0e32: 0x0dd2, // XK_Thai_saraaa + 0x0e33: 0x0dd3, // XK_Thai_saraam + 0x0e34: 0x0dd4, // XK_Thai_sarai + 0x0e35: 0x0dd5, // XK_Thai_saraii + 0x0e36: 0x0dd6, // XK_Thai_saraue + 0x0e37: 0x0dd7, // XK_Thai_sarauee + 0x0e38: 0x0dd8, // XK_Thai_sarau + 0x0e39: 0x0dd9, // XK_Thai_sarauu + 0x0e3a: 0x0dda, // XK_Thai_phinthu + 0x0e3f: 0x0ddf, // XK_Thai_baht + 0x0e40: 0x0de0, // XK_Thai_sarae + 0x0e41: 0x0de1, // XK_Thai_saraae + 0x0e42: 0x0de2, // XK_Thai_sarao + 0x0e43: 0x0de3, // XK_Thai_saraaimaimuan + 0x0e44: 0x0de4, // XK_Thai_saraaimaimalai + 0x0e45: 0x0de5, // XK_Thai_lakkhangyao + 0x0e46: 0x0de6, // XK_Thai_maiyamok + 0x0e47: 0x0de7, // XK_Thai_maitaikhu + 0x0e48: 0x0de8, // XK_Thai_maiek + 0x0e49: 0x0de9, // XK_Thai_maitho + 0x0e4a: 0x0dea, // XK_Thai_maitri + 0x0e4b: 0x0deb, // XK_Thai_maichattawa + 0x0e4c: 0x0dec, // XK_Thai_thanthakhat + 0x0e4d: 0x0ded, // XK_Thai_nikhahit + 0x0e50: 0x0df0, // XK_Thai_leksun + 0x0e51: 0x0df1, // XK_Thai_leknung + 0x0e52: 0x0df2, // XK_Thai_leksong + 0x0e53: 0x0df3, // XK_Thai_leksam + 0x0e54: 0x0df4, // XK_Thai_leksi + 0x0e55: 0x0df5, // XK_Thai_lekha + 0x0e56: 0x0df6, // XK_Thai_lekhok + 0x0e57: 0x0df7, // XK_Thai_lekchet + 0x0e58: 0x0df8, // XK_Thai_lekpaet + 0x0e59: 0x0df9, // XK_Thai_lekkao + 0x2002: 0x0aa2, // XK_enspace + 0x2003: 0x0aa1, // XK_emspace + 0x2004: 0x0aa3, // XK_em3space + 0x2005: 0x0aa4, // XK_em4space + 0x2007: 0x0aa5, // XK_digitspace + 0x2008: 0x0aa6, // XK_punctspace + 0x2009: 0x0aa7, // XK_thinspace + 0x200a: 0x0aa8, // XK_hairspace + 0x2012: 0x0abb, // XK_figdash + 0x2013: 0x0aaa, // XK_endash + 0x2014: 0x0aa9, // XK_emdash + 0x2015: 0x07af, // XK_Greek_horizbar + 0x2017: 0x0cdf, // XK_hebrew_doublelowline + 0x2018: 0x0ad0, // XK_leftsinglequotemark + 0x2019: 0x0ad1, // XK_rightsinglequotemark + 0x201a: 0x0afd, // XK_singlelowquotemark + 0x201c: 0x0ad2, // XK_leftdoublequotemark + 0x201d: 0x0ad3, // XK_rightdoublequotemark + 0x201e: 0x0afe, // XK_doublelowquotemark + 0x2020: 0x0af1, // XK_dagger + 0x2021: 0x0af2, // XK_doubledagger + 0x2022: 0x0ae6, // XK_enfilledcircbullet + 0x2025: 0x0aaf, // XK_doubbaselinedot + 0x2026: 0x0aae, // XK_ellipsis + 0x2030: 0x0ad5, // XK_permille + 0x2032: 0x0ad6, // XK_minutes + 0x2033: 0x0ad7, // XK_seconds + 0x2038: 0x0afc, // XK_caret + 0x203e: 0x047e, // XK_overline + 0x20a9: 0x0eff, // XK_Korean_Won + 0x20ac: 0x20ac, // XK_EuroSign + 0x2105: 0x0ab8, // XK_careof + 0x2116: 0x06b0, // XK_numerosign + 0x2117: 0x0afb, // XK_phonographcopyright + 0x211e: 0x0ad4, // XK_prescription + 0x2122: 0x0ac9, // XK_trademark + 0x2153: 0x0ab0, // XK_onethird + 0x2154: 0x0ab1, // XK_twothirds + 0x2155: 0x0ab2, // XK_onefifth + 0x2156: 0x0ab3, // XK_twofifths + 0x2157: 0x0ab4, // XK_threefifths + 0x2158: 0x0ab5, // XK_fourfifths + 0x2159: 0x0ab6, // XK_onesixth + 0x215a: 0x0ab7, // XK_fivesixths + 0x215b: 0x0ac3, // XK_oneeighth + 0x215c: 0x0ac4, // XK_threeeighths + 0x215d: 0x0ac5, // XK_fiveeighths + 0x215e: 0x0ac6, // XK_seveneighths + 0x2190: 0x08fb, // XK_leftarrow + 0x2191: 0x08fc, // XK_uparrow + 0x2192: 0x08fd, // XK_rightarrow + 0x2193: 0x08fe, // XK_downarrow + 0x21d2: 0x08ce, // XK_implies + 0x21d4: 0x08cd, // XK_ifonlyif + 0x2202: 0x08ef, // XK_partialderivative + 0x2207: 0x08c5, // XK_nabla + 0x2218: 0x0bca, // XK_jot + 0x221a: 0x08d6, // XK_radical + 0x221d: 0x08c1, // XK_variation + 0x221e: 0x08c2, // XK_infinity + 0x2227: 0x08de, // XK_logicaland + 0x2228: 0x08df, // XK_logicalor + 0x2229: 0x08dc, // XK_intersection + 0x222a: 0x08dd, // XK_union + 0x222b: 0x08bf, // XK_integral + 0x2234: 0x08c0, // XK_therefore + 0x223c: 0x08c8, // XK_approximate + 0x2243: 0x08c9, // XK_similarequal + 0x2245: 0x1002248, // XK_approxeq + 0x2260: 0x08bd, // XK_notequal + 0x2261: 0x08cf, // XK_identical + 0x2264: 0x08bc, // XK_lessthanequal + 0x2265: 0x08be, // XK_greaterthanequal + 0x2282: 0x08da, // XK_includedin + 0x2283: 0x08db, // XK_includes + 0x22a2: 0x0bfc, // XK_righttack + 0x22a3: 0x0bdc, // XK_lefttack + 0x22a4: 0x0bc2, // XK_downtack + 0x22a5: 0x0bce, // XK_uptack + 0x2308: 0x0bd3, // XK_upstile + 0x230a: 0x0bc4, // XK_downstile + 0x2315: 0x0afa, // XK_telephonerecorder + 0x2320: 0x08a4, // XK_topintegral + 0x2321: 0x08a5, // XK_botintegral + 0x2395: 0x0bcc, // XK_quad + 0x239b: 0x08ab, // XK_topleftparens + 0x239d: 0x08ac, // XK_botleftparens + 0x239e: 0x08ad, // XK_toprightparens + 0x23a0: 0x08ae, // XK_botrightparens + 0x23a1: 0x08a7, // XK_topleftsqbracket + 0x23a3: 0x08a8, // XK_botleftsqbracket + 0x23a4: 0x08a9, // XK_toprightsqbracket + 0x23a6: 0x08aa, // XK_botrightsqbracket + 0x23a8: 0x08af, // XK_leftmiddlecurlybrace + 0x23ac: 0x08b0, // XK_rightmiddlecurlybrace + 0x23b7: 0x08a1, // XK_leftradical + 0x23ba: 0x09ef, // XK_horizlinescan1 + 0x23bb: 0x09f0, // XK_horizlinescan3 + 0x23bc: 0x09f2, // XK_horizlinescan7 + 0x23bd: 0x09f3, // XK_horizlinescan9 + 0x2409: 0x09e2, // XK_ht + 0x240a: 0x09e5, // XK_lf + 0x240b: 0x09e9, // XK_vt + 0x240c: 0x09e3, // XK_ff + 0x240d: 0x09e4, // XK_cr + 0x2423: 0x0aac, // XK_signifblank + 0x2424: 0x09e8, // XK_nl + 0x2500: 0x08a3, // XK_horizconnector + 0x2502: 0x08a6, // XK_vertconnector + 0x250c: 0x08a2, // XK_topleftradical + 0x2510: 0x09eb, // XK_uprightcorner + 0x2514: 0x09ed, // XK_lowleftcorner + 0x2518: 0x09ea, // XK_lowrightcorner + 0x251c: 0x09f4, // XK_leftt + 0x2524: 0x09f5, // XK_rightt + 0x252c: 0x09f7, // XK_topt + 0x2534: 0x09f6, // XK_bott + 0x253c: 0x09ee, // XK_crossinglines + 0x2592: 0x09e1, // XK_checkerboard + 0x25aa: 0x0ae7, // XK_enfilledsqbullet + 0x25ab: 0x0ae1, // XK_enopensquarebullet + 0x25ac: 0x0adb, // XK_filledrectbullet + 0x25ad: 0x0ae2, // XK_openrectbullet + 0x25ae: 0x0adf, // XK_emfilledrect + 0x25af: 0x0acf, // XK_emopenrectangle + 0x25b2: 0x0ae8, // XK_filledtribulletup + 0x25b3: 0x0ae3, // XK_opentribulletup + 0x25b6: 0x0add, // XK_filledrighttribullet + 0x25b7: 0x0acd, // XK_rightopentriangle + 0x25bc: 0x0ae9, // XK_filledtribulletdown + 0x25bd: 0x0ae4, // XK_opentribulletdown + 0x25c0: 0x0adc, // XK_filledlefttribullet + 0x25c1: 0x0acc, // XK_leftopentriangle + 0x25c6: 0x09e0, // XK_soliddiamond + 0x25cb: 0x0ace, // XK_emopencircle + 0x25cf: 0x0ade, // XK_emfilledcircle + 0x25e6: 0x0ae0, // XK_enopencircbullet + 0x2606: 0x0ae5, // XK_openstar + 0x260e: 0x0af9, // XK_telephone + 0x2613: 0x0aca, // XK_signaturemark + 0x261c: 0x0aea, // XK_leftpointer + 0x261e: 0x0aeb, // XK_rightpointer + 0x2640: 0x0af8, // XK_femalesymbol + 0x2642: 0x0af7, // XK_malesymbol + 0x2663: 0x0aec, // XK_club + 0x2665: 0x0aee, // XK_heart + 0x2666: 0x0aed, // XK_diamond + 0x266d: 0x0af6, // XK_musicalflat + 0x266f: 0x0af5, // XK_musicalsharp + 0x2713: 0x0af3, // XK_checkmark + 0x2717: 0x0af4, // XK_ballotcross + 0x271d: 0x0ad9, // XK_latincross + 0x2720: 0x0af0, // XK_maltesecross + 0x27e8: 0x0abc, // XK_leftanglebracket + 0x27e9: 0x0abe, // XK_rightanglebracket + 0x3001: 0x04a4, // XK_kana_comma + 0x3002: 0x04a1, // XK_kana_fullstop + 0x300c: 0x04a2, // XK_kana_openingbracket + 0x300d: 0x04a3, // XK_kana_closingbracket + 0x309b: 0x04de, // XK_voicedsound + 0x309c: 0x04df, // XK_semivoicedsound + 0x30a1: 0x04a7, // XK_kana_a + 0x30a2: 0x04b1, // XK_kana_A + 0x30a3: 0x04a8, // XK_kana_i + 0x30a4: 0x04b2, // XK_kana_I + 0x30a5: 0x04a9, // XK_kana_u + 0x30a6: 0x04b3, // XK_kana_U + 0x30a7: 0x04aa, // XK_kana_e + 0x30a8: 0x04b4, // XK_kana_E + 0x30a9: 0x04ab, // XK_kana_o + 0x30aa: 0x04b5, // XK_kana_O + 0x30ab: 0x04b6, // XK_kana_KA + 0x30ad: 0x04b7, // XK_kana_KI + 0x30af: 0x04b8, // XK_kana_KU + 0x30b1: 0x04b9, // XK_kana_KE + 0x30b3: 0x04ba, // XK_kana_KO + 0x30b5: 0x04bb, // XK_kana_SA + 0x30b7: 0x04bc, // XK_kana_SHI + 0x30b9: 0x04bd, // XK_kana_SU + 0x30bb: 0x04be, // XK_kana_SE + 0x30bd: 0x04bf, // XK_kana_SO + 0x30bf: 0x04c0, // XK_kana_TA + 0x30c1: 0x04c1, // XK_kana_CHI + 0x30c3: 0x04af, // XK_kana_tsu + 0x30c4: 0x04c2, // XK_kana_TSU + 0x30c6: 0x04c3, // XK_kana_TE + 0x30c8: 0x04c4, // XK_kana_TO + 0x30ca: 0x04c5, // XK_kana_NA + 0x30cb: 0x04c6, // XK_kana_NI + 0x30cc: 0x04c7, // XK_kana_NU + 0x30cd: 0x04c8, // XK_kana_NE + 0x30ce: 0x04c9, // XK_kana_NO + 0x30cf: 0x04ca, // XK_kana_HA + 0x30d2: 0x04cb, // XK_kana_HI + 0x30d5: 0x04cc, // XK_kana_FU + 0x30d8: 0x04cd, // XK_kana_HE + 0x30db: 0x04ce, // XK_kana_HO + 0x30de: 0x04cf, // XK_kana_MA + 0x30df: 0x04d0, // XK_kana_MI + 0x30e0: 0x04d1, // XK_kana_MU + 0x30e1: 0x04d2, // XK_kana_ME + 0x30e2: 0x04d3, // XK_kana_MO + 0x30e3: 0x04ac, // XK_kana_ya + 0x30e4: 0x04d4, // XK_kana_YA + 0x30e5: 0x04ad, // XK_kana_yu + 0x30e6: 0x04d5, // XK_kana_YU + 0x30e7: 0x04ae, // XK_kana_yo + 0x30e8: 0x04d6, // XK_kana_YO + 0x30e9: 0x04d7, // XK_kana_RA + 0x30ea: 0x04d8, // XK_kana_RI + 0x30eb: 0x04d9, // XK_kana_RU + 0x30ec: 0x04da, // XK_kana_RE + 0x30ed: 0x04db, // XK_kana_RO + 0x30ef: 0x04dc, // XK_kana_WA + 0x30f2: 0x04a6, // XK_kana_WO + 0x30f3: 0x04dd, // XK_kana_N + 0x30fb: 0x04a5, // XK_kana_conjunctive + 0x30fc: 0x04b0, // XK_prolongedsound +}; + +export default { + lookup(u) { + // Latin-1 is one-to-one mapping + if ((u >= 0x20) && (u <= 0xff)) { + return u; + } + + // Lookup table (fairly random) + const keysym = codepoints[u]; + if (keysym !== undefined) { + return keysym; + } + + // General mapping as final fallback + return 0x01000000 | u; + }, +}; diff --git a/core/input/util.js b/core/input/util.js new file mode 100644 index 0000000..58f84e5 --- /dev/null +++ b/core/input/util.js @@ -0,0 +1,191 @@ +import KeyTable from "./keysym.js"; +import keysyms from "./keysymdef.js"; +import vkeys from "./vkeys.js"; +import fixedkeys from "./fixedkeys.js"; +import DOMKeyTable from "./domkeytable.js"; +import * as browser from "../util/browser.js"; + +// Get 'KeyboardEvent.code', handling legacy browsers +export function getKeycode(evt) { + // Are we getting proper key identifiers? + // (unfortunately Firefox and Chrome are crappy here and gives + // us an empty string on some platforms, rather than leaving it + // undefined) + if (evt.code) { + // Mozilla isn't fully in sync with the spec yet + switch (evt.code) { + case 'OSLeft': return 'MetaLeft'; + case 'OSRight': return 'MetaRight'; + } + + return evt.code; + } + + // The de-facto standard is to use Windows Virtual-Key codes + // in the 'keyCode' field for non-printable characters + if (evt.keyCode in vkeys) { + let code = vkeys[evt.keyCode]; + + // macOS has messed up this code for some reason + if (browser.isMac() && (code === 'ContextMenu')) { + code = 'MetaRight'; + } + + // The keyCode doesn't distinguish between left and right + // for the standard modifiers + if (evt.location === 2) { + switch (code) { + case 'ShiftLeft': return 'ShiftRight'; + case 'ControlLeft': return 'ControlRight'; + case 'AltLeft': return 'AltRight'; + } + } + + // Nor a bunch of the numpad keys + if (evt.location === 3) { + switch (code) { + case 'Delete': return 'NumpadDecimal'; + case 'Insert': return 'Numpad0'; + case 'End': return 'Numpad1'; + case 'ArrowDown': return 'Numpad2'; + case 'PageDown': return 'Numpad3'; + case 'ArrowLeft': return 'Numpad4'; + case 'ArrowRight': return 'Numpad6'; + case 'Home': return 'Numpad7'; + case 'ArrowUp': return 'Numpad8'; + case 'PageUp': return 'Numpad9'; + case 'Enter': return 'NumpadEnter'; + } + } + + return code; + } + + return 'Unidentified'; +} + +// Get 'KeyboardEvent.key', handling legacy browsers +export function getKey(evt) { + // Are we getting a proper key value? + if (evt.key !== undefined) { + // Mozilla isn't fully in sync with the spec yet + switch (evt.key) { + case 'OS': return 'Meta'; + case 'LaunchMyComputer': return 'LaunchApplication1'; + case 'LaunchCalculator': return 'LaunchApplication2'; + } + + // iOS leaks some OS names + switch (evt.key) { + case 'UIKeyInputUpArrow': return 'ArrowUp'; + case 'UIKeyInputDownArrow': return 'ArrowDown'; + case 'UIKeyInputLeftArrow': return 'ArrowLeft'; + case 'UIKeyInputRightArrow': return 'ArrowRight'; + case 'UIKeyInputEscape': return 'Escape'; + } + + // Broken behaviour in Chrome + if ((evt.key === '\x00') && (evt.code === 'NumpadDecimal')) { + return 'Delete'; + } + + return evt.key; + } + + // Try to deduce it based on the physical key + const code = getKeycode(evt); + if (code in fixedkeys) { + return fixedkeys[code]; + } + + // If that failed, then see if we have a printable character + if (evt.charCode) { + return String.fromCharCode(evt.charCode); + } + + // At this point we have nothing left to go on + return 'Unidentified'; +} + +// Get the most reliable keysym value we can get from a key event +export function getKeysym(evt) { + const key = getKey(evt); + + if (key === 'Unidentified') { + return null; + } + + // First look up special keys + if (key in DOMKeyTable) { + let location = evt.location; + + // Safari screws up location for the right cmd key + if ((key === 'Meta') && (location === 0)) { + location = 2; + } + + // And for Clear + if ((key === 'Clear') && (location === 3)) { + let code = getKeycode(evt); + if (code === 'NumLock') { + location = 0; + } + } + + if ((location === undefined) || (location > 3)) { + location = 0; + } + + // The original Meta key now gets confused with the Windows key + // https://bugs.chromium.org/p/chromium/issues/detail?id=1020141 + // https://bugzilla.mozilla.org/show_bug.cgi?id=1232918 + if (key === 'Meta') { + let code = getKeycode(evt); + if (code === 'AltLeft') { + return KeyTable.XK_Meta_L; + } else if (code === 'AltRight') { + return KeyTable.XK_Meta_R; + } + } + + // macOS has Clear instead of NumLock, but the remote system is + // probably not macOS, so lying here is probably best... + if (key === 'Clear') { + let code = getKeycode(evt); + if (code === 'NumLock') { + return KeyTable.XK_Num_Lock; + } + } + + // Windows sends alternating symbols for some keys when using a + // Japanese layout. We have no way of synchronising with the IM + // running on the remote system, so we send some combined keysym + // instead and hope for the best. + if (browser.isWindows()) { + switch (key) { + case 'Zenkaku': + case 'Hankaku': + return KeyTable.XK_Zenkaku_Hankaku; + case 'Romaji': + case 'KanaMode': + return KeyTable.XK_Romaji; + } + } + + return DOMKeyTable[key][location]; + } + + // Now we need to look at the Unicode symbol instead + + // Special key? (FIXME: Should have been caught earlier) + if (key.length !== 1) { + return null; + } + + const codepoint = key.charCodeAt(); + if (codepoint) { + return keysyms.lookup(codepoint); + } + + return null; +} diff --git a/core/input/vkeys.js b/core/input/vkeys.js new file mode 100644 index 0000000..dacc358 --- /dev/null +++ b/core/input/vkeys.js @@ -0,0 +1,116 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2018 The noVNC Authors + * Licensed under MPL 2.0 or any later version (see LICENSE.txt) + */ + +/* + * Mapping between Microsoft® Windows® Virtual-Key codes and + * HTML key codes. + */ + +export default { + 0x08: 'Backspace', + 0x09: 'Tab', + 0x0a: 'NumpadClear', + 0x0d: 'Enter', + 0x10: 'ShiftLeft', + 0x11: 'ControlLeft', + 0x12: 'AltLeft', + 0x13: 'Pause', + 0x14: 'CapsLock', + 0x15: 'Lang1', + 0x19: 'Lang2', + 0x1b: 'Escape', + 0x1c: 'Convert', + 0x1d: 'NonConvert', + 0x20: 'Space', + 0x21: 'PageUp', + 0x22: 'PageDown', + 0x23: 'End', + 0x24: 'Home', + 0x25: 'ArrowLeft', + 0x26: 'ArrowUp', + 0x27: 'ArrowRight', + 0x28: 'ArrowDown', + 0x29: 'Select', + 0x2c: 'PrintScreen', + 0x2d: 'Insert', + 0x2e: 'Delete', + 0x2f: 'Help', + 0x30: 'Digit0', + 0x31: 'Digit1', + 0x32: 'Digit2', + 0x33: 'Digit3', + 0x34: 'Digit4', + 0x35: 'Digit5', + 0x36: 'Digit6', + 0x37: 'Digit7', + 0x38: 'Digit8', + 0x39: 'Digit9', + 0x5b: 'MetaLeft', + 0x5c: 'MetaRight', + 0x5d: 'ContextMenu', + 0x5f: 'Sleep', + 0x60: 'Numpad0', + 0x61: 'Numpad1', + 0x62: 'Numpad2', + 0x63: 'Numpad3', + 0x64: 'Numpad4', + 0x65: 'Numpad5', + 0x66: 'Numpad6', + 0x67: 'Numpad7', + 0x68: 'Numpad8', + 0x69: 'Numpad9', + 0x6a: 'NumpadMultiply', + 0x6b: 'NumpadAdd', + 0x6c: 'NumpadDecimal', + 0x6d: 'NumpadSubtract', + 0x6e: 'NumpadDecimal', // Duplicate, because buggy on Windows + 0x6f: 'NumpadDivide', + 0x70: 'F1', + 0x71: 'F2', + 0x72: 'F3', + 0x73: 'F4', + 0x74: 'F5', + 0x75: 'F6', + 0x76: 'F7', + 0x77: 'F8', + 0x78: 'F9', + 0x79: 'F10', + 0x7a: 'F11', + 0x7b: 'F12', + 0x7c: 'F13', + 0x7d: 'F14', + 0x7e: 'F15', + 0x7f: 'F16', + 0x80: 'F17', + 0x81: 'F18', + 0x82: 'F19', + 0x83: 'F20', + 0x84: 'F21', + 0x85: 'F22', + 0x86: 'F23', + 0x87: 'F24', + 0x90: 'NumLock', + 0x91: 'ScrollLock', + 0xa6: 'BrowserBack', + 0xa7: 'BrowserForward', + 0xa8: 'BrowserRefresh', + 0xa9: 'BrowserStop', + 0xaa: 'BrowserSearch', + 0xab: 'BrowserFavorites', + 0xac: 'BrowserHome', + 0xad: 'AudioVolumeMute', + 0xae: 'AudioVolumeDown', + 0xaf: 'AudioVolumeUp', + 0xb0: 'MediaTrackNext', + 0xb1: 'MediaTrackPrevious', + 0xb2: 'MediaStop', + 0xb3: 'MediaPlayPause', + 0xb4: 'LaunchMail', + 0xb5: 'MediaSelect', + 0xb6: 'LaunchApp1', + 0xb7: 'LaunchApp2', + 0xe1: 'AltRight', // Only when it is AltGraph +}; diff --git a/core/input/xtscancodes.js b/core/input/xtscancodes.js new file mode 100644 index 0000000..8ab9c17 --- /dev/null +++ b/core/input/xtscancodes.js @@ -0,0 +1,173 @@ +/* + * This file is auto-generated from keymaps.csv + * Database checksum sha256(76d68c10e97d37fe2ea459e210125ae41796253fb217e900bf2983ade13a7920) + * To re-generate, run: + * keymap-gen code-map --lang=js keymaps.csv html atset1 +*/ +export default { + "Again": 0xe005, /* html:Again (Again) -> linux:129 (KEY_AGAIN) -> atset1:57349 */ + "AltLeft": 0x38, /* html:AltLeft (AltLeft) -> linux:56 (KEY_LEFTALT) -> atset1:56 */ + "AltRight": 0xe038, /* html:AltRight (AltRight) -> linux:100 (KEY_RIGHTALT) -> atset1:57400 */ + "ArrowDown": 0xe050, /* html:ArrowDown (ArrowDown) -> linux:108 (KEY_DOWN) -> atset1:57424 */ + "ArrowLeft": 0xe04b, /* html:ArrowLeft (ArrowLeft) -> linux:105 (KEY_LEFT) -> atset1:57419 */ + "ArrowRight": 0xe04d, /* html:ArrowRight (ArrowRight) -> linux:106 (KEY_RIGHT) -> atset1:57421 */ + "ArrowUp": 0xe048, /* html:ArrowUp (ArrowUp) -> linux:103 (KEY_UP) -> atset1:57416 */ + "AudioVolumeDown": 0xe02e, /* html:AudioVolumeDown (AudioVolumeDown) -> linux:114 (KEY_VOLUMEDOWN) -> atset1:57390 */ + "AudioVolumeMute": 0xe020, /* html:AudioVolumeMute (AudioVolumeMute) -> linux:113 (KEY_MUTE) -> atset1:57376 */ + "AudioVolumeUp": 0xe030, /* html:AudioVolumeUp (AudioVolumeUp) -> linux:115 (KEY_VOLUMEUP) -> atset1:57392 */ + "Backquote": 0x29, /* html:Backquote (Backquote) -> linux:41 (KEY_GRAVE) -> atset1:41 */ + "Backslash": 0x2b, /* html:Backslash (Backslash) -> linux:43 (KEY_BACKSLASH) -> atset1:43 */ + "Backspace": 0xe, /* html:Backspace (Backspace) -> linux:14 (KEY_BACKSPACE) -> atset1:14 */ + "BracketLeft": 0x1a, /* html:BracketLeft (BracketLeft) -> linux:26 (KEY_LEFTBRACE) -> atset1:26 */ + "BracketRight": 0x1b, /* html:BracketRight (BracketRight) -> linux:27 (KEY_RIGHTBRACE) -> atset1:27 */ + "BrowserBack": 0xe06a, /* html:BrowserBack (BrowserBack) -> linux:158 (KEY_BACK) -> atset1:57450 */ + "BrowserFavorites": 0xe066, /* html:BrowserFavorites (BrowserFavorites) -> linux:156 (KEY_BOOKMARKS) -> atset1:57446 */ + "BrowserForward": 0xe069, /* html:BrowserForward (BrowserForward) -> linux:159 (KEY_FORWARD) -> atset1:57449 */ + "BrowserHome": 0xe032, /* html:BrowserHome (BrowserHome) -> linux:172 (KEY_HOMEPAGE) -> atset1:57394 */ + "BrowserRefresh": 0xe067, /* html:BrowserRefresh (BrowserRefresh) -> linux:173 (KEY_REFRESH) -> atset1:57447 */ + "BrowserSearch": 0xe065, /* html:BrowserSearch (BrowserSearch) -> linux:217 (KEY_SEARCH) -> atset1:57445 */ + "BrowserStop": 0xe068, /* html:BrowserStop (BrowserStop) -> linux:128 (KEY_STOP) -> atset1:57448 */ + "CapsLock": 0x3a, /* html:CapsLock (CapsLock) -> linux:58 (KEY_CAPSLOCK) -> atset1:58 */ + "Comma": 0x33, /* html:Comma (Comma) -> linux:51 (KEY_COMMA) -> atset1:51 */ + "ContextMenu": 0xe05d, /* html:ContextMenu (ContextMenu) -> linux:127 (KEY_COMPOSE) -> atset1:57437 */ + "ControlLeft": 0x1d, /* html:ControlLeft (ControlLeft) -> linux:29 (KEY_LEFTCTRL) -> atset1:29 */ + "ControlRight": 0xe01d, /* html:ControlRight (ControlRight) -> linux:97 (KEY_RIGHTCTRL) -> atset1:57373 */ + "Convert": 0x79, /* html:Convert (Convert) -> linux:92 (KEY_HENKAN) -> atset1:121 */ + "Copy": 0xe078, /* html:Copy (Copy) -> linux:133 (KEY_COPY) -> atset1:57464 */ + "Cut": 0xe03c, /* html:Cut (Cut) -> linux:137 (KEY_CUT) -> atset1:57404 */ + "Delete": 0xe053, /* html:Delete (Delete) -> linux:111 (KEY_DELETE) -> atset1:57427 */ + "Digit0": 0xb, /* html:Digit0 (Digit0) -> linux:11 (KEY_0) -> atset1:11 */ + "Digit1": 0x2, /* html:Digit1 (Digit1) -> linux:2 (KEY_1) -> atset1:2 */ + "Digit2": 0x3, /* html:Digit2 (Digit2) -> linux:3 (KEY_2) -> atset1:3 */ + "Digit3": 0x4, /* html:Digit3 (Digit3) -> linux:4 (KEY_3) -> atset1:4 */ + "Digit4": 0x5, /* html:Digit4 (Digit4) -> linux:5 (KEY_4) -> atset1:5 */ + "Digit5": 0x6, /* html:Digit5 (Digit5) -> linux:6 (KEY_5) -> atset1:6 */ + "Digit6": 0x7, /* html:Digit6 (Digit6) -> linux:7 (KEY_6) -> atset1:7 */ + "Digit7": 0x8, /* html:Digit7 (Digit7) -> linux:8 (KEY_7) -> atset1:8 */ + "Digit8": 0x9, /* html:Digit8 (Digit8) -> linux:9 (KEY_8) -> atset1:9 */ + "Digit9": 0xa, /* html:Digit9 (Digit9) -> linux:10 (KEY_9) -> atset1:10 */ + "Eject": 0xe07d, /* html:Eject (Eject) -> linux:162 (KEY_EJECTCLOSECD) -> atset1:57469 */ + "End": 0xe04f, /* html:End (End) -> linux:107 (KEY_END) -> atset1:57423 */ + "Enter": 0x1c, /* html:Enter (Enter) -> linux:28 (KEY_ENTER) -> atset1:28 */ + "Equal": 0xd, /* html:Equal (Equal) -> linux:13 (KEY_EQUAL) -> atset1:13 */ + "Escape": 0x1, /* html:Escape (Escape) -> linux:1 (KEY_ESC) -> atset1:1 */ + "F1": 0x3b, /* html:F1 (F1) -> linux:59 (KEY_F1) -> atset1:59 */ + "F10": 0x44, /* html:F10 (F10) -> linux:68 (KEY_F10) -> atset1:68 */ + "F11": 0x57, /* html:F11 (F11) -> linux:87 (KEY_F11) -> atset1:87 */ + "F12": 0x58, /* html:F12 (F12) -> linux:88 (KEY_F12) -> atset1:88 */ + "F13": 0x5d, /* html:F13 (F13) -> linux:183 (KEY_F13) -> atset1:93 */ + "F14": 0x5e, /* html:F14 (F14) -> linux:184 (KEY_F14) -> atset1:94 */ + "F15": 0x5f, /* html:F15 (F15) -> linux:185 (KEY_F15) -> atset1:95 */ + "F16": 0x55, /* html:F16 (F16) -> linux:186 (KEY_F16) -> atset1:85 */ + "F17": 0xe003, /* html:F17 (F17) -> linux:187 (KEY_F17) -> atset1:57347 */ + "F18": 0xe077, /* html:F18 (F18) -> linux:188 (KEY_F18) -> atset1:57463 */ + "F19": 0xe004, /* html:F19 (F19) -> linux:189 (KEY_F19) -> atset1:57348 */ + "F2": 0x3c, /* html:F2 (F2) -> linux:60 (KEY_F2) -> atset1:60 */ + "F20": 0x5a, /* html:F20 (F20) -> linux:190 (KEY_F20) -> atset1:90 */ + "F21": 0x74, /* html:F21 (F21) -> linux:191 (KEY_F21) -> atset1:116 */ + "F22": 0xe079, /* html:F22 (F22) -> linux:192 (KEY_F22) -> atset1:57465 */ + "F23": 0x6d, /* html:F23 (F23) -> linux:193 (KEY_F23) -> atset1:109 */ + "F24": 0x6f, /* html:F24 (F24) -> linux:194 (KEY_F24) -> atset1:111 */ + "F3": 0x3d, /* html:F3 (F3) -> linux:61 (KEY_F3) -> atset1:61 */ + "F4": 0x3e, /* html:F4 (F4) -> linux:62 (KEY_F4) -> atset1:62 */ + "F5": 0x3f, /* html:F5 (F5) -> linux:63 (KEY_F5) -> atset1:63 */ + "F6": 0x40, /* html:F6 (F6) -> linux:64 (KEY_F6) -> atset1:64 */ + "F7": 0x41, /* html:F7 (F7) -> linux:65 (KEY_F7) -> atset1:65 */ + "F8": 0x42, /* html:F8 (F8) -> linux:66 (KEY_F8) -> atset1:66 */ + "F9": 0x43, /* html:F9 (F9) -> linux:67 (KEY_F9) -> atset1:67 */ + "Find": 0xe041, /* html:Find (Find) -> linux:136 (KEY_FIND) -> atset1:57409 */ + "Help": 0xe075, /* html:Help (Help) -> linux:138 (KEY_HELP) -> atset1:57461 */ + "Hiragana": 0x77, /* html:Hiragana (Lang4) -> linux:91 (KEY_HIRAGANA) -> atset1:119 */ + "Home": 0xe047, /* html:Home (Home) -> linux:102 (KEY_HOME) -> atset1:57415 */ + "Insert": 0xe052, /* html:Insert (Insert) -> linux:110 (KEY_INSERT) -> atset1:57426 */ + "IntlBackslash": 0x56, /* html:IntlBackslash (IntlBackslash) -> linux:86 (KEY_102ND) -> atset1:86 */ + "IntlRo": 0x73, /* html:IntlRo (IntlRo) -> linux:89 (KEY_RO) -> atset1:115 */ + "IntlYen": 0x7d, /* html:IntlYen (IntlYen) -> linux:124 (KEY_YEN) -> atset1:125 */ + "KanaMode": 0x70, /* html:KanaMode (KanaMode) -> linux:93 (KEY_KATAKANAHIRAGANA) -> atset1:112 */ + "Katakana": 0x78, /* html:Katakana (Lang3) -> linux:90 (KEY_KATAKANA) -> atset1:120 */ + "KeyA": 0x1e, /* html:KeyA (KeyA) -> linux:30 (KEY_A) -> atset1:30 */ + "KeyB": 0x30, /* html:KeyB (KeyB) -> linux:48 (KEY_B) -> atset1:48 */ + "KeyC": 0x2e, /* html:KeyC (KeyC) -> linux:46 (KEY_C) -> atset1:46 */ + "KeyD": 0x20, /* html:KeyD (KeyD) -> linux:32 (KEY_D) -> atset1:32 */ + "KeyE": 0x12, /* html:KeyE (KeyE) -> linux:18 (KEY_E) -> atset1:18 */ + "KeyF": 0x21, /* html:KeyF (KeyF) -> linux:33 (KEY_F) -> atset1:33 */ + "KeyG": 0x22, /* html:KeyG (KeyG) -> linux:34 (KEY_G) -> atset1:34 */ + "KeyH": 0x23, /* html:KeyH (KeyH) -> linux:35 (KEY_H) -> atset1:35 */ + "KeyI": 0x17, /* html:KeyI (KeyI) -> linux:23 (KEY_I) -> atset1:23 */ + "KeyJ": 0x24, /* html:KeyJ (KeyJ) -> linux:36 (KEY_J) -> atset1:36 */ + "KeyK": 0x25, /* html:KeyK (KeyK) -> linux:37 (KEY_K) -> atset1:37 */ + "KeyL": 0x26, /* html:KeyL (KeyL) -> linux:38 (KEY_L) -> atset1:38 */ + "KeyM": 0x32, /* html:KeyM (KeyM) -> linux:50 (KEY_M) -> atset1:50 */ + "KeyN": 0x31, /* html:KeyN (KeyN) -> linux:49 (KEY_N) -> atset1:49 */ + "KeyO": 0x18, /* html:KeyO (KeyO) -> linux:24 (KEY_O) -> atset1:24 */ + "KeyP": 0x19, /* html:KeyP (KeyP) -> linux:25 (KEY_P) -> atset1:25 */ + "KeyQ": 0x10, /* html:KeyQ (KeyQ) -> linux:16 (KEY_Q) -> atset1:16 */ + "KeyR": 0x13, /* html:KeyR (KeyR) -> linux:19 (KEY_R) -> atset1:19 */ + "KeyS": 0x1f, /* html:KeyS (KeyS) -> linux:31 (KEY_S) -> atset1:31 */ + "KeyT": 0x14, /* html:KeyT (KeyT) -> linux:20 (KEY_T) -> atset1:20 */ + "KeyU": 0x16, /* html:KeyU (KeyU) -> linux:22 (KEY_U) -> atset1:22 */ + "KeyV": 0x2f, /* html:KeyV (KeyV) -> linux:47 (KEY_V) -> atset1:47 */ + "KeyW": 0x11, /* html:KeyW (KeyW) -> linux:17 (KEY_W) -> atset1:17 */ + "KeyX": 0x2d, /* html:KeyX (KeyX) -> linux:45 (KEY_X) -> atset1:45 */ + "KeyY": 0x15, /* html:KeyY (KeyY) -> linux:21 (KEY_Y) -> atset1:21 */ + "KeyZ": 0x2c, /* html:KeyZ (KeyZ) -> linux:44 (KEY_Z) -> atset1:44 */ + "Lang1": 0x72, /* html:Lang1 (Lang1) -> linux:122 (KEY_HANGEUL) -> atset1:114 */ + "Lang2": 0x71, /* html:Lang2 (Lang2) -> linux:123 (KEY_HANJA) -> atset1:113 */ + "Lang3": 0x78, /* html:Lang3 (Lang3) -> linux:90 (KEY_KATAKANA) -> atset1:120 */ + "Lang4": 0x77, /* html:Lang4 (Lang4) -> linux:91 (KEY_HIRAGANA) -> atset1:119 */ + "Lang5": 0x76, /* html:Lang5 (Lang5) -> linux:85 (KEY_ZENKAKUHANKAKU) -> atset1:118 */ + "LaunchApp1": 0xe06b, /* html:LaunchApp1 (LaunchApp1) -> linux:157 (KEY_COMPUTER) -> atset1:57451 */ + "LaunchApp2": 0xe021, /* html:LaunchApp2 (LaunchApp2) -> linux:140 (KEY_CALC) -> atset1:57377 */ + "LaunchMail": 0xe06c, /* html:LaunchMail (LaunchMail) -> linux:155 (KEY_MAIL) -> atset1:57452 */ + "MediaPlayPause": 0xe022, /* html:MediaPlayPause (MediaPlayPause) -> linux:164 (KEY_PLAYPAUSE) -> atset1:57378 */ + "MediaSelect": 0xe06d, /* html:MediaSelect (MediaSelect) -> linux:226 (KEY_MEDIA) -> atset1:57453 */ + "MediaStop": 0xe024, /* html:MediaStop (MediaStop) -> linux:166 (KEY_STOPCD) -> atset1:57380 */ + "MediaTrackNext": 0xe019, /* html:MediaTrackNext (MediaTrackNext) -> linux:163 (KEY_NEXTSONG) -> atset1:57369 */ + "MediaTrackPrevious": 0xe010, /* html:MediaTrackPrevious (MediaTrackPrevious) -> linux:165 (KEY_PREVIOUSSONG) -> atset1:57360 */ + "MetaLeft": 0xe05b, /* html:MetaLeft (MetaLeft) -> linux:125 (KEY_LEFTMETA) -> atset1:57435 */ + "MetaRight": 0xe05c, /* html:MetaRight (MetaRight) -> linux:126 (KEY_RIGHTMETA) -> atset1:57436 */ + "Minus": 0xc, /* html:Minus (Minus) -> linux:12 (KEY_MINUS) -> atset1:12 */ + "NonConvert": 0x7b, /* html:NonConvert (NonConvert) -> linux:94 (KEY_MUHENKAN) -> atset1:123 */ + "NumLock": 0x45, /* html:NumLock (NumLock) -> linux:69 (KEY_NUMLOCK) -> atset1:69 */ + "Numpad0": 0x52, /* html:Numpad0 (Numpad0) -> linux:82 (KEY_KP0) -> atset1:82 */ + "Numpad1": 0x4f, /* html:Numpad1 (Numpad1) -> linux:79 (KEY_KP1) -> atset1:79 */ + "Numpad2": 0x50, /* html:Numpad2 (Numpad2) -> linux:80 (KEY_KP2) -> atset1:80 */ + "Numpad3": 0x51, /* html:Numpad3 (Numpad3) -> linux:81 (KEY_KP3) -> atset1:81 */ + "Numpad4": 0x4b, /* html:Numpad4 (Numpad4) -> linux:75 (KEY_KP4) -> atset1:75 */ + "Numpad5": 0x4c, /* html:Numpad5 (Numpad5) -> linux:76 (KEY_KP5) -> atset1:76 */ + "Numpad6": 0x4d, /* html:Numpad6 (Numpad6) -> linux:77 (KEY_KP6) -> atset1:77 */ + "Numpad7": 0x47, /* html:Numpad7 (Numpad7) -> linux:71 (KEY_KP7) -> atset1:71 */ + "Numpad8": 0x48, /* html:Numpad8 (Numpad8) -> linux:72 (KEY_KP8) -> atset1:72 */ + "Numpad9": 0x49, /* html:Numpad9 (Numpad9) -> linux:73 (KEY_KP9) -> atset1:73 */ + "NumpadAdd": 0x4e, /* html:NumpadAdd (NumpadAdd) -> linux:78 (KEY_KPPLUS) -> atset1:78 */ + "NumpadComma": 0x7e, /* html:NumpadComma (NumpadComma) -> linux:121 (KEY_KPCOMMA) -> atset1:126 */ + "NumpadDecimal": 0x53, /* html:NumpadDecimal (NumpadDecimal) -> linux:83 (KEY_KPDOT) -> atset1:83 */ + "NumpadDivide": 0xe035, /* html:NumpadDivide (NumpadDivide) -> linux:98 (KEY_KPSLASH) -> atset1:57397 */ + "NumpadEnter": 0xe01c, /* html:NumpadEnter (NumpadEnter) -> linux:96 (KEY_KPENTER) -> atset1:57372 */ + "NumpadEqual": 0x59, /* html:NumpadEqual (NumpadEqual) -> linux:117 (KEY_KPEQUAL) -> atset1:89 */ + "NumpadMultiply": 0x37, /* html:NumpadMultiply (NumpadMultiply) -> linux:55 (KEY_KPASTERISK) -> atset1:55 */ + "NumpadParenLeft": 0xe076, /* html:NumpadParenLeft (NumpadParenLeft) -> linux:179 (KEY_KPLEFTPAREN) -> atset1:57462 */ + "NumpadParenRight": 0xe07b, /* html:NumpadParenRight (NumpadParenRight) -> linux:180 (KEY_KPRIGHTPAREN) -> atset1:57467 */ + "NumpadSubtract": 0x4a, /* html:NumpadSubtract (NumpadSubtract) -> linux:74 (KEY_KPMINUS) -> atset1:74 */ + "Open": 0x64, /* html:Open (Open) -> linux:134 (KEY_OPEN) -> atset1:100 */ + "PageDown": 0xe051, /* html:PageDown (PageDown) -> linux:109 (KEY_PAGEDOWN) -> atset1:57425 */ + "PageUp": 0xe049, /* html:PageUp (PageUp) -> linux:104 (KEY_PAGEUP) -> atset1:57417 */ + "Paste": 0x65, /* html:Paste (Paste) -> linux:135 (KEY_PASTE) -> atset1:101 */ + "Pause": 0xe046, /* html:Pause (Pause) -> linux:119 (KEY_PAUSE) -> atset1:57414 */ + "Period": 0x34, /* html:Period (Period) -> linux:52 (KEY_DOT) -> atset1:52 */ + "Power": 0xe05e, /* html:Power (Power) -> linux:116 (KEY_POWER) -> atset1:57438 */ + "PrintScreen": 0x54, /* html:PrintScreen (PrintScreen) -> linux:99 (KEY_SYSRQ) -> atset1:84 */ + "Props": 0xe006, /* html:Props (Props) -> linux:130 (KEY_PROPS) -> atset1:57350 */ + "Quote": 0x28, /* html:Quote (Quote) -> linux:40 (KEY_APOSTROPHE) -> atset1:40 */ + "ScrollLock": 0x46, /* html:ScrollLock (ScrollLock) -> linux:70 (KEY_SCROLLLOCK) -> atset1:70 */ + "Semicolon": 0x27, /* html:Semicolon (Semicolon) -> linux:39 (KEY_SEMICOLON) -> atset1:39 */ + "ShiftLeft": 0x2a, /* html:ShiftLeft (ShiftLeft) -> linux:42 (KEY_LEFTSHIFT) -> atset1:42 */ + "ShiftRight": 0x36, /* html:ShiftRight (ShiftRight) -> linux:54 (KEY_RIGHTSHIFT) -> atset1:54 */ + "Slash": 0x35, /* html:Slash (Slash) -> linux:53 (KEY_SLASH) -> atset1:53 */ + "Sleep": 0xe05f, /* html:Sleep (Sleep) -> linux:142 (KEY_SLEEP) -> atset1:57439 */ + "Space": 0x39, /* html:Space (Space) -> linux:57 (KEY_SPACE) -> atset1:57 */ + "Suspend": 0xe025, /* html:Suspend (Suspend) -> linux:205 (KEY_SUSPEND) -> atset1:57381 */ + "Tab": 0xf, /* html:Tab (Tab) -> linux:15 (KEY_TAB) -> atset1:15 */ + "Undo": 0xe007, /* html:Undo (Undo) -> linux:131 (KEY_UNDO) -> atset1:57351 */ + "WakeUp": 0xe063, /* html:WakeUp (WakeUp) -> linux:143 (KEY_WAKEUP) -> atset1:57443 */ +}; diff --git a/core/mousebuttonmapper.js b/core/mousebuttonmapper.js new file mode 100644 index 0000000..b69475a --- /dev/null +++ b/core/mousebuttonmapper.js @@ -0,0 +1,67 @@ +export const XVNC_BUTTONS = { + LEFT_BUTTON: 1, + MIDDLE_BUTTON: 2, + RIGHT_BUTTON: 3, + TURN_SCROLL_WHEEL_UP: 4, + TURN_SCROLL_WHEEL_DOWN: 5, + PUSH_SCROLL_WHEEL_LEFT: 6, + PUSH_SCROLL_WHEEL_RIGHT: 7, + BACK_BUTTON: 8, + FORWARD_BUTTON: 9 +}; + +export function xvncButtonToMask(xvncButton) { + return 1 << (xvncButton - 1); +} + +export default class MouseButtonMapper { + constructor() { + this.map = new Map(); + } + + get(mouseButton) { + if (!this.map.has(mouseButton)) { + return mouseButton; + } + + return this.map.get(mouseButton); + } + + set(mouseButton, xorgMouseButton) { + return this.map.set(mouseButton, xorgMouseButton); + } + + delete(mouseButton) { + return this.map.delete(mouseButton); + } + + dump() { + return JSON.stringify(this.map, this._replacer); + } + + load(json) { + this.map = JSON.parse(json, this._reviver); + } + + _replacer(key, value) { + if (!(value instanceof Map)) { + return value; + } + + return { + dataType: 'Map', + value: Array.from(value.entries()) + }; + } + + _reviver(key, value) { + if (typeof value === 'object' && value !== null) { + if (value.dataType === 'Map') { + return new Map(value.value); + } + } + return value; + } +} + +export { MouseButtonMapper }; diff --git a/core/output/printer.js b/core/output/printer.js new file mode 100644 index 0000000..e746336 --- /dev/null +++ b/core/output/printer.js @@ -0,0 +1,63 @@ +const PACKETS = { + DOCUMENT_START: 0, + DOCUMENT_CHUNK: 1, + DOCUMENT_END: 2 +}; + +const printDocument = async (data) => { + const iframe = document.createElement("iframe"); + iframe.style.display = "none"; + document.body.appendChild(iframe); + + iframe.onload = () => { + setTimeout(() => { + iframe.focus(); + iframe.contentWindow.print(); + }, 1); + }; + + const blob = new Blob([new Uint8Array(data)], { type: "application/pdf" }); + iframe.src = URL.createObjectURL(blob); +} + +export default (rfb) => { + let documentSize = 0; + let downloadedSize = 0; + let documentData = []; + + const processRelayData = (payload) => { + const array = Array.from(payload); + const buffer = new Uint8Array(array).buffer; + const packetData = new DataView(buffer); + const packetId = packetData.getUint32(0, false); + + switch (packetId) { + case PACKETS.DOCUMENT_START: + documentSize = packetData.getUint32(4, false); + downloadedSize = 0; + console.log(`Downloading document for printing (${documentSize}B)`); + break; + + case PACKETS.DOCUMENT_CHUNK: + let chunkSize = packetData.getUint32(4, false); + let chunkData = new Uint8Array(buffer, 8); + downloadedSize += chunkSize; + documentData.push(...chunkData); + console.log(`Downloading document for printing (${downloadedSize}/${documentSize}B)`); + break; + + case PACKETS.DOCUMENT_END: + console.log(`Downloaded document for printing (${downloadedSize}/${documentSize}B)`); + printDocument(documentData); + downloadedSize = 0; + documentSize = 0; + break; + + default: + console.error(`Unknown packet id: ${packetId}`); + break; + } + } + + rfb.subscribeUnixRelay("printer", processRelayData); +} \ No newline at end of file diff --git a/core/rfb.js b/core/rfb.js new file mode 100644 index 0000000..4bfac51 --- /dev/null +++ b/core/rfb.js @@ -0,0 +1,4333 @@ +/* + * KasmVNC: HTML5 VNC client + * Copyright (C) 2020 Kasm Technologies + * Copyright (C) 2020 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + * + */ + +import { toUnsigned32bit, toSigned32bit } from './util/int.js'; +import * as Log from './util/logging.js'; +import { encodeUTF8, decodeUTF8 } from './util/strings.js'; +import { hashUInt8Array } from './util/int.js'; +import { dragThreshold, supportsCursorURIs, isTouchDevice, isWindows, isMac, isIOS } from './util/browser.js'; +import { clientToElement } from './util/element.js'; +import { setCapture } from './util/events.js'; +import EventTargetMixin from './util/eventtarget.js'; +import Display from "./display.js"; +import Inflator from "./inflator.js"; +import Deflator from "./deflator.js"; +import Keyboard from "./input/keyboard.js"; +import initializePrinterRelay from "./output/printer.js"; +import GestureHandler from "./input/gesturehandler.js"; +import Cursor from "./util/cursor.js"; +import Websock from "./websock.js"; +import DES from "./des.js"; +import KeyTable from "./input/keysym.js"; +import XtScancode from "./input/xtscancodes.js"; +import { encodings } from "./encodings.js"; +import { MouseButtonMapper, xvncButtonToMask } from "./mousebuttonmapper.js"; + +import RawDecoder from "./decoders/raw.js"; +import CopyRectDecoder from "./decoders/copyrect.js"; +import RREDecoder from "./decoders/rre.js"; +import HextileDecoder from "./decoders/hextile.js"; +import TightDecoder from "./decoders/tight.js"; +import TightPNGDecoder from "./decoders/tightpng.js"; +import UDPDecoder from './decoders/udp.js'; +import { toSignedRelative16bit } from './util/int.js'; + +// How many seconds to wait for a disconnect to finish +const DISCONNECT_TIMEOUT = 3; +const DEFAULT_BACKGROUND = 'rgb(40, 40, 40)'; + +var _videoQuality = 2; +var _enableWebP = false; +var _enableQOI = false; + +// Minimum wait (ms) between two mouse moves +const MOUSE_MOVE_DELAY = 17; + +// Wheel thresholds +let WHEEL_LINE_HEIGHT = 19; // Pixels for one line step (on Windows) + +// Gesture thresholds +const GESTURE_ZOOMSENS = 75; +const GESTURE_SCRLSENS = 50; +const DOUBLE_TAP_TIMEOUT = 1000; +const DOUBLE_TAP_THRESHOLD = 50; + +// Extended clipboard pseudo-encoding formats +const extendedClipboardFormatText = 1; +/*eslint-disable no-unused-vars */ +const extendedClipboardFormatRtf = 1 << 1; +const extendedClipboardFormatHtml = 1 << 2; +const extendedClipboardFormatDib = 1 << 3; +const extendedClipboardFormatFiles = 1 << 4; +/*eslint-enable */ + +// Extended clipboard pseudo-encoding actions +const extendedClipboardActionCaps = 1 << 24; +const extendedClipboardActionRequest = 1 << 25; +const extendedClipboardActionPeek = 1 << 26; +const extendedClipboardActionNotify = 1 << 27; +const extendedClipboardActionProvide = 1 << 28; + +export default class RFB extends EventTargetMixin { + constructor(target, touchInput, urlOrChannel, options) { + if (!target) { + throw new Error("Must specify target"); + } + if (!urlOrChannel) { + throw new Error("Must specify URL, WebSocket or RTCDataChannel"); + } + + super(); + + this._target = target; + + if (typeof urlOrChannel === "string") { + this._url = urlOrChannel; + } else { + this._url = null; + this._rawChannel = urlOrChannel; + } + + // Connection details + options = options || {}; + this._rfbCredentials = options.credentials || {}; + this._shared = 'shared' in options ? !!options.shared : true; + this._repeaterID = options.repeaterID || ''; + this._wsProtocols = options.wsProtocols || ['binary']; + + // Internal state + this._rfbConnectionState = ''; + this._rfbInitState = ''; + this._rfbAuthScheme = -1; + this._rfbCleanDisconnect = true; + + // Server capabilities + this._rfbVersion = 0; + this._rfbMaxVersion = 3.8; + this._rfbTightVNC = false; + this._rfbVeNCryptState = 0; + this._rfbXvpVer = 0; + this._fbWidth = 0; + this._fbHeight = 0; + this._fbName = ""; + this._capabilities = { power: false }; + this._supportsFence = false; + this._supportsContinuousUpdates = false; + this._enabledContinuousUpdates = false; + this._supportsSetDesktopSize = false; + this._screenID = 0; + this._screenFlags = 0; + this._qemuExtKeyEventSupported = false; + + // kasm defaults + this._jpegVideoQuality = 5; + this._webpVideoQuality = 5; + this._treatLossless = 7; + this._preferBandwidth = true; + this._dynamicQualityMin = 3; + this._dynamicQualityMax = 9; + this._videoArea = 65; + this._videoTime = 5; + this._videoOutTime = 3; + this._videoScaling = 2; + this._frameRate = 30; + this._maxVideoResolutionX = 960; + this._maxVideoResolutionY = 540; + this._forcedResolutionX = null; + this._forcedResolutionY = null; + this._clipboardBinary = true; + this._resendClipboardNextUserDrivenEvent = true; + this._useUdp = true; + this._hiDpi = false; + this._enableQOI = false; + this.TransitConnectionStates = { + Tcp: Symbol("tcp"), + Udp: Symbol("udp"), + Upgrading: Symbol("upgrading"), + Downgrading: Symbol("downgrading"), + Failure: Symbol("failure") + } + this._transitConnectionState = this.TransitConnectionStates.Tcp; + this._lastTransition = null; + this._udpConnectFailures = 0; //Failures in upgrading connection to udp + this._udpTransitFailures = 0; //Failures in transit after successful upgrade + + this._trackFrameStats = false; + + this._clipboardText = null; + this._clipboardServerCapabilitiesActions = {}; + this._clipboardServerCapabilitiesFormats = {}; + + // Internal objects + this._sock = null; // Websock object + this._display = null; // Display object + this._flushing = false; // Display flushing state + this._keyboard = null; // Keyboard input handler object + this._gestures = null; // Gesture input handler object + + // Timers + this._disconnTimer = null; // disconnection timer + this._resizeTimeout = null; // resize rate limiting + this._mouseMoveTimer = null; + + // Decoder states + this._decoders = {}; + + this._FBU = { + rects: 0, // current rect number + x: 0, + y: 0, + width: 0, + height: 0, + encoding: null, + frame_id: 0, + rect_total: 0, //Total rects in frame + }; + + // Mouse state + this._mousePos = {}; + this._mouseButtonMask = 0; + this._mouseLastMoveTime = 0; + this._pointerLock = false; + this._pointerLockPos = { x: 0, y: 0 }; + this._pointerRelativeEnabled = false; + this._mouseLastPinchAndZoomTime = 0; + this._viewportDragging = false; + this._viewportDragPos = {}; + this._viewportHasMoved = false; + this._accumulatedWheelDeltaX = 0; + this._accumulatedWheelDeltaY = 0; + this.mouseButtonMapper = null; + + // Gesture state + this._gestureLastTapTime = null; + this._gestureFirstDoubleTapEv = null; + this._gestureLastMagnitudeX = 0; + this._gestureLastMagnitudeY = 0; + + // Bound event handlers + this._eventHandlers = { + updateHiddenKeyboard: this._updateHiddenKeyboard.bind(this), + focusCanvas: this._focusCanvas.bind(this), + windowResize: this._windowResize.bind(this), + handleMouse: this._handleMouse.bind(this), + handlePointerLockChange: this._handlePointerLockChange.bind(this), + handlePointerLockError: this._handlePointerLockError.bind(this), + handleWheel: this._handleWheel.bind(this), + handleGesture: this._handleGesture.bind(this), + handleFocusChange: this._handleFocusChange.bind(this), + }; + + // main setup + Log.Debug(">> RFB.constructor"); + + // Create DOM elements + this._screen = document.createElement('div'); + this._screen.style.display = 'flex'; + this._screen.style.width = '100%'; + this._screen.style.height = '100%'; + this._screen.style.overflow = 'auto'; + this._screen.style.background = DEFAULT_BACKGROUND; + this._canvas = document.createElement('canvas'); + this._canvas.style.margin = 'auto'; + // Some browsers add an outline on focus + this._canvas.style.outline = 'none'; + this._canvas.width = 0; + this._canvas.height = 0; + this._canvas.tabIndex = -1; + this._canvas.overflow = 'hidden'; + this._screen.appendChild(this._canvas); + + // Cursor + this._cursor = new Cursor(); + + // XXX: TightVNC 2.8.11 sends no cursor at all until Windows changes + // it. Result: no cursor at all until a window border or an edit field + // is hit blindly. But there are also VNC servers that draw the cursor + // in the framebuffer and don't send the empty local cursor. There is + // no way to satisfy both sides. + // + // The spec is unclear on this "initial cursor" issue. Many other + // viewers (TigerVNC, RealVNC, Remmina) display an arrow as the + // initial cursor instead. + this._cursorImage = RFB.cursors.none; + + // NB: nothing that needs explicit teardown should be done + // before this point, since this can throw an exception + try { + this._display = new Display(this._canvas); + } catch (exc) { + Log.Error("Display exception: " + exc); + throw exc; + } + this._display.onflush = this._onFlush.bind(this); + + // populate decoder array with objects + this._decoders[encodings.encodingRaw] = new RawDecoder(); + this._decoders[encodings.encodingCopyRect] = new CopyRectDecoder(); + this._decoders[encodings.encodingRRE] = new RREDecoder(); + this._decoders[encodings.encodingHextile] = new HextileDecoder(); + this._decoders[encodings.encodingTight] = new TightDecoder(this._display); + this._decoders[encodings.encodingTightPNG] = new TightPNGDecoder(); + this._decoders[encodings.encodingUDP] = new UDPDecoder(); + + this._keyboard = new Keyboard(this._canvas, touchInput); + this._keyboard.onkeyevent = this._handleKeyEvent.bind(this); + + this._gestures = new GestureHandler(); + + this._sock = new Websock(); + this._sock.on('message', () => { + this._handleMessage(); + }); + this._sock.on('open', () => { + if ((this._rfbConnectionState === 'connecting') && + (this._rfbInitState === '')) { + this._rfbInitState = 'ProtocolVersion'; + Log.Debug("Starting VNC handshake"); + } else { + this._fail("Unexpected server connection while " + + this._rfbConnectionState); + } + }); + this._sock.on('close', (e) => { + Log.Debug("WebSocket on-close event"); + let msg = ""; + if (e.code) { + msg = "(code: " + e.code; + if (e.reason) { + msg += ", reason: " + e.reason; + } + msg += ")"; + } + switch (this._rfbConnectionState) { + case 'connecting': + this._fail("Connection closed " + msg); + break; + case 'connected': + // Handle disconnects that were initiated server-side + this._updateConnectionState('disconnecting'); + this._updateConnectionState('disconnected'); + break; + case 'disconnecting': + // Normal disconnection path + this._updateConnectionState('disconnected'); + break; + case 'disconnected': + this._fail("Unexpected server disconnect " + + "when already disconnected " + msg); + break; + default: + this._fail("Unexpected server disconnect before connecting " + + msg); + break; + } + this._sock.off('close'); + // Delete reference to raw channel to allow cleanup. + this._rawChannel = null; + }); + this._sock.on('error', e => Log.Warn("WebSocket on-error event")); + + // Slight delay of the actual connection so that the caller has + // time to set up callbacks + setTimeout(this._updateConnectionState.bind(this, 'connecting')); + + Log.Debug("<< RFB.constructor"); + + // ===== PROPERTIES ===== + + + + this.dragViewport = false; + this.focusOnClick = true; + this.lastActiveAt = Date.now(); + + this._viewOnly = false; + this._clipViewport = false; + this._scaleViewport = false; + this._resizeSession = false; + + this._showDotCursor = false; + if (options.showDotCursor !== undefined) { + Log.Warn("Specifying showDotCursor as a RFB constructor argument is deprecated"); + this._showDotCursor = options.showDotCursor; + } + + this._qualityLevel = 6; + this._compressionLevel = 2; + this._clipHash = 0; + } + + // ===== PROPERTIES ===== + + get pointerLock() { return this._pointerLock; } + set pointerLock(value) { + if (!this._pointerLock) { + if (this._canvas.requestPointerLock) { + this._canvas.requestPointerLock(); + this._pointerLockChanging = true; + } else if (this._canvas.mozRequestPointerLock) { + this._canvas.mozRequestPointerLock(); + this._pointerLockChanging = true; + } + } else { + if (window.document.exitPointerLock) { + window.document.exitPointerLock(); + this._pointerLockChanging = true; + } else if (window.document.mozExitPointerLock) { + window.document.mozExitPointerLock(); + this._pointerLockChanging = true; + } + } + } + + get pointerRelative() { return this._pointerRelativeEnabled; } + set pointerRelative(value) + { + this._pointerRelativeEnabled = value; + if (value) { + let max_w = ((this._display.scale === 1) ? this._fbWidth : (this._fbWidth * this._display.scale)); + let max_h = ((this._display.scale === 1) ? this._fbHeight : (this._fbHeight * this._display.scale)); + this._pointerLockPos.x = Math.floor(max_w / 2); + this._pointerLockPos.y = Math.floor(max_h / 2); + + // reset the cursor position to center + this._mousePos = { x: this._pointerLockPos.x , y: this._pointerLockPos.y }; + this._cursor.move(this._pointerLockPos.x, this._pointerLockPos.y); + } + } + + get keyboard() { return this._keyboard; } + + get clipboardBinary() { return this._clipboardMode; } + set clipboardBinary(val) { this._clipboardMode = val; } + + get videoQuality() { return this._videoQuality; } + set videoQuality(quality) + { + //if changing to or from a video quality mode that uses a fixed resolution server side + if (this._videoQuality <= 1 || quality <= 1) { + this._pendingApplyResolutionChange = true; + } + this._videoQuality = quality; + this._pendingApplyEncodingChanges = true; + } + + get preferBandwidth() { return this._preferBandwidth; } + set preferBandwidth(val) { + this._preferBandwidth = val; + this._pendingApplyEncodingChanges = true; + } + + get viewOnly() { return this._viewOnly; } + set viewOnly(viewOnly) { + this._viewOnly = viewOnly; + + if (this._rfbConnectionState === "connecting" || + this._rfbConnectionState === "connected") { + if (viewOnly) { + this._keyboard.ungrab(); + } else { + this._keyboard.grab(); + } + } + } + + get capabilities() { return this._capabilities; } + + get touchButton() { return 0; } + set touchButton(button) { Log.Warn("Using old API!"); } + + get clipViewport() { return this._clipViewport; } + set clipViewport(viewport) { + this._clipViewport = viewport; + this._updateClip(); + } + + get scaleViewport() { return this._scaleViewport; } + set scaleViewport(scale) { + this._scaleViewport = scale; + // Scaling trumps clipping, so we may need to adjust + // clipping when enabling or disabling scaling + if (scale && this._clipViewport) { + this._updateClip(); + } + this._updateScale(); + if (!scale && this._clipViewport) { + this._updateClip(); + } + } + + get resizeSession() { return this._resizeSession; } + set resizeSession(resize) { + this._resizeSession = resize; + if (resize) { + this._requestRemoteResize(); + this.scaleViewport = true; + } + } + + get showDotCursor() { return this._showDotCursor; } + set showDotCursor(show) { + this._showDotCursor = show; + this._refreshCursor(); + } + + get background() { return this._screen.style.background; } + set background(cssValue) { this._screen.style.background = cssValue; } + + get enableWebP() { return this._enableWebP; } + set enableWebP(enabled) { + if (this._enableWebP === enabled) { + return; + } + this._enableWebP = enabled; + this._pendingApplyEncodingChanges = true; + } + + get enableQOI() { return this._enableQOI; } + set enableQOI(enabled) { + if(this._enableQOI === enabled) { + return; + } + + this._decoders[encodings.encodingTight].enableQOI = enabled; + this._enableQOI = this._decoders[encodings.encodingTight].enableQOI + + if (this._enableQOI === enabled) { + this._pendingApplyEncodingChanges = true; + } + + } + + get antiAliasing() { return this._display.antiAliasing; } + set antiAliasing(value) { + this._display.antiAliasing = value; + } + + get jpegVideoQuality() { return this._jpegVideoQuality; } + set jpegVideoQuality(qualityLevel) { + if (!Number.isInteger(qualityLevel) || qualityLevel < 0 || qualityLevel > 9) { + Log.Error("qualityLevel must be an integer between 0 and 9"); + return; + } + + if (this._jpegVideoQuality === qualityLevel) { + return; + } + + this._jpegVideoQuality = qualityLevel; + this._pendingApplyEncodingChanges = true; + } + + get webpVideoQuality() { return this._webpVideoQuality; } + set webpVideoQuality(qualityLevel) { + if (!Number.isInteger(qualityLevel) || qualityLevel < 0 || qualityLevel > 9) { + Log.Error("qualityLevel must be an integer between 0 and 9"); + return; + } + + if (this._webpVideoQuality === qualityLevel) { + return; + } + + this._webpVideoQuality = qualityLevel; + this._pendingApplyEncodingChanges = true; + } + + get treatLossless() { return this._treatLossless; } + set treatLossless(qualityLevel) { + if (!Number.isInteger(qualityLevel) || qualityLevel < 0 || qualityLevel > 9) { + Log.Error("qualityLevel must be an integer between 0 and 9"); + return; + } + + if (this._treatLossless === qualityLevel) { + return; + } + + this._treatLossless = qualityLevel; + } + + get dynamicQualityMin() { return this._dynamicQualityMin; } + set dynamicQualityMin(qualityLevel) { + if (!Number.isInteger(qualityLevel) || qualityLevel < 0 || qualityLevel > 9) { + Log.Error("qualityLevel must be an integer between 0 and 9"); + return; + } + + if (this._dynamicQualityMin === qualityLevel) { + return; + } + + this._dynamicQualityMin = qualityLevel; + this._pendingApplyEncodingChanges = true; + } + + get dynamicQualityMax() { return this._dynamicQualityMax; } + set dynamicQualityMax(qualityLevel) { + if (!Number.isInteger(qualityLevel) || qualityLevel < 0 || qualityLevel > 9) { + Log.Error("qualityLevel must be an integer between 0 and 9"); + return; + } + + if (this._dynamicQualityMax === qualityLevel) { + return; + } + + this._dynamicQualityMax = qualityLevel; + this._pendingApplyEncodingChanges = true; + } + + get videoArea() { + return this._videoArea; + } + set videoArea(area) { + if (!Number.isInteger(area) || area < 0 || area > 100) { + Log.Error("video area must be an integer between 0 and 100"); + return; + } + + if (this._videoArea === area) { + return; + } + + this._videoArea = area; + this._pendingApplyEncodingChanges = true; + } + + get videoTime() { + return this._videoTime; + } + set videoTime(value) { + if (!Number.isInteger(value) || value < 0 || value > 100) { + Log.Error("video time must be an integer between 0 and 100"); + return; + } + + if (this._videoTime === value) { + return; + } + + this._videoTime = value; + this._pendingApplyEncodingChanges = true; + } + + get videoOutTime() { + return this._videoOutTime; + } + set videoOutTime(value) { + if (!Number.isInteger(value) || value < 0 || value > 100) { + Log.Error("video out time must be an integer between 0 and 100"); + return; + } + + if (this._videoOutTime === value) { + return; + } + + this._videoOutTime = value; + this._pendingApplyEncodingChanges = true; + } + + get videoScaling() { + return this._videoScaling; + } + set videoScaling(value) { + if (!Number.isInteger(value) || value < 0 || value > 2) { + Log.Error("video scaling must be an integer between 0 and 2"); + return; + } + + if (this._videoScaling === value) { + return; + } + + this._videoScaling = value; + this._pendingApplyEncodingChanges = true; + } + + get frameRate() { return this._frameRate; } + set frameRate(value) { + if (!Number.isInteger(value) || value < 1 || value > 120) { + Log.Error("frame rate must be an integer between 1 and 120"); + return; + } + + if (this._frameRate === value) { + return; + } + + this._frameRate = value; + this._pendingApplyEncodingChanges = true; + } + + get maxVideoResolutionX() { return this._maxVideoResolutionX; } + set maxVideoResolutionX(value) { + if (!Number.isInteger(value) || value < 100 ) { + Log.Error("max video resolution must be an integer greater than 100"); + return; + } + + if (this._maxVideoResolutionX === value) { + return; + } + + this._maxVideoResolutionX = value; + this._pendingApplyVideoRes = true; + } + + get maxVideoResolutionY() { return this._maxVideoResolutionY; } + set maxVideoResolutionY(value) { + if (!Number.isInteger(value) || value < 100 ) { + Log.Error("max video resolution must be an integer greater than 100"); + return; + } + + if (this._maxVideoResolutionY === value) { + return; + } + + this._maxVideoResolutionY = value; + this._pendingApplyVideoRes = true; + } + + get forcedResolutionX() { return this._forcedResolutionX; } + set forcedResolutionX(value) {this._forcedResolutionX = value;} + get forcedResolutionY() { return this._forcedResolutionY; } + set forcedResolutionY(value) {this._forcedResolutionY = value;} + + get qualityLevel() { + return this._qualityLevel; + } + set qualityLevel(qualityLevel) { + if (!Number.isInteger(qualityLevel) || qualityLevel < 0 || qualityLevel > 9) { + Log.Error("qualityLevel must be an integer between 0 and 9"); + return; + } + + if (this._qualityLevel === qualityLevel) { + return; + } + + this._qualityLevel = qualityLevel; + this._pendingApplyEncodingChanges = true; + } + + get compressionLevel() { + return this._compressionLevel; + } + set compressionLevel(compressionLevel) { + if (!Number.isInteger(compressionLevel) || compressionLevel < 0 || compressionLevel > 9) { + Log.Error("compressionLevel must be an integer between 0 and 9"); + return; + } + + if (this._compressionLevel === compressionLevel) { + return; + } + + this._compressionLevel = compressionLevel; + + if (this._rfbConnectionState === 'connected') { + this._sendEncodings(); + } + } + + get statsFps() { return this._display.fps; } + + get enableWebRTC() { return this._useUdp; } + set enableWebRTC(value) { + this._useUdp = value; + if (!value) { + if (this._rfbConnectionState === 'connected' && (this._transitConnectionState !== this.TransitConnectionStates.Tcp)) { + this._sendUdpDowngrade(); + } + } else { + if (this._rfbConnectionState === 'connected' && (this._transitConnectionState !== this.TransitConnectionStates.Udp)) { + this._sendUdpUpgrade(); + } + } + } + + get enableHiDpi() { return this._hiDpi; } + set enableHiDpi(value) { + if (value !== this._hiDpi) { + this._hiDpi = value; + this._requestRemoteResize(); + } + } + + // ===== PUBLIC METHODS ===== + + /* + This function must be called after changing any properties that effect rendering quality + */ + updateConnectionSettings() { + if (this._rfbConnectionState === 'connected') { + + if (this._pendingApplyVideoRes) { + RFB.messages.setMaxVideoResolution(this._sock, this._maxVideoResolutionX, this._maxVideoResolutionY); + } + + if (this._pendingApplyResolutionChange) { + this._requestRemoteResize(); + } + + if (this._pendingApplyEncodingChanges) { + this._sendEncodings(); + } + + this._pendingApplyVideoRes = false; + this._pendingApplyEncodingChanges = false; + this._pendingApplyResolutionChange = false; + } + + } + + disconnect() { + this._updateConnectionState('disconnecting'); + this._sock.off('error'); + this._sock.off('message'); + this._sock.off('open'); + } + + sendCredentials(creds) { + this._rfbCredentials = creds; + setTimeout(this._initMsg.bind(this), 0); + } + + sendCtrlAltDel() { + if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; } + Log.Info("Sending Ctrl-Alt-Del"); + + this.sendKey(KeyTable.XK_Control_L, "ControlLeft", true); + this.sendKey(KeyTable.XK_Alt_L, "AltLeft", true); + this.sendKey(KeyTable.XK_Delete, "Delete", true); + this.sendKey(KeyTable.XK_Delete, "Delete", false); + this.sendKey(KeyTable.XK_Alt_L, "AltLeft", false); + this.sendKey(KeyTable.XK_Control_L, "ControlLeft", false); + } + + machineShutdown() { + this._xvpOp(1, 2); + } + + machineReboot() { + this._xvpOp(1, 3); + } + + machineReset() { + this._xvpOp(1, 4); + } + + // Send a key press. If 'down' is not specified then send a down key + // followed by an up key. + sendKey(keysym, code, down) { + if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; } + + if (code !== null) { + this._setLastActive(); + } + + if (down === undefined) { + this.sendKey(keysym, code, true); + this.sendKey(keysym, code, false); + return; + } + + const scancode = XtScancode[code]; + + if (this._qemuExtKeyEventSupported && scancode) { + // 0 is NoSymbol + keysym = keysym || 0; + + Log.Info("Sending key (" + (down ? "down" : "up") + "): keysym " + keysym + ", scancode " + scancode); + + RFB.messages.QEMUExtendedKeyEvent(this._sock, keysym, down, scancode); + } else { + if (!keysym) { + return; + } + Log.Info("Sending keysym (" + (down ? "down" : "up") + "): " + keysym); + RFB.messages.keyEvent(this._sock, keysym, down ? 1 : 0); + } + } + + focus() { + this._keyboard.focus(); + } + + blur() { + this._keyboard.blur(); + } + + checkLocalClipboard() { + if (this.clipboardUp && this.clipboardSeamless && this._resendClipboardNextUserDrivenEvent) { + this._resendClipboardNextUserDrivenEvent = false; + if (this.clipboardBinary) { + navigator.clipboard.read().then((data) => { + this.clipboardPasteDataFrom(data); + }, (err) => { + Log.Debug("No data in clipboard: " + err); + }); + } else { + if (navigator.clipboard && navigator.clipboard.readText) { + navigator.clipboard.readText().then(function (text) { + this.clipboardPasteFrom(text); + }.bind(this)).catch(function () { + return Log.Debug("Failed to read system clipboard"); + }); + } + } + } + } + + clipboardPasteFrom(text) { + if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; } + if (!(typeof text === 'string' && text.length > 0)) { return; } + + let data = new TextEncoder().encode(text); + + let h = hashUInt8Array(data); + // avoid resending the same data if larger than 64k + if (h === this._clipHash) { + Log.Debug('No clipboard changes'); + return; + } else { + this._clipHash = h; + } + + let dataset = []; + let mimes = [ 'text/plain' ]; + dataset.push(data); + + RFB.messages.sendBinaryClipboard(this._sock, dataset, mimes); + } + + async clipboardPasteDataFrom(clipdata) { + if (this._rfbConnectionState !== 'connected' || this._viewOnly) { return; } + + let dataset = []; + let mimes = []; + let h = 0; + for (let i = 0; i < clipdata.length; i++) { + for (let ti = 0; ti < clipdata[i].types.length; ti++) { + let mime = clipdata[i].types[ti]; + + switch (mime) { + case 'image/png': + case 'text/plain': + case 'text/html': + let blob = await clipdata[i].getType(mime); + if (!blob) { + continue; + } + let buff = await blob.arrayBuffer(); + let data = new Uint8Array(buff); + + if (!h) { + h = hashUInt8Array(data); + // avoid resending the same data if larger than 64k + if (h === this._clipHash) { + Log.Debug('No clipboard changes'); + return; + } else { + this._clipHash = h; + } + } + + if (mimes.includes(mime)) { + continue; + } + + mimes.push(mime); + dataset.push(data); + Log.Debug('Sending mime type: ' + mime); + break; + default: + Log.Info('skipping clip send mime type: ' + mime) + } + + } + } + + //if png is present and text/plain is not, remove other variations of images to save bandwidth + //if png is present with text/plain, then remove png. Word will put in a png of copied text + if (mimes.includes('image/png') && !mimes.includes('text/plain')) { + let i = mimes.indexOf('image/png'); + mimes = mimes.slice(i, i+1); + dataset = dataset.slice(i, i+1); + } else if (mimes.includes('image/png') && mimes.includes('text/plain')) { + let i = mimes.indexOf('image/png'); + mimes.splice(i, 1); + dataset.splice(i, 1); + } + + + if (dataset.length > 0) { + RFB.messages.sendBinaryClipboard(this._sock, dataset, mimes); + } + + } + + requestBottleneckStats() { + RFB.messages.requestStats(this._sock); + } + + subscribeUnixRelay(name, processRelayFn) { + this._unixRelays = this._unixRelays || {}; + this._unixRelays[name] = processRelayFn; + RFB.messages.sendSubscribeUnixRelay(this._sock, name); + } + + sendUnixRelayData(name, payload) { + RFB.messages.sendUnixRelay(this._sock, name, payload); + } + + // ===== PRIVATE METHODS ===== + + _setLastActive() { + this.lastActiveAt = Date.now(); + } + + _changeTransitConnectionState(value) { + Log.Info("Transit state change from " + this._transitConnectionState.toString() + ' to ' + value.toString()); + this._transitConnectionState = value; + } + + _connect() { + Log.Debug(">> RFB.connect"); + + if (this._url) { + try { + Log.Info(`connecting to ${this._url}`); + this._sock.open(this._url, this._wsProtocols); + this._setLastActive(); + } catch (e) { + if (e.name === 'SyntaxError') { + this._fail("Invalid host or port (" + e + ")"); + } else { + this._fail("Error when opening socket (" + e + ")"); + } + } + } else { + try { + Log.Info(`attaching ${this._rawChannel} to Websock`); + this._sock.attach(this._rawChannel); + } catch (e) { + this._fail("Error attaching channel (" + e + ")"); + } + } + + // Make our elements part of the page + this._target.appendChild(this._screen); + + this._gestures.attach(this._canvas); + + this._cursor.attach(this._canvas); + this._refreshCursor(); + + // Monitor size changes of the screen + // FIXME: Use ResizeObserver, or hidden overflow + window.addEventListener('resize', this._eventHandlers.windowResize); + + // Always grab focus on some kind of click event + this._canvas.addEventListener("mousedown", this._eventHandlers.focusCanvas); + this._canvas.addEventListener("touchstart", this._eventHandlers.focusCanvas); + this._canvas.addEventListener("focus", this._eventHandlers.handleFocusChange); + window.addEventListener("focus", this._eventHandlers.handleFocusChange); + window.addEventListener("blur", this._eventHandlers.handleFocusChange); + + // In order for the keyboard to not occlude the input being edited + // we move the hidden input we use for triggering the keyboard to the last click + // position which should trigger a page being moved down enough + // to show the input. On Android the whole website gets resized so we don't + // have to do anything. + if (isIOS()) { + this._canvas.addEventListener("touchend", this._eventHandlers.updateHiddenKeyboard); + } + + // Mouse events + this._canvas.addEventListener('mousedown', this._eventHandlers.handleMouse); + this._canvas.addEventListener('mouseup', this._eventHandlers.handleMouse); + this._canvas.addEventListener('mousemove', this._eventHandlers.handleMouse); + // Prevent middle-click pasting (see handler for why we bind to document) + this._canvas.addEventListener('click', this._eventHandlers.handleMouse); + // preventDefault() on mousedown doesn't stop this event for some + // reason so we have to explicitly block it + this._canvas.addEventListener('contextmenu', this._eventHandlers.handleMouse); + + // Pointer Lock listeners need to be installed in document instead of the canvas. + if (document.onpointerlockchange !== undefined) { + document.addEventListener('pointerlockchange', this._eventHandlers.handlePointerLockChange, false); + document.addEventListener('pointerlockerror', this._eventHandlers.handlePointerLockError, false); + } else if (document.onmozpointerlockchange !== undefined) { + document.addEventListener('mozpointerlockchange', this._eventHandlers.handlePointerLockChange, false); + document.addEventListener('mozpointerlockerror', this._eventHandlers.handlePointerLockError, false); + } + + // Wheel events + this._canvas.addEventListener("wheel", this._eventHandlers.handleWheel); + + // Gesture events + this._canvas.addEventListener("gesturestart", this._eventHandlers.handleGesture); + this._canvas.addEventListener("gesturemove", this._eventHandlers.handleGesture); + this._canvas.addEventListener("gestureend", this._eventHandlers.handleGesture); + + this._resendClipboardNextUserDrivenEvent = true; + + // WebRTC UDP datachannel inits + if (typeof RTCPeerConnection !== 'undefined') { + this._udpBuffer = new Map(); + + this._udpPeer = new RTCPeerConnection({ + iceServers: [{ + urls: ["stun:stun.l.google.com:19302"] + }] + }); + let peer = this._udpPeer; + + peer.onicecandidate = function(e) { + if (e.candidate) + Log.Debug("received ice candidate", e.candidate); + else + Log.Debug("all candidates received"); + } + + peer.ondatachannel = function(e) { + Log.Debug("peer connection on data channel", e); + } + + this._udpChannel = peer.createDataChannel("webudp", { + ordered: false, + maxRetransmits: 0 + }); + this._udpChannel.binaryType = "arraybuffer"; + + this._udpChannel.onerror = function(e) { + Log.Error("data channel error " + e.message); + this._udpTransitFailures+=1; + this._sendUdpDowngrade(); + } + + let sock = this._sock; + let udpBuffer = this._udpBuffer; + let me = this; + this._udpChannel.onmessage = function(e) { + //Log.Info("got udp msg", e.data); + const u8 = new Uint8Array(e.data); + // Got an UDP packet. Do we need reassembly? + const id = parseInt(u8[0] + + (u8[1] << 8) + + (u8[2] << 16) + + (u8[3] << 24), 10); + const i = parseInt(u8[4] + + (u8[5] << 8) + + (u8[6] << 16) + + (u8[7] << 24), 10); + const pieces = parseInt(u8[8] + + (u8[9] << 8) + + (u8[10] << 16) + + (u8[11] << 24), 10); + const hash = parseInt(u8[12] + + (u8[13] << 8) + + (u8[14] << 16) + + (u8[15] << 24), 10); + // TODO: check the hash. It's the low 32 bits of XXH64, seed 0 + const frame_id = parseInt(u8[16] + + (u8[17] << 8) + + (u8[18] << 16) + + (u8[19] << 24), 10); + + if (me._transitConnectionState !== me.TransitConnectionStates.Udp) { + me._display.clear(); + me._changeTransitConnectionState(me.TransitConnectionStates.Udp); + } + + if (pieces == 1) { // Handle it immediately + me._handleUdpRect(u8.slice(20), frame_id); + } else { // Use buffer + const now = Date.now(); + + if (udpBuffer.has(id)) { + let item = udpBuffer.get(id); + item.recieved_pieces += 1; + item.data[i] = u8.slice(20); + item.total_bytes += item.data[i].length; + + if (item.total_pieces == item.recieved_pieces) { + // Message is complete, combile data into a single array + var finaldata = new Uint8Array(item.total_bytes); + let z = 0; + for (let x = 0; x < item.data.length; x++) { + finaldata.set(item.data[x], z); + z += item.data[x].length; + } + udpBuffer.delete(id); + me._handleUdpRect(finaldata, frame_id); + } + } else { + let item = { + total_pieces: pieces, // number of pieces expected + arrival: now, //time first piece was recieved + recieved_pieces: 1, // current number of pieces in data + total_bytes: 0, // total size of all data pieces combined + data: new Array(pieces) + } + item.data[i] = u8.slice(20); + item.total_bytes = item.data[i].length; + udpBuffer.set(id, item); + } + } + } + } + + if (this._useUdp && typeof RTCPeerConnection !== 'undefined') { + setTimeout(function() { this._sendUdpUpgrade() }.bind(this), 3000); + } + + Log.Debug("<< RFB.connect"); + } + + _disconnect() { + Log.Debug(">> RFB.disconnect"); + this._cursor.detach(); + this._canvas.removeEventListener("gesturestart", this._eventHandlers.handleGesture); + this._canvas.removeEventListener("gesturemove", this._eventHandlers.handleGesture); + this._canvas.removeEventListener("gestureend", this._eventHandlers.handleGesture); + this._canvas.removeEventListener("wheel", this._eventHandlers.handleWheel); + this._canvas.removeEventListener('mousedown', this._eventHandlers.handleMouse); + this._canvas.removeEventListener('mouseup', this._eventHandlers.handleMouse); + this._canvas.removeEventListener('mousemove', this._eventHandlers.handleMouse); + this._canvas.removeEventListener('click', this._eventHandlers.handleMouse); + this._canvas.removeEventListener('contextmenu', this._eventHandlers.handleMouse); + if (document.onpointerlockchange !== undefined) { + document.removeEventListener('pointerlockchange', this._eventHandlers.handlePointerLockChange); + document.removeEventListener('pointerlockerror', this._eventHandlers.handlePointerLockError); + } else if (document.onmozpointerlockchange !== undefined) { + document.removeEventListener('mozpointerlockchange', this._eventHandlers.handlePointerLockChange); + document.removeEventListener('mozpointerlockerror', this._eventHandlers.handlePointerLockError); + } + this._canvas.removeEventListener("mousedown", this._eventHandlers.focusCanvas); + this._canvas.removeEventListener("touchstart", this._eventHandlers.focusCanvas); + this._canvas.removeEventListener("focus", this._eventHandlers.handleFocusChange); + window.removeEventListener('resize', this._eventHandlers.windowResize); + window.removeEventListener('focus', this._eventHandlers.handleFocusChange); + window.removeEventListener('focus', this._eventHandlers.handleFocusChange); + this._keyboard.ungrab(); + this._gestures.detach(); + this._sock.close(); + try { + this._target.removeChild(this._screen); + } catch (e) { + if (e.name === 'NotFoundError') { + // Some cases where the initial connection fails + // can disconnect before the _screen is created + } else { + throw e; + } + } + this._display.dispose(); + clearTimeout(this._resizeTimeout); + clearTimeout(this._mouseMoveTimer); + Log.Debug("<< RFB.disconnect"); + } + + _updateHiddenKeyboard(event) { + // On iOS 15 the navigation bar is at the bottom so we need to account for it + const y = Math.max(0, event.pageY - 50); + document.querySelector("#noVNC_keyboardinput").style.top = `${y}px`; + } + + _handleFocusChange(event) { + this._resendClipboardNextUserDrivenEvent = true; + } + + _focusCanvas(event) { + // Hack: + // On most mobile phones it's possible to play audio + // only if it's triggered by user action. It's also + // impossible to listen for touch events on child frames (on mobile phones) + // so we catch those events here but forward the audio unlocking to the parent window + window.parent.postMessage({ + action: "enable_audio", + value: null + }, "*"); + + // Re-enable pointerLock if relative cursor is enabled + // pointerLock must come from user initiated event + if (!this._pointerLock && this._pointerRelativeEnabled) { + this.pointerLock = true; + } + + if (this._resendClipboardNextUserDrivenEvent) { + this.checkLocalClipboard(); + } + + if (!this.focusOnClick) { + return; + } + + this.focus(); + + } + + _setDesktopName(name) { + this._fbName = name; + this.dispatchEvent(new CustomEvent( + "desktopname", + { detail: { name: this._fbName } })); + } + + _windowResize(event) { + // If the window resized then our screen element might have + // as well. Update the viewport dimensions. + window.requestAnimationFrame(() => { + this._updateClip(); + this._updateScale(); + }); + + if (this._resizeSession) { + // Request changing the resolution of the remote display to + // the size of the local browser viewport. + + // In order to not send multiple requests before the browser-resize + // is finished we wait 0.5 seconds before sending the request. + clearTimeout(this._resizeTimeout); + this._resizeTimeout = setTimeout(this._requestRemoteResize.bind(this), 500); + } + } + + // Update state of clipping in Display object, and make sure the + // configured viewport matches the current screen size + _updateClip() { + const curClip = this._display.clipViewport; + let newClip = this._clipViewport; + + if (this._scaleViewport) { + // Disable viewport clipping if we are scaling + newClip = false; + } + + if (curClip !== newClip) { + this._display.clipViewport = newClip; + } + + if (newClip) { + // When clipping is enabled, the screen is limited to + // the size of the container. + const size = this._screenSize(); + this._display.viewportChangeSize(size.w, size.h); + this._fixScrollbars(); + } + } + + _updateScale() { + if (!this._scaleViewport) { + this._display.scale = 1.0; + } else { + const size = this._screenSize(false); + this._display.autoscale(size.w, size.h, size.scale); + } + this._fixScrollbars(); + } + + // Requests a change of remote desktop size. This message is an extension + // and may only be sent if we have received an ExtendedDesktopSize message + _requestRemoteResize() { + clearTimeout(this._resizeTimeout); + this._resizeTimeout = null; + + if (!this._resizeSession || this._viewOnly || + !this._supportsSetDesktopSize) { + return; + } + const size = this._screenSize(); + RFB.messages.setDesktopSize(this._sock, + Math.floor(size.w), Math.floor(size.h), + this._screenID, this._screenFlags); + + Log.Debug('Requested new desktop size: ' + + size.w + 'x' + size.h); + } + + // Gets the the size of the available screen + _screenSize (limited) { + if (limited === undefined) { + limited = true; + } + var x = this.forcedResolutionX || this._screen.offsetWidth; + var y = this.forcedResolutionY || this._screen.offsetHeight; + var scale = 0; // 0=auto + try { + if (x > 1280 && limited && this.videoQuality == 1) { + var ratio = y / x; + Log.Debug(ratio); + x = 1280; + y = x * ratio; + } + else if (limited && this.videoQuality == 0){ + x = 1280; + y = 720; + } else if (this._hiDpi == true) { + x = x * window.devicePixelRatio; + y = y * window.devicePixelRatio; + scale = 1 / window.devicePixelRatio; + } else if (this._display.antiAliasing === 0 && window.devicePixelRatio > 1 && x < 1000 && x > 0) { + // small device with high resolution, browser is essentially zooming greater than 200% + Log.Info('Device Pixel ratio: ' + window.devicePixelRatio + ' Reported Resolution: ' + x + 'x' + y); + let targetDevicePixelRatio = 1.5; + if (window.devicePixelRatio > 2) { targetDevicePixelRatio = 2; } + let scaledWidth = (x * window.devicePixelRatio) * (1 / targetDevicePixelRatio); + let scaleRatio = scaledWidth / x; + x = x * scaleRatio; + y = y * scaleRatio; + scale = 1 / scaleRatio; + Log.Info('Small device with hDPI screen detected, auto scaling at ' + scaleRatio + ' to ' + x + 'x' + y); + } + } catch (err) { + Log.Debug(err); + } + + return { w: x, + h: y, + scale: scale }; + } + + _fixScrollbars() { + // This is a hack because Chrome screws up the calculation + // for when scrollbars are needed. So to fix it we temporarily + // toggle them off and on. + const orig = this._screen.style.overflow; + this._screen.style.overflow = 'hidden'; + // Force Chrome to recalculate the layout by asking for + // an element's dimensions + this._screen.getBoundingClientRect(); + this._screen.style.overflow = orig; + } + + /* + * Connection states: + * connecting + * connected + * disconnecting + * disconnected - permanent state + */ + _updateConnectionState(state) { + const oldstate = this._rfbConnectionState; + + if (state === oldstate) { + Log.Debug("Already in state '" + state + "', ignoring"); + return; + } + + // The 'disconnected' state is permanent for each RFB object + if (oldstate === 'disconnected') { + Log.Error("Tried changing state of a disconnected RFB object"); + return; + } + + // Ensure proper transitions before doing anything + switch (state) { + case 'connected': + if (oldstate !== 'connecting') { + Log.Error("Bad transition to connected state, " + + "previous connection state: " + oldstate); + return; + } + break; + + case 'disconnected': + if (oldstate !== 'disconnecting') { + Log.Error("Bad transition to disconnected state, " + + "previous connection state: " + oldstate); + return; + } + break; + + case 'connecting': + if (oldstate !== '') { + Log.Error("Bad transition to connecting state, " + + "previous connection state: " + oldstate); + return; + } + break; + + case 'disconnecting': + if (oldstate !== 'connected' && oldstate !== 'connecting') { + Log.Error("Bad transition to disconnecting state, " + + "previous connection state: " + oldstate); + return; + } + break; + + default: + Log.Error("Unknown connection state: " + state); + return; + } + + // State change actions + + this._rfbConnectionState = state; + + Log.Debug("New state '" + state + "', was '" + oldstate + "'."); + + if (this._disconnTimer && state !== 'disconnecting') { + Log.Debug("Clearing disconnect timer"); + clearTimeout(this._disconnTimer); + this._disconnTimer = null; + + // make sure we don't get a double event + this._sock.off('close'); + } + + switch (state) { + case 'connecting': + this._connect(); + break; + + case 'connected': + this.dispatchEvent(new CustomEvent("connect", { detail: {} })); + break; + + case 'disconnecting': + this._disconnect(); + + this._disconnTimer = setTimeout(() => { + Log.Error("Disconnection timed out."); + this._updateConnectionState('disconnected'); + }, DISCONNECT_TIMEOUT * 1000); + break; + + case 'disconnected': + this.dispatchEvent(new CustomEvent( + "disconnect", { detail: + { clean: this._rfbCleanDisconnect } })); + break; + } + } + + /* Print errors and disconnect + * + * The parameter 'details' is used for information that + * should be logged but not sent to the user interface. + */ + _fail(details) { + switch (this._rfbConnectionState) { + case 'disconnecting': + Log.Error("Failed when disconnecting: " + details); + break; + case 'connected': + Log.Error("Failed while connected: " + details); + break; + case 'connecting': + Log.Error("Failed when connecting: " + details); + break; + default: + Log.Error("RFB failure: " + details); + break; + } + this._rfbCleanDisconnect = false; //This is sent to the UI + + // Transition to disconnected without waiting for socket to close + this._updateConnectionState('disconnecting'); + this._updateConnectionState('disconnected'); + + return false; + } + + _setCapability(cap, val) { + this._capabilities[cap] = val; + this.dispatchEvent(new CustomEvent("capabilities", + { detail: { capabilities: this._capabilities } })); + } + + _handleMessage() { + if (this._sock.rQlen === 0) { + Log.Warn("handleMessage called on an empty receive queue"); + return; + } + + switch (this._rfbConnectionState) { + case 'disconnected': + Log.Error("Got data while disconnected"); + break; + case 'connected': + while (true) { + if (this._flushing) { + break; + } + if (!this._normalMsg()) { + break; + } + if (this._sock.rQlen === 0) { + break; + } + } + break; + default: + this._initMsg(); + break; + } + } + + _handleKeyEvent(keysym, code, down) { + this.sendKey(keysym, code, down); + } + + _handleMouse(ev) { + /* + * We don't check connection status or viewOnly here as the + * mouse events might be used to control the viewport + */ + + if (ev.type === 'click') { + /* + * Note: This is only needed for the 'click' event as it fails + * to fire properly for the target element so we have + * to listen on the document element instead. + */ + if (ev.target !== this._canvas) { + return; + } + } + + // FIXME: if we're in view-only and not dragging, + // should we stop events? + ev.stopPropagation(); + ev.preventDefault(); + + if ((ev.type === 'click') || (ev.type === 'contextmenu')) { + return; + } + + let pos; + if (this._pointerLock && !this._pointerRelativeEnabled) { + let max_w = ((this._display.scale === 1) ? this._fbWidth : (this._fbWidth * this._display.scale)); + let max_h = ((this._display.scale === 1) ? this._fbHeight : (this._fbHeight * this._display.scale)); + pos = { + x: this._mousePos.x + ev.movementX, + y: this._mousePos.y + ev.movementY, + }; + if (pos.x < 0) { + pos.x = 0; + } else if (pos.x > max_w) { + pos.x = max_w; + } + if (pos.y < 0) { + pos.y = 0; + } else if (pos.y > max_h) { + pos.y = max_h; + } + this._cursor.move(pos.x, pos.y); + } else if (this._pointerLock && this._pointerRelativeEnabled) { + pos = { + x: this._mousePos.x + ev.movementX, + y: this._mousePos.y + ev.movementY, + }; + } else { + pos = clientToElement(ev.clientX, ev.clientY, + this._canvas); + } + + this._setLastActive(); + const mappedButton = this.mouseButtonMapper.get(ev.button); + switch (ev.type) { + case 'mousedown': + setCapture(this._canvas); + + // Translate CMD+Click into CTRL+click on MacOs + if ( + isMac() && + ev.metaKey && + (this._keyboard._keyDownList["MetaLeft"] || this._keyboard._keyDownList["MetaRight"]) + ) { + this._keyboard._sendKeyEvent(this._keyboard._keyDownList["MetaLeft"], "MetaLeft", false); + this._keyboard._sendKeyEvent(this._keyboard._keyDownList["MetaRight"], "MetaRight", false); + this._keyboard._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); + } + + this._handleMouseButton(pos.x, pos.y, + true, xvncButtonToMask(mappedButton)); + break; + case 'mouseup': + this._handleMouseButton(pos.x, pos.y, + false, xvncButtonToMask(mappedButton)); + break; + case 'mousemove': + this._handleMouseMove(pos.x, pos.y); + break; + } + } + + _handleMouseButton(x, y, down, bmask) { + if (this.dragViewport) { + if (down && !this._viewportDragging) { + this._viewportDragging = true; + this._viewportDragPos = {'x': x, 'y': y}; + this._viewportHasMoved = false; + + // Skip sending mouse events + return; + } else { + this._viewportDragging = false; + + // If we actually performed a drag then we are done + // here and should not send any mouse events + if (this._viewportHasMoved) { + return; + } + + // Otherwise we treat this as a mouse click event. + // Send the button down event here, as the button up + // event is sent at the end of this function. + this._sendMouse(x, y, bmask); + } + } + + // Flush waiting move event first + if (this._mouseMoveTimer !== null) { + clearTimeout(this._mouseMoveTimer); + this._mouseMoveTimer = null; + this._sendMouse(x, y, this._mouseButtonMask); + } + + if (down) { + this._mouseButtonMask |= bmask; + } else { + this._mouseButtonMask &= ~bmask; + } + + this._sendMouse(x, y, this._mouseButtonMask); + } + + _handleMouseMove(x, y) { + if (this._viewportDragging) { + const deltaX = this._viewportDragPos.x - x; + const deltaY = this._viewportDragPos.y - y; + + if (this._viewportHasMoved || (Math.abs(deltaX) > dragThreshold || + Math.abs(deltaY) > dragThreshold)) { + this._viewportHasMoved = true; + + this._viewportDragPos = {'x': x, 'y': y}; + this._display.viewportChangePos(deltaX, deltaY); + } + + // Skip sending mouse events + return; + } + + this._mousePos = { 'x': x, 'y': y }; + + // Limit many mouse move events to one every MOUSE_MOVE_DELAY ms + if (this._mouseMoveTimer == null) { + + const timeSinceLastMove = Date.now() - this._mouseLastMoveTime; + if (timeSinceLastMove > MOUSE_MOVE_DELAY) { + this._sendMouse(x, y, this._mouseButtonMask); + this._mouseLastMoveTime = Date.now(); + } else { + // Too soon since the latest move, wait the remaining time + this._mouseMoveTimer = setTimeout(() => { + this._handleDelayedMouseMove(); + }, MOUSE_MOVE_DELAY - timeSinceLastMove); + } + } + } + + _handleDelayedMouseMove() { + this._mouseMoveTimer = null; + this._sendMouse(this._mousePos.x, this._mousePos.y, + this._mouseButtonMask); + this._mouseLastMoveTime = Date.now(); + } + + _handlePointerLockChange(env) { + if ( + document.pointerLockElement === this._canvas || + document.mozPointerLockElement === this._canvas + ) { + this._pointerLock = true; + this._cursor.setEmulateCursor(true); + } else { + this._pointerLock = false; + this._cursor.setEmulateCursor(false); + } + this.dispatchEvent(new CustomEvent( + "inputlock", + { detail: { pointer: this._pointerLock }, })); + } + + _handlePointerLockError() { + this._pointerLockChanging = false; + this.dispatchEvent(new CustomEvent( + "inputlockerror", + { detail: { pointer: this._pointerLock }, })); + } + + _sendMouse(x, y, mask) { + if (this._rfbConnectionState !== 'connected') { return; } + if (this._viewOnly) { return; } // View only, skip mouse events + + if (this._pointerLock && this._pointerRelativeEnabled) { + + // Use releative cursor position + var rel_16_x = toSignedRelative16bit(x - this._pointerLockPos.x); + var rel_16_y = toSignedRelative16bit(y - this._pointerLockPos.y); + + //console.log("new_pos x" + x + ", y" + y); + //console.log("lock x " + this._pointerLockPos.x + ", y " + this._pointerLockPos.y); + //console.log("rel x " + rel_16_x + ", y " + rel_16_y); + + RFB.messages.pointerEvent(this._sock, rel_16_x, + rel_16_y, mask); + + // reset the cursor position to center + this._mousePos = { x: this._pointerLockPos.x , y: this._pointerLockPos.y }; + this._cursor.move(this._pointerLockPos.x, this._pointerLockPos.y); + } else { + RFB.messages.pointerEvent(this._sock, this._display.absX(x), + this._display.absY(y), mask); + } + + } + + _sendScroll(x, y, dX, dY) { + if (this._rfbConnectionState !== 'connected') { return; } + if (this._viewOnly) { return; } // View only, skip mouse events + + RFB.messages.pointerEvent(this._sock, this._display.absX(x), this._display.absY(y), 0, dX, dY); + } + + _handleWheel(ev) { + if (this._rfbConnectionState !== 'connected') { return; } + if (this._viewOnly) { return; } // View only, skip mouse events + + ev.stopPropagation(); + ev.preventDefault(); + + // On MacOs we need to translate zooming CMD+wheel to CTRL+wheel + if (isMac() && (this._keyboard._keyDownList["MetaLeft"] || this._keyboard._keyDownList["MetaRight"])) { + this._keyboard._sendKeyEvent(this._keyboard._keyDownList["MetaLeft"], "MetaLeft", false); + this._keyboard._sendKeyEvent(this._keyboard._keyDownList["MetaRight"], "MetaRight", false); + this._keyboard._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); + } + + // In a pinch and zoom gesture we're sending only a wheel event so we need + // to make sure a CTRL press event is sent alongside it if we want to trigger zooming. + // Moreover, we don't have a way to know that the gesture has stopped so we + // need to check manually every now and then and "unpress" the CTRL key when it ends. + if (ev.ctrlKey && !this._keyboard._keyDownList["ControlLeft"]) { + this._keyboard._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); + + this._watchForPinchAndZoom = this._watchForPinchAndZoom || setInterval(() => { + const timeSinceLastPinchAndZoom = +new Date() - this._mouseLastPinchAndZoomTime; + if (timeSinceLastPinchAndZoom > 250) { + clearInterval(this._watchForPinchAndZoom); + this._keyboard._sendKeyEvent(KeyTable.XK_Control_L, "ControlLeft", false); + this._watchForPinchAndZoom = null; + this._mouseLastPinchAndZoomTime = 0; + } + }, 10); + } + + if (this._watchForPinchAndZoom) { + this._mouseLastPinchAndZoomTime = +new Date(); + } + + // Pixel units unless it's non-zero. + // Note that if deltamode is line or page won't matter since we aren't + // sending the mouse wheel delta to the server anyway. + // The difference between pixel and line can be important however since + // we have a threshold that can be smaller than the line height. + let dX = ev.deltaX; + let dY = ev.deltaY; + + if (ev.deltaMode !== 0) { + dX *= WHEEL_LINE_HEIGHT; + dY *= WHEEL_LINE_HEIGHT; + } + + const pointer = clientToElement(ev.clientX, ev.clientY, this._canvas); + this._sendScroll(pointer.x, pointer.y, dX, dY); + } + + _fakeMouseMove(ev, elementX, elementY) { + this._handleMouseMove(elementX, elementY); + this._cursor.move(ev.detail.clientX, ev.detail.clientY); + } + + _handleTapEvent(ev, bmask) { + let pos = clientToElement(ev.detail.clientX, ev.detail.clientY, + this._canvas); + + // If the user quickly taps multiple times we assume they meant to + // hit the same spot, so slightly adjust coordinates + + if ((this._gestureLastTapTime !== null) && + ((Date.now() - this._gestureLastTapTime) < DOUBLE_TAP_TIMEOUT) && + (this._gestureFirstDoubleTapEv.detail.type === ev.detail.type)) { + let dx = this._gestureFirstDoubleTapEv.detail.clientX - ev.detail.clientX; + let dy = this._gestureFirstDoubleTapEv.detail.clientY - ev.detail.clientY; + let distance = Math.hypot(dx, dy); + + if (distance < DOUBLE_TAP_THRESHOLD) { + pos = clientToElement(this._gestureFirstDoubleTapEv.detail.clientX, + this._gestureFirstDoubleTapEv.detail.clientY, + this._canvas); + } else { + this._gestureFirstDoubleTapEv = ev; + } + } else { + this._gestureFirstDoubleTapEv = ev; + } + this._gestureLastTapTime = Date.now(); + + this._fakeMouseMove(this._gestureFirstDoubleTapEv, pos.x, pos.y); + this._handleMouseButton(pos.x, pos.y, true, bmask); + this._handleMouseButton(pos.x, pos.y, false, bmask); + } + + _handleGesture(ev) { + let magnitude; + + let pos = clientToElement(ev.detail.clientX, ev.detail.clientY, + this._canvas); + switch (ev.type) { + case 'gesturestart': + switch (ev.detail.type) { + case 'onetap': + this._handleTapEvent(ev, 0x1); + break; + case 'twotap': + this._handleTapEvent(ev, 0x4); + break; + case 'threetap': + this._handleTapEvent(ev, 0x2); + break; + case 'drag': + this._fakeMouseMove(ev, pos.x, pos.y); + this._handleMouseButton(pos.x, pos.y, true, 0x1); + break; + case 'longpress': + this._fakeMouseMove(ev, pos.x, pos.y); + this._handleMouseButton(pos.x, pos.y, true, 0x4); + break; + + case 'twodrag': + this._gestureLastMagnitudeX = ev.detail.magnitudeX; + this._gestureLastMagnitudeY = ev.detail.magnitudeY; + this._fakeMouseMove(ev, pos.x, pos.y); + break; + case 'pinch': + this._gestureLastMagnitudeX = Math.hypot(ev.detail.magnitudeX, + ev.detail.magnitudeY); + this._fakeMouseMove(ev, pos.x, pos.y); + break; + } + break; + + case 'gesturemove': + switch (ev.detail.type) { + case 'onetap': + case 'twotap': + case 'threetap': + break; + case 'drag': + case 'longpress': + this._fakeMouseMove(ev, pos.x, pos.y); + break; + case 'twodrag': + // Always scroll in the same position. + // We don't know if the mouse was moved so we need to move it + // every update. + this._fakeMouseMove(ev, pos.x, pos.y); + while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) > GESTURE_SCRLSENS) { + this._handleMouseButton(pos.x, pos.y, true, 0x8); + this._handleMouseButton(pos.x, pos.y, false, 0x8); + this._gestureLastMagnitudeY += GESTURE_SCRLSENS; + } + while ((ev.detail.magnitudeY - this._gestureLastMagnitudeY) < -GESTURE_SCRLSENS) { + this._handleMouseButton(pos.x, pos.y, true, 0x10); + this._handleMouseButton(pos.x, pos.y, false, 0x10); + this._gestureLastMagnitudeY -= GESTURE_SCRLSENS; + } + while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) > GESTURE_SCRLSENS) { + this._handleMouseButton(pos.x, pos.y, true, 0x20); + this._handleMouseButton(pos.x, pos.y, false, 0x20); + this._gestureLastMagnitudeX += GESTURE_SCRLSENS; + } + while ((ev.detail.magnitudeX - this._gestureLastMagnitudeX) < -GESTURE_SCRLSENS) { + this._handleMouseButton(pos.x, pos.y, true, 0x40); + this._handleMouseButton(pos.x, pos.y, false, 0x40); + this._gestureLastMagnitudeX -= GESTURE_SCRLSENS; + } + break; + case 'pinch': + // Always scroll in the same position. + // We don't know if the mouse was moved so we need to move it + // every update. + this._fakeMouseMove(ev, pos.x, pos.y); + magnitude = Math.hypot(ev.detail.magnitudeX, ev.detail.magnitudeY); + if (Math.abs(magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) { + this._handleKeyEvent(KeyTable.XK_Control_L, "ControlLeft", true); + while ((magnitude - this._gestureLastMagnitudeX) > GESTURE_ZOOMSENS) { + this._handleMouseButton(pos.x, pos.y, true, 0x8); + this._handleMouseButton(pos.x, pos.y, false, 0x8); + this._gestureLastMagnitudeX += GESTURE_ZOOMSENS; + } + while ((magnitude - this._gestureLastMagnitudeX) < -GESTURE_ZOOMSENS) { + this._handleMouseButton(pos.x, pos.y, true, 0x10); + this._handleMouseButton(pos.x, pos.y, false, 0x10); + this._gestureLastMagnitudeX -= GESTURE_ZOOMSENS; + } + } + this._handleKeyEvent(KeyTable.XK_Control_L, "ControlLeft", false); + break; + } + break; + + case 'gestureend': + switch (ev.detail.type) { + case 'onetap': + case 'twotap': + case 'threetap': + case 'pinch': + case 'twodrag': + break; + case 'drag': + this._fakeMouseMove(ev, pos.x, pos.y); + this._handleMouseButton(pos.x, pos.y, false, 0x1); + break; + case 'longpress': + this._fakeMouseMove(ev, pos.x, pos.y); + this._handleMouseButton(pos.x, pos.y, false, 0x4); + break; + } + break; + } + } + + // Message Handlers + + _negotiateProtocolVersion() { + if (this._sock.rQwait("version", 12)) { + return false; + } + + const sversion = this._sock.rQshiftStr(12).substr(4, 7); + Log.Info("Server ProtocolVersion: " + sversion); + let isRepeater = 0; + switch (sversion) { + case "000.000": // UltraVNC repeater + isRepeater = 1; + break; + case "003.003": + case "003.006": // UltraVNC + case "003.889": // Apple Remote Desktop + this._rfbVersion = 3.3; + break; + case "003.007": + this._rfbVersion = 3.7; + break; + case "003.008": + case "004.000": // Intel AMT KVM + case "004.001": // RealVNC 4.6 + case "005.000": // RealVNC 5.3 + this._rfbVersion = 3.8; + break; + default: + return this._fail("Invalid server version " + sversion); + } + + if (isRepeater) { + let repeaterID = "ID:" + this._repeaterID; + while (repeaterID.length < 250) { + repeaterID += "\0"; + } + this._sock.sendString(repeaterID); + return true; + } + + if (this._rfbVersion > this._rfbMaxVersion) { + this._rfbVersion = this._rfbMaxVersion; + } + + const cversion = "00" + parseInt(this._rfbVersion, 10) + + ".00" + ((this._rfbVersion * 10) % 10); + this._sock.sendString("RFB " + cversion + "\n"); + Log.Debug('Sent ProtocolVersion: ' + cversion); + + this._rfbInitState = 'Security'; + } + + _negotiateSecurity() { + if (this._rfbVersion >= 3.7) { + // Server sends supported list, client decides + const numTypes = this._sock.rQshift8(); + if (this._sock.rQwait("security type", numTypes, 1)) { return false; } + + if (numTypes === 0) { + this._rfbInitState = "SecurityReason"; + this._securityContext = "no security types"; + this._securityStatus = 1; + return this._initMsg(); + } + + const types = this._sock.rQshiftBytes(numTypes); + Log.Debug("Server security types: " + types); + + // Look for each auth in preferred order + if (types.includes(1)) { + this._rfbAuthScheme = 1; // None + } else if (types.includes(22)) { + this._rfbAuthScheme = 22; // XVP + } else if (types.includes(16)) { + this._rfbAuthScheme = 16; // Tight + } else if (types.includes(2)) { + this._rfbAuthScheme = 2; // VNC Auth + } else if (types.includes(19)) { + this._rfbAuthScheme = 19; // VeNCrypt Auth + } else { + return this._fail("Unsupported security types (types: " + types + ")"); + } + + this._sock.send([this._rfbAuthScheme]); + } else { + // Server decides + if (this._sock.rQwait("security scheme", 4)) { return false; } + this._rfbAuthScheme = this._sock.rQshift32(); + + if (this._rfbAuthScheme == 0) { + this._rfbInitState = "SecurityReason"; + this._securityContext = "authentication scheme"; + this._securityStatus = 1; + return this._initMsg(); + } + } + + this._rfbInitState = 'Authentication'; + Log.Debug('Authenticating using scheme: ' + this._rfbAuthScheme); + + return this._initMsg(); // jump to authentication + } + + _handleSecurityReason() { + if (this._sock.rQwait("reason length", 4)) { + return false; + } + const strlen = this._sock.rQshift32(); + let reason = ""; + + if (strlen > 0) { + if (this._sock.rQwait("reason", strlen, 4)) { return false; } + reason = this._sock.rQshiftStr(strlen); + } + + if (reason !== "") { + this.dispatchEvent(new CustomEvent( + "securityfailure", + { detail: { status: this._securityStatus, + reason: reason } })); + + return this._fail("Security negotiation failed on " + + this._securityContext + + " (reason: " + reason + ")"); + } else { + this.dispatchEvent(new CustomEvent( + "securityfailure", + { detail: { status: this._securityStatus } })); + + return this._fail("Security negotiation failed on " + + this._securityContext); + } + } + + // authentication + _negotiateXvpAuth() { + if (this._rfbCredentials.username === undefined || + this._rfbCredentials.password === undefined || + this._rfbCredentials.target === undefined) { + this.dispatchEvent(new CustomEvent( + "credentialsrequired", + { detail: { types: ["username", "password", "target"] } })); + return false; + } + + const xvpAuthStr = String.fromCharCode(this._rfbCredentials.username.length) + + String.fromCharCode(this._rfbCredentials.target.length) + + this._rfbCredentials.username + + this._rfbCredentials.target; + this._sock.sendString(xvpAuthStr); + this._rfbAuthScheme = 2; + return this._negotiateAuthentication(); + } + + // VeNCrypt authentication, currently only supports version 0.2 and only Plain subtype + _negotiateVeNCryptAuth() { + + // waiting for VeNCrypt version + if (this._rfbVeNCryptState == 0) { + if (this._sock.rQwait("vencrypt version", 2)) { return false; } + + const major = this._sock.rQshift8(); + const minor = this._sock.rQshift8(); + + if (!(major == 0 && minor == 2)) { + return this._fail("Unsupported VeNCrypt version " + major + "." + minor); + } + + this._sock.send([0, 2]); + this._rfbVeNCryptState = 1; + } + + // waiting for ACK + if (this._rfbVeNCryptState == 1) { + if (this._sock.rQwait("vencrypt ack", 1)) { return false; } + + const res = this._sock.rQshift8(); + + if (res != 0) { + return this._fail("VeNCrypt failure " + res); + } + + this._rfbVeNCryptState = 2; + } + // must fall through here (i.e. no "else if"), beacause we may have already received + // the subtypes length and won't be called again + + if (this._rfbVeNCryptState == 2) { // waiting for subtypes length + if (this._sock.rQwait("vencrypt subtypes length", 1)) { return false; } + + const subtypesLength = this._sock.rQshift8(); + if (subtypesLength < 1) { + return this._fail("VeNCrypt subtypes empty"); + } + + this._rfbVeNCryptSubtypesLength = subtypesLength; + this._rfbVeNCryptState = 3; + } + + // waiting for subtypes list + if (this._rfbVeNCryptState == 3) { + if (this._sock.rQwait("vencrypt subtypes", 4 * this._rfbVeNCryptSubtypesLength)) { return false; } + + const subtypes = []; + for (let i = 0; i < this._rfbVeNCryptSubtypesLength; i++) { + subtypes.push(this._sock.rQshift32()); + } + + // 256 = Plain subtype + if (subtypes.indexOf(256) != -1) { + // 0x100 = 256 + this._sock.send([0, 0, 1, 0]); + this._rfbVeNCryptState = 4; + } else { + return this._fail("VeNCrypt Plain subtype not offered by server"); + } + } + + // negotiated Plain subtype, server waits for password + if (this._rfbVeNCryptState == 4) { + if (this._rfbCredentials.username === undefined || + this._rfbCredentials.password === undefined) { + this.dispatchEvent(new CustomEvent( + "credentialsrequired", + { detail: { types: ["username", "password"] } })); + return false; + } + + const user = encodeUTF8(this._rfbCredentials.username); + const pass = encodeUTF8(this._rfbCredentials.password); + + this._sock.send([ + (user.length >> 24) & 0xFF, + (user.length >> 16) & 0xFF, + (user.length >> 8) & 0xFF, + user.length & 0xFF + ]); + this._sock.send([ + (pass.length >> 24) & 0xFF, + (pass.length >> 16) & 0xFF, + (pass.length >> 8) & 0xFF, + pass.length & 0xFF + ]); + this._sock.sendString(user); + this._sock.sendString(pass); + + this._rfbInitState = "SecurityResult"; + return true; + } + } + + _negotiateStdVNCAuth() { + if (this._sock.rQwait("auth challenge", 16)) { return false; } + + // KasmVNC uses basic Auth, clear the VNC password, which is not used + this._rfbCredentials.password = ""; + + // TODO(directxman12): make genDES not require an Array + const challenge = Array.prototype.slice.call(this._sock.rQshiftBytes(16)); + const response = RFB.genDES(this._rfbCredentials.password, challenge); + this._sock.send(response); + this._rfbInitState = "SecurityResult"; + return true; + } + + _negotiateTightUnixAuth() { + if (this._rfbCredentials.username === undefined || + this._rfbCredentials.password === undefined) { + this.dispatchEvent(new CustomEvent( + "credentialsrequired", + { detail: { types: ["username", "password"] } })); + return false; + } + + this._sock.send([0, 0, 0, this._rfbCredentials.username.length]); + this._sock.send([0, 0, 0, this._rfbCredentials.password.length]); + this._sock.sendString(this._rfbCredentials.username); + this._sock.sendString(this._rfbCredentials.password); + this._rfbInitState = "SecurityResult"; + return true; + } + + _negotiateTightTunnels(numTunnels) { + const clientSupportedTunnelTypes = { + 0: { vendor: 'TGHT', signature: 'NOTUNNEL' } + }; + const serverSupportedTunnelTypes = {}; + // receive tunnel capabilities + for (let i = 0; i < numTunnels; i++) { + const capCode = this._sock.rQshift32(); + const capVendor = this._sock.rQshiftStr(4); + const capSignature = this._sock.rQshiftStr(8); + serverSupportedTunnelTypes[capCode] = { vendor: capVendor, signature: capSignature }; + } + + Log.Debug("Server Tight tunnel types: " + serverSupportedTunnelTypes); + + // Siemens touch panels have a VNC server that supports NOTUNNEL, + // but forgets to advertise it. Try to detect such servers by + // looking for their custom tunnel type. + if (serverSupportedTunnelTypes[1] && + (serverSupportedTunnelTypes[1].vendor === "SICR") && + (serverSupportedTunnelTypes[1].signature === "SCHANNEL")) { + Log.Debug("Detected Siemens server. Assuming NOTUNNEL support."); + serverSupportedTunnelTypes[0] = { vendor: 'TGHT', signature: 'NOTUNNEL' }; + } + + // choose the notunnel type + if (serverSupportedTunnelTypes[0]) { + if (serverSupportedTunnelTypes[0].vendor != clientSupportedTunnelTypes[0].vendor || + serverSupportedTunnelTypes[0].signature != clientSupportedTunnelTypes[0].signature) { + return this._fail("Client's tunnel type had the incorrect " + + "vendor or signature"); + } + Log.Debug("Selected tunnel type: " + clientSupportedTunnelTypes[0]); + this._sock.send([0, 0, 0, 0]); // use NOTUNNEL + return false; // wait until we receive the sub auth count to continue + } else { + return this._fail("Server wanted tunnels, but doesn't support " + + "the notunnel type"); + } + } + + _negotiateTightAuth() { + if (!this._rfbTightVNC) { // first pass, do the tunnel negotiation + if (this._sock.rQwait("num tunnels", 4)) { return false; } + const numTunnels = this._sock.rQshift32(); + if (numTunnels > 0 && this._sock.rQwait("tunnel capabilities", 16 * numTunnels, 4)) { return false; } + + this._rfbTightVNC = true; + + if (numTunnels > 0) { + this._negotiateTightTunnels(numTunnels); + return false; // wait until we receive the sub auth to continue + } + } + + // second pass, do the sub-auth negotiation + if (this._sock.rQwait("sub auth count", 4)) { return false; } + const subAuthCount = this._sock.rQshift32(); + if (subAuthCount === 0) { // empty sub-auth list received means 'no auth' subtype selected + this._rfbInitState = 'SecurityResult'; + return true; + } + + if (this._sock.rQwait("sub auth capabilities", 16 * subAuthCount, 4)) { return false; } + + const clientSupportedTypes = { + 'STDVNOAUTH__': 1, + 'STDVVNCAUTH_': 2, + 'TGHTULGNAUTH': 129 + }; + + const serverSupportedTypes = []; + + for (let i = 0; i < subAuthCount; i++) { + this._sock.rQshift32(); // capNum + const capabilities = this._sock.rQshiftStr(12); + serverSupportedTypes.push(capabilities); + } + + Log.Debug("Server Tight authentication types: " + serverSupportedTypes); + + for (let authType in clientSupportedTypes) { + if (serverSupportedTypes.indexOf(authType) != -1) { + this._sock.send([0, 0, 0, clientSupportedTypes[authType]]); + Log.Debug("Selected authentication type: " + authType); + + switch (authType) { + case 'STDVNOAUTH__': // no auth + this._rfbInitState = 'SecurityResult'; + return true; + case 'STDVVNCAUTH_': // VNC auth + this._rfbAuthScheme = 2; + return this._initMsg(); + case 'TGHTULGNAUTH': // UNIX auth + this._rfbAuthScheme = 129; + return this._initMsg(); + default: + return this._fail("Unsupported tiny auth scheme " + + "(scheme: " + authType + ")"); + } + } + } + + return this._fail("No supported sub-auth types!"); + } + + _negotiateAuthentication() { + switch (this._rfbAuthScheme) { + case 1: // no auth + if (this._rfbVersion >= 3.8) { + this._rfbInitState = 'SecurityResult'; + return true; + } + this._rfbInitState = 'ClientInitialisation'; + return this._initMsg(); + + case 22: // XVP auth + return this._negotiateXvpAuth(); + + case 2: // VNC authentication + return this._negotiateStdVNCAuth(); + + case 16: // TightVNC Security Type + return this._negotiateTightAuth(); + + case 19: // VeNCrypt Security Type + return this._negotiateVeNCryptAuth(); + + case 129: // TightVNC UNIX Security Type + return this._negotiateTightUnixAuth(); + + default: + return this._fail("Unsupported auth scheme (scheme: " + + this._rfbAuthScheme + ")"); + } + } + + _handleSecurityResult() { + if (this._sock.rQwait('VNC auth response ', 4)) { return false; } + + const status = this._sock.rQshift32(); + + if (status === 0) { // OK + this._rfbInitState = 'ClientInitialisation'; + Log.Debug('Authentication OK'); + return this._initMsg(); + } else { + if (this._rfbVersion >= 3.8) { + this._rfbInitState = "SecurityReason"; + this._securityContext = "security result"; + this._securityStatus = status; + return this._initMsg(); + } else { + this.dispatchEvent(new CustomEvent( + "securityfailure", + { detail: { status: status } })); + + return this._fail("Security handshake failed"); + } + } + } + + _negotiateServerInit() { + if (this._sock.rQwait("server initialization", 24)) { return false; } + + /* Screen size */ + const width = this._sock.rQshift16(); + const height = this._sock.rQshift16(); + + /* PIXEL_FORMAT */ + const bpp = this._sock.rQshift8(); + const depth = this._sock.rQshift8(); + const bigEndian = this._sock.rQshift8(); + const trueColor = this._sock.rQshift8(); + + const redMax = this._sock.rQshift16(); + const greenMax = this._sock.rQshift16(); + const blueMax = this._sock.rQshift16(); + const redShift = this._sock.rQshift8(); + const greenShift = this._sock.rQshift8(); + const blueShift = this._sock.rQshift8(); + this._sock.rQskipBytes(3); // padding + + // NB(directxman12): we don't want to call any callbacks or print messages until + // *after* we're past the point where we could backtrack + + /* Connection name/title */ + const nameLength = this._sock.rQshift32(); + if (this._sock.rQwait('server init name', nameLength, 24)) { return false; } + let name = this._sock.rQshiftStr(nameLength); + name = decodeUTF8(name, true); + + if (this._rfbTightVNC) { + if (this._sock.rQwait('TightVNC extended server init header', 8, 24 + nameLength)) { return false; } + // In TightVNC mode, ServerInit message is extended + const numServerMessages = this._sock.rQshift16(); + const numClientMessages = this._sock.rQshift16(); + const numEncodings = this._sock.rQshift16(); + this._sock.rQskipBytes(2); // padding + + const totalMessagesLength = (numServerMessages + numClientMessages + numEncodings) * 16; + if (this._sock.rQwait('TightVNC extended server init header', totalMessagesLength, 32 + nameLength)) { return false; } + + // we don't actually do anything with the capability information that TIGHT sends, + // so we just skip the all of this. + + // TIGHT server message capabilities + this._sock.rQskipBytes(16 * numServerMessages); + + // TIGHT client message capabilities + this._sock.rQskipBytes(16 * numClientMessages); + + // TIGHT encoding capabilities + this._sock.rQskipBytes(16 * numEncodings); + } + + // NB(directxman12): these are down here so that we don't run them multiple times + // if we backtrack + Log.Info("Screen: " + width + "x" + height + + ", bpp: " + bpp + ", depth: " + depth + + ", bigEndian: " + bigEndian + + ", trueColor: " + trueColor + + ", redMax: " + redMax + + ", greenMax: " + greenMax + + ", blueMax: " + blueMax + + ", redShift: " + redShift + + ", greenShift: " + greenShift + + ", blueShift: " + blueShift); + + // we're past the point where we could backtrack, so it's safe to call this + this._setDesktopName(name); + this._resize(width, height); + + if (!this._viewOnly) { this._keyboard.grab(); } + + this._fbDepth = 24; + + if (this._fbName === "Intel(r) AMT KVM") { + Log.Warn("Intel AMT KVM only supports 8/16 bit depths. Using low color mode."); + this._fbDepth = 8; + } + + RFB.messages.pixelFormat(this._sock, this._fbDepth, true); + this._sendEncodings(); + RFB.messages.fbUpdateRequest(this._sock, false, 0, 0, this._fbWidth, this._fbHeight); + + this._updateConnectionState('connected'); + + //Register pipe based extensions + initializePrinterRelay(this); + + return true; + } + + _hasWebp() { + /* + return new Promise(res => { + const webP = new Image(); + webP.src = 'data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA'; + webP.onload = webP.onerror = function () { + res(webP.height === 2); + }; + }) + */ + if (!this.enableWebP) + return false; + // It's not possible to check for webp synchronously, and hacking promises + // into everything would be too time-consuming. So test for FF and Chrome. + var uagent = navigator.userAgent.toLowerCase(); + var match = uagent.match(/firefox\/([0-9]+)\./); + if (match && parseInt(match[1]) >= 65) + return true; + match = uagent.match(/chrome\/([0-9]+)\./); + if (match && parseInt(match[1]) >= 23) + return true; + return false; + } + + _sendEncodings() { + const encs = []; + + // In preference order + encs.push(encodings.encodingCopyRect); + // Only supported with full depth support + if (this._fbDepth == 24) { + encs.push(encodings.encodingTight); + encs.push(encodings.encodingTightPNG); + encs.push(encodings.encodingHextile); + encs.push(encodings.encodingRRE); + } + encs.push(encodings.encodingRaw); + + // Psuedo-encoding settings + encs.push(encodings.pseudoEncodingQualityLevel0 + this._qualityLevel); + encs.push(encodings.pseudoEncodingCompressLevel0 + this._compressionLevel); + encs.push(encodings.pseudoEncodingDesktopSize); + encs.push(encodings.pseudoEncodingLastRect); + encs.push(encodings.pseudoEncodingQEMUExtendedKeyEvent); + encs.push(encodings.pseudoEncodingExtendedDesktopSize); + encs.push(encodings.pseudoEncodingXvp); + encs.push(encodings.pseudoEncodingFence); + encs.push(encodings.pseudoEncodingContinuousUpdates); + encs.push(encodings.pseudoEncodingDesktopName); + encs.push(encodings.pseudoEncodingExtendedClipboard); + if (this._hasWebp()) + encs.push(encodings.pseudoEncodingWEBP); + if (this._enableQOI) + encs.push(encodings.pseudoEncodingQOI); + + + // kasm settings; the server may be configured to ignore these + encs.push(encodings.pseudoEncodingJpegVideoQualityLevel0 + this.jpegVideoQuality); + encs.push(encodings.pseudoEncodingWebpVideoQualityLevel0 + this.webpVideoQuality); + encs.push(encodings.pseudoEncodingTreatLosslessLevel0 + this.treatLossless); + encs.push(encodings.pseudoEncodingDynamicQualityMinLevel0 + this.dynamicQualityMin); + encs.push(encodings.pseudoEncodingDynamicQualityMaxLevel0 + this.dynamicQualityMax); + encs.push(encodings.pseudoEncodingVideoAreaLevel1 + this.videoArea - 1); + encs.push(encodings.pseudoEncodingVideoTimeLevel0 + this.videoTime); + encs.push(encodings.pseudoEncodingVideoOutTimeLevel1 + this.videoOutTime - 1); + encs.push(encodings.pseudoEncodingVideoScalingLevel0 + this.videoScaling); + encs.push(encodings.pseudoEncodingFrameRateLevel10 + this.frameRate - 10); + encs.push(encodings.pseudoEncodingMaxVideoResolution); + + // preferBandwidth choses preset settings. Since we expose all the settings, lets not pass this + if (this.preferBandwidth) // must be last - server processes in reverse order + encs.push(encodings.pseudoEncodingPreferBandwidth); + + if (this._fbDepth == 24) { + encs.push(encodings.pseudoEncodingVMwareCursor); + encs.push(encodings.pseudoEncodingCursor); + } + encs.push(encodings.pseudoEncodingVMwareCursorPosition); + + RFB.messages.clientEncodings(this._sock, encs); + } + + /* RFB protocol initialization states: + * ProtocolVersion + * Security + * Authentication + * SecurityResult + * ClientInitialization - not triggered by server message + * ServerInitialization + */ + _initMsg() { + switch (this._rfbInitState) { + case 'ProtocolVersion': + return this._negotiateProtocolVersion(); + + case 'Security': + return this._negotiateSecurity(); + + case 'Authentication': + return this._negotiateAuthentication(); + + case 'SecurityResult': + return this._handleSecurityResult(); + + case 'SecurityReason': + return this._handleSecurityReason(); + + case 'ClientInitialisation': + this._sock.send([this._shared ? 1 : 0]); // ClientInitialisation + this._rfbInitState = 'ServerInitialisation'; + return true; + + case 'ServerInitialisation': + return this._negotiateServerInit(); + + default: + return this._fail("Unknown init state (state: " + + this._rfbInitState + ")"); + } + } + + _handleSetColourMapMsg() { + Log.Debug("SetColorMapEntries"); + + return this._fail("Unexpected SetColorMapEntries message"); + } + + _handleServerCutText() { + Log.Debug("ServerCutText"); + + if (this._sock.rQwait("ServerCutText header", 7, 1)) { return false; } + + this._sock.rQskipBytes(3); // Padding + + let length = this._sock.rQshift32(); + length = toSigned32bit(length); + + if (this._sock.rQwait("ServerCutText content", Math.abs(length), 8)) { return false; } + + if (length >= 0) { + //Standard msg + const text = this._sock.rQshiftStr(length); + if (this._viewOnly) { + return true; + } + + this.dispatchEvent(new CustomEvent( + "clipboard", + { detail: { text: text } }) + ); + + this._clipHash = 0; + + } else { + //Extended msg. + length = Math.abs(length); + const flags = this._sock.rQshift32(); + let formats = flags & 0x0000FFFF; + let actions = flags & 0xFF000000; + + let isCaps = (!!(actions & extendedClipboardActionCaps)); + if (isCaps) { + this._clipboardServerCapabilitiesFormats = {}; + this._clipboardServerCapabilitiesActions = {}; + + // Update our server capabilities for Formats + for (let i = 0; i <= 15; i++) { + let index = 1 << i; + + // Check if format flag is set. + if ((formats & index)) { + this._clipboardServerCapabilitiesFormats[index] = true; + // We don't send unsolicited clipboard, so we + // ignore the size + this._sock.rQshift32(); + } + } + + // Update our server capabilities for Actions + for (let i = 24; i <= 31; i++) { + let index = 1 << i; + this._clipboardServerCapabilitiesActions[index] = !!(actions & index); + } + + /* Caps handling done, send caps with the clients + capabilities set as a response */ + let clientActions = [ + extendedClipboardActionCaps, + extendedClipboardActionRequest, + extendedClipboardActionPeek, + extendedClipboardActionNotify, + extendedClipboardActionProvide + ]; + RFB.messages.extendedClipboardCaps(this._sock, clientActions, {extendedClipboardFormatText: 0}); + + } else if (actions === extendedClipboardActionRequest) { + if (this._viewOnly) { + return true; + } + + // Check if server has told us it can handle Provide and there is clipboard data to send. + if (this._clipboardText != null && + this._clipboardServerCapabilitiesActions[extendedClipboardActionProvide]) { + + if (formats & extendedClipboardFormatText) { + RFB.messages.extendedClipboardProvide(this._sock, [extendedClipboardFormatText], [this._clipboardText]); + } + } + + } else if (actions === extendedClipboardActionPeek) { + if (this._viewOnly) { + return true; + } + + if (this._clipboardServerCapabilitiesActions[extendedClipboardActionNotify]) { + + if (this._clipboardText != null) { + RFB.messages.extendedClipboardNotify(this._sock, [extendedClipboardFormatText]); + } else { + RFB.messages.extendedClipboardNotify(this._sock, []); + } + } + + } else if (actions === extendedClipboardActionNotify) { + if (this._viewOnly) { + return true; + } + + if (this._clipboardServerCapabilitiesActions[extendedClipboardActionRequest]) { + + if (formats & extendedClipboardFormatText) { + RFB.messages.extendedClipboardRequest(this._sock, [extendedClipboardFormatText]); + } + } + + } else if (actions === extendedClipboardActionProvide) { + if (this._viewOnly) { + return true; + } + + if (!(formats & extendedClipboardFormatText)) { + return true; + } + // Ignore what we had in our clipboard client side. + this._clipboardText = null; + + // FIXME: Should probably verify that this data was actually requested + let zlibStream = this._sock.rQshiftBytes(length - 4); + let streamInflator = new Inflator(); + let textData = null; + + streamInflator.setInput(zlibStream); + for (let i = 0; i <= 15; i++) { + let format = 1 << i; + + if (formats & format) { + + let size = 0x00; + let sizeArray = streamInflator.inflate(4); + + size |= (sizeArray[0] << 24); + size |= (sizeArray[1] << 16); + size |= (sizeArray[2] << 8); + size |= (sizeArray[3]); + let chunk = streamInflator.inflate(size); + + if (format === extendedClipboardFormatText) { + textData = chunk; + } + } + } + streamInflator.setInput(null); + + if (textData !== null) { + let tmpText = ""; + for (let i = 0; i < textData.length; i++) { + tmpText += String.fromCharCode(textData[i]); + } + textData = tmpText; + + textData = decodeUTF8(textData); + if ((textData.length > 0) && "\0" === textData.charAt(textData.length - 1)) { + textData = textData.slice(0, -1); + } + + textData = textData.replace("\r\n", "\n"); + + this.dispatchEvent(new CustomEvent( + "clipboard", + { detail: { text: textData } })); + } + } else { + return this._fail("Unexpected action in extended clipboard message: " + actions); + } + } + return true; + } + + _handleBinaryClipboard() { + Log.Debug("HandleBinaryClipboard"); + + if (this._sock.rQwait("Binary Clipboard header", 2, 1)) { return false; } + + let num = this._sock.rQshift8(); // how many different mime types + let mimes = []; + let clipItemData = {}; + let buffByteLen = 2; + let textdata = ''; + Log.Info(num + ' Clipboard items recieved.'); + Log.Debug('Started clipbooard processing with Client sockjs buffer size ' + this._sock.rQlen); + + + + for (let i = 0; i < num; i++) { + if (this._sock.rQwait("Binary Clipboard op id", 4, buffByteLen)) { return false; } + buffByteLen += 4; + let clipid = this._sock.rQshift32(); + + if (this._sock.rQwait("Binary Clipboard mimelen", 1, buffByteLen)) { return false; } + buffByteLen++; + let mimelen = this._sock.rQshift8(); + + if (this._sock.rQwait("Binary Clipboard mime", Math.abs(mimelen), buffByteLen)) { return false; } + buffByteLen+=mimelen; + let mime = this._sock.rQshiftStr(mimelen); + + if (this._sock.rQwait("Binary Clipboard data len", 4, buffByteLen)) { return false; } + buffByteLen+=4; + let len = this._sock.rQshift32(); + + if (this._sock.rQwait("Binary Clipboard data", Math.abs(len), buffByteLen)) { return false; } + let data = this._sock.rQshiftBytes(len); + buffByteLen+=len; + + switch(mime) { + case "image/png": + case "text/html": + case "text/plain": + mimes.push(mime); + + if (mime == "text/plain") { + textdata = new TextDecoder().decode(data); + + if ((textdata.length > 0) && "\0" === textdata.charAt(textdata.length - 1)) { + textdata = textdata.slice(0, -1); + } + + Log.Debug("Plain text clipboard recieved and placed in text element, size: " + textdata.length); + this.dispatchEvent(new CustomEvent( + "clipboard", + { detail: { text: textdata } }) + ); + } + + Log.Info("Processed binary clipboard (ID: " + clipid + ") of MIME " + mime + " of length " + len); + + if (!this.clipboardBinary) { continue; } + + clipItemData[mime] = new Blob([data], { type: mime }); + break; + default: + Log.Debug('Mime type skipped: ' + mime); + break; + } + } + + Log.Debug('Finished processing binary clipboard with client sockjs buffer size ' + this._sock.rQlen); + + if (Object.keys(clipItemData).length > 0) { + if (this.clipboardBinary) { + this._clipHash = 0; + + navigator.clipboard.write([new ClipboardItem(clipItemData)]).then( + () => { + if (textdata) { + this._clipHash = hashUInt8Array(textdata); + } + }, + (err) => { + Log.Error("Error writing to client clipboard: " + err); + // Lets try writeText + if (textdata.length > 0) { + navigator.clipboard.writeText(textdata).then( + () => { + this._clipHash = hashUInt8Array(textdata); + }, + (err) => { + Log.Error("Error writing text to client clipboard: " + err); + } + ); + } + } + ); + } + } + + return true; + } + + _handle_server_stats_msg() { + this._sock.rQskipBytes(3); // Padding + const length = this._sock.rQshift32(); + if (this._sock.rQwait("KASM bottleneck stats", length, 8)) { return false; } + + const text = this._sock.rQshiftStr(length); + + Log.Debug("Received KASM bottleneck stats:"); + Log.Debug(text); + this.dispatchEvent(new CustomEvent( + "bottleneck_stats", + { detail: { text: text } })); + + return true; + } + + _handleServerFenceMsg() { + if (this._sock.rQwait("ServerFence header", 8, 1)) { return false; } + this._sock.rQskipBytes(3); // Padding + let flags = this._sock.rQshift32(); + let length = this._sock.rQshift8(); + + if (this._sock.rQwait("ServerFence payload", length, 9)) { return false; } + + if (length > 64) { + Log.Warn("Bad payload length (" + length + ") in fence response"); + length = 64; + } + + const payload = this._sock.rQshiftStr(length); + + this._supportsFence = true; + + /* + * Fence flags + * + * (1<<0) - BlockBefore + * (1<<1) - BlockAfter + * (1<<2) - SyncNext + * (1<<31) - Request + */ + + if (!(flags & (1<<31))) { + return this._fail("Unexpected fence response"); + } + + // Filter out unsupported flags + // FIXME: support syncNext + flags &= (1<<0) | (1<<1); + + // BlockBefore and BlockAfter are automatically handled by + // the fact that we process each incoming message + // synchronuosly. + RFB.messages.clientFence(this._sock, flags, payload); + + return true; + } + + _handleXvpMsg() { + if (this._sock.rQwait("XVP version and message", 3, 1)) { return false; } + this._sock.rQskipBytes(1); // Padding + const xvpVer = this._sock.rQshift8(); + const xvpMsg = this._sock.rQshift8(); + + switch (xvpMsg) { + case 0: // XVP_FAIL + Log.Error("XVP Operation Failed"); + break; + case 1: // XVP_INIT + this._rfbXvpVer = xvpVer; + Log.Info("XVP extensions enabled (version " + this._rfbXvpVer + ")"); + this._setCapability("power", true); + break; + default: + this._fail("Illegal server XVP message (msg: " + xvpMsg + ")"); + break; + } + + return true; + } + + _normalMsg() { + let msgType; + if (this._FBU.rects > 0) { + msgType = 0; + } else { + msgType = this._sock.rQshift8(); + } + + let first, ret; + switch (msgType) { + case 0: // FramebufferUpdate + this._display.renderMs = 0; + ret = this._framebufferUpdate(); + if (ret && !this._enabledContinuousUpdates) { + RFB.messages.fbUpdateRequest(this._sock, true, 0, 0, + this._fbWidth, this._fbHeight); + } + if (this._trackFrameStats) { + RFB.messages.sendFrameStats(this._sock, this._display.fps, this._display.renderMs); + this._trackFrameStats = false; + } + + return ret; + + case 1: // SetColorMapEntries + return this._handleSetColourMapMsg(); + + case 2: // Bell + Log.Debug("Bell"); + this.dispatchEvent(new CustomEvent( + "bell", + { detail: {} })); + return true; + + case 3: // ServerCutText + return this._handleServerCutText(); + + case 150: // EndOfContinuousUpdates + first = !this._supportsContinuousUpdates; + this._supportsContinuousUpdates = true; + this._enabledContinuousUpdates = false; + if (first) { + this._enabledContinuousUpdates = true; + this._updateContinuousUpdates(); + Log.Info("Enabling continuous updates."); + } else { + // FIXME: We need to send a framebufferupdaterequest here + // if we add support for turning off continuous updates + } + return true; + + case 178: // KASM bottleneck stats + return this._handle_server_stats_msg(); + + case 179: // KASM requesting frame stats + this._trackFrameStats = true; + return true; + + case 180: // KASM binary clipboard + return this._handleBinaryClipboard(); + + case 181: // KASM UDP upgrade + return this._handleUdpUpgrade(); + + case 182: // KASM unix relay subscription + return this._handleSubscribeUnixRelay(); + + case 183: // KASM unix relay data + return this._handleUnixRelay(); + + case 248: // ServerFence + return this._handleServerFenceMsg(); + + case 250: // XVP + return this._handleXvpMsg(); + + default: + this._fail("Unexpected server message (type " + msgType + ")"); + Log.Debug("sock.rQslice(0, 30): " + this._sock.rQslice(0, 30)); + return true; + } + } + + _onFlush() { + this._flushing = false; + // Resume processing + if (this._sock.rQlen > 0) { + this._handleMessage(); + } + } + + _handleUdpRect(data, frame_id) { + let frame = { + x: (data[0] << 8) + data[1], + y: (data[2] << 8) + data[3], + width: (data[4] << 8) + data[5], + height: (data[6] << 8) + data[7], + encoding: parseInt((data[8] << 24) + (data[9] << 16) + + (data[10] << 8) + data[11], 10) + }; + + switch (frame.encoding) { + case encodings.pseudoEncodingLastRect: + this._display.flip(frame_id, frame.x + 1); //Last Rect message, first 16 bytes contain rect count + if (this._display.pending()) + this._display.flush(false); + break; + case encodings.encodingTight: + let decoder = this._decoders[encodings.encodingUDP]; + try { + decoder.decodeRect(frame.x, frame.y, + frame.width, frame.height, + data, this._display, + this._fbDepth, frame_id); + } catch (err) { + this._fail("Error decoding rect: " + err); + return false; + } + break; + default: + Log.Error("Invalid rect encoding via UDP: " + frame.encoding); + return false; + } + + return true; + } + + _sendUdpUpgrade() { + if (this._transitConnectionState == this.TransitConnectionStates.Upgrading) { + return; + } + this._changeTransitConnectionState(this.TransitConnectionStates.Upgrading); + + let peer = this._udpPeer; + let sock = this._sock; + + peer.createOffer().then(function(offer) { + return peer.setLocalDescription(offer); + }).then(function() { + const buff = sock._sQ; + const offset = sock._sQlen; + const str = Uint8Array.from(Array.from(peer.localDescription.sdp).map(letter => letter.charCodeAt(0))); + + buff[offset] = 181; // msg-type + buff[offset + 1] = str.length >> 8; // u16 len + buff[offset + 2] = str.length; + + buff.set(str, offset + 3); + + sock._sQlen += 3 + str.length; + sock.flush(); + }).catch(function(reason) { + Log.Error("Failed to create offer " + reason); + this._changeTransitConnectionState(this.TransitConnectionStates.Tcp); + this._udpConnectFailures++; + }); + } + + _sendUdpDowngrade() { + this._changeTransitConnectionState(this.TransitConnectionStates.Downgrading); + const buff = this._sock._sQ; + const offset = this._sock._sQlen; + + buff[offset] = 181; // msg-type + buff[offset + 1] = 0; // u16 len + buff[offset + 2] = 0; + + this._sock._sQlen += 3; + this._sock.flush(); + } + + _handleUdpUpgrade() { + if (this._sock.rQwait("UdpUgrade header", 2, 1)) { return false; } + let len = this._sock.rQshift16(); + if (this._sock.rQwait("UdpUpgrade payload", len, 3)) { return false; } + + const payload = this._sock.rQshiftStr(len); + + let peer = this._udpPeer; + + var response = JSON.parse(payload); + Log.Debug("UDP Upgrade recieved from server: " + payload); + peer.setRemoteDescription(new RTCSessionDescription(response.answer)).then(function() { + var candidate = new RTCIceCandidate(response.candidate); + peer.addIceCandidate(candidate).then(function() { + Log.Debug("success in addicecandidate"); + }.bind(this)).catch(function(err) { + Log.Error("Failure in addIceCandidate", err); + this._changeTransitConnectionState(this.TransitConnectionStates.Failure) + this._udpConnectFailures++; + }.bind(this)); + }.bind(this)).catch(function(e) { + Log.Error("Failure in setRemoteDescription", e); + this._changeTransitConnectionState(this.TransitConnectionStates.Failure) + this._udpConnectFailures++; + }.bind(this)); + } + + _handleSubscribeUnixRelay() { + if (this._sock.rQwait("SubscribeUnixRelay header", 2, 1)) { return false; } + let status = this._sock.rQshift8(); + let len = this._sock.rQshift8(); + if (this._sock.rQwait("SubscribeUnixRelay message", len, 3)) { return false; } + + const payload = this._sock.rQshiftStr(len); + + if (status) { + console.log("Unix relay subscription succeeded"); + } else { + console.log("Unix relay subscription failed, " + payload); + } + } + + _handleUnixRelay() { + if (this._sock.rQwait("UnixRelay header", 1, 1)) { return false; } + let namelen = this._sock.rQshift8(); + if (this._sock.rQwait("UnixRelay name", namelen, 2)) { return false; } + const name = this._sock.rQshiftStr(namelen); + + if (this._sock.rQwait("UnixRelay len", 4, 2 + namelen)) { return false; } + let len = this._sock.rQshift32(); + if (this._sock.rQwait("UnixRelay data", len, 6 + namelen)) { return false; } + + const payload = this._sock.rQshiftBytes(len); + const processRelay = this._unixRelays[name]; + processRelay && processRelay(payload); + } + + _framebufferUpdate() { + if (this._FBU.rects === 0) { + if (this._sock.rQwait("FBU header", 3, 1)) { return false; } + this._sock.rQskipBytes(1); // Padding + this._FBU.rects = this._sock.rQshift16(); + + this._FBU.frame_id++; + this._FBU.rect_total = 0; + + // Make sure the previous frame is fully rendered first + // to avoid building up an excessive queue + if (this._display.pending()) { + this._flushing = true; + this._display.flush(); + return false; + } + } + + while (this._FBU.rects > 0) { + if (this._FBU.encoding === null) { + if (this._sock.rQwait("rect header", 12)) { return false; } + /* New FramebufferUpdate */ + + const hdr = this._sock.rQshiftBytes(12); + this._FBU.x = (hdr[0] << 8) + hdr[1]; + this._FBU.y = (hdr[2] << 8) + hdr[3]; + this._FBU.width = (hdr[4] << 8) + hdr[5]; + this._FBU.height = (hdr[6] << 8) + hdr[7]; + this._FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) + + (hdr[10] << 8) + hdr[11], 10); + } + + + if (!this._handleRect()) { + return false; + } + + this._FBU.rects--; + this._FBU.encoding = null; + } + + if (this._FBU.rect_total > 1) { + this._display.flip(this._FBU.frame_id, this._FBU.rect_total); + } + + return true; // We finished this FBU + } + + _handleRect() { + switch (this._FBU.encoding) { + case encodings.pseudoEncodingLastRect: + this._FBU.rect_total++; //only track rendered rects and last rect + this._FBU.rects = 1; // Will be decreased when we return + return true; + + case encodings.pseudoEncodingVMwareCursor: + return this._handleVMwareCursor(); + + case encodings.pseudoEncodingVMwareCursorPosition: + return this._handleVMwareCursorPosition(); + + case encodings.pseudoEncodingCursor: + return this._handleCursor(); + + case encodings.pseudoEncodingQEMUExtendedKeyEvent: + this._qemuExtKeyEventSupported = true; + return true; + + case encodings.pseudoEncodingDesktopName: + return this._handleDesktopName(); + + case encodings.pseudoEncodingDesktopSize: + this._resize(this._FBU.width, this._FBU.height); + return true; + + case encodings.pseudoEncodingExtendedDesktopSize: + return this._handleExtendedDesktopSize(); + + default: + if (this._handleDataRect()) { + this._FBU.rect_total++; //only track rendered rects and last rect + return true; + } + return false; + } + } + + _handleVMwareCursor() { + const hotx = this._FBU.x; // hotspot-x + const hoty = this._FBU.y; // hotspot-y + const w = this._FBU.width; + const h = this._FBU.height; + if (this._sock.rQwait("VMware cursor encoding", 1)) { + return false; + } + + const cursorType = this._sock.rQshift8(); + + this._sock.rQshift8(); //Padding + + let rgba; + const bytesPerPixel = 4; + + //Classic cursor + if (cursorType == 0) { + //Used to filter away unimportant bits. + //OR is used for correct conversion in js. + const PIXEL_MASK = 0xffffff00 | 0; + rgba = new Array(w * h * bytesPerPixel); + + if (this._sock.rQwait("VMware cursor classic encoding", + (w * h * bytesPerPixel) * 2, 2)) { + return false; + } + + let andMask = new Array(w * h); + for (let pixel = 0; pixel < (w * h); pixel++) { + andMask[pixel] = this._sock.rQshift32(); + } + + let xorMask = new Array(w * h); + for (let pixel = 0; pixel < (w * h); pixel++) { + xorMask[pixel] = this._sock.rQshift32(); + } + + for (let pixel = 0; pixel < (w * h); pixel++) { + if (andMask[pixel] == 0) { + //Fully opaque pixel + let bgr = xorMask[pixel]; + let r = bgr >> 8 & 0xff; + let g = bgr >> 16 & 0xff; + let b = bgr >> 24 & 0xff; + + rgba[(pixel * bytesPerPixel) ] = r; //r + rgba[(pixel * bytesPerPixel) + 1 ] = g; //g + rgba[(pixel * bytesPerPixel) + 2 ] = b; //b + rgba[(pixel * bytesPerPixel) + 3 ] = 0xff; //a + + } else if ((andMask[pixel] & PIXEL_MASK) == + PIXEL_MASK) { + //Only screen value matters, no mouse colouring + if (xorMask[pixel] == 0) { + //Transparent pixel + rgba[(pixel * bytesPerPixel) ] = 0x00; + rgba[(pixel * bytesPerPixel) + 1 ] = 0x00; + rgba[(pixel * bytesPerPixel) + 2 ] = 0x00; + rgba[(pixel * bytesPerPixel) + 3 ] = 0x00; + + } else if ((xorMask[pixel] & PIXEL_MASK) == + PIXEL_MASK) { + //Inverted pixel, not supported in browsers. + //Fully opaque instead. + rgba[(pixel * bytesPerPixel) ] = 0x00; + rgba[(pixel * bytesPerPixel) + 1 ] = 0x00; + rgba[(pixel * bytesPerPixel) + 2 ] = 0x00; + rgba[(pixel * bytesPerPixel) + 3 ] = 0xff; + + } else { + //Unhandled xorMask + rgba[(pixel * bytesPerPixel) ] = 0x00; + rgba[(pixel * bytesPerPixel) + 1 ] = 0x00; + rgba[(pixel * bytesPerPixel) + 2 ] = 0x00; + rgba[(pixel * bytesPerPixel) + 3 ] = 0xff; + } + + } else { + //Unhandled andMask + rgba[(pixel * bytesPerPixel) ] = 0x00; + rgba[(pixel * bytesPerPixel) + 1 ] = 0x00; + rgba[(pixel * bytesPerPixel) + 2 ] = 0x00; + rgba[(pixel * bytesPerPixel) + 3 ] = 0xff; + } + } + + //Alpha cursor. + } else if (cursorType == 1) { + if (this._sock.rQwait("VMware cursor alpha encoding", + (w * h * 4), 2)) { + return false; + } + + rgba = new Array(w * h * bytesPerPixel); + + for (let pixel = 0; pixel < (w * h); pixel++) { + let data = this._sock.rQshift32(); + + rgba[(pixel * 4) ] = data >> 24 & 0xff; //r + rgba[(pixel * 4) + 1 ] = data >> 16 & 0xff; //g + rgba[(pixel * 4) + 2 ] = data >> 8 & 0xff; //b + rgba[(pixel * 4) + 3 ] = data & 0xff; //a + } + + } else { + Log.Warn("The given cursor type is not supported: " + + cursorType + " given."); + return false; + } + + this._updateCursor(rgba, hotx, hoty, w, h); + + return true; + } + + _handleVMwareCursorPosition() { + const x = this._FBU.x; + const y = this._FBU.y; + + if (this._pointerLock) { + // Only attempt to match the server's pointer position if we are in + // pointer lock mode. + this._mousePos = { x: x, y: y }; + } + + return true; + } + + _handleCursor() { + const hotx = this._FBU.x; // hotspot-x + const hoty = this._FBU.y; // hotspot-y + const w = this._FBU.width; + const h = this._FBU.height; + + const pixelslength = w * h * 4; + const masklength = Math.ceil(w / 8) * h; + + let bytes = pixelslength + masklength; + if (this._sock.rQwait("cursor encoding", bytes)) { + return false; + } + + // Decode from BGRX pixels + bit mask to RGBA + const pixels = this._sock.rQshiftBytes(pixelslength); + const mask = this._sock.rQshiftBytes(masklength); + let rgba = new Uint8Array(w * h * 4); + + let pixIdx = 0; + for (let y = 0; y < h; y++) { + for (let x = 0; x < w; x++) { + let maskIdx = y * Math.ceil(w / 8) + Math.floor(x / 8); + let alpha = (mask[maskIdx] << (x % 8)) & 0x80 ? 255 : 0; + rgba[pixIdx ] = pixels[pixIdx + 2]; + rgba[pixIdx + 1] = pixels[pixIdx + 1]; + rgba[pixIdx + 2] = pixels[pixIdx]; + rgba[pixIdx + 3] = alpha; + pixIdx += 4; + } + } + + this._updateCursor(rgba, hotx, hoty, w, h); + + return true; + } + + _handleDesktopName() { + if (this._sock.rQwait("DesktopName", 4)) { + return false; + } + + let length = this._sock.rQshift32(); + + if (this._sock.rQwait("DesktopName", length, 4)) { + return false; + } + + let name = this._sock.rQshiftStr(length); + name = decodeUTF8(name, true); + + this._setDesktopName(name); + + return true; + } + + _handleExtendedDesktopSize() { + if (this._sock.rQwait("ExtendedDesktopSize", 4)) { + return false; + } + + const numberOfScreens = this._sock.rQpeek8(); + + let bytes = 4 + (numberOfScreens * 16); + if (this._sock.rQwait("ExtendedDesktopSize", bytes)) { + return false; + } + + const firstUpdate = !this._supportsSetDesktopSize; + this._supportsSetDesktopSize = true; + + // Normally we only apply the current resize mode after a + // window resize event. However there is no such trigger on the + // initial connect. And we don't know if the server supports + // resizing until we've gotten here. + if (firstUpdate) { + this._requestRemoteResize(); + + RFB.messages.setMaxVideoResolution(this._sock, + this._maxVideoResolutionX, + this._maxVideoResolutionY); + } + + this._sock.rQskipBytes(1); // number-of-screens + this._sock.rQskipBytes(3); // padding + + for (let i = 0; i < numberOfScreens; i += 1) { + // Save the id and flags of the first screen + if (i === 0) { + this._screenID = this._sock.rQshiftBytes(4); // id + this._sock.rQskipBytes(2); // x-position + this._sock.rQskipBytes(2); // y-position + this._sock.rQskipBytes(2); // width + this._sock.rQskipBytes(2); // height + this._screenFlags = this._sock.rQshiftBytes(4); // flags + } else { + this._sock.rQskipBytes(16); + } + } + + /* + * The x-position indicates the reason for the change: + * + * 0 - server resized on its own + * 1 - this client requested the resize + * 2 - another client requested the resize + */ + + // We need to handle errors when we requested the resize. + if (this._FBU.x === 1 && this._FBU.y !== 0) { + let msg = ""; + // The y-position indicates the status code from the server + switch (this._FBU.y) { + case 1: + msg = "Resize is administratively prohibited"; + break; + case 2: + msg = "Out of resources"; + break; + case 3: + msg = "Invalid screen layout"; + break; + default: + msg = "Unknown reason"; + break; + } + Log.Warn("Server did not accept the resize request: " + + msg); + } else { + this._resize(this._FBU.width, this._FBU.height); + } + + return true; + } + + _handleDataRect() { + let decoder = this._decoders[this._FBU.encoding]; + if (!decoder) { + this._fail("Unsupported encoding (encoding: " + + this._FBU.encoding + ")"); + return false; + } + + try { + if (this._transitConnectionState == this.TransitConnectionStates.Udp || this._transitConnectionState == this.TransitConnectionStates.Failure) { + if (this._transitConnectionState == this.TransitConnectionStates.Udp) { + Log.Warn("Implicit UDP Transit Failure, TCP rects recieved while in UDP mode.") + this._udpTransitFailures++; + } + this._changeTransitConnectionState(this.TransitConnectionStates.Tcp); + this._display.clear(); + if (this._useUdp) { + if (this._udpConnectFailures < 3 && this._udpTransitFailures < 3) { + setTimeout(function() { + Log.Warn("Attempting to connect via UDP again after failure.") + this.enableWebRTC = true; + }.bind(this), 3000); + } else { + Log.Warn("UDP connection failures exceeded limit, remaining on TCP transit.") + } + } + } else if (this._transitConnectionState == this.TransitConnectionStates.Downgrading) { + this._display.clear(); + this._changeTransitConnectionState(this.TransitConnectionStates.Tcp); + } + return decoder.decodeRect(this._FBU.x, this._FBU.y, + this._FBU.width, this._FBU.height, + this._sock, this._display, + this._fbDepth, this._FBU.frame_id); + } catch (err) { + this._fail("Error decoding rect: " + err); + return false; + } + } + + _updateContinuousUpdates() { + if (!this._enabledContinuousUpdates) { return; } + + RFB.messages.enableContinuousUpdates(this._sock, true, 0, 0, + this._fbWidth, this._fbHeight); + } + + _resize(width, height) { + this._fbWidth = width; + this._fbHeight = height; + + this._display.resize(this._fbWidth, this._fbHeight); + + // Adjust the visible viewport based on the new dimensions + this._updateClip(); + this._updateScale(); + + this._updateContinuousUpdates(); + } + + _xvpOp(ver, op) { + if (this._rfbXvpVer < ver) { return; } + Log.Info("Sending XVP operation " + op + " (version " + ver + ")"); + RFB.messages.xvpOp(this._sock, ver, op); + } + + _updateCursor(rgba, hotx, hoty, w, h) { + this._cursorImage = { + rgbaPixels: rgba, + hotx: hotx, hoty: hoty, w: w, h: h, + }; + this._refreshCursor(); + } + + _shouldShowDotCursor() { + // Called when this._cursorImage is updated + if (!this._showDotCursor) { + // User does not want to see the dot, so... + return false; + } + + // The dot should not be shown if the cursor is already visible, + // i.e. contains at least one not-fully-transparent pixel. + // So iterate through all alpha bytes in rgba and stop at the + // first non-zero. + for (let i = 3; i < this._cursorImage.rgbaPixels.length; i += 4) { + if (this._cursorImage.rgbaPixels[i]) { + return false; + } + } + + // At this point, we know that the cursor is fully transparent, and + // the user wants to see the dot instead of this. + return true; + } + + _refreshCursor() { + if (this._rfbConnectionState !== "connecting" && + this._rfbConnectionState !== "connected") { + return; + } + const image = this._shouldShowDotCursor() ? RFB.cursors.dot : this._cursorImage; + this._cursor.change(image.rgbaPixels, + image.hotx, image.hoty, + image.w, image.h + ); + } + + static genDES(password, challenge) { + const passwordChars = password.split('').map(c => c.charCodeAt(0)); + return (new DES(passwordChars)).encrypt(challenge); + } +} + +// Class Methods +RFB.messages = { + keyEvent(sock, keysym, down) { + const buff = sock._sQ; + const offset = sock._sQlen; + + buff[offset] = 4; // msg-type + buff[offset + 1] = down; + + buff[offset + 2] = 0; + buff[offset + 3] = 0; + + buff[offset + 4] = (keysym >> 24); + buff[offset + 5] = (keysym >> 16); + buff[offset + 6] = (keysym >> 8); + buff[offset + 7] = keysym; + + sock._sQlen += 8; + sock.flush(); + }, + + QEMUExtendedKeyEvent(sock, keysym, down, keycode) { + function getRFBkeycode(xtScanCode) { + const upperByte = (keycode >> 8); + const lowerByte = (keycode & 0x00ff); + if (upperByte === 0xe0 && lowerByte < 0x7f) { + return lowerByte | 0x80; + } + return xtScanCode; + } + + const buff = sock._sQ; + const offset = sock._sQlen; + + buff[offset] = 255; // msg-type + buff[offset + 1] = 0; // sub msg-type + + buff[offset + 2] = (down >> 8); + buff[offset + 3] = down; + + buff[offset + 4] = (keysym >> 24); + buff[offset + 5] = (keysym >> 16); + buff[offset + 6] = (keysym >> 8); + buff[offset + 7] = keysym; + + const RFBkeycode = getRFBkeycode(keycode); + + buff[offset + 8] = (RFBkeycode >> 24); + buff[offset + 9] = (RFBkeycode >> 16); + buff[offset + 10] = (RFBkeycode >> 8); + buff[offset + 11] = RFBkeycode; + + sock._sQlen += 12; + sock.flush(); + }, + + pointerEvent(sock, x, y, mask, dX = 0, dY = 0) { + const buff = sock._sQ; + const offset = sock._sQlen; + + buff[offset] = 5; // msg-type + + buff[offset + 1] = mask >> 8; + buff[offset + 2] = mask; + + buff[offset + 3] = x >> 8; + buff[offset + 4] = x; + + buff[offset + 5] = y >> 8; + buff[offset + 6] = y; + + buff[offset + 7] = dX >> 8; + buff[offset + 8] = dX; + + buff[offset + 9] = dY >> 8; + buff[offset + 10] = dY; + + sock._sQlen += 11; + sock.flush(); + }, + + // Used to build Notify and Request data. + _buildExtendedClipboardFlags(actions, formats) { + let data = new Uint8Array(4); + let formatFlag = 0x00000000; + let actionFlag = 0x00000000; + + for (let i = 0; i < actions.length; i++) { + actionFlag |= actions[i]; + } + + for (let i = 0; i < formats.length; i++) { + formatFlag |= formats[i]; + } + + data[0] = actionFlag >> 24; // Actions + data[1] = 0x00; // Reserved + data[2] = 0x00; // Reserved + data[3] = formatFlag; // Formats + + return data; + }, + + extendedClipboardProvide(sock, formats, inData) { + // Deflate incomming data and their sizes + let deflator = new Deflator(); + let dataToDeflate = []; + + for (let i = 0; i < formats.length; i++) { + // We only support the format Text at this time + if (formats[i] != extendedClipboardFormatText) { + throw new Error("Unsupported extended clipboard format for Provide message."); + } + + // Change lone \r or \n into \r\n as defined in rfbproto + inData[i] = inData[i].replace(/\r\n|\r|\n/gm, "\r\n"); + + // Check if it already has \0 + let text = encodeUTF8(inData[i] + "\0"); + + dataToDeflate.push( (text.length >> 24) & 0xFF, + (text.length >> 16) & 0xFF, + (text.length >> 8) & 0xFF, + (text.length & 0xFF)); + + for (let j = 0; j < text.length; j++) { + dataToDeflate.push(text.charCodeAt(j)); + } + } + + let deflatedData = deflator.deflate(new Uint8Array(dataToDeflate)); + + // Build data to send + let data = new Uint8Array(4 + deflatedData.length); + data.set(RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionProvide], + formats)); + data.set(deflatedData, 4); + + RFB.messages.clientCutText(sock, data, true); + }, + + extendedClipboardNotify(sock, formats) { + let flags = RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionNotify], + formats); + RFB.messages.clientCutText(sock, flags, true); + }, + + extendedClipboardRequest(sock, formats) { + let flags = RFB.messages._buildExtendedClipboardFlags([extendedClipboardActionRequest], + formats); + RFB.messages.clientCutText(sock, flags, true); + }, + + extendedClipboardCaps(sock, actions, formats) { + let formatKeys = Object.keys(formats); + let data = new Uint8Array(4 + (4 * formatKeys.length)); + + formatKeys.map(x => parseInt(x)); + formatKeys.sort((a, b) => a - b); + + data.set(RFB.messages._buildExtendedClipboardFlags(actions, [])); + + let loopOffset = 4; + for (let i = 0; i < formatKeys.length; i++) { + data[loopOffset] = formats[formatKeys[i]] >> 24; + data[loopOffset + 1] = formats[formatKeys[i]] >> 16; + data[loopOffset + 2] = formats[formatKeys[i]] >> 8; + data[loopOffset + 3] = formats[formatKeys[i]] >> 0; + + loopOffset += 4; + data[3] |= (1 << formatKeys[i]); // Update our format flags + } + + RFB.messages.clientCutText(sock, data, true); + }, + + clientCutText(sock, data, extended = false) { + const buff = sock._sQ; + const offset = sock._sQlen; + + buff[offset] = 6; // msg-type + + buff[offset + 1] = 0; // padding + buff[offset + 2] = 0; // padding + buff[offset + 3] = 0; // padding + + let length; + if (extended) { + length = toUnsigned32bit(-data.length); + } else { + length = data.length; + } + + buff[offset + 4] = length >> 24; + buff[offset + 5] = length >> 16; + buff[offset + 6] = length >> 8; + buff[offset + 7] = length; + + sock._sQlen += 8; + + // We have to keep track of from where in the data we begin creating the + // buffer for the flush in the next iteration. + let dataOffset = 0; + + let remaining = data.length; + while (remaining > 0) { + + let flushSize = Math.min(remaining, (sock._sQbufferSize - sock._sQlen)); + for (let i = 0; i < flushSize; i++) { + buff[sock._sQlen + i] = data[dataOffset + i]; + } + + sock._sQlen += flushSize; + sock.flush(); + + remaining -= flushSize; + dataOffset += flushSize; + } + + }, + + sendBinaryClipboard(sock, dataset, mimes) { + + + const buff = sock._sQ; + let offset = sock._sQlen; + + buff[offset] = 180; // msg-type + buff[offset + 1] = dataset.length; // how many mime types + sock._sQlen += 2; + offset += 2; + + for (let i=0; i < dataset.length; i++) { + let mime = mimes[i]; + let data = dataset[i]; + + buff[offset++] = mime.length; + + for (let i = 0; i < mime.length; i++) { + buff[offset++] = mime.charCodeAt(i); // change to [] if not a string + } + + let length = data.length; + + Log.Info('Clipboard data sent mime type ' + mime + ' len ' + length); + + buff[offset++] = length >> 24; + buff[offset++] = length >> 16; + buff[offset++] = length >> 8; + buff[offset++] = length; + + sock._sQlen += 1 + mime.length + 4; + + // We have to keep track of from where in the data we begin creating the + // buffer for the flush in the next iteration. + let dataOffset = 0; + + let remaining = data.length; + while (remaining > 0) { + + let flushSize = Math.min(remaining, (sock._sQbufferSize - sock._sQlen)); + for (let i = 0; i < flushSize; i++) { + buff[sock._sQlen + i] = data[dataOffset + i]; + } + + sock._sQlen += flushSize; + sock.flush(); + + remaining -= flushSize; + dataOffset += flushSize; + } + + offset = sock._sQlen; + } + }, + + sendSubscribeUnixRelay(sock, name) { + const buff = sock._sQ; + const offset = sock._sQlen; + + buff[offset] = 182; // msg-type + buff[offset + 1] = name.length; // len + for (let i = 0; i < name.length; i++) { + buff[offset + 2 + i] = name.charCodeAt(i); + } + + sock._sQlen += 2 + name.length; + sock.flush(); + }, + + sendUnixRelay(sock, name, data) { + const buff = sock._sQ; + let offset = sock._sQlen; + + buff[offset++] = 183; // msg-type + buff[offset++] = name.length; // len + for (let i = 0; i < name.length; i++) { + buff[offset++] = name.charCodeAt(i); + } + + let length = data.length; + + Log.Info('Sent unix relay data len ' + length); + + buff[offset++] = length >> 24; + buff[offset++] = length >> 16; + buff[offset++] = length >> 8; + buff[offset++] = length; + + sock._sQlen += 2 + name.length + 4; + + // We have to keep track of from where in the data we begin creating the + // buffer for the flush in the next iteration. + let dataOffset = 0; + + let remaining = data.length; + while (remaining > 0) { + + let flushSize = Math.min(remaining, (sock._sQbufferSize - sock._sQlen)); + for (let i = 0; i < flushSize; i++) { + buff[sock._sQlen + i] = data[dataOffset + i]; + } + + sock._sQlen += flushSize; + sock.flush(); + + remaining -= flushSize; + dataOffset += flushSize; + } + }, + + setDesktopSize(sock, width, height, id, flags) { + const buff = sock._sQ; + const offset = sock._sQlen; + + buff[offset] = 251; // msg-type + buff[offset + 1] = 0; // padding + buff[offset + 2] = width >> 8; // width + buff[offset + 3] = width; + buff[offset + 4] = height >> 8; // height + buff[offset + 5] = height; + + buff[offset + 6] = 1; // number-of-screens + buff[offset + 7] = 0; // padding + + // screen array + buff[offset + 8] = id >> 24; // id + buff[offset + 9] = id >> 16; + buff[offset + 10] = id >> 8; + buff[offset + 11] = id; + buff[offset + 12] = 0; // x-position + buff[offset + 13] = 0; + buff[offset + 14] = 0; // y-position + buff[offset + 15] = 0; + buff[offset + 16] = width >> 8; // width + buff[offset + 17] = width; + buff[offset + 18] = height >> 8; // height + buff[offset + 19] = height; + buff[offset + 20] = flags >> 24; // flags + buff[offset + 21] = flags >> 16; + buff[offset + 22] = flags >> 8; + buff[offset + 23] = flags; + + sock._sQlen += 24; + sock.flush(); + }, + + setMaxVideoResolution(sock, width, height) { + const buff = sock._sQ; + const offset = sock._sQlen; + + buff[offset] = 252; // msg-type + buff[offset + 1] = width >> 8; // width + buff[offset + 2] = width; + buff[offset + 3] = height >> 8; // height + buff[offset + 4] = height; + + sock._sQlen += 5; + sock.flush(); + }, + + clientFence(sock, flags, payload) { + const buff = sock._sQ; + const offset = sock._sQlen; + + buff[offset] = 248; // msg-type + + buff[offset + 1] = 0; // padding + buff[offset + 2] = 0; // padding + buff[offset + 3] = 0; // padding + + buff[offset + 4] = flags >> 24; // flags + buff[offset + 5] = flags >> 16; + buff[offset + 6] = flags >> 8; + buff[offset + 7] = flags; + + const n = payload.length; + + buff[offset + 8] = n; // length + + for (let i = 0; i < n; i++) { + buff[offset + 9 + i] = payload.charCodeAt(i); + } + + sock._sQlen += 9 + n; + sock.flush(); + }, + + requestStats(sock) { + const buff = sock._sQ; + const offset = sock._sQlen; + + if (buff == null) { return; } + + buff[offset] = 178; // msg-type + + buff[offset + 1] = 0; // padding + buff[offset + 2] = 0; // padding + buff[offset + 3] = 0; // padding + + sock._sQlen += 4; + sock.flush(); + }, + + sendFrameStats(sock, allMs, renderMs) { + const buff = sock._sQ; + const offset = sock._sQlen; + + if (buff == null) { return; } + + buff[offset] = 179; // msg-type + + buff[offset + 1] = 0; // padding + buff[offset + 2] = 0; // padding + buff[offset + 3] = 0; // padding + + buff[offset + 4] = allMs >> 24; + buff[offset + 5] = allMs >> 16; + buff[offset + 6] = allMs >> 8; + buff[offset + 7] = allMs; + + buff[offset + 8] = renderMs >> 24; + buff[offset + 9] = renderMs >> 16; + buff[offset + 10] = renderMs >> 8; + buff[offset + 11] = renderMs; + + sock._sQlen += 12; + sock.flush(); + }, + + + enableContinuousUpdates(sock, enable, x, y, width, height) { + const buff = sock._sQ; + const offset = sock._sQlen; + + buff[offset] = 150; // msg-type + buff[offset + 1] = enable; // enable-flag + + buff[offset + 2] = x >> 8; // x + buff[offset + 3] = x; + buff[offset + 4] = y >> 8; // y + buff[offset + 5] = y; + buff[offset + 6] = width >> 8; // width + buff[offset + 7] = width; + buff[offset + 8] = height >> 8; // height + buff[offset + 9] = height; + + sock._sQlen += 10; + sock.flush(); + }, + + pixelFormat(sock, depth, trueColor) { + const buff = sock._sQ; + const offset = sock._sQlen; + + let bpp; + + if (depth > 16) { + bpp = 32; + } else if (depth > 8) { + bpp = 16; + } else { + bpp = 8; + } + + const bits = Math.floor(depth/3); + + buff[offset] = 0; // msg-type + + buff[offset + 1] = 0; // padding + buff[offset + 2] = 0; // padding + buff[offset + 3] = 0; // padding + + buff[offset + 4] = bpp; // bits-per-pixel + buff[offset + 5] = depth; // depth + buff[offset + 6] = 0; // little-endian + buff[offset + 7] = trueColor ? 1 : 0; // true-color + + buff[offset + 8] = 0; // red-max + buff[offset + 9] = (1 << bits) - 1; // red-max + + buff[offset + 10] = 0; // green-max + buff[offset + 11] = (1 << bits) - 1; // green-max + + buff[offset + 12] = 0; // blue-max + buff[offset + 13] = (1 << bits) - 1; // blue-max + + buff[offset + 14] = bits * 0; // red-shift + buff[offset + 15] = bits * 1; // green-shift + buff[offset + 16] = bits * 2; // blue-shift + + buff[offset + 17] = 0; // padding + buff[offset + 18] = 0; // padding + buff[offset + 19] = 0; // padding + + sock._sQlen += 20; + sock.flush(); + }, + + clientEncodings(sock, encodings) { + const buff = sock._sQ; + const offset = sock._sQlen; + + buff[offset] = 2; // msg-type + buff[offset + 1] = 0; // padding + + buff[offset + 2] = encodings.length >> 8; + buff[offset + 3] = encodings.length; + + let j = offset + 4; + for (let i = 0; i < encodings.length; i++) { + const enc = encodings[i]; + buff[j] = enc >> 24; + buff[j + 1] = enc >> 16; + buff[j + 2] = enc >> 8; + buff[j + 3] = enc; + + j += 4; + } + + sock._sQlen += j - offset; + sock.flush(); + }, + + fbUpdateRequest(sock, incremental, x, y, w, h) { + const buff = sock._sQ; + const offset = sock._sQlen; + + if (typeof(x) === "undefined") { x = 0; } + if (typeof(y) === "undefined") { y = 0; } + + buff[offset] = 3; // msg-type + buff[offset + 1] = incremental ? 1 : 0; + + buff[offset + 2] = (x >> 8) & 0xFF; + buff[offset + 3] = x & 0xFF; + + buff[offset + 4] = (y >> 8) & 0xFF; + buff[offset + 5] = y & 0xFF; + + buff[offset + 6] = (w >> 8) & 0xFF; + buff[offset + 7] = w & 0xFF; + + buff[offset + 8] = (h >> 8) & 0xFF; + buff[offset + 9] = h & 0xFF; + + sock._sQlen += 10; + sock.flush(); + }, + + xvpOp(sock, ver, op) { + const buff = sock._sQ; + const offset = sock._sQlen; + + buff[offset] = 250; // msg-type + buff[offset + 1] = 0; // padding + + buff[offset + 2] = ver; + buff[offset + 3] = op; + + sock._sQlen += 4; + sock.flush(); + } +}; + +RFB.cursors = { + none: { + rgbaPixels: new Uint8Array(), + w: 0, h: 0, + hotx: 0, hoty: 0, + }, + + dot: { + /* eslint-disable indent */ + rgbaPixels: new Uint8Array([ + 255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, + 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 255, + 255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, + ]), + /* eslint-enable indent */ + w: 3, h: 3, + hotx: 1, hoty: 1, + } +}; diff --git a/core/util/browser.js b/core/util/browser.js new file mode 100644 index 0000000..23bf6cb --- /dev/null +++ b/core/util/browser.js @@ -0,0 +1,161 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + * + * Browser feature support detection + */ + +import * as Log from './logging.js'; + +// Touch detection +export let isTouchDevice = ('ontouchstart' in document.documentElement) || + // requried for Chrome debugger + (document.ontouchstart !== undefined) || + // required for MS Surface + (navigator.maxTouchPoints > 0) || + (navigator.msMaxTouchPoints > 0); +window.addEventListener('touchstart', function onFirstTouch() { + isTouchDevice = true; + window.removeEventListener('touchstart', onFirstTouch, false); +}, false); + + +// The goal is to find a certain physical width, the devicePixelRatio +// brings us a bit closer but is not optimal. +export let dragThreshold = 10 * (window.devicePixelRatio || 1); + +let _supportsCursorURIs = false; + +try { + const target = document.createElement('canvas'); + target.style.cursor = 'url("data:image/x-icon;base64,AAACAAEACAgAAAIAAgA4AQAAFgAAACgAAAAIAAAAEAAAAAEAIAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAAAAAAAAAAAAAAAAAAAAA==") 2 2, default'; + + if (target.style.cursor.indexOf("url") === 0) { + Log.Info("Data URI scheme cursor supported"); + _supportsCursorURIs = true; + } else { + Log.Warn("Data URI scheme cursor not supported"); + } +} catch (exc) { + Log.Error("Data URI scheme cursor test exception: " + exc); +} + +export const supportsCursorURIs = _supportsCursorURIs; + +let _hasScrollbarGutter = true; +try { + // Create invisible container + const container = document.createElement('div'); + container.style.visibility = 'hidden'; + container.style.overflow = 'scroll'; // forcing scrollbars + document.body.appendChild(container); + + // Create a div and place it in the container + const child = document.createElement('div'); + container.appendChild(child); + + // Calculate the difference between the container's full width + // and the child's width - the difference is the scrollbars + const scrollbarWidth = (container.offsetWidth - child.offsetWidth); + + // Clean up + container.parentNode.removeChild(container); + + _hasScrollbarGutter = scrollbarWidth != 0; +} catch (exc) { + Log.Error("Scrollbar test exception: " + exc); +} +export const hasScrollbarGutter = _hasScrollbarGutter; + +/* + * The functions for detection of platforms and browsers below are exported + * but the use of these should be minimized as much as possible. + * + * It's better to use feature detection than platform detection. + */ + +export function isMac() { + return navigator && !!(/mac/i).exec(navigator.platform); +} + +export function isWindows() { + return navigator && !!(/win/i).exec(navigator.platform); +} + +export function isIOS() { + return navigator && + (!!(/ipad/i).exec(navigator.platform) || + !!(/iphone/i).exec(navigator.platform) || + !!(/ipod/i).exec(navigator.platform)); +} + +export function isSafari() { + return navigator && (navigator.userAgent.indexOf('Safari') !== -1 && + navigator.userAgent.indexOf('Chrome') === -1); +} + +// Returns IE version number if IE or older Edge browser +export function isIE() { + var ua = window.navigator.userAgent; + + // Test values; Uncomment to check result & + + // IE 10 + // ua = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)'; + + // IE 11 + // ua = 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko'; + + // Edge 12 (Spartan) + // ua = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0'; + + // Edge 13 + // ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586'; + + var msie = ua.indexOf('MSIE '); + var ie_ver = false; + if (msie > 0) { + // IE 10 or older => return version number + ie_ver = parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); + } + + var trident = ua.indexOf('Trident/'); + if (trident > 0) { + // IE 11 => return version number + var rv = ua.indexOf('rv:'); + ie_ver = parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); + } + + var edge = ua.indexOf('Edge/'); + if (edge > 0) { + // Edge (IE 12+) => return version number + ie_ver = parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); + } + + return ie_ver; +} + +export function isChromiumBased() { + return (!!window.chrome); +} + +export function isFirefox() { + return navigator && !!(/firefox/i).exec(navigator.userAgent); +} + +export function supportsBinaryClipboard() { + //Safari does support the clipbaord API but has a lot of security restrictions + if (isSafari()) { return false; } + return (navigator.clipboard && typeof navigator.clipboard.read === "function"); +} + +export function supportsPointerLock() { + //Older versions of edge do support browser lock, but seems to not behave as expected + //Disable on browsers that don't fully support or work as expected + if (isIOS() || isIE()) { return false; } + return (document.exitPointerLock); +} + diff --git a/core/util/cursor.js b/core/util/cursor.js new file mode 100644 index 0000000..6d5200c --- /dev/null +++ b/core/util/cursor.js @@ -0,0 +1,264 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 or any later version (see LICENSE.txt) + */ + +import { supportsCursorURIs, isTouchDevice } from './browser.js'; + +const needsFallback = !supportsCursorURIs || isTouchDevice; + +export default class Cursor { + constructor() { + this._target = null; + + this._canvas = document.createElement('canvas'); + this._canvas.style.position = 'fixed'; + this._canvas.style.zIndex = '65535'; + this._canvas.style.pointerEvents = 'none'; + // Can't use "display" because of Firefox bug #1445997 + this._canvas.style.visibility = 'hidden'; + this._useFallback = needsFallback; + + this._position = { x: 0, y: 0 }; + this._hotSpot = { x: 0, y: 0 }; + + this._eventHandlers = { + 'mouseover': this._handleMouseOver.bind(this), + 'mouseleave': this._handleMouseLeave.bind(this), + 'mousemove': this._handleMouseMove.bind(this), + 'mouseup': this._handleMouseUp.bind(this), + }; + } + + attach(target) { + if (this._target) { + this.detach(); + } + + this._target = target; + + + document.body.appendChild(this._canvas); + + if (needsFallback) { + // Only add the event listeners if this will be responsible for + // rendering the cursor all the time. Otherwise, the cursor will + // only be rendered then the forced emulation is turned on, and + // that doesn't require this class to be adjusting the cursor + // position. + const options = { capture: true, passive: true }; + this._target.addEventListener('mouseover', this._eventHandlers.mouseover, options); + this._target.addEventListener('mouseleave', this._eventHandlers.mouseleave, options); + this._target.addEventListener('mousemove', this._eventHandlers.mousemove, options); + this._target.addEventListener('mouseup', this._eventHandlers.mouseup, options); + } + + this.clear(); + } + + detach() { + if (!this._target) { + return; + } + + if (needsFallback) { + const options = { capture: true, passive: true }; + this._target.removeEventListener('mouseover', this._eventHandlers.mouseover, options); + this._target.removeEventListener('mouseleave', this._eventHandlers.mouseleave, options); + this._target.removeEventListener('mousemove', this._eventHandlers.mousemove, options); + this._target.removeEventListener('mouseup', this._eventHandlers.mouseup, options); + } + + document.body.removeChild(this._canvas); + + this._target = null; + } + + change(rgba, hotx, hoty, w, h) { + if ((w === 0) || (h === 0)) { + this.clear(); + return; + } + + this._position.x = this._position.x + this._hotSpot.x - hotx; + this._position.y = this._position.y + this._hotSpot.y - hoty; + this._hotSpot.x = hotx; + this._hotSpot.y = hoty; + + let ctx = this._canvas.getContext('2d'); + + this._canvas.width = w; + this._canvas.height = h; + + let img = new ImageData(new Uint8ClampedArray(rgba), w, h); + ctx.clearRect(0, 0, w, h); + ctx.putImageData(img, 0, 0); + + if (this._useFallback || needsFallback) { + this._updatePosition(); + } + if (!needsFallback) { + let url = this._canvas.toDataURL(); + this._target.style.cursor = 'url(' + url + ')' + hotx + ' ' + hoty + ', default'; + } + } + + clear() { + this._target.style.cursor = 'none'; + this._canvas.width = 0; + this._canvas.height = 0; + this._position.x = this._position.x + this._hotSpot.x; + this._position.y = this._position.y + this._hotSpot.y; + this._hotSpot.x = 0; + this._hotSpot.y = 0; + } + + // Mouse events might be emulated, this allows + // moving the cursor in such cases + move(clientX, clientY) { + if (!this._useFallback) { + return; + } + // clientX/clientY are relative the _visual viewport_, + // but our position is relative the _layout viewport_, + // so try to compensate when we can + if (window.visualViewport) { + this._position.x = clientX + window.visualViewport.offsetLeft; + this._position.y = clientY + window.visualViewport.offsetTop; + } else { + this._position.x = clientX; + this._position.y = clientY; + } + this._updatePosition(); + let target = document.elementFromPoint(clientX, clientY); + this._updateVisibility(target); + } + + // Force the use of cursor emulation. This is needed when the pointer lock + // is in use, since the browser will not render the cursor. + setEmulateCursor(emulate) { + if (needsFallback) { + // We need to use the fallback all the time, so we shouldn't update + // the fallback flag. + return; + } + this._useFallback = emulate; + if (this._useFallback) { + this._showCursor(); + } else { + this._hideCursor(); + } + } + + _handleMouseOver(event) { + // This event could be because we're entering the target, or + // moving around amongst its sub elements. Let the move handler + // sort things out. + this._handleMouseMove(event); + } + + _handleMouseLeave(event) { + // Check if we should show the cursor on the element we are leaving to + this._updateVisibility(event.relatedTarget); + } + + _handleMouseMove(event) { + this._updateVisibility(event.target); + + this._position.x = event.clientX - this._hotSpot.x; + this._position.y = event.clientY - this._hotSpot.y; + + this._updatePosition(); + } + + _handleMouseUp(event) { + // We might get this event because of a drag operation that + // moved outside of the target. Check what's under the cursor + // now and adjust visibility based on that. + let target = document.elementFromPoint(event.clientX, event.clientY); + this._updateVisibility(target); + + // Captures end with a mouseup but we can't know the event order of + // mouseup vs releaseCapture. + // + // In the cases when releaseCapture comes first, the code above is + // enough. + // + // In the cases when the mouseup comes first, we need wait for the + // browser to flush all events and then check again if the cursor + // should be visible. + if (this._captureIsActive()) { + window.setTimeout(() => { + // We might have detached at this point + if (!this._target) { + return; + } + // Refresh the target from elementFromPoint since queued events + // might have altered the DOM + target = document.elementFromPoint(event.clientX, + event.clientY); + this._updateVisibility(target); + }, 0); + } + } + + _showCursor() { + if (this._canvas.style.visibility === 'hidden') { + this._canvas.style.visibility = ''; + } + } + + _hideCursor() { + if (this._canvas.style.visibility !== 'hidden') { + this._canvas.style.visibility = 'hidden'; + } + } + + // Should we currently display the cursor? + // (i.e. are we over the target, or a child of the target without a + // different cursor set) + _shouldShowCursor(target) { + if (!target) { + return false; + } + // Easy case + if (target === this._target) { + return true; + } + // Other part of the DOM? + if (!this._target.contains(target)) { + return false; + } + // Has the child its own cursor? + // FIXME: How can we tell that a sub element has an + // explicit "cursor: none;"? + if (window.getComputedStyle(target).cursor !== 'none') { + return false; + } + return true; + } + + _updateVisibility(target) { + // When the cursor target has capture we want to show the cursor. + // So, if a capture is active - look at the captured element instead. + if (this._captureIsActive()) { + target = document.captureElement; + } + if (this._shouldShowCursor(target)) { + this._showCursor(); + } else { + this._hideCursor(); + } + } + + _updatePosition() { + this._canvas.style.left = this._position.x + "px"; + this._canvas.style.top = this._position.y + "px"; + } + + _captureIsActive() { + return document.captureElement && + document.documentElement.contains(document.captureElement); + } +} diff --git a/core/util/element.js b/core/util/element.js new file mode 100644 index 0000000..466a745 --- /dev/null +++ b/core/util/element.js @@ -0,0 +1,32 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2020 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +/* + * HTML element utility functions + */ + +export function clientToElement(x, y, elem) { + const bounds = elem.getBoundingClientRect(); + let pos = { x: 0, y: 0 }; + // Clip to target bounds + if (x < bounds.left) { + pos.x = 0; + } else if (x >= bounds.right) { + pos.x = bounds.width - 1; + } else { + pos.x = x - bounds.left; + } + if (y < bounds.top) { + pos.y = 0; + } else if (y >= bounds.bottom) { + pos.y = bounds.height - 1; + } else { + pos.y = y - bounds.top; + } + return pos; +} diff --git a/core/util/events.js b/core/util/events.js new file mode 100644 index 0000000..eb09fe1 --- /dev/null +++ b/core/util/events.js @@ -0,0 +1,138 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2018 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +/* + * Cross-browser event and position routines + */ + +export function getPointerEvent(e) { + return e.changedTouches ? e.changedTouches[0] : e.touches ? e.touches[0] : e; +} + +export function stopEvent(e) { + e.stopPropagation(); + e.preventDefault(); +} + +// Emulate Element.setCapture() when not supported +let _captureRecursion = false; +let _elementForUnflushedEvents = null; +document.captureElement = null; +function _captureProxy(e) { + // Recursion protection as we'll see our own event + if (_captureRecursion) return; + + // Clone the event as we cannot dispatch an already dispatched event + const newEv = new e.constructor(e.type, e); + + _captureRecursion = true; + if (document.captureElement) { + document.captureElement.dispatchEvent(newEv); + } else { + _elementForUnflushedEvents.dispatchEvent(newEv); + } + _captureRecursion = false; + + // Avoid double events + e.stopPropagation(); + + // Respect the wishes of the redirected event handlers + if (newEv.defaultPrevented) { + e.preventDefault(); + } + + // Implicitly release the capture on button release + if (e.type === "mouseup") { + releaseCapture(); + } +} + +// Follow cursor style of target element +function _capturedElemChanged() { + const proxyElem = document.getElementById("noVNC_mouse_capture_elem"); + proxyElem.style.cursor = window.getComputedStyle(document.captureElement).cursor; +} + +const _captureObserver = new MutationObserver(_capturedElemChanged); + +export function setCapture(target) { + if (target.setCapture) { + + target.setCapture(); + document.captureElement = target; + } else { + // Release any existing capture in case this method is + // called multiple times without coordination + releaseCapture(); + + let proxyElem = document.getElementById("noVNC_mouse_capture_elem"); + + if (proxyElem === null) { + proxyElem = document.createElement("div"); + proxyElem.id = "noVNC_mouse_capture_elem"; + proxyElem.style.position = "fixed"; + proxyElem.style.top = "0px"; + proxyElem.style.left = "0px"; + proxyElem.style.width = "100%"; + proxyElem.style.height = "100%"; + proxyElem.style.zIndex = 10000; + proxyElem.style.display = "none"; + document.body.appendChild(proxyElem); + + // This is to make sure callers don't get confused by having + // our blocking element as the target + proxyElem.addEventListener('contextmenu', _captureProxy); + + proxyElem.addEventListener('mousemove', _captureProxy); + proxyElem.addEventListener('mouseup', _captureProxy); + } + + document.captureElement = target; + + // Track cursor and get initial cursor + _captureObserver.observe(target, {attributes: true}); + _capturedElemChanged(); + + proxyElem.style.display = ""; + + // We listen to events on window in order to keep tracking if it + // happens to leave the viewport + window.addEventListener('mousemove', _captureProxy); + window.addEventListener('mouseup', _captureProxy); + } +} + +export function releaseCapture() { + if (document.releaseCapture) { + + document.releaseCapture(); + document.captureElement = null; + + } else { + if (!document.captureElement) { + return; + } + + // There might be events already queued. The event proxy needs + // access to the captured element for these queued events. + // E.g. contextmenu (right-click) in Microsoft Edge + // + // Before removing the capturedElem pointer we save it to a + // temporary variable that the unflushed events can use. + _elementForUnflushedEvents = document.captureElement; + document.captureElement = null; + + _captureObserver.disconnect(); + + const proxyElem = document.getElementById("noVNC_mouse_capture_elem"); + proxyElem.style.display = "none"; + + window.removeEventListener('mousemove', _captureProxy); + window.removeEventListener('mouseup', _captureProxy); + } +} diff --git a/core/util/eventtarget.js b/core/util/eventtarget.js new file mode 100644 index 0000000..a21aa54 --- /dev/null +++ b/core/util/eventtarget.js @@ -0,0 +1,35 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +export default class EventTargetMixin { + constructor() { + this._listeners = new Map(); + } + + addEventListener(type, callback) { + if (!this._listeners.has(type)) { + this._listeners.set(type, new Set()); + } + this._listeners.get(type).add(callback); + } + + removeEventListener(type, callback) { + if (this._listeners.has(type)) { + this._listeners.get(type).delete(callback); + } + } + + dispatchEvent(event) { + if (!this._listeners.has(event.type)) { + return true; + } + this._listeners.get(event.type) + .forEach(callback => callback.call(this, event)); + return !event.defaultPrevented; + } +} diff --git a/core/util/int.js b/core/util/int.js new file mode 100644 index 0000000..854bbe3 --- /dev/null +++ b/core/util/int.js @@ -0,0 +1,60 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2020 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +export function toUnsigned32bit(toConvert) { + return toConvert >>> 0; +} + +export function toSigned32bit(toConvert) { + return toConvert | 0; +} + +/* +* Converts a signed 32bit integer to a signed 16bit int +* Uses second most significant bit to represent it is relative +*/ +export function toSignedRelative16bit(toConvert) { + // TODO: move these so they are not computed with every func call + var negmask16 = 1 << 15; + var negmask32 = 1 << 31; + var relmask16 = 1 << 14; + + var converted16 = toConvert | 0; + + // number is negative + if ((toConvert & negmask32) != 0) { + // clear the 32bit negative bit + // not neccessary because the last 16bits will get dropped anyway + converted16 *= -1; + + // set the 16bit negative bit + converted16 |= negmask16; + // set the relative bit + converted16 |= relmask16; + } else { + // set the relative bit + converted16 |= relmask16; + } + + return converted16; +} + +/* Fast hashing function with low entropy */ +export function hashUInt8Array(data) { + if (typeof data === "string") { + data = [...data].map(character => character.charCodeAt(0)); + } + + let h = 0; + + for (let i = 0; i < data.length; i++) { + h = Math.imul(31, h) + data[i] | 0; + } + + return h; +} diff --git a/core/util/logging.js b/core/util/logging.js new file mode 100644 index 0000000..fe449e9 --- /dev/null +++ b/core/util/logging.js @@ -0,0 +1,56 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +/* + * Logging/debug routines + */ + +let _logLevel = 'warn'; + +let Debug = () => {}; +let Info = () => {}; +let Warn = () => {}; +let Error = () => {}; + +export function initLogging(level) { + if (typeof level === 'undefined') { + level = _logLevel; + } else { + _logLevel = level; + } + + Debug = Info = Warn = Error = () => {}; + + if (typeof window.console !== "undefined") { + /* eslint-disable no-console, no-fallthrough */ + switch (level) { + case 'debug': + Debug = console.debug.bind(window.console); + case 'info': + Info = console.info.bind(window.console); + case 'warn': + Warn = console.warn.bind(window.console); + case 'error': + Error = console.error.bind(window.console); + case 'none': + break; + default: + throw new window.Error("invalid logging type '" + level + "'"); + } + /* eslint-enable no-console, no-fallthrough */ + } +} + +export function getLogging() { + return _logLevel; +} + +export { Debug, Info, Warn, Error }; + +// Initialize logging level +initLogging(); diff --git a/core/util/strings.js b/core/util/strings.js new file mode 100644 index 0000000..3dd4b29 --- /dev/null +++ b/core/util/strings.js @@ -0,0 +1,28 @@ +/* + * noVNC: HTML5 VNC client + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * See README.md for usage and integration instructions. + */ + +// Decode from UTF-8 +export function decodeUTF8(utf8string, allowLatin1=false) { + try { + return decodeURIComponent(escape(utf8string)); + } catch (e) { + if (e instanceof URIError) { + if (allowLatin1) { + // If we allow Latin1 we can ignore any decoding fails + // and in these cases return the original string + return utf8string; + } + } + throw e; + } +} + +// Encode to UTF-8 +export function encodeUTF8(DOMString) { + return unescape(encodeURIComponent(DOMString)); +} diff --git a/core/websock.js b/core/websock.js new file mode 100644 index 0000000..32c6d7e --- /dev/null +++ b/core/websock.js @@ -0,0 +1,351 @@ +/* + * Websock: high-performance buffering wrapper + * Copyright (C) 2019 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + * + * Websock is similar to the standard WebSocket / RTCDataChannel object + * but with extra buffer handling. + * + * Websock has built-in receive queue buffering; the message event + * does not contain actual data but is simply a notification that + * there is new data available. Several rQ* methods are available to + * read binary data off of the receive queue. + */ + +import * as Log from './util/logging.js'; + +// this has performance issues in some versions Chromium, and +// doesn't gain a tremendous amount of performance increase in Firefox +// at the moment. It may be valuable to turn it on in the future. +const MAX_RQ_GROW_SIZE = 40 * 1024 * 1024; // 40 MiB + +// Constants pulled from RTCDataChannelState enum +// https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/readyState#RTCDataChannelState_enum +const DataChannel = { + CONNECTING: "connecting", + OPEN: "open", + CLOSING: "closing", + CLOSED: "closed" +}; + +const ReadyStates = { + CONNECTING: [WebSocket.CONNECTING, DataChannel.CONNECTING], + OPEN: [WebSocket.OPEN, DataChannel.OPEN], + CLOSING: [WebSocket.CLOSING, DataChannel.CLOSING], + CLOSED: [WebSocket.CLOSED, DataChannel.CLOSED], +}; + +// Properties a raw channel must have, WebSocket and RTCDataChannel are two examples +const rawChannelProps = [ + "send", + "close", + "binaryType", + "onerror", + "onmessage", + "onopen", + "protocol", + "readyState", +]; + +export default class Websock { + constructor() { + this._websocket = null; // WebSocket or RTCDataChannel object + + this._rQi = 0; // Receive queue index + this._rQlen = 0; // Next write position in the receive queue + this._rQbufferSize = 1024 * 1024 * 4; // Receive queue buffer size (4 MiB) + // called in init: this._rQ = new Uint8Array(this._rQbufferSize); + this._rQ = null; // Receive queue + + this._sQbufferSize = 1024 * 10; // 10 KiB + // called in init: this._sQ = new Uint8Array(this._sQbufferSize); + this._sQlen = 0; + this._sQ = null; // Send queue + + this._eventHandlers = { + message: () => {}, + open: () => {}, + close: () => {}, + error: () => {} + }; + } + + // Getters and Setters + get sQ() { + return this._sQ; + } + + get rQ() { + return this._rQ; + } + + get rQi() { + return this._rQi; + } + + set rQi(val) { + this._rQi = val; + } + + // Receive Queue + get rQlen() { + return this._rQlen - this._rQi; + } + + rQpeek8() { + return this._rQ[this._rQi]; + } + + rQskipBytes(bytes) { + this._rQi += bytes; + } + + rQshift8() { + return this._rQshift(1); + } + + rQshift16() { + return this._rQshift(2); + } + + rQshift32() { + return this._rQshift(4); + } + + // TODO(directxman12): test performance with these vs a DataView + _rQshift(bytes) { + let res = 0; + for (let byte = bytes - 1; byte >= 0; byte--) { + res += this._rQ[this._rQi++] << (byte * 8); + } + return res; + } + + rQshiftStr(len) { + if (typeof(len) === 'undefined') { len = this.rQlen; } + let str = ""; + // Handle large arrays in steps to avoid long strings on the stack + for (let i = 0; i < len; i += 4096) { + let part = this.rQshiftBytes(Math.min(4096, len - i)); + str += String.fromCharCode.apply(null, part); + } + return str; + } + + rQshiftBytes(len) { + if (typeof(len) === 'undefined') { len = this.rQlen; } + this._rQi += len; + return new Uint8Array(this._rQ.buffer, this._rQi - len, len); + } + + rQshiftTo(target, len) { + if (len === undefined) { len = this.rQlen; } + // TODO: make this just use set with views when using a ArrayBuffer to store the rQ + target.set(new Uint8Array(this._rQ.buffer, this._rQi, len)); + this._rQi += len; + } + + rQslice(start, end = this.rQlen) { + return new Uint8Array(this._rQ.buffer, this._rQi + start, end - start); + } + + // Check to see if we must wait for 'num' bytes (default to FBU.bytes) + // to be available in the receive queue. Return true if we need to + // wait (and possibly print a debug message), otherwise false. + rQwait(msg, num, goback) { + if (this.rQlen < num) { + if (goback) { + if (this._rQi < goback) { + throw new Error("rQwait cannot backup " + goback + " bytes"); + } + this._rQi -= goback; + } + return true; // true means need more data + } + return false; + } + + // Send Queue + + flush() { + if (this._sQlen > 0 && ReadyStates.OPEN.indexOf(this._websocket.readyState) >= 0) { + this._websocket.send(this._encodeMessage()); + this._sQlen = 0; + } + } + + send(arr) { + this._sQ.set(arr, this._sQlen); + this._sQlen += arr.length; + this.flush(); + } + + sendString(str) { + this.send(str.split('').map(chr => chr.charCodeAt(0))); + } + + // Event Handlers + off(evt) { + this._eventHandlers[evt] = () => {}; + } + + on(evt, handler) { + this._eventHandlers[evt] = handler; + } + + _allocateBuffers() { + this._rQ = new Uint8Array(this._rQbufferSize); + this._sQ = new Uint8Array(this._sQbufferSize); + } + + init() { + this._allocateBuffers(); + this._rQi = 0; + this._websocket = null; + } + + open(uri, protocols) { + this.attach(new WebSocket(uri, protocols)); + } + + attach(rawChannel) { + this.init(); + + // Must get object and class methods to be compatible with the tests. + const channelProps = [...Object.keys(rawChannel), ...Object.getOwnPropertyNames(Object.getPrototypeOf(rawChannel))]; + for (let i = 0; i < rawChannelProps.length; i++) { + const prop = rawChannelProps[i]; + if (channelProps.indexOf(prop) < 0) { + throw new Error('Raw channel missing property: ' + prop); + } + } + + this._websocket = rawChannel; + this._websocket.binaryType = "arraybuffer"; + this._websocket.onmessage = this._recvMessage.bind(this); + + const onOpen = () => { + Log.Debug('>> WebSock.onopen'); + if (this._websocket.protocol) { + Log.Info("Server choose sub-protocol: " + this._websocket.protocol); + } + + this._eventHandlers.open(); + Log.Debug("<< WebSock.onopen"); + }; + + // If the readyState cannot be found this defaults to assuming it's not open. + const isOpen = ReadyStates.OPEN.indexOf(this._websocket.readyState) >= 0; + if (isOpen) { + onOpen(); + } else { + this._websocket.onopen = onOpen; + } + + this._websocket.onclose = (e) => { + Log.Debug(">> WebSock.onclose"); + this._eventHandlers.close(e); + Log.Debug("<< WebSock.onclose"); + }; + + this._websocket.onerror = (e) => { + Log.Debug(">> WebSock.onerror: " + e); + this._eventHandlers.error(e); + Log.Debug("<< WebSock.onerror: " + e); + }; + } + + close() { + if (this._websocket) { + if (ReadyStates.CONNECTING.indexOf(this._websocket.readyState) >= 0 || + ReadyStates.OPEN.indexOf(this._websocket.readyState) >= 0) { + Log.Info("Closing WebSocket connection"); + this._websocket.close(); + } + + this._websocket.onmessage = () => {}; + } + } + + // private methods + _encodeMessage() { + // Put in a binary arraybuffer + // according to the spec, you can send ArrayBufferViews with the send method + return new Uint8Array(this._sQ.buffer, 0, this._sQlen); + } + + // We want to move all the unread data to the start of the queue, + // e.g. compacting. + // The function also expands the receive que if needed, and for + // performance reasons we combine these two actions to avoid + // unneccessary copying. + _expandCompactRQ(minFit) { + // if we're using less than 1/8th of the buffer even with the incoming bytes, compact in place + // instead of resizing + const requiredBufferSize = (this._rQlen - this._rQi + minFit) * 8; + const resizeNeeded = this._rQbufferSize < requiredBufferSize; + + if (resizeNeeded) { + // Make sure we always *at least* double the buffer size, and have at least space for 8x + // the current amount of data + this._rQbufferSize = Math.max(this._rQbufferSize * 2, requiredBufferSize); + } + + // we don't want to grow unboundedly + if (this._rQbufferSize > MAX_RQ_GROW_SIZE) { + this._rQbufferSize = MAX_RQ_GROW_SIZE; + if (this._rQbufferSize - this.rQlen < minFit) { + throw new Error("Receive Queue buffer exceeded " + MAX_RQ_GROW_SIZE + " bytes, and the new message could not fit"); + } + } + + if (resizeNeeded) { + const oldRQbuffer = this._rQ.buffer; + this._rQ = new Uint8Array(this._rQbufferSize); + this._rQ.set(new Uint8Array(oldRQbuffer, this._rQi, this._rQlen - this._rQi)); + } else { + this._rQ.copyWithin(0, this._rQi, this._rQlen); + } + + this._rQlen = this._rQlen - this._rQi; + this._rQi = 0; + } + + // push arraybuffer values onto the end of the receive que + _DecodeMessage(data) { + const u8 = new Uint8Array(data); + if (u8.length > this._rQbufferSize - this._rQlen) { + this._expandCompactRQ(u8.length); + } + this._rQ.set(u8, this._rQlen); + this._rQlen += u8.length; + } + + // Insert some new data into the current position, pushing the old data back + _insertIntoMiddle(data) { + const u8 = new Uint8Array(data); + if (u8.length > this._rQbufferSize - this._rQlen) { + this._expandCompactRQ(u8.length); + } + + this._rQ.copyWithin(this._rQi + u8.length, this._rQi, this._rQlen - this._rQi); + + this._rQ.set(u8, this._rQi); + this._rQlen += u8.length; + } + + _recvMessage(e) { + this._DecodeMessage(e.data); + if (this.rQlen > 0) { + this._eventHandlers.message(); + if (this._rQlen == this._rQi) { + // All data has now been processed, this means we + // can reset the receive queue. + this._rQlen = 0; + this._rQi = 0; + } + } else { + Log.Debug("Ignoring empty message"); + } + } +} diff --git a/docs/API-internal.md b/docs/API-internal.md new file mode 100644 index 0000000..2cac8dd --- /dev/null +++ b/docs/API-internal.md @@ -0,0 +1,89 @@ +# 1. Internal Modules + +The noVNC client is composed of several internal modules that handle +rendering, input, networking, etc. Each of the modules is designed to +be cross-browser and independent from each other. + +Note however that the API of these modules is not guaranteed to be +stable, and this documentation is not maintained as well as the +official external API. + + +## 1.1 Module List + +* __Keyboard__ (core/input/keyboard.js): Keyboard input event handler with +non-US keyboard support. Translates keyDown and keyUp events to X11 +keysym values. + +* __Display__ (core/display.js): Efficient 2D rendering abstraction +layered on the HTML5 canvas element. + +* __Websock__ (core/websock.js): Websock client from websockify +with transparent binary data support. +[Websock API](https://github.com/novnc/websockify-js/wiki/websock.js) wiki page. + + +## 1.2 Callbacks + +For the Mouse, Keyboard and Display objects the callback functions are +assigned to configuration attributes, just as for the RFB object. The +WebSock module has a method named 'on' that takes two parameters: the +callback event name, and the callback function. + +## 2. Modules + +## 2.1 Keyboard Module + +### 2.1.1 Configuration Attributes + +None + +### 2.1.2 Methods + +| name | parameters | description +| ------ | ---------- | ------------ +| grab | () | Begin capturing keyboard events +| ungrab | () | Stop capturing keyboard events + +### 2.1.3 Callbacks + +| name | parameters | description +| ---------- | -------------------- | ------------ +| onkeypress | (keysym, code, down) | Handler for key press/release + + +## 2.2 Display Module + +### 2.2.1 Configuration Attributes + +| name | type | mode | default | description +| ------------ | ----- | ---- | ------- | ------------ +| scale | float | RW | 1.0 | Display area scale factor 0.0 - 1.0 +| clipViewport | bool | RW | false | Use viewport clipping +| width | int | RO | | Display area width +| height | int | RO | | Display area height + +### 2.2.2 Methods + +| name | parameters | description +| ------------------ | ------------------------------------------------------- | ------------ +| viewportChangePos | (deltaX, deltaY) | Move the viewport relative to the current location +| viewportChangeSize | (width, height) | Change size of the viewport +| absX | (x) | Return X relative to the remote display +| absY | (y) | Return Y relative to the remote display +| resize | (width, height) | Set width and height +| flip | (from_queue) | Update the visible canvas with the contents of the rendering canvas +| pending | () | Check if there are waiting items in the render queue +| flush | () | Resume processing the render queue unless it's empty +| fillRect | (x, y, width, height, color, from_queue) | Draw a filled in rectangle +| copyImage | (old_x, old_y, new_x, new_y, width, height, from_queue) | Copy a rectangular area +| imageRect | (x, y, width, height, mime, arr) | Draw a rectangle with an image +| blitImage | (x, y, width, height, arr, offset, from_queue) | Blit pixels (of R,G,B,A) to the display +| drawImage | (img, x, y) | Draw image and track damage +| autoscale | (containerWidth, containerHeight) | Scale the display + +### 2.2.3 Callbacks + +| name | parameters | description +| ------- | ---------- | ------------ +| onflush | () | A display flush has been requested and we are now ready to resume FBU processing diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 0000000..af601ab --- /dev/null +++ b/docs/API.md @@ -0,0 +1,423 @@ +# noVNC API + +The interface of the noVNC client consists of a single RFB object that +is instantiated once per connection. + +## RFB + +The `RFB` object represents a single connection to a VNC server. It +communicates using a WebSocket that must provide a standard RFB +protocol stream. + +### Constructor + +[`RFB()`](#rfb-1) + - Creates and returns a new `RFB` object. + +### Properties + +`viewOnly` + - Is a `boolean` indicating if any events (e.g. key presses or mouse + movement) should be prevented from being sent to the server. + Disabled by default. + +`focusOnClick` + - Is a `boolean` indicating if keyboard focus should automatically be + moved to the remote session when a `mousedown` or `touchstart` + event is received. Enabled by default. + +`clipViewport` + - Is a `boolean` indicating if the remote session should be clipped + to its container. When disabled scrollbars will be shown to handle + the resulting overflow. Disabled by default. + +`dragViewport` + - Is a `boolean` indicating if mouse events should control the + relative position of a clipped remote session. Only relevant if + `clipViewport` is enabled. Disabled by default. + +`scaleViewport` + - Is a `boolean` indicating if the remote session should be scaled + locally so it fits its container. When disabled it will be centered + if the remote session is smaller than its container, or handled + according to `clipViewport` if it is larger. Disabled by default. + +`resizeSession` + - Is a `boolean` indicating if a request to resize the remote session + should be sent whenever the container changes dimensions. Disabled + by default. + +`showDotCursor` + - Is a `boolean` indicating whether a dot cursor should be shown + instead of a zero-sized or fully-transparent cursor if the server + sets such invisible cursor. Disabled by default. + +`background` + - Is a valid CSS [background](https://developer.mozilla.org/en-US/docs/Web/CSS/background) + style value indicating which background style should be applied + to the element containing the remote session screen. The default value is `rgb(40, 40, 40)` + (solid gray color). + +`qualityLevel` + - Is an `int` in range `[0-9]` controlling the desired JPEG quality. + Value `0` implies low quality and `9` implies high quality. + Default value is `6`. + +`compressionLevel` + - Is an `int` in range `[0-9]` controlling the desired compression + level. Value `0` means no compression. Level 1 uses a minimum of CPU + resources and achieves weak compression ratios, while level 9 offers + best compression but is slow in terms of CPU consumption on the server + side. Use high levels with very slow network connections. + Default value is `2`. + +`capabilities` *Read only* + - Is an `Object` indicating which optional extensions are available + on the server. Some methods may only be called if the corresponding + capability is set. The following capabilities are defined: + + | name | type | description + | -------- | --------- | ----------- + | `power` | `boolean` | Machine power control is available + +### Events + +[`connect`](#connect) + - The `connect` event is fired when the `RFB` object has completed + the connection and handshaking with the server. + +[`disconnect`](#disconnected) + - The `disconnect` event is fired when the `RFB` object disconnects. + +[`credentialsrequired`](#credentialsrequired) + - The `credentialsrequired` event is fired when more credentials must + be given to continue. + +[`securityfailure`](#securityfailure) + - The `securityfailure` event is fired when the security negotiation + with the server fails. + +[`clipboard`](#clipboard) + - The `clipboard` event is fired when clipboard data is received from + the server. + +[`bell`](#bell) + - The `bell` event is fired when a audible bell request is received + from the server. + +[`desktopname`](#desktopname) + - The `desktopname` event is fired when the remote desktop name + changes. + +[`capabilities`](#capabilities) + - The `capabilities` event is fired when `RFB.capabilities` is + updated. + +[`inputlock`](#inputlock) + - The `inputlock` event is fired when an input lock is acquired (or released) + by the canvas. + +### Methods + +[`RFB.disconnect()`](#rfbdisconnect) + - Disconnect from the server. + +[`RFB.sendCredentials()`](#rfbsendcredentials) + - Send credentials to server. Should be called after the + [`credentialsrequired`](#credentialsrequired) event has fired. + +[`RFB.sendKey()`](#rfbsendKey) + - Send a key event. + +[`RFB.sendCtrlAltDel()`](#rfbsendctrlaltdel) + - Send Ctrl-Alt-Del key sequence. + +[`RFB.focus()`](#rfbfocus) + - Move keyboard focus to the remote session. + +[`RFB.blur()`](#rfbblur) + - Remove keyboard focus from the remote session. + +[`RFB.machineShutdown()`](#rfbmachineshutdown) + - Request a shutdown of the remote machine. + +[`RFB.machineReboot()`](#rfbmachinereboot) + - Request a reboot of the remote machine. + +[`RFB.machineReset()`](#rfbmachinereset) + - Request a reset of the remote machine. + +[`RFB.clipboardPasteFrom()`](#rfbclipboardPasteFrom) + - Send clipboard contents to server. + +[`inputlock`](#inputlock) + - The `inputlock` event is fired when an input lock is acquired (or released) + by the canvas. + +### Details + +#### RFB() + +The `RFB()` constructor returns a new `RFB` object and initiates a new +connection to a specified VNC server. + +##### Syntax + + let rfb = new RFB( target, url [, options] ); + +###### Parameters + +**`target`** + - A block [`HTMLElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement) + that specifies where the `RFB` object should attach itself. The + existing contents of the `HTMLElement` will be untouched, but new + elements will be added during the lifetime of the `RFB` object. + +**`urlOrDataChannel`** + - A `DOMString` specifying the VNC server to connect to. This must be + a valid WebSocket URL. This can also be a `WebSocket` or `RTCDataChannel`. + +**`options`** *Optional* + - An `Object` specifying extra details about how the connection + should be made. + + Possible options: + + `shared` + - A `boolean` indicating if the remote server should be shared or + if any other connected clients should be disconnected. Enabled + by default. + + `credentials` + - An `Object` specifying the credentials to provide to the server + when authenticating. The following credentials are possible: + + | name | type | description + | ------------ | ----------- | ----------- + | `"username"` | `DOMString` | The user that authenticates + | `"password"` | `DOMString` | Password for the user + | `"target"` | `DOMString` | Target machine or session + + `repeaterID` + - A `DOMString` specifying the ID to provide to any VNC repeater + encountered. + + `wsProtocols` + - An `Array` of `DOMString`s specifying the sub-protocols to use + in the WebSocket connection. Empty by default. + +#### connect + +The `connect` event is fired after all the handshaking with the server +is completed and the connection is fully established. After this event +the `RFB` object is ready to recieve graphics updates and to send input. + +#### disconnect + +The `disconnect` event is fired when the connection has been +terminated. The `detail` property is an `Object` that contains the +property `clean`. `clean` is a `boolean` indicating if the termination +was clean or not. In the event of an unexpected termination or an error +`clean` will be set to false. + +#### credentialsrequired + +The `credentialsrequired` event is fired when the server requests more +credentials than were specified to [`RFB()`](#rfb-1). The `detail` +property is an `Object` containing the property `types` which is an +`Array` of `DOMString` listing the credentials that are required. + +#### securityfailure + +The `securityfailure` event is fired when the handshaking process with +the server fails during the security negotiation step. The `detail` +property is an `Object` containing the following properties: + +| Property | Type | Description +| -------- | ----------- | ----------- +| `status` | `long` | The failure status code +| `reason` | `DOMString` | The **optional** reason for the failure + +The property `status` corresponds to the +[SecurityResult](https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#securityresult) +status code in cases of failure. A status of zero will not be sent in +this event since that indicates a successful security handshaking +process. The optional property `reason` is provided by the server and +thus the language of the string is not known. However most servers will +probably send English strings. The server can choose to not send a +reason and in these cases the `reason` property will be omitted. + +#### clipboard + +The `clipboard` event is fired when the server has sent clipboard data. +The `detail` property is an `Object` containing the property `text` +which is a `DOMString` with the clipboard data. + +#### bell + +The `bell` event is fired when the server has requested an audible +bell. + +#### desktopname + +The `desktopname` event is fired when the name of the remote desktop +changes. The `detail` property is an `Object` with the property `name` +which is a `DOMString` specifying the new name. + +#### capabilities + +The `capabilities` event is fired whenever an entry is added or removed +from `RFB.capabilities`. The `detail` property is an `Object` with the +property `capabilities` containing the new value of `RFB.capabilities`. + +#### inputlock + +The `inputlock` event is fired after a request to acquire an input lock or +whenever the state of the canvas' input lock has changed, the latter typically +occurs because the lock was released by the user pressing the ESC key or +performing a browser-specific gesture. The `detail` property is an `Object` +with the property `pointer` containing whether the Pointer Lock is currently +held or not. + +#### RFB.disconnect() + +The `RFB.disconnect()` method is used to disconnect from the currently +connected server. + +##### Syntax + + RFB.disconnect( ); + +#### RFB.sendCredentials() + +The `RFB.sendCredentials()` method is used to provide the missing +credentials after a `credentialsrequired` event has been fired. + +##### Syntax + + RFB.sendCredentials( credentials ); + +###### Parameters + +**`credentials`** + - An `Object` specifying the credentials to provide to the server + when authenticating. See [`RFB()`](#rfb-1) for details. + +#### RFB.sendKey() + +The `RFB.sendKey()` method is used to send a key event to the server. + +##### Syntax + + RFB.sendKey( keysym, code [, down] ); + +###### Parameters + +**`keysym`** + - A `long` specifying the RFB keysym to send. Can be `0` if a valid + **`code`** is specified. + +**`code`** + - A `DOMString` specifying the physical key to send. Valid values are + those that can be specified to + [`KeyboardEvent.code`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code). + If the physical key cannot be determined then `null` shall be + specified. + +**`down`** *Optional* + - A `boolean` specifying if a press or a release event should be + sent. If omitted then both a press and release event are sent. + +#### RFB.sendCtrlAltDel() + +The `RFB.sendCtrlAltDel()` method is used to send the key sequence +*left Control*, *left Alt*, *Delete*. This is a convenience wrapper +around [`RFB.sendKey()`](#rfbsendkey). + +##### Syntax + + RFB.sendCtrlAltDel( ); + +#### RFB.focus() + +The `RFB.focus()` method sets the keyboard focus on the remote session. +Keyboard events will be sent to the remote server after this point. + +##### Syntax + + RFB.focus( ); + +#### RFB.blur() + +The `RFB.blur()` method remove keyboard focus on the remote session. +Keyboard events will no longer be sent to the remote server after this +point. + +##### Syntax + + RFB.blur( ); + +#### RFB.machineShutdown() + +The `RFB.machineShutdown()` method is used to request to shut down the +remote machine. The capability `power` must be set for this method to +have any effect. + +##### Syntax + + RFB.machineShutdown( ); + +#### RFB.machineReboot() + +The `RFB.machineReboot()` method is used to request a clean reboot of +the remote machine. The capability `power` must be set for this method +to have any effect. + +##### Syntax + + RFB.machineReboot( ); + +#### RFB.machineReset() + +The `RFB.machineReset()` method is used to request a forced reset of +the remote machine. The capability `power` must be set for this method +to have any effect. + +##### Syntax + + RFB.machineReset( ); + +#### RFB.clipboardPasteFrom() + +The `RFB.clipboardPasteFrom()` method is used to send clipboard data +to the remote server. + +##### Syntax + + RFB.clipboardPasteFrom( text ); + +###### Parameters + +**`text`** + - A `DOMString` specifying the clipboard data to send. + +#### RFB.requestInputLock() + +The `RFB.requestInputLock()` method is used to request that the RFB canvas hold +an input lock. An `inputlock` event will be fired with the result of the +acquisition of the requested locks. + +##### Syntax + + RFB.requestInputLock( { pointer: true } ); + +###### Parameters + +**`pointer`** + - Requests to acquire a [Pointer + Lock](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API), + which hides the local mouse cursor and provides relative motion events. + This must be called directly from an event handler where a user has + directly interacted with an element through an [engagement + gesture](https://w3c.github.io/pointerlock/#dfn-engagement-gesture) (e.g. a + click or touch event) for the browser to allow this. \ No newline at end of file diff --git a/docs/DEVELOP.md b/docs/DEVELOP.md new file mode 100644 index 0000000..5eb0042 --- /dev/null +++ b/docs/DEVELOP.md @@ -0,0 +1,30 @@ +# Overview +This fork of noVNC is designed to work with KasmVNC, which has an embedded web server. It will not work with other VNC servers and does not strictly follow the RFB protocol. + +## Dev Environment Setup +Install KasmVNC or use a Kasm Workspaces container. Remove the installed www directory, clone the git repository, and finally modify the JS so that it runs directly without the webpack + +```bash +cd /usr/share/kasmvnc +sudo rm -rf www +sudo git clone https://github.com/kasmtech/noVNC.git www +sudo chown -R user:user www +cd www +sed -i 's##' vnc.html +sed -i 's##' vnc.html +sed -i 's## #00FF00 bg color + data.push(0x00); // becomes 0000ff00 --> #0000FF fg color + data.push(0x00); + data.push(0xff); + data.push(0x00); + data.push(2); // 2 subrects + data.push(0); // x: 0, y: 0 + data.push(1 | (1 << 4)); // width: 2, height: 2 + data.push(2 | (2 << 4)); // x: 2, y: 2 + data.push(1 | (1 << 4)); // width: 2, height: 2 + + testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle a raw tile', function () { + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + let data = []; + data.push(0x01); // raw + for (let i = 0; i < targetData.length; i += 4) { + data.push(targetData[i]); + data.push(targetData[i + 1]); + data.push(targetData[i + 2]); + // Last byte zero to test correct alpha handling + data.push(0); + } + + testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle a tile with only bg specified (solid bg)', function () { + let data = []; + data.push(0x02); + push32(data, 0x00ff0000); // becomes 00ff0000 --> #00FF00 bg color + + testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + let expected = []; + for (let i = 0; i < 16; i++) { + push32(expected, 0x00ff00ff); + } + + expect(display).to.have.displayed(new Uint8Array(expected)); + }); + + it('should handle a tile with only bg specified and an empty frame afterwards', function () { + // set the width so we can have two tiles + display.resize(8, 4); + + let data = []; + + // send a bg frame + data.push(0x02); + push32(data, 0x00ff0000); // becomes 00ff0000 --> #00FF00 bg color + + // send an empty frame + data.push(0x00); + + testDecodeRect(decoder, 0, 0, 32, 4, data, display, 24); + + let expected = []; + for (let i = 0; i < 16; i++) { + push32(expected, 0x00ff00ff); // rect 1: solid + } + for (let i = 0; i < 16; i++) { + push32(expected, 0x00ff00ff); // rect 2: same bkground color + } + + expect(display).to.have.displayed(new Uint8Array(expected)); + }); + + it('should handle a tile with bg and coloured subrects', function () { + let data = []; + data.push(0x02 | 0x08 | 0x10); // bg spec, anysubrects, colouredsubrects + push32(data, 0x00ff0000); // becomes 00ff0000 --> #00FF00 bg color + data.push(2); // 2 subrects + data.push(0x00); // becomes 0000ff00 --> #0000FF fg color + data.push(0x00); + data.push(0xff); + data.push(0x00); + data.push(0); // x: 0, y: 0 + data.push(1 | (1 << 4)); // width: 2, height: 2 + data.push(0x00); // becomes 0000ff00 --> #0000FF fg color + data.push(0x00); + data.push(0xff); + data.push(0x00); + data.push(2 | (2 << 4)); // x: 2, y: 2 + data.push(1 | (1 << 4)); // width: 2, height: 2 + + testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should carry over fg and bg colors from the previous tile if not specified', function () { + display.resize(4, 17); + + let data = []; + data.push(0x02 | 0x04 | 0x08); // bg spec, fg spec, anysubrects + push32(data, 0xff00ff); // becomes 00ff00ff --> #00FF00 bg color + data.push(0x00); // becomes 0000ffff --> #0000FF fg color + data.push(0x00); + data.push(0xff); + data.push(0xff); + data.push(8); // 8 subrects + for (let i = 0; i < 4; i++) { + data.push((0 << 4) | (i * 4)); // x: 0, y: i*4 + data.push(1 | (1 << 4)); // width: 2, height: 2 + data.push((2 << 4) | (i * 4 + 2)); // x: 2, y: i * 4 + 2 + data.push(1 | (1 << 4)); // width: 2, height: 2 + } + data.push(0x08); // anysubrects + data.push(1); // 1 subrect + data.push(0); // x: 0, y: 0 + data.push(1 | (1 << 4)); // width: 2, height: 2 + + testDecodeRect(decoder, 0, 0, 4, 17, data, display, 24); + + let targetData = [ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]; + + let expected = []; + for (let i = 0; i < 4; i++) { + expected = expected.concat(targetData); + } + expected = expected.concat(targetData.slice(0, 16)); + + expect(display).to.have.displayed(new Uint8Array(expected)); + }); + + it('should fail on an invalid subencoding', function () { + let data = [45]; // an invalid subencoding + expect(() => testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24)).to.throw(); + }); + + it('should handle empty rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, [], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); +}); diff --git a/tests/test.inflator.js b/tests/test.inflator.js new file mode 100644 index 0000000..533bcd8 --- /dev/null +++ b/tests/test.inflator.js @@ -0,0 +1,113 @@ +/* eslint-disable no-console */ +const expect = chai.expect; + +import { deflateInit, deflate, Z_FULL_FLUSH } from "../vendor/pako/lib/zlib/deflate.js"; +import ZStream from "../vendor/pako/lib/zlib/zstream.js"; +import Inflator from "../core/inflator.js"; + +function _deflator(data) { + let strm = new ZStream(); + + deflateInit(strm, 5); + + /* eslint-disable camelcase */ + strm.input = data; + strm.avail_in = strm.input.length; + strm.next_in = 0; + /* eslint-enable camelcase */ + + let chunks = []; + let totalLen = 0; + while (strm.avail_in > 0) { + /* eslint-disable camelcase */ + strm.output = new Uint8Array(1024 * 10 * 10); + strm.avail_out = strm.output.length; + strm.next_out = 0; + /* eslint-enable camelcase */ + + let ret = deflate(strm, Z_FULL_FLUSH); + + // Check that return code is not an error + expect(ret).to.be.greaterThan(-1); + + let chunk = new Uint8Array(strm.output.buffer, 0, strm.next_out); + totalLen += chunk.length; + chunks.push(chunk); + } + + // Combine chunks into a single data + + let outData = new Uint8Array(totalLen); + let offset = 0; + + for (let i = 0; i < chunks.length; i++) { + outData.set(chunks[i], offset); + offset += chunks[i].length; + } + + return outData; +} + +describe('Inflate data', function () { + + it('should be able to inflate messages', function () { + let inflator = new Inflator(); + + let text = "123asdf"; + let preText = new Uint8Array(text.length); + for (let i = 0; i < preText.length; i++) { + preText[i] = text.charCodeAt(i); + } + + let compText = _deflator(preText); + + inflator.setInput(compText); + let inflatedText = inflator.inflate(preText.length); + + expect(inflatedText).to.array.equal(preText); + + }); + + it('should be able to inflate large messages', function () { + let inflator = new Inflator(); + + /* Generate a big string with random characters. Used because + repetition of letters might be deflated more effectively than + random ones. */ + let text = ""; + let characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < 300000; i++) { + text += characters.charAt(Math.floor(Math.random() * characters.length)); + } + + let preText = new Uint8Array(text.length); + for (let i = 0; i < preText.length; i++) { + preText[i] = text.charCodeAt(i); + } + + let compText = _deflator(preText); + + //Check that the compressed size is expected size + expect(compText.length).to.be.greaterThan((1024 * 10 * 10) * 2); + + inflator.setInput(compText); + let inflatedText = inflator.inflate(preText.length); + + expect(inflatedText).to.array.equal(preText); + }); + + it('should throw an error on insufficient data', function () { + let inflator = new Inflator(); + + let text = "123asdf"; + let preText = new Uint8Array(text.length); + for (let i = 0; i < preText.length; i++) { + preText[i] = text.charCodeAt(i); + } + + let compText = _deflator(preText); + + inflator.setInput(compText); + expect(() => inflator.inflate(preText.length * 2)).to.throw(); + }); +}); diff --git a/tests/test.int.js b/tests/test.int.js new file mode 100644 index 0000000..954fd27 --- /dev/null +++ b/tests/test.int.js @@ -0,0 +1,16 @@ +/* eslint-disable no-console */ +const expect = chai.expect; + +import { toUnsigned32bit, toSigned32bit } from '../core/util/int.js'; + +describe('Integer casting', function () { + it('should cast unsigned to signed', function () { + let expected = 4294967286; + expect(toUnsigned32bit(-10)).to.equal(expected); + }); + + it('should cast signed to unsigned', function () { + let expected = -10; + expect(toSigned32bit(4294967286)).to.equal(expected); + }); +}); diff --git a/tests/test.jpeg.js b/tests/test.jpeg.js new file mode 100644 index 0000000..6834f03 --- /dev/null +++ b/tests/test.jpeg.js @@ -0,0 +1,288 @@ +const expect = chai.expect; + +import Websock from '../core/websock.js'; +import Display from '../core/display.js'; + +import JPEGDecoder from '../core/decoders/jpeg.js'; + +import FakeWebSocket from './fake.websocket.js'; + +function testDecodeRect(decoder, x, y, width, height, data, display, depth) { + let sock; + + sock = new Websock; + sock.open("ws://example.com"); + + sock.on('message', () => { + decoder.decodeRect(x, y, width, height, sock, display, depth); + }); + + // Empty messages are filtered at multiple layers, so we need to + // do a direct call + if (data.length === 0) { + decoder.decodeRect(x, y, width, height, sock, display, depth); + } else { + sock._websocket._receiveData(new Uint8Array(data)); + } + + display.flip(); +} + +describe('JPEG Decoder', function () { + let decoder; + let display; + + before(FakeWebSocket.replace); + after(FakeWebSocket.restore); + + beforeEach(function () { + decoder = new JPEGDecoder(); + display = new Display(document.createElement('canvas')); + display.resize(4, 4); + }); + + it('should handle JPEG rects', function (done) { + let data = [ + // JPEG data + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, + 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x01, 0x2c, + 0x01, 0x2c, 0x00, 0x42, 0xff, 0xdb, 0x00, 0x43, + 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03, + 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, + 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0a, 0x07, + 0x07, 0x06, 0x08, 0x0c, 0x0a, 0x0c, 0x0c, 0x0b, + 0x0a, 0x0b, 0x0b, 0x0d, 0x0e, 0x12, 0x10, 0x0d, + 0x0e, 0x11, 0x0e, 0x0b, 0x0b, 0x10, 0x16, 0x10, + 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0c, 0x0f, + 0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, + 0x14, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x03, 0x04, + 0x04, 0x05, 0x04, 0x05, 0x09, 0x05, 0x05, 0x09, + 0x14, 0x0d, 0x0b, 0x0d, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xff, 0xc0, + 0x00, 0x11, 0x08, 0x00, 0x04, 0x00, 0x04, 0x03, + 0x01, 0x11, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, + 0x01, 0xff, 0xc4, 0x00, 0x1f, 0x00, 0x00, 0x01, + 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0xff, 0xc4, 0x00, 0xb5, 0x10, 0x00, + 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, + 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, + 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, + 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, + 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, + 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, + 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, + 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, + 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, + 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, + 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, + 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, + 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, + 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xff, 0xc4, 0x00, 0x1f, 0x01, 0x00, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0xff, 0xc4, 0x00, 0xb5, 0x11, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, + 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, + 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, + 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, + 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, + 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, + 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, + 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, + 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, + 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, + 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, + 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, + 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf9, + 0xf7, 0xfb, 0x67, 0x56, 0xff, 0x00, 0x9f, 0xf8, + 0x3f, 0xf0, 0x51, 0xa7, 0xff, 0x00, 0xf2, 0x3d, + 0x7e, 0x6f, 0xfd, 0xab, 0x94, 0x7f, 0xd0, 0x9a, + 0x8f, 0xfe, 0x0d, 0xc7, 0x7f, 0xf3, 0x61, 0xfd, + 0xa7, 0xff, 0x00, 0x10, 0x77, 0x0d, 0xff, 0x00, + 0x43, 0xec, 0xcf, 0xff, 0x00, 0x0b, 0xab, 0x1f, + 0xff, 0xd9, + ]; + + testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + let targetData = new Uint8Array([ + 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255 + ]); + + // Browsers have rounding errors, so we need an approximate + // comparing function + function almost(a, b) { + let diff = Math.abs(a - b); + return diff < 5; + } + + display.onflush = () => { + expect(display).to.have.displayed(targetData, almost); + done(); + }; + display.flush(); + }); + + it('should handle JPEG rects without Huffman and quantification tables', function (done) { + let data1 = [ + // JPEG data + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, + 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x01, 0x2c, + 0x01, 0x2c, 0x00, 0x42, 0xff, 0xdb, 0x00, 0x43, + 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03, + 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, + 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0a, 0x07, + 0x07, 0x06, 0x08, 0x0c, 0x0a, 0x0c, 0x0c, 0x0b, + 0x0a, 0x0b, 0x0b, 0x0d, 0x0e, 0x12, 0x10, 0x0d, + 0x0e, 0x11, 0x0e, 0x0b, 0x0b, 0x10, 0x16, 0x10, + 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0c, 0x0f, + 0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, + 0x14, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x03, 0x04, + 0x04, 0x05, 0x04, 0x05, 0x09, 0x05, 0x05, 0x09, + 0x14, 0x0d, 0x0b, 0x0d, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xff, 0xc0, + 0x00, 0x11, 0x08, 0x00, 0x04, 0x00, 0x04, 0x03, + 0x01, 0x11, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, + 0x01, 0xff, 0xc4, 0x00, 0x1f, 0x00, 0x00, 0x01, + 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0xff, 0xc4, 0x00, 0xb5, 0x10, 0x00, + 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, + 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, + 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, + 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, + 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, + 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, + 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, + 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, + 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, + 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, + 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, + 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, + 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, + 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xff, 0xc4, 0x00, 0x1f, 0x01, 0x00, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0xff, 0xc4, 0x00, 0xb5, 0x11, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, + 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, + 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, + 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, + 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, + 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, + 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, + 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, + 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, + 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, + 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, + 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, + 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf9, + 0xf7, 0xfb, 0x67, 0x56, 0xff, 0x00, 0x9f, 0xf8, + 0x3f, 0xf0, 0x51, 0xa7, 0xff, 0x00, 0xf2, 0x3d, + 0x7e, 0x6f, 0xfd, 0xab, 0x94, 0x7f, 0xd0, 0x9a, + 0x8f, 0xfe, 0x0d, 0xc7, 0x7f, 0xf3, 0x61, 0xfd, + 0xa7, 0xff, 0x00, 0x10, 0x77, 0x0d, 0xff, 0x00, + 0x43, 0xec, 0xcf, 0xff, 0x00, 0x0b, 0xab, 0x1f, + 0xff, 0xd9, + ]; + + testDecodeRect(decoder, 0, 0, 4, 4, data1, display, 24); + + let data2 = [ + // JPEG data + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, + 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x01, 0x2c, + 0x01, 0x2c, 0x00, 0x73, 0xff, 0xc0, 0x00, 0x11, + 0x08, 0x00, 0x04, 0x00, 0x04, 0x03, 0x01, 0x11, + 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, + 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, + 0x03, 0x11, 0x00, 0x3f, 0x00, 0xf9, 0xf7, 0xfb, + 0x67, 0x56, 0xff, 0x00, 0x9f, 0xf8, 0x3f, 0xf0, + 0x51, 0xa7, 0xff, 0x00, 0xf2, 0x3d, 0x7e, 0x6f, + 0xfd, 0xab, 0x94, 0x7f, 0xd0, 0x9a, 0x8f, 0xfe, + 0x0d, 0xc7, 0x7f, 0xf3, 0x61, 0xfd, 0xa7, 0xff, + 0x00, 0x10, 0x77, 0x0d, 0xff, 0x00, 0x43, 0xec, + 0xcf, 0xff, 0x00, 0x0b, 0xab, 0x1f, 0xff, 0xd9, + ]; + + testDecodeRect(decoder, 0, 0, 4, 4, data2, display, 24); + + let targetData = new Uint8Array([ + 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255 + ]); + + // Browsers have rounding errors, so we need an approximate + // comparing function + function almost(a, b) { + let diff = Math.abs(a - b); + return diff < 5; + } + + display.onflush = () => { + expect(display).to.have.displayed(targetData, almost); + done(); + }; + display.flush(); + }); +}); diff --git a/tests/test.keyboard.js b/tests/test.keyboard.js new file mode 100644 index 0000000..381cd30 --- /dev/null +++ b/tests/test.keyboard.js @@ -0,0 +1,521 @@ +const expect = chai.expect; + +import Keyboard from '../core/input/keyboard.js'; + +describe('Key Event Handling', function () { + "use strict"; + + // The real KeyboardEvent constructor might not work everywhere we + // want to run these tests + function keyevent(typeArg, KeyboardEventInit) { + const e = { type: typeArg }; + for (let key in KeyboardEventInit) { + e[key] = KeyboardEventInit[key]; + } + e.stopPropagation = sinon.spy(); + e.preventDefault = sinon.spy(); + return e; + } + + describe('Decode Keyboard Events', function () { + it('should decode keydown events', function (done) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { + expect(keysym).to.be.equal(0x61); + expect(code).to.be.equal('KeyA'); + expect(down).to.be.equal(true); + done(); + }; + kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); + }); + it('should decode keyup events', function (done) { + let calls = 0; + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { + expect(keysym).to.be.equal(0x61); + expect(code).to.be.equal('KeyA'); + if (calls++ === 1) { + expect(down).to.be.equal(false); + done(); + } + }; + kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); + kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'})); + }); + }); + + describe('Fake keyup', function () { + it('should fake keyup events for virtual keyboards', function (done) { + let count = 0; + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { + switch (count++) { + case 0: + expect(keysym).to.be.equal(0x61); + expect(code).to.be.equal('Unidentified'); + expect(down).to.be.equal(true); + break; + case 1: + expect(keysym).to.be.equal(0x61); + expect(code).to.be.equal('Unidentified'); + expect(down).to.be.equal(false); + done(); + } + }; + kbd._handleKeyDown(keyevent('keydown', {code: 'Unidentified', key: 'a'})); + }); + }); + + describe('Track Key State', function () { + it('should send release using the same keysym as the press', function (done) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { + expect(keysym).to.be.equal(0x61); + expect(code).to.be.equal('KeyA'); + if (!down) { + done(); + } + }; + kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); + kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'b'})); + }); + it('should send the same keysym for multiple presses', function () { + let count = 0; + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { + expect(keysym).to.be.equal(0x61); + expect(code).to.be.equal('KeyA'); + expect(down).to.be.equal(true); + count++; + }; + kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); + kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'b'})); + expect(count).to.be.equal(2); + }); + it('should do nothing on keyup events if no keys are down', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'})); + expect(kbd.onkeyevent).to.not.have.been.called; + }); + + describe('Legacy Events', function () { + it('should track keys using keyCode if no code', function (done) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { + expect(keysym).to.be.equal(0x61); + expect(code).to.be.equal('Platform65'); + if (!down) { + done(); + } + }; + kbd._handleKeyDown(keyevent('keydown', {keyCode: 65, key: 'a'})); + kbd._handleKeyUp(keyevent('keyup', {keyCode: 65, key: 'b'})); + }); + it('should ignore compositing code', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { + expect(keysym).to.be.equal(0x61); + expect(code).to.be.equal('Unidentified'); + }; + kbd._handleKeyDown(keyevent('keydown', {keyCode: 229, key: 'a'})); + }); + it('should track keys using keyIdentifier if no code', function (done) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { + expect(keysym).to.be.equal(0x61); + expect(code).to.be.equal('Platform65'); + if (!down) { + done(); + } + }; + kbd._handleKeyDown(keyevent('keydown', {keyIdentifier: 'U+0041', key: 'a'})); + kbd._handleKeyUp(keyevent('keyup', {keyIdentifier: 'U+0041', key: 'b'})); + }); + }); + }); + + describe('Shuffle modifiers on macOS', function () { + let origNavigator; + beforeEach(function () { + // window.navigator is a protected read-only property in many + // environments, so we need to redefine it whilst running these + // tests. + origNavigator = Object.getOwnPropertyDescriptor(window, "navigator"); + + Object.defineProperty(window, "navigator", {value: {}}); + if (window.navigator.platform !== undefined) { + // Object.defineProperty() doesn't work properly in old + // versions of Chrome + this.skip(); + } + + window.navigator.platform = "Mac x86_64"; + }); + afterEach(function () { + if (origNavigator !== undefined) { + Object.defineProperty(window, "navigator", origNavigator); + } + }); + + it('should change Alt to AltGraph', function () { + let count = 0; + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { + switch (count++) { + case 0: + expect(keysym).to.be.equal(0xFF7E); + expect(code).to.be.equal('AltLeft'); + break; + case 1: + expect(keysym).to.be.equal(0xFE03); + expect(code).to.be.equal('AltRight'); + break; + } + }; + kbd._handleKeyDown(keyevent('keydown', {code: 'AltLeft', key: 'Alt', location: 1})); + kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2})); + expect(count).to.be.equal(2); + }); + it('should change left Super to Alt', function (done) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { + expect(keysym).to.be.equal(0xFFE9); + expect(code).to.be.equal('MetaLeft'); + done(); + }; + kbd._handleKeyDown(keyevent('keydown', {code: 'MetaLeft', key: 'Meta', location: 1})); + }); + it('should change right Super to left Super', function (done) { + const kbd = new Keyboard(document); + kbd.onkeyevent = (keysym, code, down) => { + expect(keysym).to.be.equal(0xFFEB); + expect(code).to.be.equal('MetaRight'); + done(); + }; + kbd._handleKeyDown(keyevent('keydown', {code: 'MetaRight', key: 'Meta', location: 2})); + }); + }); + + describe('Caps Lock on iOS and macOS', function () { + let origNavigator; + beforeEach(function () { + // window.navigator is a protected read-only property in many + // environments, so we need to redefine it whilst running these + // tests. + origNavigator = Object.getOwnPropertyDescriptor(window, "navigator"); + + Object.defineProperty(window, "navigator", {value: {}}); + if (window.navigator.platform !== undefined) { + // Object.defineProperty() doesn't work properly in old + // versions of Chrome + this.skip(); + } + }); + + afterEach(function () { + if (origNavigator !== undefined) { + Object.defineProperty(window, "navigator", origNavigator); + } + }); + + it('should toggle caps lock on key press on iOS', function () { + window.navigator.platform = "iPad"; + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'CapsLock', key: 'CapsLock'})); + + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xFFE5, "CapsLock", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xFFE5, "CapsLock", false); + }); + + it('should toggle caps lock on key press on mac', function () { + window.navigator.platform = "Mac"; + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'CapsLock', key: 'CapsLock'})); + + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xFFE5, "CapsLock", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xFFE5, "CapsLock", false); + }); + + it('should toggle caps lock on key release on iOS', function () { + window.navigator.platform = "iPad"; + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyUp(keyevent('keyup', {code: 'CapsLock', key: 'CapsLock'})); + + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xFFE5, "CapsLock", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xFFE5, "CapsLock", false); + }); + + it('should toggle caps lock on key release on mac', function () { + window.navigator.platform = "Mac"; + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyUp(keyevent('keyup', {code: 'CapsLock', key: 'CapsLock'})); + + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xFFE5, "CapsLock", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xFFE5, "CapsLock", false); + }); + }); + + describe('Japanese IM keys on Windows', function () { + let origNavigator; + beforeEach(function () { + // window.navigator is a protected read-only property in many + // environments, so we need to redefine it whilst running these + // tests. + origNavigator = Object.getOwnPropertyDescriptor(window, "navigator"); + + Object.defineProperty(window, "navigator", {value: {}}); + if (window.navigator.platform !== undefined) { + // Object.defineProperty() doesn't work properly in old + // versions of Chrome + this.skip(); + } + + window.navigator.platform = "Windows"; + }); + + afterEach(function () { + if (origNavigator !== undefined) { + Object.defineProperty(window, "navigator", origNavigator); + } + }); + + const keys = { 'Zenkaku': 0xff2a, 'Hankaku': 0xff2a, + 'Alphanumeric': 0xff30, 'Katakana': 0xff26, + 'Hiragana': 0xff25, 'Romaji': 0xff24, + 'KanaMode': 0xff24 }; + for (let [key, keysym] of Object.entries(keys)) { + it(`should fake key release for ${key} on Windows`, function () { + let kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'FakeIM', key: key})); + + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(keysym, "FakeIM", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(keysym, "FakeIM", false); + }); + } + }); + + describe('Escape AltGraph on Windows', function () { + let origNavigator; + beforeEach(function () { + // window.navigator is a protected read-only property in many + // environments, so we need to redefine it whilst running these + // tests. + origNavigator = Object.getOwnPropertyDescriptor(window, "navigator"); + + Object.defineProperty(window, "navigator", {value: {}}); + if (window.navigator.platform !== undefined) { + // Object.defineProperty() doesn't work properly in old + // versions of Chrome + this.skip(); + } + + window.navigator.platform = "Windows x86_64"; + + this.clock = sinon.useFakeTimers(); + }); + afterEach(function () { + if (origNavigator !== undefined) { + Object.defineProperty(window, "navigator", origNavigator); + } + if (this.clock !== undefined) { + this.clock.restore(); + } + }); + + it('should supress ControlLeft until it knows if it is AltGr', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); + expect(kbd.onkeyevent).to.not.have.been.called; + }); + + it('should not trigger on repeating ControlLeft', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffe3, "ControlLeft", true); + }); + + it('should not supress ControlRight', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlRight', key: 'Control', location: 2})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe4, "ControlRight", true); + }); + + it('should release ControlLeft after 100 ms', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); + expect(kbd.onkeyevent).to.not.have.been.called; + this.clock.tick(100); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe3, "ControlLeft", true); + }); + + it('should release ControlLeft on other key press', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); + expect(kbd.onkeyevent).to.not.have.been.called; + kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0x61, "KeyA", true); + + // Check that the timer is properly dead + kbd.onkeyevent.resetHistory(); + this.clock.tick(100); + expect(kbd.onkeyevent).to.not.have.been.called; + }); + + it('should release ControlLeft on other key release', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'KeyA', key: 'a'})); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0x61, "KeyA", true); + kbd._handleKeyUp(keyevent('keyup', {code: 'KeyA', key: 'a'})); + expect(kbd.onkeyevent).to.have.been.calledThrice; + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffe3, "ControlLeft", true); + expect(kbd.onkeyevent.thirdCall).to.have.been.calledWith(0x61, "KeyA", false); + + // Check that the timer is properly dead + kbd.onkeyevent.resetHistory(); + this.clock.tick(100); + expect(kbd.onkeyevent).to.not.have.been.called; + }); + + it('should generate AltGraph for quick Ctrl+Alt sequence', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1, timeStamp: Date.now()})); + this.clock.tick(20); + kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2, timeStamp: Date.now()})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xfe03, 'AltRight', true); + + // Check that the timer is properly dead + kbd.onkeyevent.resetHistory(); + this.clock.tick(100); + expect(kbd.onkeyevent).to.not.have.been.called; + }); + + it('should generate Ctrl, Alt for slow Ctrl+Alt sequence', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'ControlLeft', key: 'Control', location: 1, timeStamp: Date.now()})); + this.clock.tick(60); + kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2, timeStamp: Date.now()})); + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent.firstCall).to.have.been.calledWith(0xffe3, "ControlLeft", true); + expect(kbd.onkeyevent.secondCall).to.have.been.calledWith(0xffea, "AltRight", true); + + // Check that the timer is properly dead + kbd.onkeyevent.resetHistory(); + this.clock.tick(100); + expect(kbd.onkeyevent).to.not.have.been.called; + }); + + it('should pass through single Alt', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'Alt', location: 2})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffea, 'AltRight', true); + }); + + it('should pass through single AltGr', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + kbd._handleKeyDown(keyevent('keydown', {code: 'AltRight', key: 'AltGraph', location: 2})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xfe03, 'AltRight', true); + }); + }); + + describe('Missing Shift keyup on Windows', function () { + let origNavigator; + beforeEach(function () { + // window.navigator is a protected read-only property in many + // environments, so we need to redefine it whilst running these + // tests. + origNavigator = Object.getOwnPropertyDescriptor(window, "navigator"); + + Object.defineProperty(window, "navigator", {value: {}}); + if (window.navigator.platform !== undefined) { + // Object.defineProperty() doesn't work properly in old + // versions of Chrome + this.skip(); + } + + window.navigator.platform = "Windows x86_64"; + + this.clock = sinon.useFakeTimers(); + }); + afterEach(function () { + if (origNavigator !== undefined) { + Object.defineProperty(window, "navigator", origNavigator); + } + if (this.clock !== undefined) { + this.clock.restore(); + } + }); + + it('should fake a left Shift keyup', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + + kbd._handleKeyDown(keyevent('keydown', {code: 'ShiftLeft', key: 'Shift', location: 1})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe1, 'ShiftLeft', true); + kbd.onkeyevent.resetHistory(); + + kbd._handleKeyDown(keyevent('keydown', {code: 'ShiftRight', key: 'Shift', location: 2})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe2, 'ShiftRight', true); + kbd.onkeyevent.resetHistory(); + + kbd._handleKeyUp(keyevent('keyup', {code: 'ShiftLeft', key: 'Shift', location: 1})); + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe2, 'ShiftRight', false); + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe1, 'ShiftLeft', false); + }); + + it('should fake a right Shift keyup', function () { + const kbd = new Keyboard(document); + kbd.onkeyevent = sinon.spy(); + + kbd._handleKeyDown(keyevent('keydown', {code: 'ShiftLeft', key: 'Shift', location: 1})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe1, 'ShiftLeft', true); + kbd.onkeyevent.resetHistory(); + + kbd._handleKeyDown(keyevent('keydown', {code: 'ShiftRight', key: 'Shift', location: 2})); + expect(kbd.onkeyevent).to.have.been.calledOnce; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe2, 'ShiftRight', true); + kbd.onkeyevent.resetHistory(); + + kbd._handleKeyUp(keyevent('keyup', {code: 'ShiftRight', key: 'Shift', location: 2})); + expect(kbd.onkeyevent).to.have.been.calledTwice; + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe2, 'ShiftRight', false); + expect(kbd.onkeyevent).to.have.been.calledWith(0xffe1, 'ShiftLeft', false); + }); + }); +}); diff --git a/tests/test.localization.js b/tests/test.localization.js new file mode 100644 index 0000000..311353a --- /dev/null +++ b/tests/test.localization.js @@ -0,0 +1,69 @@ +const expect = chai.expect; +import { l10n } from '../app/localization.js'; + +describe('Localization', function () { + "use strict"; + + describe('language selection', function () { + let origNavigator; + beforeEach(function () { + // window.navigator is a protected read-only property in many + // environments, so we need to redefine it whilst running these + // tests. + origNavigator = Object.getOwnPropertyDescriptor(window, "navigator"); + + Object.defineProperty(window, "navigator", {value: {}}); + if (window.navigator.languages !== undefined) { + // Object.defineProperty() doesn't work properly in old + // versions of Chrome + this.skip(); + } + + window.navigator.languages = []; + }); + afterEach(function () { + if (origNavigator !== undefined) { + Object.defineProperty(window, "navigator", origNavigator); + } + }); + + it('should use English by default', function () { + expect(l10n.language).to.equal('en'); + }); + it('should use English if no user language matches', function () { + window.navigator.languages = ["nl", "de"]; + l10n.setup(["es", "fr"]); + expect(l10n.language).to.equal('en'); + }); + it('should use the most preferred user language', function () { + window.navigator.languages = ["nl", "de", "fr"]; + l10n.setup(["es", "fr", "de"]); + expect(l10n.language).to.equal('de'); + }); + it('should prefer sub-languages languages', function () { + window.navigator.languages = ["pt-BR"]; + l10n.setup(["pt", "pt-BR"]); + expect(l10n.language).to.equal('pt-BR'); + }); + it('should fall back to language "parents"', function () { + window.navigator.languages = ["pt-BR"]; + l10n.setup(["fr", "pt", "de"]); + expect(l10n.language).to.equal('pt'); + }); + it('should not use specific language when user asks for a generic language', function () { + window.navigator.languages = ["pt", "de"]; + l10n.setup(["fr", "pt-BR", "de"]); + expect(l10n.language).to.equal('de'); + }); + it('should handle underscore as a separator', function () { + window.navigator.languages = ["pt-BR"]; + l10n.setup(["pt_BR"]); + expect(l10n.language).to.equal('pt_BR'); + }); + it('should handle difference in case', function () { + window.navigator.languages = ["pt-br"]; + l10n.setup(["pt-BR"]); + expect(l10n.language).to.equal('pt-BR'); + }); + }); +}); diff --git a/tests/test.ra2.js b/tests/test.ra2.js new file mode 100644 index 0000000..cc505b1 --- /dev/null +++ b/tests/test.ra2.js @@ -0,0 +1,357 @@ +const expect = chai.expect; + +import RFB from '../core/rfb.js'; + +import FakeWebSocket from './fake.websocket.js'; + +function fakeGetRandomValues(arr) { + if (arr.length === 16) { + arr.set(new Uint8Array([ + 0x1c, 0x08, 0xfe, 0x21, 0x78, 0xef, 0x4e, 0xf9, + 0x3f, 0x05, 0xec, 0xea, 0xd4, 0x6b, 0xa5, 0xd5, + ])); + } else { + arr.set(new Uint8Array([ + 0xee, 0xe2, 0xf1, 0x5a, 0x3c, 0xa7, 0xbe, 0x95, + 0x6f, 0x2a, 0x75, 0xfd, 0x62, 0x01, 0xcb, 0xbf, + 0x43, 0x74, 0xca, 0x47, 0x4d, 0xfb, 0x0f, 0xcf, + 0x3a, 0x6d, 0x55, 0x6b, 0x59, 0x3a, 0xf6, 0x87, + 0xcb, 0x03, 0xb7, 0x28, 0x35, 0x7b, 0x15, 0x8e, + 0xb6, 0xc8, 0x8f, 0x2d, 0x5e, 0x7b, 0x1c, 0x9a, + 0x32, 0x55, 0xe7, 0x64, 0x36, 0x25, 0x7b, 0xa3, + 0xe9, 0x4f, 0x6f, 0x97, 0xdc, 0xa4, 0xd4, 0x62, + 0x6d, 0x7f, 0xab, 0x02, 0x6b, 0x13, 0x56, 0x69, + 0xfb, 0xd0, 0xd4, 0x13, 0x76, 0xcd, 0x0d, 0xd0, + 0x1f, 0xd1, 0x0c, 0x63, 0x3a, 0x34, 0x20, 0x6c, + 0xbb, 0x60, 0x45, 0x82, 0x23, 0xfd, 0x7c, 0x77, + 0x6d, 0xcc, 0x5e, 0xaa, 0xc3, 0x0c, 0x43, 0xb7, + 0x8d, 0xc0, 0x27, 0x6e, 0xeb, 0x1d, 0x6c, 0x5f, + 0xd8, 0x1c, 0x3c, 0x1c, 0x60, 0x2e, 0x82, 0x15, + 0xfd, 0x2e, 0x5f, 0x3a, 0x15, 0x53, 0x14, 0x70, + 0x4f, 0xe1, 0x65, 0x68, 0x35, 0x6d, 0xc7, 0x64, + 0xdb, 0xdd, 0x09, 0x31, 0x4f, 0x7b, 0x6d, 0x6c, + 0x77, 0x59, 0x5e, 0x1e, 0xfa, 0x4b, 0x06, 0x14, + 0xbe, 0xdc, 0x9c, 0x3d, 0x7b, 0xed, 0xf3, 0x2b, + 0x19, 0x26, 0x11, 0x8e, 0x3f, 0xab, 0x73, 0x9a, + 0x0a, 0x3a, 0xaa, 0x85, 0x06, 0xd5, 0xca, 0x3f, + 0xc3, 0xe2, 0x33, 0x7f, 0x97, 0x74, 0x98, 0x8f, + 0x2f, 0xa5, 0xfc, 0x7e, 0xb1, 0x77, 0x71, 0x58, + 0xf0, 0xbc, 0x04, 0x59, 0xbb, 0xb4, 0xc6, 0xcc, + 0x0f, 0x06, 0xcd, 0xa2, 0xd5, 0x01, 0x2f, 0xb2, + 0x22, 0x0b, 0xfc, 0x1e, 0x59, 0x9f, 0xd3, 0x4f, + 0x30, 0x95, 0xc6, 0x80, 0x0f, 0x69, 0xf3, 0x4a, + 0xd4, 0x36, 0xb6, 0x5a, 0x0b, 0x16, 0x0d, 0x81, + 0x31, 0xb0, 0x69, 0xd4, 0x4e, + ])); + } +} + +async function fakeGeneratekey() { + let key = JSON.parse('{"alg":"RSA-OAEP-256","d":"B7QR2yI8sXjo8vQhJpX9odqqR\ +6wIuPrTM1B1JJEKVeSrr7OYcc1FRJ52Vap9LIAU-ezigs9QDvWMxknB8motLnG69Wck37nt9_z4s8l\ +FQp0nROA-oaR92HW34KNL1b2fEVWGI0N86h730MvTJC5O2cmKeMezIG-oNqbbfFyP8AW-WLdDlgZm1\ +1-FjzhbVpb0Bc7nRSgBPSV-EY6Sl-LuglxDx4LaTdQW7QE_WXoRUt-GYGfTseuFQQK5WeoyX3yBtQy\ +dpauW6rrgyWdtP4hDFIoZsX6w1i-UMWMMwlIB5FdnUSi26igVGADGpV_vGMP36bv-EHp0bY-Qp0gpI\ +fLfgQ","dp":"Z1v5UceFfV2bhmbG19eGYb30jFxqoRBq36PKNY7IunMs1keYy0FpLbyGhtgMZ1Ymm\ +c8wEzGYsCPEP-ykcun_rlyu7YxmcnyC9YQqTqLyqvO-7rUqDvk9TMfdqWFP6heADRhKZmEbmcau6_m\ +2MwwK9kOkMKWvpqp8_TpJMnAH7zE","dq":"OBacRE15aY3NtCR4cvP5os3sT70JbDdDLHT3IHZM6r\ +E35CYNpLDia2chm_wnMcYvKFW9zC2ajRZ15i9c_VXQzS7ZlTaQYBFyMt7kVhxMEMFsPv1crD6t3uEI\ +j0LNuNYyy0jkon_LPZKQFK654CiL-L2YaNXOH4HbHP02dWeVQIE","e":"AQAB","ext":true,"ke\ +y_ops":["decrypt"],"kty":"RSA","n":"m1c92ZFk9ZI6l_O4YFiNxbv0Ng94SB3yThy1P_mcqr\ +GDQkRiGVdcTxAk38T9PgLztmspF-6U5TAHO-gSmmW88AC9m6f1Mspps6r7zl-M_OG-TwvGzf3BDz8z\ +Eg1FPbZV7whO1M4TCAZ0PqwG7qCc6nK1WiAhaKrSpzuPdL1igfNBsX7qu5wgw4ZTTGSLbVC_LfULQ5\ +FADgFTRXUSaxm1F8C_Lwy6a2e4nTcXilmtN2IHUjHegzm-Tq2HizmR3ARdWJpESYIW5-AXoiqj29tD\ +rqCmu2WPkB2psVp83IzZfaQNQzjNfvA8GpimkcDCkP5VMRrtKCcG4ZAFnO-A3NBX_Q","p":"2Q_lN\ +L7vCOBzAppYzCZo3WSh0hX-MOZyPUznks5U2TjmfdNZoL6_FJRiGyyLvwSiZFdEAAvpAyESFfFigng\ +AqMLSf448nPg15VUGj533CotsEM0WpoEr1JCgqdUbgDAfJQIBcwOmegBqd7lWm7uzEnRCvouB70ybk\ +JfpdprhkVE","q":"tzTt-F3g2u_3Ctj26Ho9iN_wC_W0lXGzslLt5nLmss8JqdLoDDrijjU-gjeRh\ +7lgiuHdUc3dorfFKbaMNOjoW3QKqt9oZ1JM0HKeRw0X2PnWW_0WK6DK5ASWDTXbMq2sUZqJvYEyL74\ +H2Zrt0RPAux7XQLEVgND6ROdXnMJ70O0","qi":"qfl4cXQkz4BNqa2De0-PfdU-8d1w3onnaGqx1D\ +s2fHzD_SJ4cNghn2TksoT9Qo64b3pUjH9igi2pyEjomk6D12N6FG0e10u7vFKv3W5YqUOgTpYdbcWH\ +dZ2qZWJU0XQZIrF8jLGTOO4GYP6_9sJ5R7Wk_0MdqQy8qvixWD4zLcY"}'); + key = await window.crypto.subtle.importKey("jwk", key, { + name: "RSA-OAEP", + hash: {name: "SHA-256"} + }, true, ["decrypt"]); + return {privateKey: key}; +} + +const receiveData = new Uint8Array([ + // server public key + 0x00, 0x00, 0x08, 0x00, 0xac, 0x1a, 0xbc, 0x42, + 0x8a, 0x2a, 0x69, 0x65, 0x54, 0xf8, 0x9a, 0xe6, + 0x43, 0xaa, 0xf7, 0x27, 0xf6, 0x2a, 0xf8, 0x8f, + 0x36, 0xd4, 0xae, 0x54, 0x0f, 0x16, 0x28, 0x08, + 0xc2, 0x5b, 0xca, 0x23, 0xdc, 0x27, 0x88, 0x1a, + 0x12, 0x82, 0xa8, 0x54, 0xea, 0x00, 0x99, 0x8d, + 0x02, 0x1d, 0x77, 0x4a, 0xeb, 0xd0, 0x93, 0x40, + 0x79, 0x86, 0xcb, 0x37, 0xd4, 0xb2, 0xc7, 0xcd, + 0x93, 0xe1, 0x00, 0x4d, 0x86, 0xff, 0x97, 0x33, + 0x0c, 0xad, 0x51, 0x47, 0x45, 0x85, 0x56, 0x07, + 0x65, 0x21, 0x7c, 0x57, 0x6d, 0x68, 0x7d, 0xd7, + 0x00, 0x43, 0x0c, 0x9d, 0x3b, 0xa1, 0x5a, 0x11, + 0xed, 0x51, 0x77, 0xf9, 0xd1, 0x5b, 0x33, 0xd7, + 0x1a, 0xeb, 0x65, 0x57, 0xc0, 0x01, 0x51, 0xff, + 0x9b, 0x82, 0xb3, 0xeb, 0x82, 0xc2, 0x1f, 0xca, + 0x47, 0xc0, 0x6a, 0x09, 0xe0, 0xf7, 0xda, 0x39, + 0x85, 0x12, 0xe7, 0x45, 0x8d, 0xb4, 0x1a, 0xda, + 0xcb, 0x86, 0x58, 0x52, 0x37, 0x66, 0x9d, 0x8a, + 0xce, 0xf2, 0x18, 0x78, 0x7d, 0x7f, 0xf0, 0x07, + 0x94, 0x8e, 0x6b, 0x17, 0xd9, 0x00, 0x2a, 0x3a, + 0xb9, 0xd4, 0x77, 0xde, 0x70, 0x85, 0xc4, 0x3a, + 0x62, 0x10, 0x02, 0xee, 0xba, 0xd8, 0xc0, 0x62, + 0xd0, 0x8e, 0xc1, 0x98, 0x19, 0x8e, 0x39, 0x0f, + 0x3e, 0x1d, 0x61, 0xb1, 0x93, 0x13, 0x59, 0x39, + 0xcb, 0x96, 0xf2, 0x17, 0xc9, 0xe1, 0x41, 0xd3, + 0x20, 0xdd, 0x62, 0x5e, 0x7d, 0x53, 0xd6, 0xb7, + 0x1d, 0xfe, 0x02, 0x18, 0x1f, 0xe0, 0xef, 0x3d, + 0x94, 0xe3, 0x0a, 0x9c, 0x59, 0x54, 0xd8, 0x98, + 0x16, 0x9c, 0x31, 0xda, 0x41, 0x0f, 0x2e, 0x71, + 0x68, 0xe0, 0xa2, 0x62, 0x3e, 0xe5, 0x25, 0x31, + 0xcf, 0xfc, 0x67, 0x63, 0xc3, 0xb0, 0xda, 0x3f, + 0x7b, 0x59, 0xbe, 0x7e, 0x9e, 0xa8, 0xd0, 0x01, + 0x4f, 0x43, 0x7f, 0x8d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x01, + // server random + 0x01, 0x00, 0x5b, 0x58, 0x2a, 0x96, 0x2d, 0xbb, + 0x88, 0xec, 0xc3, 0x54, 0x00, 0xf3, 0xbb, 0xbe, + 0x17, 0xa3, 0x84, 0xd3, 0xef, 0xd8, 0x4a, 0x31, + 0x09, 0x20, 0xdd, 0xbc, 0x16, 0x9d, 0xc9, 0x5b, + 0x99, 0x62, 0x86, 0xfe, 0x0b, 0x28, 0x4b, 0xfe, + 0x5b, 0x56, 0x2d, 0xcb, 0x6e, 0x6f, 0xec, 0xf0, + 0x53, 0x0c, 0x33, 0x84, 0x93, 0xc9, 0xbf, 0x79, + 0xde, 0xb3, 0xb9, 0x29, 0x60, 0x78, 0xde, 0xe6, + 0x1d, 0xa7, 0x89, 0x48, 0x3f, 0xd1, 0x58, 0x66, + 0x27, 0x9c, 0xd4, 0x6e, 0x72, 0x9c, 0x6e, 0x4a, + 0xc0, 0x69, 0x79, 0x6f, 0x79, 0x0f, 0x13, 0xc4, + 0x20, 0xcf, 0xa6, 0xbb, 0xce, 0x18, 0x6d, 0xd5, + 0x9e, 0xd9, 0x67, 0xbe, 0x61, 0x43, 0x67, 0x11, + 0x76, 0x2f, 0xfd, 0x78, 0x75, 0x2b, 0x89, 0x35, + 0xdd, 0x0f, 0x13, 0x7f, 0xee, 0x78, 0xad, 0x32, + 0x56, 0x21, 0x81, 0x08, 0x1f, 0xcf, 0x4c, 0x29, + 0xa3, 0xeb, 0x89, 0x2d, 0xbe, 0xba, 0x8d, 0xe4, + 0x69, 0x28, 0xba, 0x53, 0x82, 0xce, 0x5c, 0xf6, + 0x5e, 0x5e, 0xa5, 0xb3, 0x88, 0xd8, 0x3d, 0xab, + 0xf4, 0x24, 0x9e, 0x3f, 0x04, 0xaf, 0xdc, 0x48, + 0x90, 0x53, 0x37, 0xe6, 0x82, 0x1d, 0xe0, 0x15, + 0x91, 0xa1, 0xc6, 0xa9, 0x54, 0xe5, 0x2a, 0xb5, + 0x64, 0x2d, 0x93, 0xc0, 0xc0, 0xe1, 0x0f, 0x6a, + 0x4b, 0xdb, 0x77, 0xf8, 0x4a, 0x0f, 0x83, 0x36, + 0xdd, 0x5e, 0x1e, 0xdd, 0x39, 0x65, 0xa2, 0x11, + 0xc2, 0xcf, 0x56, 0x1e, 0xa1, 0x29, 0xae, 0x11, + 0x9f, 0x3a, 0x82, 0xc7, 0xbd, 0x89, 0x6e, 0x59, + 0xb8, 0x59, 0x17, 0xcb, 0x65, 0xa0, 0x4b, 0x4d, + 0xbe, 0x33, 0x32, 0x85, 0x9c, 0xca, 0x5e, 0x95, + 0xc2, 0x5a, 0xd0, 0xc9, 0x8b, 0xf1, 0xf5, 0x14, + 0xcf, 0x76, 0x80, 0xc2, 0x24, 0x0a, 0x39, 0x7e, + 0x60, 0x64, 0xce, 0xd9, 0xb8, 0xad, 0x24, 0xa8, + 0xdf, 0xcb, + // server hash + 0x00, 0x14, 0x39, 0x30, 0x66, 0xb5, 0x66, 0x8a, + 0xcd, 0xb9, 0xda, 0xe0, 0xde, 0xcb, 0xf6, 0x47, + 0x5f, 0x54, 0x66, 0xe0, 0xbc, 0x49, 0x37, 0x01, + 0xf2, 0x9e, 0xef, 0xcc, 0xcd, 0x4d, 0x6c, 0x0e, + 0xc6, 0xab, 0x28, 0xd4, 0x7b, 0x13, + // subtype + 0x00, 0x01, 0x30, 0x2a, 0xc3, 0x0b, 0xc2, 0x1c, + 0xeb, 0x02, 0x44, 0x92, 0x5d, 0xfd, 0xf9, 0xa7, + 0x94, 0xd0, 0x19, +]); + +const sendData = new Uint8Array([ + // client public key + 0x00, 0x00, 0x08, 0x00, 0x9b, 0x57, 0x3d, 0xd9, + 0x91, 0x64, 0xf5, 0x92, 0x3a, 0x97, 0xf3, 0xb8, + 0x60, 0x58, 0x8d, 0xc5, 0xbb, 0xf4, 0x36, 0x0f, + 0x78, 0x48, 0x1d, 0xf2, 0x4e, 0x1c, 0xb5, 0x3f, + 0xf9, 0x9c, 0xaa, 0xb1, 0x83, 0x42, 0x44, 0x62, + 0x19, 0x57, 0x5c, 0x4f, 0x10, 0x24, 0xdf, 0xc4, + 0xfd, 0x3e, 0x02, 0xf3, 0xb6, 0x6b, 0x29, 0x17, + 0xee, 0x94, 0xe5, 0x30, 0x07, 0x3b, 0xe8, 0x12, + 0x9a, 0x65, 0xbc, 0xf0, 0x00, 0xbd, 0x9b, 0xa7, + 0xf5, 0x32, 0xca, 0x69, 0xb3, 0xaa, 0xfb, 0xce, + 0x5f, 0x8c, 0xfc, 0xe1, 0xbe, 0x4f, 0x0b, 0xc6, + 0xcd, 0xfd, 0xc1, 0x0f, 0x3f, 0x33, 0x12, 0x0d, + 0x45, 0x3d, 0xb6, 0x55, 0xef, 0x08, 0x4e, 0xd4, + 0xce, 0x13, 0x08, 0x06, 0x74, 0x3e, 0xac, 0x06, + 0xee, 0xa0, 0x9c, 0xea, 0x72, 0xb5, 0x5a, 0x20, + 0x21, 0x68, 0xaa, 0xd2, 0xa7, 0x3b, 0x8f, 0x74, + 0xbd, 0x62, 0x81, 0xf3, 0x41, 0xb1, 0x7e, 0xea, + 0xbb, 0x9c, 0x20, 0xc3, 0x86, 0x53, 0x4c, 0x64, + 0x8b, 0x6d, 0x50, 0xbf, 0x2d, 0xf5, 0x0b, 0x43, + 0x91, 0x40, 0x0e, 0x01, 0x53, 0x45, 0x75, 0x12, + 0x6b, 0x19, 0xb5, 0x17, 0xc0, 0xbf, 0x2f, 0x0c, + 0xba, 0x6b, 0x67, 0xb8, 0x9d, 0x37, 0x17, 0x8a, + 0x59, 0xad, 0x37, 0x62, 0x07, 0x52, 0x31, 0xde, + 0x83, 0x39, 0xbe, 0x4e, 0xad, 0x87, 0x8b, 0x39, + 0x91, 0xdc, 0x04, 0x5d, 0x58, 0x9a, 0x44, 0x49, + 0x82, 0x16, 0xe7, 0xe0, 0x17, 0xa2, 0x2a, 0xa3, + 0xdb, 0xdb, 0x43, 0xae, 0xa0, 0xa6, 0xbb, 0x65, + 0x8f, 0x90, 0x1d, 0xa9, 0xb1, 0x5a, 0x7c, 0xdc, + 0x8c, 0xd9, 0x7d, 0xa4, 0x0d, 0x43, 0x38, 0xcd, + 0x7e, 0xf0, 0x3c, 0x1a, 0x98, 0xa6, 0x91, 0xc0, + 0xc2, 0x90, 0xfe, 0x55, 0x31, 0x1a, 0xed, 0x28, + 0x27, 0x06, 0xe1, 0x90, 0x05, 0x9c, 0xef, 0x80, + 0xdc, 0xd0, 0x57, 0xfd, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x01, + // client random + 0x01, 0x00, 0x84, 0x7f, 0x26, 0x54, 0x74, 0xf6, + 0x47, 0xaf, 0x33, 0x64, 0x0d, 0xa6, 0xe5, 0x30, + 0xba, 0xe6, 0xe4, 0x8e, 0x50, 0x40, 0x71, 0x1c, + 0x0e, 0x06, 0x63, 0xf5, 0x07, 0x2a, 0x26, 0x68, + 0xd6, 0xcf, 0xa6, 0x80, 0x84, 0x5e, 0x64, 0xd4, + 0x5e, 0x62, 0x31, 0xfe, 0x44, 0x51, 0x0b, 0x7c, + 0x4d, 0x55, 0xc5, 0x4a, 0x7e, 0x0d, 0x4d, 0x9b, + 0x84, 0xb4, 0x32, 0x2b, 0x4d, 0x8a, 0x34, 0x8d, + 0xc8, 0xcf, 0x19, 0x3b, 0x64, 0x82, 0x27, 0x9e, + 0xa7, 0x70, 0x2a, 0xc1, 0xb8, 0xf3, 0x6a, 0x3a, + 0xf2, 0x75, 0x6e, 0x1d, 0xeb, 0xb6, 0x70, 0x7a, + 0x15, 0x18, 0x38, 0x00, 0xb4, 0x4f, 0x55, 0xb5, + 0xd8, 0x03, 0x4e, 0xb8, 0x53, 0xff, 0x80, 0x62, + 0xf1, 0x9d, 0x27, 0xe8, 0x2a, 0x3d, 0x98, 0x19, + 0x32, 0x09, 0x7e, 0x9a, 0xb0, 0xc7, 0x46, 0x23, + 0x10, 0x85, 0x35, 0x00, 0x96, 0xce, 0xb3, 0x2c, + 0x84, 0x8d, 0xf4, 0x9e, 0xa8, 0x42, 0x67, 0xed, + 0x09, 0xa6, 0x09, 0x97, 0xb3, 0x64, 0x26, 0xfb, + 0x71, 0x11, 0x9b, 0x3f, 0xbb, 0x57, 0xb8, 0x5b, + 0x2e, 0xc5, 0x2d, 0x8c, 0x5c, 0xf7, 0xef, 0x27, + 0x25, 0x88, 0x42, 0x45, 0x43, 0xa4, 0xe7, 0xde, + 0xea, 0xf9, 0x15, 0x7b, 0x5d, 0x66, 0x24, 0xce, + 0xf7, 0xc8, 0x2f, 0xc5, 0xc0, 0x3d, 0xcd, 0xf2, + 0x62, 0xfc, 0x1a, 0x5e, 0xec, 0xff, 0xf1, 0x1b, + 0xc8, 0xdb, 0xc1, 0x0f, 0x54, 0x66, 0x9e, 0xfd, + 0x99, 0x9b, 0x23, 0x70, 0x62, 0x37, 0x80, 0xad, + 0x91, 0x6b, 0x84, 0x85, 0x6a, 0x4c, 0x80, 0x9e, + 0x60, 0x8a, 0x93, 0xa3, 0xc8, 0x8e, 0xc4, 0x4b, + 0x4d, 0xb4, 0x8e, 0x3e, 0xaf, 0xce, 0xcd, 0x83, + 0xe5, 0x21, 0x90, 0x95, 0x20, 0x3c, 0x82, 0xb4, + 0x7c, 0xab, 0x63, 0x9c, 0xae, 0xc3, 0xc9, 0x71, + 0x1a, 0xec, 0x34, 0x18, 0x47, 0xec, 0x5c, 0x4d, + 0xed, 0x84, + // client hash + 0x00, 0x14, 0x9c, 0x91, 0x9e, 0x76, 0xcf, 0x1e, + 0x66, 0x87, 0x5e, 0x29, 0xf1, 0x13, 0x80, 0xea, + 0x7d, 0xec, 0xae, 0xf9, 0x60, 0x01, 0xd3, 0x6f, + 0xb7, 0x9e, 0xb2, 0xcd, 0x2d, 0xc8, 0xf8, 0x84, + 0xb2, 0x9f, 0xc3, 0x7e, 0xb4, 0xbe, + // credentials + 0x00, 0x08, 0x9d, 0xc8, 0x3a, 0xb8, 0x80, 0x4f, + 0xe3, 0x52, 0xdb, 0x62, 0x9e, 0x97, 0x64, 0x82, + 0xa8, 0xa1, 0x6b, 0x7e, 0x4d, 0x68, 0x8c, 0x29, + 0x91, 0x38, +]); + +describe('RA2 handshake', function () { + let sock; + let rfb; + let sentData; + + before(() => { + FakeWebSocket.replace(); + sinon.stub(window.crypto, "getRandomValues").callsFake(fakeGetRandomValues); + sinon.stub(window.crypto.subtle, "generateKey").callsFake(fakeGeneratekey); + }); + after(() => { + FakeWebSocket.restore(); + window.crypto.getRandomValues.restore(); + window.crypto.subtle.generateKey.restore(); + }); + + it('should fire the serververification event', function (done) { + sentData = new Uint8Array(); + rfb = new RFB(document.createElement('div'), "ws://example.com"); + sock = rfb._sock; + sock.send = (data) => { + let res = new Uint8Array(sentData.length + data.length); + res.set(sentData); + res.set(data, sentData.length); + sentData = res; + }; + rfb._rfbInitState = "Security"; + rfb._rfbVersion = 3.8; + sock._websocket._receiveData(new Uint8Array([1, 6])); + rfb.addEventListener("serververification", (e) => { + expect(e.detail.publickey).to.eql(receiveData.slice(0, 516)); + done(); + }); + sock._websocket._receiveData(receiveData); + }); + + it('should handle approveServer and fire the credentialsrequired event', function (done) { + rfb.addEventListener("credentialsrequired", (e) => { + expect(e.detail.types).to.eql(["password"]); + done(); + }); + rfb.approveServer(); + }); + + it('should match sendData after sending credentials', function (done) { + rfb.addEventListener("securityresult", (event) => { + expect(sentData.slice(1)).to.eql(sendData); + done(); + }); + rfb.sendCredentials({ "password": "123456" }); + }); +}); diff --git a/tests/test.raw.js b/tests/test.raw.js new file mode 100644 index 0000000..bc7adc7 --- /dev/null +++ b/tests/test.raw.js @@ -0,0 +1,129 @@ +const expect = chai.expect; + +import Websock from '../core/websock.js'; +import Display from '../core/display.js'; + +import RawDecoder from '../core/decoders/raw.js'; + +import FakeWebSocket from './fake.websocket.js'; + +function testDecodeRect(decoder, x, y, width, height, data, display, depth) { + let sock; + + sock = new Websock; + sock.open("ws://example.com"); + + sock.on('message', () => { + decoder.decodeRect(x, y, width, height, sock, display, depth); + }); + + // Empty messages are filtered at multiple layers, so we need to + // do a direct call + if (data.length === 0) { + decoder.decodeRect(x, y, width, height, sock, display, depth); + } else { + sock._websocket._receiveData(new Uint8Array(data)); + } + + display.flip(); +} + +describe('Raw Decoder', function () { + let decoder; + let display; + + before(FakeWebSocket.replace); + after(FakeWebSocket.restore); + + beforeEach(function () { + decoder = new RawDecoder(); + display = new Display(document.createElement('canvas')); + display.resize(4, 4); + }); + + it('should handle the Raw encoding', function () { + testDecodeRect(decoder, 0, 0, 2, 2, + [0xff, 0x00, 0x00, 0, 0x00, 0xff, 0x00, 0, + 0x00, 0xff, 0x00, 0, 0xff, 0x00, 0x00, 0], + display, 24); + testDecodeRect(decoder, 2, 0, 2, 2, + [0x00, 0x00, 0xff, 0, 0x00, 0x00, 0xff, 0, + 0x00, 0x00, 0xff, 0, 0x00, 0x00, 0xff, 0], + display, 24); + testDecodeRect(decoder, 0, 2, 4, 1, + [0xee, 0x00, 0xff, 0, 0x00, 0xee, 0xff, 0, + 0xaa, 0xee, 0xff, 0, 0xab, 0xee, 0xff, 0], + display, 24); + testDecodeRect(decoder, 0, 3, 4, 1, + [0xee, 0x00, 0xff, 0, 0x00, 0xee, 0xff, 0, + 0xaa, 0xee, 0xff, 0, 0xab, 0xee, 0xff, 0], + display, 24); + + let targetData = new Uint8Array([ + 0xff, 0x00, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0xff, 0x00, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0xee, 0x00, 0xff, 255, 0x00, 0xee, 0xff, 255, 0xaa, 0xee, 0xff, 255, 0xab, 0xee, 0xff, 255, + 0xee, 0x00, 0xff, 255, 0x00, 0xee, 0xff, 255, 0xaa, 0xee, 0xff, 255, 0xab, 0xee, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle the Raw encoding in low colour mode', function () { + testDecodeRect(decoder, 0, 0, 2, 2, + [0x30, 0x30, 0x30, 0x30], + display, 8); + testDecodeRect(decoder, 2, 0, 2, 2, + [0x0c, 0x0c, 0x0c, 0x0c], + display, 8); + testDecodeRect(decoder, 0, 2, 4, 1, + [0x0c, 0x0c, 0x30, 0x30], + display, 8); + testDecodeRect(decoder, 0, 3, 4, 1, + [0x0c, 0x0c, 0x30, 0x30], + display, 8); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle empty rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, [], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle empty rects in low colour mode', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, [], display, 8); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); +}); diff --git a/tests/test.rfb.js b/tests/test.rfb.js new file mode 100644 index 0000000..75d1e11 --- /dev/null +++ b/tests/test.rfb.js @@ -0,0 +1,4224 @@ +const expect = chai.expect; + +import RFB from '../core/rfb.js'; +import Websock from '../core/websock.js'; +import ZStream from "../vendor/pako/lib/zlib/zstream.js"; +import { deflateInit, deflate } from "../vendor/pako/lib/zlib/deflate.js"; +import { encodings } from '../core/encodings.js'; +import { toUnsigned32bit } from '../core/util/int.js'; +import { encodeUTF8 } from '../core/util/strings.js'; +import KeyTable from '../core/input/keysym.js'; + +import FakeWebSocket from './fake.websocket.js'; + +function push8(arr, num) { + "use strict"; + arr.push(num & 0xFF); +} + +function push16(arr, num) { + "use strict"; + arr.push((num >> 8) & 0xFF, + num & 0xFF); +} + +function push32(arr, num) { + "use strict"; + arr.push((num >> 24) & 0xFF, + (num >> 16) & 0xFF, + (num >> 8) & 0xFF, + num & 0xFF); +} + +function pushString(arr, string) { + let utf8 = unescape(encodeURIComponent(string)); + for (let i = 0; i < utf8.length; i++) { + arr.push(utf8.charCodeAt(i)); + } +} + +function deflateWithSize(data) { + // Adds the size of the string in front before deflating + + let unCompData = []; + unCompData.push((data.length >> 24) & 0xFF, + (data.length >> 16) & 0xFF, + (data.length >> 8) & 0xFF, + (data.length & 0xFF)); + + for (let i = 0; i < data.length; i++) { + unCompData.push(data.charCodeAt(i)); + } + + let strm = new ZStream(); + let chunkSize = 1024 * 10 * 10; + strm.output = new Uint8Array(chunkSize); + deflateInit(strm, 5); + + /* eslint-disable camelcase */ + strm.input = unCompData; + strm.avail_in = strm.input.length; + strm.next_in = 0; + strm.next_out = 0; + strm.avail_out = chunkSize; + /* eslint-enable camelcase */ + + deflate(strm, 3); + + return new Uint8Array(strm.output.buffer, 0, strm.next_out); +} + +describe('Remote Frame Buffer Protocol Client', function () { + let clock; + let raf; + let fakeResizeObserver = null; + const realObserver = window.ResizeObserver; + + // Since we are using fake timers we don't actually want + // to wait for the browser to observe the size change, + // that's why we use a fake ResizeObserver + class FakeResizeObserver { + constructor(handler) { + this.fire = handler; + fakeResizeObserver = this; + } + disconnect() {} + observe(target, options) {} + unobserve(target) {} + } + + before(FakeWebSocket.replace); + after(FakeWebSocket.restore); + + before(function () { + this.clock = clock = sinon.useFakeTimers(Date.now()); + // sinon doesn't support this yet + raf = window.requestAnimationFrame; + window.requestAnimationFrame = setTimeout; + // We must do this in a 'before' since it needs to be set before + // the RFB constructor, which runs in beforeEach further down + window.ResizeObserver = FakeResizeObserver; + // Use a single set of buffers instead of reallocating to + // speed up tests + const sock = new Websock(); + const _sQ = new Uint8Array(sock._sQbufferSize); + const rQ = new Uint8Array(sock._rQbufferSize); + + Websock.prototype._oldAllocateBuffers = Websock.prototype._allocateBuffers; + Websock.prototype._allocateBuffers = function () { + this._sQ = _sQ; + this._rQ = rQ; + }; + + // Avoiding printing the entire Websock buffer on errors + Websock.prototype.toString = function () { return "[object Websock]"; }; + }); + + after(function () { + delete Websock.prototype.toString; + this.clock.restore(); + window.requestAnimationFrame = raf; + window.ResizeObserver = realObserver; + }); + + let container; + let rfbs; + + beforeEach(function () { + // Create a container element for all RFB objects to attach to + container = document.createElement('div'); + container.style.width = "100%"; + container.style.height = "100%"; + document.body.appendChild(container); + + // And track all created RFB objects + rfbs = []; + }); + afterEach(function () { + // Make sure every created RFB object is properly cleaned up + // or they might affect subsequent tests + rfbs.forEach(function (rfb) { + rfb.disconnect(); + expect(rfb._disconnect).to.have.been.called; + }); + rfbs = []; + + document.body.removeChild(container); + container = null; + }); + + function makeRFB(url, options) { + url = url || 'wss://host:8675'; + const rfb = new RFB(container, url, options); + clock.tick(); + rfb._sock._websocket._open(); + rfb._rfbConnectionState = 'connected'; + sinon.spy(rfb, "_disconnect"); + rfbs.push(rfb); + return rfb; + } + + describe('Connecting/Disconnecting', function () { + describe('#RFB (constructor)', function () { + let open, attach; + beforeEach(function () { + open = sinon.spy(Websock.prototype, 'open'); + attach = sinon.spy(Websock.prototype, 'attach'); + }); + afterEach(function () { + open.restore(); + attach.restore(); + }); + + it('should actually connect to the websocket', function () { + new RFB(document.createElement('div'), 'ws://HOST:8675/PATH'); + expect(open).to.have.been.calledOnceWithExactly('ws://HOST:8675/PATH', []); + }); + + it('should pass on connection problems', function () { + open.restore(); + open = sinon.stub(Websock.prototype, 'open'); + open.throws(new Error('Failure')); + expect(() => new RFB(document.createElement('div'), 'ws://HOST:8675/PATH')).to.throw('Failure'); + }); + + it('should handle WebSocket/RTCDataChannel objects', function () { + let sock = new FakeWebSocket('ws://HOST:8675/PATH', []); + new RFB(document.createElement('div'), sock); + expect(open).to.not.have.been.called; + expect(attach).to.have.been.calledOnceWithExactly(sock); + }); + + it('should handle already open WebSocket/RTCDataChannel objects', function () { + let sock = new FakeWebSocket('ws://HOST:8675/PATH', []); + sock._open(); + const client = new RFB(document.createElement('div'), sock); + let callback = sinon.spy(); + client.addEventListener('disconnect', callback); + expect(open).to.not.have.been.called; + expect(attach).to.have.been.calledOnceWithExactly(sock); + // Check if it is ready for some data + sock._receiveData(new Uint8Array(['R', 'F', 'B', '0', '0', '3', '0', '0', '8'])); + expect(callback).to.not.have.been.called; + }); + + it('should refuse closed WebSocket/RTCDataChannel objects', function () { + let sock = new FakeWebSocket('ws://HOST:8675/PATH', []); + sock.readyState = WebSocket.CLOSED; + expect(() => new RFB(document.createElement('div'), sock)).to.throw(); + }); + + it('should pass on attach problems', function () { + attach.restore(); + attach = sinon.stub(Websock.prototype, 'attach'); + attach.throws(new Error('Failure')); + let sock = new FakeWebSocket('ws://HOST:8675/PATH', []); + expect(() => new RFB(document.createElement('div'), sock)).to.throw('Failure'); + }); + }); + + describe('#disconnect', function () { + let client; + let close; + + beforeEach(function () { + client = makeRFB(); + close = sinon.stub(Websock.prototype, "close"); + }); + afterEach(function () { + close.restore(); + }); + + it('should start closing WebSocket', function () { + let callback = sinon.spy(); + client.addEventListener('disconnect', callback); + client.disconnect(); + expect(close).to.have.been.calledOnceWithExactly(); + expect(callback).to.not.have.been.called; + }); + + it('should send disconnect event', function () { + let callback = sinon.spy(); + client.addEventListener('disconnect', callback); + client.disconnect(); + close.thisValues[0]._eventHandlers.close(new CloseEvent("close", { 'code': 1000, 'reason': "", 'wasClean': true })); + expect(callback).to.have.been.calledOnce; + expect(callback.args[0][0].detail.clean).to.be.true; + }); + + it('should force disconnect if disconnecting takes too long', function () { + let callback = sinon.spy(); + client.addEventListener('disconnect', callback); + client.disconnect(); + this.clock.tick(3 * 1000); + expect(callback).to.have.been.calledOnce; + expect(callback.args[0][0].detail.clean).to.be.true; + }); + + it('should not fail if disconnect completes before timeout', function () { + let callback = sinon.spy(); + client.addEventListener('disconnect', callback); + client.disconnect(); + client._updateConnectionState('disconnecting'); + this.clock.tick(3 * 1000 / 2); + close.thisValues[0]._eventHandlers.close(new CloseEvent("close", { 'code': 1000, 'reason': "", 'wasClean': true })); + this.clock.tick(3 * 1000 / 2 + 1); + expect(callback).to.have.been.calledOnce; + expect(callback.args[0][0].detail.clean).to.be.true; + }); + + it('should unregister error event handler', function () { + sinon.spy(client._sock, 'off'); + client.disconnect(); + expect(client._sock.off).to.have.been.calledWith('error'); + }); + + it('should unregister message event handler', function () { + sinon.spy(client._sock, 'off'); + client.disconnect(); + expect(client._sock.off).to.have.been.calledWith('message'); + }); + + it('should unregister open event handler', function () { + sinon.spy(client._sock, 'off'); + client.disconnect(); + expect(client._sock.off).to.have.been.calledWith('open'); + }); + }); + + describe('#sendCredentials', function () { + let client; + beforeEach(function () { + client = makeRFB(); + client._rfbConnectionState = 'connecting'; + }); + + it('should set the rfb credentials properly"', function () { + client.sendCredentials({ password: 'pass' }); + expect(client._rfbCredentials).to.deep.equal({ password: 'pass' }); + }); + + it('should call initMsg "soon"', function () { + client._initMsg = sinon.spy(); + client.sendCredentials({ password: 'pass' }); + this.clock.tick(5); + expect(client._initMsg).to.have.been.calledOnce; + }); + }); + }); + + describe('Public API Basic Behavior', function () { + let client; + beforeEach(function () { + client = makeRFB(); + }); + + describe('#sendCtrlAlDel', function () { + it('should sent ctrl[down]-alt[down]-del[down] then del[up]-alt[up]-ctrl[up]', function () { + const expected = {_sQ: new Uint8Array(48), _sQlen: 0, flush: () => {}}; + RFB.messages.keyEvent(expected, 0xFFE3, 1); + RFB.messages.keyEvent(expected, 0xFFE9, 1); + RFB.messages.keyEvent(expected, 0xFFFF, 1); + RFB.messages.keyEvent(expected, 0xFFFF, 0); + RFB.messages.keyEvent(expected, 0xFFE9, 0); + RFB.messages.keyEvent(expected, 0xFFE3, 0); + + client.sendCtrlAltDel(); + expect(client._sock).to.have.sent(expected._sQ); + }); + + it('should not send the keys if we are not in a normal state', function () { + sinon.spy(client._sock, 'flush'); + client._rfbConnectionState = "connecting"; + client.sendCtrlAltDel(); + expect(client._sock.flush).to.not.have.been.called; + }); + + it('should not send the keys if we are set as view_only', function () { + sinon.spy(client._sock, 'flush'); + client._viewOnly = true; + client.sendCtrlAltDel(); + expect(client._sock.flush).to.not.have.been.called; + }); + }); + + describe('#sendKey', function () { + it('should send a single key with the given code and state (down = true)', function () { + const expected = {_sQ: new Uint8Array(8), _sQlen: 0, flush: () => {}}; + RFB.messages.keyEvent(expected, 123, 1); + client.sendKey(123, 'Key123', true); + expect(client._sock).to.have.sent(expected._sQ); + }); + + it('should send both a down and up event if the state is not specified', function () { + const expected = {_sQ: new Uint8Array(16), _sQlen: 0, flush: () => {}}; + RFB.messages.keyEvent(expected, 123, 1); + RFB.messages.keyEvent(expected, 123, 0); + client.sendKey(123, 'Key123'); + expect(client._sock).to.have.sent(expected._sQ); + }); + + it('should not send the key if we are not in a normal state', function () { + sinon.spy(client._sock, 'flush'); + client._rfbConnectionState = "connecting"; + client.sendKey(123, 'Key123'); + expect(client._sock.flush).to.not.have.been.called; + }); + + it('should not send the key if we are set as view_only', function () { + sinon.spy(client._sock, 'flush'); + client._viewOnly = true; + client.sendKey(123, 'Key123'); + expect(client._sock.flush).to.not.have.been.called; + }); + + it('should send QEMU extended events if supported', function () { + client._qemuExtKeyEventSupported = true; + const expected = {_sQ: new Uint8Array(12), _sQlen: 0, flush: () => {}}; + RFB.messages.QEMUExtendedKeyEvent(expected, 0x20, true, 0x0039); + client.sendKey(0x20, 'Space', true); + expect(client._sock).to.have.sent(expected._sQ); + }); + + it('should not send QEMU extended events if unknown key code', function () { + client._qemuExtKeyEventSupported = true; + const expected = {_sQ: new Uint8Array(8), _sQlen: 0, flush: () => {}}; + RFB.messages.keyEvent(expected, 123, 1); + client.sendKey(123, 'FooBar', true); + expect(client._sock).to.have.sent(expected._sQ); + }); + }); + + describe('#focus', function () { + it('should move focus to canvas object', function () { + client._canvas.focus = sinon.spy(); + client.focus(); + expect(client._canvas.focus).to.have.been.calledOnce; + }); + + it('should include focus options', function () { + client._canvas.focus = sinon.spy(); + client.focus({ foobar: 12, gazonk: true }); + expect(client._canvas.focus).to.have.been.calledOnce; + expect(client._canvas.focus).to.have.been.calledWith({ foobar: 12, gazonk: true}); + }); + }); + + describe('#blur', function () { + it('should remove focus from canvas object', function () { + client._canvas.blur = sinon.spy(); + client.blur(); + expect(client._canvas.blur).to.have.been.calledOnce; + }); + }); + + describe('#clipboardPasteFrom', function () { + describe('Clipboard update handling', function () { + beforeEach(function () { + sinon.spy(RFB.messages, 'clientCutText'); + sinon.spy(RFB.messages, 'extendedClipboardNotify'); + }); + + afterEach(function () { + RFB.messages.clientCutText.restore(); + RFB.messages.extendedClipboardNotify.restore(); + }); + + it('should send the given text in an clipboard update', function () { + client.clipboardPasteFrom('abc'); + + expect(RFB.messages.clientCutText).to.have.been.calledOnce; + expect(RFB.messages.clientCutText).to.have.been.calledWith(client._sock, + new Uint8Array([97, 98, 99])); + }); + + it('should send an notify if extended clipboard is supported by server', function () { + // Send our capabilities + let data = [3, 0, 0, 0]; + const flags = [0x1F, 0x00, 0x00, 0x01]; + let fileSizes = [0x00, 0x00, 0x00, 0x1E]; + + push32(data, toUnsigned32bit(-8)); + data = data.concat(flags); + data = data.concat(fileSizes); + client._sock._websocket._receiveData(new Uint8Array(data)); + + client.clipboardPasteFrom('extended test'); + expect(RFB.messages.extendedClipboardNotify).to.have.been.calledOnce; + }); + }); + + it('should flush multiple times for large clipboards', function () { + sinon.spy(client._sock, 'flush'); + let longText = ""; + for (let i = 0; i < client._sock._sQbufferSize + 100; i++) { + longText += 'a'; + } + client.clipboardPasteFrom(longText); + expect(client._sock.flush).to.have.been.calledTwice; + }); + + it('should not send the text if we are not in a normal state', function () { + sinon.spy(client._sock, 'flush'); + client._rfbConnectionState = "connecting"; + client.clipboardPasteFrom('abc'); + expect(client._sock.flush).to.not.have.been.called; + }); + }); + + describe("XVP operations", function () { + beforeEach(function () { + client._rfbXvpVer = 1; + }); + + it('should send the shutdown signal on #machineShutdown', function () { + client.machineShutdown(); + expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x02])); + }); + + it('should send the reboot signal on #machineReboot', function () { + client.machineReboot(); + expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x03])); + }); + + it('should send the reset signal on #machineReset', function () { + client.machineReset(); + expect(client._sock).to.have.sent(new Uint8Array([0xFA, 0x00, 0x01, 0x04])); + }); + + it('should not send XVP operations with higher versions than we support', function () { + sinon.spy(client._sock, 'flush'); + client._xvpOp(2, 7); + expect(client._sock.flush).to.not.have.been.called; + }); + }); + }); + + describe('Clipping', function () { + let client; + + beforeEach(function () { + client = makeRFB(); + container.style.width = '70px'; + container.style.height = '80px'; + client.clipViewport = true; + }); + + it('should update display clip state when changing the property', function () { + const spy = sinon.spy(client._display, "clipViewport", ["set"]); + + client.clipViewport = false; + expect(spy.set).to.have.been.calledOnce; + expect(spy.set).to.have.been.calledWith(false); + spy.set.resetHistory(); + + client.clipViewport = true; + expect(spy.set).to.have.been.calledOnce; + expect(spy.set).to.have.been.calledWith(true); + }); + + it('should update the viewport when the container size changes', function () { + sinon.spy(client._display, "viewportChangeSize"); + + container.style.width = '40px'; + container.style.height = '50px'; + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(client._display.viewportChangeSize).to.have.been.calledOnce; + expect(client._display.viewportChangeSize).to.have.been.calledWith(40, 50); + }); + + it('should update the viewport when the remote session resizes', function () { + // Simple ExtendedDesktopSize FBU message + const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xcc, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00 ]; + + sinon.spy(client._display, "viewportChangeSize"); + + client._sock._websocket._receiveData(new Uint8Array(incoming)); + // The resize will cause scrollbars on the container, this causes a + // resize observation in the browsers + fakeResizeObserver.fire(); + clock.tick(1000); + + // FIXME: Display implicitly calls viewportChangeSize() when + // resizing the framebuffer, hence calledTwice. + expect(client._display.viewportChangeSize).to.have.been.calledTwice; + expect(client._display.viewportChangeSize).to.have.been.calledWith(70, 80); + }); + + it('should not update the viewport if not clipping', function () { + client.clipViewport = false; + sinon.spy(client._display, "viewportChangeSize"); + + container.style.width = '40px'; + container.style.height = '50px'; + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(client._display.viewportChangeSize).to.not.have.been.called; + }); + + it('should not update the viewport if scaling', function () { + client.scaleViewport = true; + sinon.spy(client._display, "viewportChangeSize"); + + container.style.width = '40px'; + container.style.height = '50px'; + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(client._display.viewportChangeSize).to.not.have.been.called; + }); + + describe('Clipping and remote resize', function () { + beforeEach(function () { + // Given a remote (100, 100) larger than the container (70x80), + client._resize(100, 100); + client._supportsSetDesktopSize = true; + client.resizeSession = true; + sinon.spy(RFB.messages, "setDesktopSize"); + }); + afterEach(function () { + RFB.messages.setDesktopSize.restore(); + }); + it('should not change remote size when changing clipping', function () { + // When changing clipping the scrollbars of the container + // will appear and disappear and thus trigger resize observations + client.clipViewport = false; + fakeResizeObserver.fire(); + clock.tick(1000); + client.clipViewport = true; + fakeResizeObserver.fire(); + clock.tick(1000); + + // Then no resize requests should be sent + expect(RFB.messages.setDesktopSize).to.not.have.been.called; + }); + }); + + describe('Dragging', function () { + beforeEach(function () { + client.dragViewport = true; + sinon.spy(RFB.messages, "pointerEvent"); + }); + + afterEach(function () { + RFB.messages.pointerEvent.restore(); + }); + + it('should not send button messages when initiating viewport dragging', function () { + client._handleMouseButton(13, 9, 0x001); + expect(RFB.messages.pointerEvent).to.not.have.been.called; + }); + + it('should send button messages when release without movement', function () { + // Just up and down + client._handleMouseButton(13, 9, 0x001); + client._handleMouseButton(13, 9, 0x000); + expect(RFB.messages.pointerEvent).to.have.been.calledTwice; + + RFB.messages.pointerEvent.resetHistory(); + + // Small movement + client._handleMouseButton(13, 9, 0x001); + client._handleMouseMove(15, 14); + client._handleMouseButton(15, 14, 0x000); + expect(RFB.messages.pointerEvent).to.have.been.calledTwice; + }); + + it('should not send button messages when in view only', function () { + client._viewOnly = true; + client._handleMouseButton(13, 9, 0x001); + client._handleMouseButton(13, 9, 0x000); + expect(RFB.messages.pointerEvent).to.not.have.been.called; + }); + + it('should send button message directly when drag is disabled', function () { + client.dragViewport = false; + client._handleMouseButton(13, 9, 0x001); + expect(RFB.messages.pointerEvent).to.have.been.calledOnce; + }); + + it('should be initiate viewport dragging on sufficient movement', function () { + sinon.spy(client._display, "viewportChangePos"); + + // Too small movement + + client._handleMouseButton(13, 9, 0x001); + client._handleMouseMove(18, 9); + + expect(RFB.messages.pointerEvent).to.not.have.been.called; + expect(client._display.viewportChangePos).to.not.have.been.called; + + // Sufficient movement + + client._handleMouseMove(43, 9); + + expect(RFB.messages.pointerEvent).to.not.have.been.called; + expect(client._display.viewportChangePos).to.have.been.calledOnce; + expect(client._display.viewportChangePos).to.have.been.calledWith(-30, 0); + + client._display.viewportChangePos.resetHistory(); + + // Now a small movement should move right away + + client._handleMouseMove(43, 14); + + expect(RFB.messages.pointerEvent).to.not.have.been.called; + expect(client._display.viewportChangePos).to.have.been.calledOnce; + expect(client._display.viewportChangePos).to.have.been.calledWith(0, -5); + }); + + it('should not send button messages when dragging ends', function () { + // First the movement + + client._handleMouseButton(13, 9, 0x001); + client._handleMouseMove(43, 9); + client._handleMouseButton(43, 9, 0x000); + + expect(RFB.messages.pointerEvent).to.not.have.been.called; + }); + + it('should terminate viewport dragging on a button up event', function () { + // First the dragging movement + + client._handleMouseButton(13, 9, 0x001); + client._handleMouseMove(43, 9); + client._handleMouseButton(43, 9, 0x000); + + // Another movement now should not move the viewport + + sinon.spy(client._display, "viewportChangePos"); + + client._handleMouseMove(43, 59); + + expect(client._display.viewportChangePos).to.not.have.been.called; + }); + }); + }); + + describe('Scaling', function () { + let client; + beforeEach(function () { + client = makeRFB(); + container.style.width = '70px'; + container.style.height = '80px'; + client.scaleViewport = true; + }); + + it('should update display scale factor when changing the property', function () { + const spy = sinon.spy(client._display, "scale", ["set"]); + sinon.spy(client._display, "autoscale"); + + client.scaleViewport = false; + expect(spy.set).to.have.been.calledOnce; + expect(spy.set).to.have.been.calledWith(1.0); + expect(client._display.autoscale).to.not.have.been.called; + + client.scaleViewport = true; + expect(client._display.autoscale).to.have.been.calledOnce; + expect(client._display.autoscale).to.have.been.calledWith(70, 80); + }); + + it('should update the clipping setting when changing the property', function () { + client.clipViewport = true; + + const spy = sinon.spy(client._display, "clipViewport", ["set"]); + + client.scaleViewport = false; + expect(spy.set).to.have.been.calledOnce; + expect(spy.set).to.have.been.calledWith(true); + + spy.set.resetHistory(); + + client.scaleViewport = true; + expect(spy.set).to.have.been.calledOnce; + expect(spy.set).to.have.been.calledWith(false); + }); + + it('should update the scaling when the container size changes', function () { + sinon.spy(client._display, "autoscale"); + + container.style.width = '40px'; + container.style.height = '50px'; + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(client._display.autoscale).to.have.been.calledOnce; + expect(client._display.autoscale).to.have.been.calledWith(40, 50); + }); + + it('should update the scaling when the remote session resizes', function () { + // Simple ExtendedDesktopSize FBU message + const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xcc, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00 ]; + + sinon.spy(client._display, "autoscale"); + + client._sock._websocket._receiveData(new Uint8Array(incoming)); + // The resize will cause scrollbars on the container, this causes a + // resize observation in the browsers + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(client._display.autoscale).to.have.been.calledOnce; + expect(client._display.autoscale).to.have.been.calledWith(70, 80); + }); + + it('should not update the display scale factor if not scaling', function () { + client.scaleViewport = false; + + sinon.spy(client._display, "autoscale"); + + container.style.width = '40px'; + container.style.height = '50px'; + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(client._display.autoscale).to.not.have.been.called; + }); + }); + + describe('Remote resize', function () { + let client; + beforeEach(function () { + client = makeRFB(); + client._supportsSetDesktopSize = true; + client.resizeSession = true; + container.style.width = '70px'; + container.style.height = '80px'; + sinon.spy(RFB.messages, "setDesktopSize"); + }); + + afterEach(function () { + RFB.messages.setDesktopSize.restore(); + }); + + it('should only request a resize when turned on', function () { + client.resizeSession = false; + expect(RFB.messages.setDesktopSize).to.not.have.been.called; + client.resizeSession = true; + expect(RFB.messages.setDesktopSize).to.have.been.calledOnce; + }); + + it('should request a resize when initially connecting', function () { + // Simple ExtendedDesktopSize FBU message + const incoming = [ 0x00, // msg-type=FBU + 0x00, // padding + 0x00, 0x01, // number of rects = 1 + 0x00, 0x00, // reason = server initialized + 0x00, 0x00, // status = no error + 0x00, 0x04, // new width = 4 + 0x00, 0x04, // new height = 4 + 0xff, 0xff, + 0xfe, 0xcc, // enc = (-308) ExtendedDesktopSize + 0x01, // number of screens = 1 + 0x00, 0x00, + 0x00, // padding + 0x00, 0x00, + 0x00, 0x00, // screen id = 0 + 0x00, 0x00, // screen x = 0 + 0x00, 0x00, // screen y = 0 + 0x00, 0x04, // screen width = 4 + 0x00, 0x04, // screen height = 4 + 0x00, 0x00, + 0x00, 0x00]; // screen flags + + // This property is indirectly used as a marker for the first update + client._supportsSetDesktopSize = false; + + // First message should trigger a resize + + client._sock._websocket._receiveData(new Uint8Array(incoming)); + + // It should match the current size of the container, + // not the reported size from the server + expect(RFB.messages.setDesktopSize).to.have.been.calledOnce; + expect(RFB.messages.setDesktopSize).to.have.been.calledWith( + sinon.match.object, 70, 80, 0, 0); + + RFB.messages.setDesktopSize.resetHistory(); + + // Second message should not trigger a resize + + client._sock._websocket._receiveData(new Uint8Array(incoming)); + + expect(RFB.messages.setDesktopSize).to.not.have.been.called; + }); + + it('should request a resize when the container resizes', function () { + container.style.width = '40px'; + container.style.height = '50px'; + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(RFB.messages.setDesktopSize).to.have.been.calledOnce; + expect(RFB.messages.setDesktopSize).to.have.been.calledWith(sinon.match.object, 40, 50, 0, 0); + }); + + it('should not request the same size twice', function () { + container.style.width = '40px'; + container.style.height = '50px'; + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(RFB.messages.setDesktopSize).to.have.been.calledOnce; + expect(RFB.messages.setDesktopSize).to.have.been.calledWith( + sinon.match.object, 40, 50, 0, 0); + + // Server responds with the requested size 40x50 + const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x32, 0xff, 0xff, 0xfe, 0xcc, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x00]; + + client._sock._websocket._receiveData(new Uint8Array(incoming)); + clock.tick(1000); + + RFB.messages.setDesktopSize.resetHistory(); + + // size is still 40x50 + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(RFB.messages.setDesktopSize).to.not.have.been.called; + }); + + it('should not resize until the container size is stable', function () { + container.style.width = '20px'; + container.style.height = '30px'; + fakeResizeObserver.fire(); + clock.tick(400); + + expect(RFB.messages.setDesktopSize).to.not.have.been.called; + + container.style.width = '40px'; + container.style.height = '50px'; + fakeResizeObserver.fire(); + clock.tick(400); + + expect(RFB.messages.setDesktopSize).to.not.have.been.called; + + clock.tick(200); + + expect(RFB.messages.setDesktopSize).to.have.been.calledOnce; + expect(RFB.messages.setDesktopSize).to.have.been.calledWith(sinon.match.object, 40, 50, 0, 0); + }); + + it('should not resize when resize is disabled', function () { + client._resizeSession = false; + + container.style.width = '40px'; + container.style.height = '50px'; + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(RFB.messages.setDesktopSize).to.not.have.been.called; + }); + + it('should not resize when resize is not supported', function () { + client._supportsSetDesktopSize = false; + + container.style.width = '40px'; + container.style.height = '50px'; + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(RFB.messages.setDesktopSize).to.not.have.been.called; + }); + + it('should not resize when in view only mode', function () { + client._viewOnly = true; + + container.style.width = '40px'; + container.style.height = '50px'; + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(RFB.messages.setDesktopSize).to.not.have.been.called; + }); + + it('should not try to override a server resize', function () { + // Simple ExtendedDesktopSize FBU message, new size: 100x100 + const incoming = [ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x64, 0x00, 0x64, 0xff, 0xff, 0xfe, 0xcc, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00 ]; + + // Note that this will cause the browser to display scrollbars + // since the framebuffer is 100x100 and the container is 70x80. + // The usable space (clientWidth/clientHeight) will be even smaller + // due to the scrollbars taking up space. + client._sock._websocket._receiveData(new Uint8Array(incoming)); + // The scrollbars cause the ResizeObserver to fire + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(RFB.messages.setDesktopSize).to.not.have.been.called; + + // An actual size change must not be ignored afterwards + container.style.width = '120px'; + container.style.height = '130px'; + fakeResizeObserver.fire(); + clock.tick(1000); + + expect(RFB.messages.setDesktopSize).to.have.been.calledOnce; + expect(RFB.messages.setDesktopSize.firstCall.args[1]).to.equal(120); + expect(RFB.messages.setDesktopSize.firstCall.args[2]).to.equal(130); + }); + }); + + describe('Misc Internals', function () { + describe('#_fail', function () { + let client; + beforeEach(function () { + client = makeRFB(); + }); + + it('should close the WebSocket connection', function () { + sinon.spy(client._sock, 'close'); + client._fail(); + expect(client._sock.close).to.have.been.calledOnce; + }); + + it('should transition to disconnected', function () { + sinon.spy(client, '_updateConnectionState'); + client._fail(); + this.clock.tick(2000); + expect(client._updateConnectionState).to.have.been.called; + expect(client._rfbConnectionState).to.equal('disconnected'); + }); + + it('should set clean_disconnect variable', function () { + client._rfbCleanDisconnect = true; + client._rfbConnectionState = 'connected'; + client._fail(); + expect(client._rfbCleanDisconnect).to.be.false; + }); + + it('should result in disconnect event with clean set to false', function () { + client._rfbConnectionState = 'connected'; + const spy = sinon.spy(); + client.addEventListener("disconnect", spy); + client._fail(); + this.clock.tick(2000); + expect(spy).to.have.been.calledOnce; + expect(spy.args[0][0].detail.clean).to.be.false; + }); + + }); + }); + + describe('Protocol Initialization States', function () { + let client; + beforeEach(function () { + client = makeRFB(); + client._rfbConnectionState = 'connecting'; + }); + + function sendVer(ver, client) { + const arr = new Uint8Array(12); + for (let i = 0; i < ver.length; i++) { + arr[i+4] = ver.charCodeAt(i); + } + arr[0] = 'R'; arr[1] = 'F'; arr[2] = 'B'; arr[3] = ' '; + arr[11] = '\n'; + client._sock._websocket._receiveData(arr); + } + + function sendSecurity(type, cl) { + cl._sock._websocket._receiveData(new Uint8Array([1, type])); + } + + describe('ProtocolVersion', function () { + describe('version parsing', function () { + it('should interpret version 003.003 as version 3.3', function () { + sendVer('003.003', client); + expect(client._rfbVersion).to.equal(3.3); + }); + + it('should interpret version 003.006 as version 3.3', function () { + sendVer('003.006', client); + expect(client._rfbVersion).to.equal(3.3); + }); + + it('should interpret version 003.889 as version 3.8', function () { + sendVer('003.889', client); + expect(client._rfbVersion).to.equal(3.8); + }); + + it('should interpret version 003.007 as version 3.7', function () { + sendVer('003.007', client); + expect(client._rfbVersion).to.equal(3.7); + }); + + it('should interpret version 003.008 as version 3.8', function () { + sendVer('003.008', client); + expect(client._rfbVersion).to.equal(3.8); + }); + + it('should interpret version 004.000 as version 3.8', function () { + sendVer('004.000', client); + expect(client._rfbVersion).to.equal(3.8); + }); + + it('should interpret version 004.001 as version 3.8', function () { + sendVer('004.001', client); + expect(client._rfbVersion).to.equal(3.8); + }); + + it('should interpret version 005.000 as version 3.8', function () { + sendVer('005.000', client); + expect(client._rfbVersion).to.equal(3.8); + }); + + it('should fail on an invalid version', function () { + sinon.spy(client, "_fail"); + sendVer('002.000', client); + expect(client._fail).to.have.been.calledOnce; + }); + }); + + it('should send back the interpreted version', function () { + sendVer('004.000', client); + + const expectedStr = 'RFB 003.008\n'; + const expected = []; + for (let i = 0; i < expectedStr.length; i++) { + expected[i] = expectedStr.charCodeAt(i); + } + + expect(client._sock).to.have.sent(new Uint8Array(expected)); + }); + + it('should transition to the Security state on successful negotiation', function () { + sendVer('003.008', client); + expect(client._rfbInitState).to.equal('Security'); + }); + + describe('Repeater', function () { + beforeEach(function () { + client = makeRFB('wss://host:8675', { repeaterID: "12345" }); + client._rfbConnectionState = 'connecting'; + }); + + it('should interpret version 000.000 as a repeater', function () { + sendVer('000.000', client); + expect(client._rfbVersion).to.equal(0); + + const sentData = client._sock._websocket._getSentData(); + expect(new Uint8Array(sentData.buffer, 0, 9)).to.array.equal(new Uint8Array([73, 68, 58, 49, 50, 51, 52, 53, 0])); + expect(sentData).to.have.length(250); + }); + + it('should handle two step repeater negotiation', function () { + sendVer('000.000', client); + sendVer('003.008', client); + expect(client._rfbVersion).to.equal(3.8); + }); + }); + }); + + describe('Security', function () { + beforeEach(function () { + sendVer('003.008\n', client); + client._sock._websocket._getSentData(); + }); + + it('should respect server preference order', function () { + const authSchemes = [ 6, 79, 30, 188, 16, 6, 1 ]; + client._sock._websocket._receiveData(new Uint8Array(authSchemes)); + expect(client._sock).to.have.sent(new Uint8Array([30])); + }); + + it('should fail if there are no supported schemes', function () { + sinon.spy(client, "_fail"); + const authSchemes = [1, 32]; + client._sock._websocket._receiveData(new Uint8Array(authSchemes)); + expect(client._fail).to.have.been.calledOnce; + }); + + it('should fail with the appropriate message if no types are sent', function () { + const failureData = [0, 0, 0, 0, 6, 119, 104, 111, 111, 112, 115]; + sinon.spy(client, '_fail'); + client._sock._websocket._receiveData(new Uint8Array(failureData)); + + expect(client._fail).to.have.been.calledOnce; + expect(client._fail).to.have.been.calledWith( + 'Security negotiation failed on no security types (reason: whoops)'); + }); + + it('should transition to the Authentication state and continue on successful negotiation', function () { + const authSchemes = [1, 1]; + client._negotiateAuthentication = sinon.spy(); + client._sock._websocket._receiveData(new Uint8Array(authSchemes)); + expect(client._rfbInitState).to.equal('Authentication'); + expect(client._negotiateAuthentication).to.have.been.calledOnce; + }); + }); + + describe('Legacy Authentication', function () { + it('should fail on auth scheme 0 (pre 3.7) with the given message', function () { + const errMsg = "Whoopsies"; + const data = [0, 0, 0, 0]; + const errLen = errMsg.length; + push32(data, errLen); + for (let i = 0; i < errLen; i++) { + data.push(errMsg.charCodeAt(i)); + } + + sendVer('003.006\n', client); + client._sock._websocket._getSentData(); + + sinon.spy(client, '_fail'); + client._sock._websocket._receiveData(new Uint8Array(data)); + expect(client._fail).to.have.been.calledWith( + 'Security negotiation failed on authentication scheme (reason: Whoopsies)'); + }); + + it('should transition straight to ServerInitialisation on "no auth" for versions < 3.7', function () { + sendVer('003.006\n', client); + client._sock._websocket._getSentData(); + + client._sock._websocket._receiveData(new Uint8Array([0, 0, 0, 1])); + expect(client._rfbInitState).to.equal('ServerInitialisation'); + }); + }); + + describe('Authentication', function () { + beforeEach(function () { + sendVer('003.008\n', client); + client._sock._websocket._getSentData(); + }); + + it('should transition straight to SecurityResult on "no auth" (1)', function () { + sendSecurity(1, client); + expect(client._rfbInitState).to.equal('SecurityResult'); + }); + + it('should fail on an unknown auth scheme', function () { + sinon.spy(client, "_fail"); + sendSecurity(57, client); + expect(client._fail).to.have.been.calledOnce; + }); + + describe('VNC Authentication (type 2) Handler', function () { + it('should fire the credentialsrequired event if missing a password', function () { + const spy = sinon.spy(); + client.addEventListener("credentialsrequired", spy); + sendSecurity(2, client); + + const challenge = []; + for (let i = 0; i < 16; i++) { challenge[i] = i; } + client._sock._websocket._receiveData(new Uint8Array(challenge)); + + expect(client._rfbCredentials).to.be.empty; + expect(spy).to.have.been.calledOnce; + expect(spy.args[0][0].detail.types).to.have.members(["password"]); + }); + + it('should encrypt the password with DES and then send it back', function () { + client._rfbCredentials = { password: 'passwd' }; + sendSecurity(2, client); + client._sock._websocket._getSentData(); // skip the choice of auth reply + + const challenge = []; + for (let i = 0; i < 16; i++) { challenge[i] = i; } + client._sock._websocket._receiveData(new Uint8Array(challenge)); + + const desPass = RFB.genDES('passwd', challenge); + expect(client._sock).to.have.sent(new Uint8Array(desPass)); + }); + + it('should transition to SecurityResult immediately after sending the password', function () { + client._rfbCredentials = { password: 'passwd' }; + sendSecurity(2, client); + + const challenge = []; + for (let i = 0; i < 16; i++) { challenge[i] = i; } + client._sock._websocket._receiveData(new Uint8Array(challenge)); + + expect(client._rfbInitState).to.equal('SecurityResult'); + }); + }); + + describe('ARD Authentication (type 30) Handler', function () { + it('should fire the credentialsrequired event if all credentials are missing', function () { + const spy = sinon.spy(); + client.addEventListener("credentialsrequired", spy); + client._rfbCredentials = {}; + sendSecurity(30, client); + + expect(client._rfbCredentials).to.be.empty; + expect(spy).to.have.been.calledOnce; + expect(spy.args[0][0].detail.types).to.have.members(["username", "password"]); + }); + + it('should fire the credentialsrequired event if some credentials are missing', function () { + const spy = sinon.spy(); + client.addEventListener("credentialsrequired", spy); + client._rfbCredentials = { password: 'password'}; + sendSecurity(30, client); + + expect(spy).to.have.been.calledOnce; + expect(spy.args[0][0].detail.types).to.have.members(["username", "password"]); + }); + + it('should return properly encrypted credentials and public key', async function () { + client._rfbCredentials = { username: 'user', + password: 'password' }; + sendSecurity(30, client); + + expect(client._sock).to.have.sent([30]); + + function byteArray(length) { + return Array.from(new Uint8Array(length).keys()); + } + + let generator = [127, 255]; + let prime = byteArray(128); + let serverPrivateKey = byteArray(128); + let serverPublicKey = client._modPow(generator, serverPrivateKey, prime); + + let clientPrivateKey = byteArray(128); + let clientPublicKey = client._modPow(generator, clientPrivateKey, prime); + + let padding = Array.from(byteArray(64), byte => String.fromCharCode(65+byte%26)).join(''); + + await client._negotiateARDAuthAsync(generator, 128, prime, serverPublicKey, clientPrivateKey, padding); + + client._negotiateARDAuth(); + + expect(client._rfbInitState).to.equal('SecurityResult'); + + let expectEncrypted = new Uint8Array([ + 232, 234, 159, 162, 170, 180, 138, 104, 164, 49, 53, 96, 20, 36, 21, 15, + 217, 219, 107, 173, 196, 60, 96, 142, 215, 71, 13, 185, 185, 47, 5, 175, + 151, 30, 194, 55, 173, 214, 141, 161, 36, 138, 146, 3, 178, 89, 43, 248, + 131, 134, 205, 174, 9, 150, 171, 74, 222, 201, 20, 2, 30, 168, 162, 123, + 46, 86, 81, 221, 44, 211, 180, 247, 221, 61, 95, 155, 157, 241, 76, 76, + 49, 217, 234, 75, 147, 237, 199, 159, 93, 140, 191, 174, 52, 90, 133, 58, + 243, 81, 112, 182, 64, 62, 149, 7, 151, 28, 36, 161, 247, 247, 36, 96, + 230, 95, 58, 207, 46, 183, 100, 139, 143, 155, 224, 43, 219, 3, 71, 139]); + + let output = new Uint8Array(256); + output.set(expectEncrypted, 0); + output.set(clientPublicKey, 128); + + expect(client._sock).to.have.sent(output); + }); + }); + + describe('XVP Authentication (type 22) Handler', function () { + it('should fall through to standard VNC authentication upon completion', function () { + client._rfbCredentials = { username: 'user', + target: 'target', + password: 'password' }; + client._negotiateStdVNCAuth = sinon.spy(); + sendSecurity(22, client); + expect(client._negotiateStdVNCAuth).to.have.been.calledOnce; + }); + + it('should fire the credentialsrequired event if all credentials are missing', function () { + const spy = sinon.spy(); + client.addEventListener("credentialsrequired", spy); + client._rfbCredentials = {}; + sendSecurity(22, client); + + expect(client._rfbCredentials).to.be.empty; + expect(spy).to.have.been.calledOnce; + expect(spy.args[0][0].detail.types).to.have.members(["username", "password", "target"]); + }); + + it('should fire the credentialsrequired event if some credentials are missing', function () { + const spy = sinon.spy(); + client.addEventListener("credentialsrequired", spy); + client._rfbCredentials = { username: 'user', + target: 'target' }; + sendSecurity(22, client); + + expect(spy).to.have.been.calledOnce; + expect(spy.args[0][0].detail.types).to.have.members(["username", "password", "target"]); + }); + + it('should send user and target separately', function () { + client._rfbCredentials = { username: 'user', + target: 'target', + password: 'password' }; + client._negotiateStdVNCAuth = sinon.spy(); + + sendSecurity(22, client); + + const expected = [22, 4, 6]; // auth selection, len user, len target + for (let i = 0; i < 10; i++) { expected[i+3] = 'usertarget'.charCodeAt(i); } + + expect(client._sock).to.have.sent(new Uint8Array(expected)); + }); + }); + + describe('TightVNC Authentication (type 16) Handler', function () { + beforeEach(function () { + sendSecurity(16, client); + client._sock._websocket._getSentData(); // skip the security reply + }); + + function sendNumStrPairs(pairs, client) { + const data = []; + push32(data, pairs.length); + + for (let i = 0; i < pairs.length; i++) { + push32(data, pairs[i][0]); + for (let j = 0; j < 4; j++) { + data.push(pairs[i][1].charCodeAt(j)); + } + for (let j = 0; j < 8; j++) { + data.push(pairs[i][2].charCodeAt(j)); + } + } + + client._sock._websocket._receiveData(new Uint8Array(data)); + } + + it('should skip tunnel negotiation if no tunnels are requested', function () { + client._sock._websocket._receiveData(new Uint8Array([0, 0, 0, 0])); + expect(client._rfbTightVNC).to.be.true; + }); + + it('should fail if no supported tunnels are listed', function () { + sinon.spy(client, "_fail"); + sendNumStrPairs([[123, 'OTHR', 'SOMETHNG']], client); + expect(client._fail).to.have.been.calledOnce; + }); + + it('should choose the notunnel tunnel type', function () { + sendNumStrPairs([[0, 'TGHT', 'NOTUNNEL'], [123, 'OTHR', 'SOMETHNG']], client); + expect(client._sock).to.have.sent(new Uint8Array([0, 0, 0, 0])); + }); + + it('should choose the notunnel tunnel type for Siemens devices', function () { + sendNumStrPairs([[1, 'SICR', 'SCHANNEL'], [2, 'SICR', 'SCHANLPW']], client); + expect(client._sock).to.have.sent(new Uint8Array([0, 0, 0, 0])); + }); + + it('should continue to sub-auth negotiation after tunnel negotiation', function () { + sendNumStrPairs([[0, 'TGHT', 'NOTUNNEL']], client); + client._sock._websocket._getSentData(); // skip the tunnel choice here + sendNumStrPairs([[1, 'STDV', 'NOAUTH__']], client); + expect(client._sock).to.have.sent(new Uint8Array([0, 0, 0, 1])); + expect(client._rfbInitState).to.equal('SecurityResult'); + }); + + /*it('should attempt to use VNC auth over no auth when possible', function () { + client._rfbTightVNC = true; + client._negotiateStdVNCAuth = sinon.spy(); + sendNumStrPairs([[1, 'STDV', 'NOAUTH__'], [2, 'STDV', 'VNCAUTH_']], client); + expect(client._sock).to.have.sent([0, 0, 0, 1]); + expect(client._negotiateStdVNCAuth).to.have.been.calledOnce; + expect(client._rfbAuthScheme).to.equal(2); + });*/ // while this would make sense, the original code doesn't actually do this + + it('should accept the "no auth" auth type and transition to SecurityResult', function () { + client._rfbTightVNC = true; + sendNumStrPairs([[1, 'STDV', 'NOAUTH__']], client); + expect(client._sock).to.have.sent(new Uint8Array([0, 0, 0, 1])); + expect(client._rfbInitState).to.equal('SecurityResult'); + }); + + it('should accept VNC authentication and transition to that', function () { + client._rfbTightVNC = true; + client._negotiateStdVNCAuth = sinon.spy(); + sendNumStrPairs([[2, 'STDV', 'VNCAUTH__']], client); + expect(client._sock).to.have.sent(new Uint8Array([0, 0, 0, 2])); + expect(client._negotiateStdVNCAuth).to.have.been.calledOnce; + expect(client._rfbAuthScheme).to.equal(2); + }); + + it('should fail if there are no supported auth types', function () { + sinon.spy(client, "_fail"); + client._rfbTightVNC = true; + sendNumStrPairs([[23, 'stdv', 'badval__']], client); + expect(client._fail).to.have.been.calledOnce; + }); + }); + + describe('VeNCrypt Authentication (type 19) Handler', function () { + beforeEach(function () { + sendSecurity(19, client); + expect(client._sock).to.have.sent(new Uint8Array([19])); + }); + + it('should fail with non-0.2 versions', function () { + sinon.spy(client, "_fail"); + client._sock._websocket._receiveData(new Uint8Array([0, 1])); + expect(client._fail).to.have.been.calledOnce; + }); + + it('should fail if there are no supported subtypes', function () { + // VeNCrypt version + client._sock._websocket._receiveData(new Uint8Array([0, 2])); + expect(client._sock).to.have.sent(new Uint8Array([0, 2])); + // Server ACK. + client._sock._websocket._receiveData(new Uint8Array([0])); + // Subtype list + sinon.spy(client, "_fail"); + client._sock._websocket._receiveData(new Uint8Array([2, 0, 0, 0, 9, 0, 0, 1, 4])); + expect(client._fail).to.have.been.calledOnce; + }); + + it('should support standard types', function () { + // VeNCrypt version + client._sock._websocket._receiveData(new Uint8Array([0, 2])); + expect(client._sock).to.have.sent(new Uint8Array([0, 2])); + // Server ACK. + client._sock._websocket._receiveData(new Uint8Array([0])); + // Subtype list + client._sock._websocket._receiveData(new Uint8Array([2, 0, 0, 0, 2, 0, 0, 1, 4])); + + let expectedResponse = []; + push32(expectedResponse, 2); // Chosen subtype. + + expect(client._sock).to.have.sent(new Uint8Array(expectedResponse)); + }); + + it('should respect server preference order', function () { + // VeNCrypt version + client._sock._websocket._receiveData(new Uint8Array([0, 2])); + expect(client._sock).to.have.sent(new Uint8Array([0, 2])); + // Server ACK. + client._sock._websocket._receiveData(new Uint8Array([0])); + // Subtype list + let subtypes = [ 6 ]; + push32(subtypes, 79); + push32(subtypes, 30); + push32(subtypes, 188); + push32(subtypes, 256); + push32(subtypes, 6); + push32(subtypes, 1); + client._sock._websocket._receiveData(new Uint8Array(subtypes)); + + let expectedResponse = []; + push32(expectedResponse, 30); // Chosen subtype. + + expect(client._sock).to.have.sent(new Uint8Array(expectedResponse)); + }); + + it('should ignore redundant VeNCrypt subtype', function () { + // VeNCrypt version + client._sock._websocket._receiveData(new Uint8Array([0, 2])); + expect(client._sock).to.have.sent(new Uint8Array([0, 2])); + // Server ACK. + client._sock._websocket._receiveData(new Uint8Array([0])); + // Subtype list + client._sock._websocket._receiveData(new Uint8Array([2, 0, 0, 0, 19, 0, 0, 0, 2])); + + let expectedResponse = []; + push32(expectedResponse, 2); // Chosen subtype. + + expect(client._sock).to.have.sent(new Uint8Array(expectedResponse)); + }); + + it('should support Plain authentication', function () { + client._rfbCredentials = { username: 'username', password: 'password' }; + // VeNCrypt version + client._sock._websocket._receiveData(new Uint8Array([0, 2])); + expect(client._sock).to.have.sent(new Uint8Array([0, 2])); + // Server ACK. + client._sock._websocket._receiveData(new Uint8Array([0])); + // Subtype list. + client._sock._websocket._receiveData(new Uint8Array([1, 0, 0, 1, 0])); + + const expectedResponse = []; + push32(expectedResponse, 256); // Chosen subtype. + push32(expectedResponse, client._rfbCredentials.username.length); + push32(expectedResponse, client._rfbCredentials.password.length); + pushString(expectedResponse, client._rfbCredentials.username); + pushString(expectedResponse, client._rfbCredentials.password); + expect(client._sock).to.have.sent(new Uint8Array(expectedResponse)); + + client._initMsg = sinon.spy(); + client._sock._websocket._receiveData(new Uint8Array([0, 0, 0, 0])); + expect(client._initMsg).to.have.been.called; + }); + + it('should support Plain authentication with an empty password', function () { + client._rfbCredentials = { username: 'username', password: '' }; + // VeNCrypt version + client._sock._websocket._receiveData(new Uint8Array([0, 2])); + expect(client._sock).to.have.sent(new Uint8Array([0, 2])); + // Server ACK. + client._sock._websocket._receiveData(new Uint8Array([0])); + // Subtype list. + client._sock._websocket._receiveData(new Uint8Array([1, 0, 0, 1, 0])); + + const expectedResponse = []; + push32(expectedResponse, 256); // Chosen subtype. + push32(expectedResponse, client._rfbCredentials.username.length); + push32(expectedResponse, client._rfbCredentials.password.length); + pushString(expectedResponse, client._rfbCredentials.username); + pushString(expectedResponse, client._rfbCredentials.password); + expect(client._sock).to.have.sent(new Uint8Array(expectedResponse)); + + client._initMsg = sinon.spy(); + client._sock._websocket._receiveData(new Uint8Array([0, 0, 0, 0])); + expect(client._initMsg).to.have.been.called; + }); + + it('should support Plain authentication with a very long username and password', function () { + client._rfbCredentials = { username: 'a'.repeat(300), password: 'a'.repeat(300) }; + // VeNCrypt version + client._sock._websocket._receiveData(new Uint8Array([0, 2])); + expect(client._sock).to.have.sent(new Uint8Array([0, 2])); + // Server ACK. + client._sock._websocket._receiveData(new Uint8Array([0])); + // Subtype list. + client._sock._websocket._receiveData(new Uint8Array([1, 0, 0, 1, 0])); + + const expectedResponse = []; + push32(expectedResponse, 256); // Chosen subtype. + push32(expectedResponse, client._rfbCredentials.username.length); + push32(expectedResponse, client._rfbCredentials.password.length); + pushString(expectedResponse, client._rfbCredentials.username); + pushString(expectedResponse, client._rfbCredentials.password); + expect(client._sock).to.have.sent(new Uint8Array(expectedResponse)); + + client._initMsg = sinon.spy(); + client._sock._websocket._receiveData(new Uint8Array([0, 0, 0, 0])); + expect(client._initMsg).to.have.been.called; + }); + }); + }); + + describe('Legacy SecurityResult', function () { + beforeEach(function () { + sendVer('003.007\n', client); + client._sock._websocket._getSentData(); + sendSecurity(1, client); + client._sock._websocket._getSentData(); + }); + + it('should not include reason in securityfailure event', function () { + const spy = sinon.spy(); + client.addEventListener("securityfailure", spy); + client._sock._websocket._receiveData(new Uint8Array([0, 0, 0, 2])); + expect(spy).to.have.been.calledOnce; + expect(spy.args[0][0].detail.status).to.equal(2); + expect('reason' in spy.args[0][0].detail).to.be.false; + }); + }); + + describe('SecurityResult', function () { + beforeEach(function () { + sendVer('003.008\n', client); + client._sock._websocket._getSentData(); + sendSecurity(1, client); + client._sock._websocket._getSentData(); + }); + + it('should fall through to ServerInitialisation on a response code of 0', function () { + client._sock._websocket._receiveData(new Uint8Array([0, 0, 0, 0])); + expect(client._rfbInitState).to.equal('ServerInitialisation'); + }); + + it('should include reason when provided in securityfailure event', function () { + const spy = sinon.spy(); + client.addEventListener("securityfailure", spy); + const failureData = [0, 0, 0, 1, 0, 0, 0, 12, 115, 117, 99, 104, + 32, 102, 97, 105, 108, 117, 114, 101]; + client._sock._websocket._receiveData(new Uint8Array(failureData)); + expect(spy).to.have.been.calledOnce; + expect(spy.args[0][0].detail.status).to.equal(1); + expect(spy.args[0][0].detail.reason).to.equal('such failure'); + }); + + it('should not include reason when length is zero in securityfailure event', function () { + const spy = sinon.spy(); + client.addEventListener("securityfailure", spy); + const failureData = [0, 0, 0, 1, 0, 0, 0, 0]; + client._sock._websocket._receiveData(new Uint8Array(failureData)); + expect(spy).to.have.been.calledOnce; + expect(spy.args[0][0].detail.status).to.equal(1); + expect('reason' in spy.args[0][0].detail).to.be.false; + }); + }); + + describe('ClientInitialisation', function () { + it('should transition to the ServerInitialisation state', function () { + const client = makeRFB(); + client._rfbConnectionState = 'connecting'; + client._rfbInitState = 'SecurityResult'; + client._sock._websocket._receiveData(new Uint8Array([0, 0, 0, 0])); + expect(client._rfbInitState).to.equal('ServerInitialisation'); + }); + + it('should send 1 if we are in shared mode', function () { + const client = makeRFB('wss://host:8675', { shared: true }); + client._rfbConnectionState = 'connecting'; + client._rfbInitState = 'SecurityResult'; + client._sock._websocket._receiveData(new Uint8Array([0, 0, 0, 0])); + expect(client._sock).to.have.sent(new Uint8Array([1])); + }); + + it('should send 0 if we are not in shared mode', function () { + const client = makeRFB('wss://host:8675', { shared: false }); + client._rfbConnectionState = 'connecting'; + client._rfbInitState = 'SecurityResult'; + client._sock._websocket._receiveData(new Uint8Array([0, 0, 0, 0])); + expect(client._sock).to.have.sent(new Uint8Array([0])); + }); + }); + + describe('ServerInitialisation', function () { + beforeEach(function () { + client._rfbInitState = 'ServerInitialisation'; + }); + + function sendServerInit(opts, client) { + const fullOpts = { width: 10, height: 12, bpp: 24, depth: 24, bigEndian: 0, + trueColor: 1, redMax: 255, greenMax: 255, blueMax: 255, + redShift: 16, greenShift: 8, blueShift: 0, name: 'a name' }; + for (let opt in opts) { + fullOpts[opt] = opts[opt]; + } + const data = []; + + push16(data, fullOpts.width); + push16(data, fullOpts.height); + + data.push(fullOpts.bpp); + data.push(fullOpts.depth); + data.push(fullOpts.bigEndian); + data.push(fullOpts.trueColor); + + push16(data, fullOpts.redMax); + push16(data, fullOpts.greenMax); + push16(data, fullOpts.blueMax); + push8(data, fullOpts.redShift); + push8(data, fullOpts.greenShift); + push8(data, fullOpts.blueShift); + + // padding + push8(data, 0); + push8(data, 0); + push8(data, 0); + + client._sock._websocket._receiveData(new Uint8Array(data)); + + const nameData = []; + let nameLen = []; + pushString(nameData, fullOpts.name); + push32(nameLen, nameData.length); + + client._sock._websocket._receiveData(new Uint8Array(nameLen)); + client._sock._websocket._receiveData(new Uint8Array(nameData)); + } + + it('should set the framebuffer width and height', function () { + sendServerInit({ width: 32, height: 84 }, client); + expect(client._fbWidth).to.equal(32); + expect(client._fbHeight).to.equal(84); + }); + + // NB(sross): we just warn, not fail, for endian-ness and shifts, so we don't test them + + it('should set the framebuffer name and call the callback', function () { + const spy = sinon.spy(); + client.addEventListener("desktopname", spy); + sendServerInit({ name: 'som€ nam€' }, client); + + expect(client._fbName).to.equal('som€ nam€'); + expect(spy).to.have.been.calledOnce; + expect(spy.args[0][0].detail.name).to.equal('som€ nam€'); + }); + + it('should handle the extended init message of the tight encoding', function () { + // NB(sross): we don't actually do anything with it, so just test that we can + // read it w/o throwing an error + client._rfbTightVNC = true; + sendServerInit({}, client); + + const tightData = []; + push16(tightData, 1); + push16(tightData, 2); + push16(tightData, 3); + push16(tightData, 0); + for (let i = 0; i < 16 + 32 + 48; i++) { + tightData.push(i); + } + client._sock._websocket._receiveData(new Uint8Array(tightData)); + + expect(client._rfbConnectionState).to.equal('connected'); + }); + + it('should resize the display', function () { + sinon.spy(client._display, 'resize'); + sendServerInit({ width: 27, height: 32 }, client); + + expect(client._display.resize).to.have.been.calledOnce; + expect(client._display.resize).to.have.been.calledWith(27, 32); + }); + + it('should grab the keyboard', function () { + sinon.spy(client._keyboard, 'grab'); + sendServerInit({}, client); + expect(client._keyboard.grab).to.have.been.calledOnce; + }); + + describe('Initial Update Request', function () { + beforeEach(function () { + sinon.spy(RFB.messages, "pixelFormat"); + sinon.spy(RFB.messages, "clientEncodings"); + sinon.spy(RFB.messages, "fbUpdateRequest"); + }); + + afterEach(function () { + RFB.messages.pixelFormat.restore(); + RFB.messages.clientEncodings.restore(); + RFB.messages.fbUpdateRequest.restore(); + }); + + // TODO(directxman12): test the various options in this configuration matrix + it('should reply with the pixel format, client encodings, and initial update request', function () { + sendServerInit({ width: 27, height: 32 }, client); + + expect(RFB.messages.pixelFormat).to.have.been.calledOnce; + expect(RFB.messages.pixelFormat).to.have.been.calledWith(client._sock, 24, true); + expect(RFB.messages.pixelFormat).to.have.been.calledBefore(RFB.messages.clientEncodings); + expect(RFB.messages.clientEncodings).to.have.been.calledOnce; + expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.encodingTight); + RFB.messages.clientEncodings.getCall(0).args[1].forEach((enc) => { + expect(enc).to.be.a('number'); + expect(Number.isInteger(enc)).to.be.true; + }); + expect(RFB.messages.clientEncodings).to.have.been.calledBefore(RFB.messages.fbUpdateRequest); + expect(RFB.messages.fbUpdateRequest).to.have.been.calledOnce; + expect(RFB.messages.fbUpdateRequest).to.have.been.calledWith(client._sock, false, 0, 0, 27, 32); + }); + + it('should reply with restricted settings for Intel AMT servers', function () { + sendServerInit({ width: 27, height: 32, name: "Intel(r) AMT KVM"}, client); + + expect(RFB.messages.pixelFormat).to.have.been.calledOnce; + expect(RFB.messages.pixelFormat).to.have.been.calledWith(client._sock, 8, true); + expect(RFB.messages.pixelFormat).to.have.been.calledBefore(RFB.messages.clientEncodings); + expect(RFB.messages.clientEncodings).to.have.been.calledOnce; + expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.not.include(encodings.encodingTight); + expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.not.include(encodings.encodingHextile); + expect(RFB.messages.clientEncodings).to.have.been.calledBefore(RFB.messages.fbUpdateRequest); + expect(RFB.messages.fbUpdateRequest).to.have.been.calledOnce; + expect(RFB.messages.fbUpdateRequest).to.have.been.calledWith(client._sock, false, 0, 0, 27, 32); + }); + }); + + it('should send the "connect" event', function () { + let spy = sinon.spy(); + client.addEventListener('connect', spy); + sendServerInit({}, client); + expect(spy).to.have.been.calledOnce; + }); + }); + }); + + describe('Protocol Message Processing After Completing Initialization', function () { + let client; + + beforeEach(function () { + client = makeRFB(); + client._fbName = 'some device'; + client._fbWidth = 640; + client._fbHeight = 20; + }); + + describe('Framebuffer Update Handling', function () { + function sendFbuMsg(rectInfo, rectData, client, rectCnt) { + let data = []; + + if (!rectCnt || rectCnt > -1) { + // header + data.push(0); // msg type + data.push(0); // padding + push16(data, rectCnt || rectData.length); + } + + for (let i = 0; i < rectData.length; i++) { + if (rectInfo[i]) { + push16(data, rectInfo[i].x); + push16(data, rectInfo[i].y); + push16(data, rectInfo[i].width); + push16(data, rectInfo[i].height); + push32(data, rectInfo[i].encoding); + } + data = data.concat(rectData[i]); + } + + client._sock._websocket._receiveData(new Uint8Array(data)); + } + + it('should send an update request if there is sufficient data', function () { + const expectedMsg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: () => {}}; + RFB.messages.fbUpdateRequest(expectedMsg, true, 0, 0, 640, 20); + + client._framebufferUpdate = () => true; + client._sock._websocket._receiveData(new Uint8Array([0])); + + expect(client._sock).to.have.sent(expectedMsg._sQ); + }); + + it('should not send an update request if we need more data', function () { + client._sock._websocket._receiveData(new Uint8Array([0])); + expect(client._sock._websocket._getSentData()).to.have.length(0); + }); + + it('should resume receiving an update if we previously did not have enough data', function () { + const expectedMsg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: () => {}}; + RFB.messages.fbUpdateRequest(expectedMsg, true, 0, 0, 640, 20); + + // just enough to set FBU.rects + client._sock._websocket._receiveData(new Uint8Array([0, 0, 0, 3])); + expect(client._sock._websocket._getSentData()).to.have.length(0); + + client._framebufferUpdate = function () { this._sock.rQskipBytes(1); return true; }; // we magically have enough data + // 247 should *not* be used as the message type here + client._sock._websocket._receiveData(new Uint8Array([247])); + expect(client._sock).to.have.sent(expectedMsg._sQ); + }); + + it('should not send a request in continuous updates mode', function () { + client._enabledContinuousUpdates = true; + client._framebufferUpdate = () => true; + client._sock._websocket._receiveData(new Uint8Array([0])); + + expect(client._sock._websocket._getSentData()).to.have.length(0); + }); + + it('should fail on an unsupported encoding', function () { + sinon.spy(client, "_fail"); + const rectInfo = { x: 8, y: 11, width: 27, height: 32, encoding: 234 }; + sendFbuMsg([rectInfo], [[]], client); + expect(client._fail).to.have.been.calledOnce; + }); + + describe('Message Encoding Handlers', function () { + beforeEach(function () { + // a really small frame + client._fbWidth = 4; + client._fbHeight = 4; + client._fbDepth = 24; + client._display.resize(4, 4); + }); + + it('should handle the DesktopSize pseduo-encoding', function () { + sinon.spy(client._display, 'resize'); + sendFbuMsg([{ x: 0, y: 0, width: 20, height: 50, encoding: -223 }], [[]], client); + + expect(client._fbWidth).to.equal(20); + expect(client._fbHeight).to.equal(50); + + expect(client._display.resize).to.have.been.calledOnce; + expect(client._display.resize).to.have.been.calledWith(20, 50); + }); + + describe('the ExtendedDesktopSize pseudo-encoding handler', function () { + beforeEach(function () { + // a really small frame + client._fbWidth = 4; + client._fbHeight = 4; + client._display.resize(4, 4); + sinon.spy(client._display, 'resize'); + }); + + function makeScreenData(nrOfScreens) { + const data = []; + push8(data, nrOfScreens); // number-of-screens + push8(data, 0); // padding + push16(data, 0); // padding + for (let i=0; i {}}; + const incomingMsg = {_sQ: new Uint8Array(16), _sQlen: 0, flush: () => {}}; + + const payload = "foo\x00ab9"; + + // ClientFence and ServerFence are identical in structure + RFB.messages.clientFence(expectedMsg, (1<<0) | (1<<1), payload); + RFB.messages.clientFence(incomingMsg, 0xffffffff, payload); + + client._sock._websocket._receiveData(incomingMsg._sQ); + + expect(client._sock).to.have.sent(expectedMsg._sQ); + + expectedMsg._sQlen = 0; + incomingMsg._sQlen = 0; + + RFB.messages.clientFence(expectedMsg, (1<<0), payload); + RFB.messages.clientFence(incomingMsg, (1<<0) | (1<<31), payload); + + client._sock._websocket._receiveData(incomingMsg._sQ); + + expect(client._sock).to.have.sent(expectedMsg._sQ); + }); + + it('should enable continuous updates on first EndOfContinousUpdates', function () { + const expectedMsg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: () => {}}; + + RFB.messages.enableContinuousUpdates(expectedMsg, true, 0, 0, 640, 20); + + expect(client._enabledContinuousUpdates).to.be.false; + + client._sock._websocket._receiveData(new Uint8Array([150])); + + expect(client._enabledContinuousUpdates).to.be.true; + expect(client._sock).to.have.sent(expectedMsg._sQ); + }); + + it('should disable continuous updates on subsequent EndOfContinousUpdates', function () { + client._enabledContinuousUpdates = true; + client._supportsContinuousUpdates = true; + + client._sock._websocket._receiveData(new Uint8Array([150])); + + expect(client._enabledContinuousUpdates).to.be.false; + }); + + it('should update continuous updates on resize', function () { + const expectedMsg = {_sQ: new Uint8Array(10), _sQlen: 0, flush: () => {}}; + RFB.messages.enableContinuousUpdates(expectedMsg, true, 0, 0, 90, 700); + + client._resize(450, 160); + + expect(client._sock._websocket._getSentData()).to.have.length(0); + + client._enabledContinuousUpdates = true; + + client._resize(90, 700); + + expect(client._sock).to.have.sent(expectedMsg._sQ); + }); + + it('should fail on an unknown message type', function () { + sinon.spy(client, "_fail"); + client._sock._websocket._receiveData(new Uint8Array([87])); + expect(client._fail).to.have.been.calledOnce; + }); + }); + + describe('Asynchronous Events', function () { + let client; + let pointerEvent; + let keyEvent; + let qemuKeyEvent; + + beforeEach(function () { + client = makeRFB(); + client._display.resize(100, 100); + + // We need to disable this as focusing the canvas will + // cause the browser to scoll to it, messing up our + // client coordinate calculations + client.focusOnClick = false; + + pointerEvent = sinon.spy(RFB.messages, 'pointerEvent'); + keyEvent = sinon.spy(RFB.messages, 'keyEvent'); + qemuKeyEvent = sinon.spy(RFB.messages, 'QEMUExtendedKeyEvent'); + }); + + afterEach(function () { + pointerEvent.restore(); + keyEvent.restore(); + qemuKeyEvent.restore(); + }); + + function elementToClient(x, y) { + let res = { x: 0, y: 0 }; + + let bounds = client._canvas.getBoundingClientRect(); + + /* + * If the canvas is on a fractional position we will calculate + * a fractional mouse position. But that gets truncated when we + * send the event, AND the same thing happens in RFB when it + * generates the PointerEvent message. To compensate for that + * fact we round the value upwards here. + */ + res.x = Math.ceil(bounds.left + x); + res.y = Math.ceil(bounds.top + y); + + return res; + } + + describe('Mouse Events', function () { + function sendMouseMoveEvent(x, y) { + let pos = elementToClient(x, y); + let ev; + + ev = new MouseEvent('mousemove', + { 'screenX': pos.x + window.screenX, + 'screenY': pos.y + window.screenY, + 'clientX': pos.x, + 'clientY': pos.y }); + client._canvas.dispatchEvent(ev); + } + + function sendMouseButtonEvent(x, y, down, button) { + let pos = elementToClient(x, y); + let ev; + + ev = new MouseEvent(down ? 'mousedown' : 'mouseup', + { 'screenX': pos.x + window.screenX, + 'screenY': pos.y + window.screenY, + 'clientX': pos.x, + 'clientY': pos.y, + 'button': button, + 'buttons': 1 << button }); + client._canvas.dispatchEvent(ev); + } + + it('should not send button messages in view-only mode', function () { + client._viewOnly = true; + sendMouseButtonEvent(10, 10, true, 0); + clock.tick(50); + expect(pointerEvent).to.not.have.been.called; + }); + + it('should not send movement messages in view-only mode', function () { + client._viewOnly = true; + sendMouseMoveEvent(10, 10); + clock.tick(50); + expect(pointerEvent).to.not.have.been.called; + }); + + it('should handle left mouse button', function () { + sendMouseButtonEvent(10, 10, true, 0); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 10, 10, 0x1); + pointerEvent.resetHistory(); + + sendMouseButtonEvent(10, 10, false, 0); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 10, 10, 0x0); + }); + + it('should handle middle mouse button', function () { + sendMouseButtonEvent(10, 10, true, 1); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 10, 10, 0x2); + pointerEvent.resetHistory(); + + sendMouseButtonEvent(10, 10, false, 1); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 10, 10, 0x0); + }); + + it('should handle right mouse button', function () { + sendMouseButtonEvent(10, 10, true, 2); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 10, 10, 0x4); + pointerEvent.resetHistory(); + + sendMouseButtonEvent(10, 10, false, 2); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 10, 10, 0x0); + }); + + it('should handle multiple mouse buttons', function () { + sendMouseButtonEvent(10, 10, true, 0); + sendMouseButtonEvent(10, 10, true, 2); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 10, 0x1); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 10, 0x5); + + pointerEvent.resetHistory(); + + sendMouseButtonEvent(10, 10, false, 0); + sendMouseButtonEvent(10, 10, false, 2); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 10, 0x4); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 10, 0x0); + }); + + it('should handle mouse movement', function () { + sendMouseMoveEvent(50, 70); + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 50, 70, 0x0); + }); + + it('should handle click and drag', function () { + sendMouseButtonEvent(10, 10, true, 0); + sendMouseMoveEvent(50, 70); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 10, 0x1); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 50, 70, 0x1); + + pointerEvent.resetHistory(); + + sendMouseButtonEvent(50, 70, false, 0); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 50, 70, 0x0); + }); + + describe('Event Aggregation', function () { + it('should send a single pointer event on mouse movement', function () { + sendMouseMoveEvent(50, 70); + clock.tick(100); + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 50, 70, 0x0); + }); + + it('should delay one move if two events are too close', function () { + sendMouseMoveEvent(18, 30); + sendMouseMoveEvent(20, 50); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 18, 30, 0x0); + pointerEvent.resetHistory(); + + clock.tick(100); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 50, 0x0); + }); + + it('should only send first and last move of many close events', function () { + sendMouseMoveEvent(18, 30); + sendMouseMoveEvent(20, 50); + sendMouseMoveEvent(21, 55); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 18, 30, 0x0); + pointerEvent.resetHistory(); + + clock.tick(100); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 21, 55, 0x0); + }); + + // We selected the 17ms since that is ~60 FPS + it('should send move events every 17 ms', function () { + sendMouseMoveEvent(1, 10); // instant send + clock.tick(10); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 1, 10, 0x0); + pointerEvent.resetHistory(); + + sendMouseMoveEvent(2, 20); // delayed + clock.tick(10); // timeout send + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 2, 20, 0x0); + pointerEvent.resetHistory(); + + sendMouseMoveEvent(3, 30); // delayed + clock.tick(10); + sendMouseMoveEvent(4, 40); // delayed + clock.tick(10); // timeout send + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 4, 40, 0x0); + pointerEvent.resetHistory(); + + sendMouseMoveEvent(5, 50); // delayed + + expect(pointerEvent).to.not.have.been.called; + }); + + it('should send waiting move events before a button press', function () { + sendMouseMoveEvent(13, 9); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 13, 9, 0x0); + pointerEvent.resetHistory(); + + sendMouseMoveEvent(20, 70); + + expect(pointerEvent).to.not.have.been.called; + + sendMouseButtonEvent(20, 70, true, 0); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 70, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 70, 0x1); + }); + + it('should send move events with enough time apart normally', function () { + sendMouseMoveEvent(58, 60); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 58, 60, 0x0); + pointerEvent.resetHistory(); + + clock.tick(20); + + sendMouseMoveEvent(25, 60); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 25, 60, 0x0); + pointerEvent.resetHistory(); + }); + + it('should not send waiting move events if disconnected', function () { + sendMouseMoveEvent(88, 99); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 88, 99, 0x0); + pointerEvent.resetHistory(); + + sendMouseMoveEvent(66, 77); + client.disconnect(); + clock.tick(20); + + expect(pointerEvent).to.not.have.been.called; + }); + }); + + it.skip('should block click events', function () { + /* FIXME */ + }); + + it.skip('should block contextmenu events', function () { + /* FIXME */ + }); + }); + + describe('Wheel Events', function () { + function sendWheelEvent(x, y, dx, dy, mode=0) { + let pos = elementToClient(x, y); + let ev; + + ev = new WheelEvent('wheel', + { 'screenX': pos.x + window.screenX, + 'screenY': pos.y + window.screenY, + 'clientX': pos.x, + 'clientY': pos.y, + 'deltaX': dx, + 'deltaY': dy, + 'deltaMode': mode }); + client._canvas.dispatchEvent(ev); + } + + it('should handle wheel up event', function () { + sendWheelEvent(10, 10, 0, -50); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 10, 1<<3); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 10, 0); + }); + + it('should handle wheel down event', function () { + sendWheelEvent(10, 10, 0, 50); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 10, 1<<4); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 10, 0); + }); + + it('should handle wheel left event', function () { + sendWheelEvent(10, 10, -50, 0); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 10, 1<<5); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 10, 0); + }); + + it('should handle wheel right event', function () { + sendWheelEvent(10, 10, 50, 0); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 10, 1<<6); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 10, 0); + }); + + it('should ignore wheel when in view only', function () { + client._viewOnly = true; + + sendWheelEvent(10, 10, 50, 0); + + expect(pointerEvent).to.not.have.been.called; + }); + + it('should accumulate wheel events if small enough', function () { + sendWheelEvent(10, 10, 0, 20); + sendWheelEvent(10, 10, 0, 20); + + expect(pointerEvent).to.not.have.been.called; + + sendWheelEvent(10, 10, 0, 20); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 10, 1<<4); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 10, 0); + }); + + it('should not accumulate large wheel events', function () { + sendWheelEvent(10, 10, 0, 400); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 10, 1<<4); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 10, 0); + }); + + it('should handle line based wheel event', function () { + sendWheelEvent(10, 10, 0, 3, 1); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 10, 1<<4); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 10, 0); + }); + + it('should handle page based wheel event', function () { + sendWheelEvent(10, 10, 0, 3, 2); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 10, 1<<4); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 10, 0); + }); + }); + + describe('Keyboard Events', function () { + it('should send a key message on a key press', function () { + client._handleKeyEvent(0x41, 'KeyA', true); + const keyMsg = {_sQ: new Uint8Array(8), _sQlen: 0, flush: () => {}}; + RFB.messages.keyEvent(keyMsg, 0x41, 1); + expect(client._sock).to.have.sent(keyMsg._sQ); + }); + + it('should not send messages in view-only mode', function () { + client._viewOnly = true; + sinon.spy(client._sock, 'flush'); + client._handleKeyEvent('a', 'KeyA', true); + expect(client._sock.flush).to.not.have.been.called; + }); + }); + + describe('Gesture event handlers', function () { + function gestureStart(gestureType, x, y, + magnitudeX = 0, magnitudeY = 0) { + let pos = elementToClient(x, y); + let detail = {type: gestureType, clientX: pos.x, clientY: pos.y}; + + detail.magnitudeX = magnitudeX; + detail.magnitudeY = magnitudeY; + + let ev = new CustomEvent('gesturestart', { detail: detail }); + client._canvas.dispatchEvent(ev); + } + + function gestureMove(gestureType, x, y, + magnitudeX = 0, magnitudeY = 0) { + let pos = elementToClient(x, y); + let detail = {type: gestureType, clientX: pos.x, clientY: pos.y}; + + detail.magnitudeX = magnitudeX; + detail.magnitudeY = magnitudeY; + + let ev = new CustomEvent('gesturemove', { detail: detail }); + client._canvas.dispatchEvent(ev); + } + + function gestureEnd(gestureType, x, y) { + let pos = elementToClient(x, y); + let detail = {type: gestureType, clientX: pos.x, clientY: pos.y}; + let ev = new CustomEvent('gestureend', { detail: detail }); + client._canvas.dispatchEvent(ev); + } + + describe('Gesture onetap', function () { + it('should handle onetap events', function () { + let bmask = 0x1; + + gestureStart('onetap', 20, 40); + gestureEnd('onetap', 20, 40); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + }); + + it('should keep same position for multiple onetap events', function () { + let bmask = 0x1; + + gestureStart('onetap', 20, 40); + gestureEnd('onetap', 20, 40); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureStart('onetap', 20, 50); + gestureEnd('onetap', 20, 50); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureStart('onetap', 30, 50); + gestureEnd('onetap', 30, 50); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + }); + + it('should not keep same position for onetap events when too far apart', function () { + let bmask = 0x1; + + gestureStart('onetap', 20, 40); + gestureEnd('onetap', 20, 40); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureStart('onetap', 80, 95); + gestureEnd('onetap', 80, 95); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 80, 95, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 80, 95, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 80, 95, 0x0); + }); + + it('should not keep same position for onetap events when enough time inbetween', function () { + let bmask = 0x1; + + gestureStart('onetap', 10, 20); + gestureEnd('onetap', 10, 20); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 20, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 20, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 10, 20, 0x0); + + pointerEvent.resetHistory(); + this.clock.tick(1500); + + gestureStart('onetap', 15, 20); + gestureEnd('onetap', 15, 20); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 15, 20, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 15, 20, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 15, 20, 0x0); + + pointerEvent.resetHistory(); + }); + }); + + describe('Gesture twotap', function () { + it('should handle gesture twotap events', function () { + let bmask = 0x4; + + gestureStart("twotap", 20, 40); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + }); + + it('should keep same position for multiple twotap events', function () { + let bmask = 0x4; + + for (let offset = 0;offset < 30;offset += 10) { + pointerEvent.resetHistory(); + + gestureStart('twotap', 20, 40 + offset); + gestureEnd('twotap', 20, 40 + offset); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + } + }); + }); + + describe('Gesture threetap', function () { + it('should handle gesture start for threetap events', function () { + let bmask = 0x2; + + gestureStart("threetap", 20, 40); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + }); + + it('should keep same position for multiple threetap events', function () { + let bmask = 0x2; + + for (let offset = 0;offset < 30;offset += 10) { + pointerEvent.resetHistory(); + + gestureStart('threetap', 20, 40 + offset); + gestureEnd('threetap', 20, 40 + offset); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + } + }); + }); + + describe('Gesture drag', function () { + it('should handle gesture drag events', function () { + let bmask = 0x1; + + gestureStart('drag', 20, 40); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + + pointerEvent.resetHistory(); + + gestureMove('drag', 30, 50); + clock.tick(50); + + expect(pointerEvent).to.have.been.calledOnce; + expect(pointerEvent).to.have.been.calledWith(client._sock, + 30, 50, bmask); + + pointerEvent.resetHistory(); + + gestureEnd('drag', 30, 50); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 30, 50, bmask); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 30, 50, 0x0); + }); + }); + + describe('Gesture long press', function () { + it('should handle long press events', function () { + let bmask = 0x4; + + gestureStart('longpress', 20, 40); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + pointerEvent.resetHistory(); + + gestureMove('longpress', 40, 60); + clock.tick(50); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 40, 60, bmask); + + pointerEvent.resetHistory(); + + gestureEnd('longpress', 40, 60); + + expect(pointerEvent).to.have.been.calledTwice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 40, 60, bmask); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 40, 60, 0x0); + }); + }); + + describe('Gesture twodrag', function () { + it('should handle gesture twodrag up events', function () { + let bmask = 0x10; // Button mask for scroll down + + gestureStart('twodrag', 20, 40, 0, 0); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureMove('twodrag', 20, 40, 0, -60); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + }); + + it('should handle gesture twodrag down events', function () { + let bmask = 0x8; // Button mask for scroll up + + gestureStart('twodrag', 20, 40, 0, 0); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureMove('twodrag', 20, 40, 0, 60); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + }); + + it('should handle gesture twodrag right events', function () { + let bmask = 0x20; // Button mask for scroll right + + gestureStart('twodrag', 20, 40, 0, 0); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureMove('twodrag', 20, 40, 60, 0); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + }); + + it('should handle gesture twodrag left events', function () { + let bmask = 0x40; // Button mask for scroll left + + gestureStart('twodrag', 20, 40, 0, 0); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureMove('twodrag', 20, 40, -60, 0); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + }); + + it('should handle gesture twodrag diag events', function () { + let scrlUp = 0x8; // Button mask for scroll up + let scrlRight = 0x20; // Button mask for scroll right + + gestureStart('twodrag', 20, 40, 0, 0); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureMove('twodrag', 20, 40, 60, 60); + + expect(pointerEvent).to.have.been.callCount(5); + expect(pointerEvent.getCall(0)).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.getCall(1)).to.have.been.calledWith(client._sock, + 20, 40, scrlUp); + expect(pointerEvent.getCall(2)).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.getCall(3)).to.have.been.calledWith(client._sock, + 20, 40, scrlRight); + expect(pointerEvent.getCall(4)).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + }); + + it('should handle multiple small gesture twodrag events', function () { + let bmask = 0x8; // Button mask for scroll up + + gestureStart('twodrag', 20, 40, 0, 0); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureMove('twodrag', 20, 40, 0, 10); + clock.tick(50); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureMove('twodrag', 20, 40, 0, 20); + clock.tick(50); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureMove('twodrag', 20, 40, 0, 60); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + }); + + it('should handle large gesture twodrag events', function () { + let bmask = 0x8; // Button mask for scroll up + + gestureStart('twodrag', 30, 50, 0, 0); + + expect(pointerEvent). + to.have.been.calledOnceWith(client._sock, 30, 50, 0x0); + + pointerEvent.resetHistory(); + + gestureMove('twodrag', 30, 50, 0, 200); + + expect(pointerEvent).to.have.callCount(7); + expect(pointerEvent.getCall(0)).to.have.been.calledWith(client._sock, + 30, 50, 0x0); + expect(pointerEvent.getCall(1)).to.have.been.calledWith(client._sock, + 30, 50, bmask); + expect(pointerEvent.getCall(2)).to.have.been.calledWith(client._sock, + 30, 50, 0x0); + expect(pointerEvent.getCall(3)).to.have.been.calledWith(client._sock, + 30, 50, bmask); + expect(pointerEvent.getCall(4)).to.have.been.calledWith(client._sock, + 30, 50, 0x0); + expect(pointerEvent.getCall(5)).to.have.been.calledWith(client._sock, + 30, 50, bmask); + expect(pointerEvent.getCall(6)).to.have.been.calledWith(client._sock, + 30, 50, 0x0); + }); + }); + + describe('Gesture pinch', function () { + it('should handle gesture pinch in events', function () { + let keysym = KeyTable.XK_Control_L; + let bmask = 0x10; // Button mask for scroll down + + gestureStart('pinch', 20, 40, 90, 90); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + expect(keyEvent).to.not.have.been.called; + + pointerEvent.resetHistory(); + + gestureMove('pinch', 20, 40, 30, 30); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + + expect(keyEvent).to.have.been.calledTwice; + expect(keyEvent.firstCall).to.have.been.calledWith(client._sock, + keysym, 1); + expect(keyEvent.secondCall).to.have.been.calledWith(client._sock, + keysym, 0); + + expect(keyEvent.firstCall).to.have.been.calledBefore(pointerEvent.secondCall); + expect(keyEvent.lastCall).to.have.been.calledAfter(pointerEvent.lastCall); + + pointerEvent.resetHistory(); + keyEvent.resetHistory(); + + gestureEnd('pinch', 20, 40); + + expect(pointerEvent).to.not.have.been.called; + expect(keyEvent).to.not.have.been.called; + }); + + it('should handle gesture pinch out events', function () { + let keysym = KeyTable.XK_Control_L; + let bmask = 0x8; // Button mask for scroll up + + gestureStart('pinch', 10, 20, 10, 20); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 10, 20, 0x0); + expect(keyEvent).to.not.have.been.called; + + pointerEvent.resetHistory(); + + gestureMove('pinch', 10, 20, 70, 80); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 10, 20, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 10, 20, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 10, 20, 0x0); + + expect(keyEvent).to.have.been.calledTwice; + expect(keyEvent.firstCall).to.have.been.calledWith(client._sock, + keysym, 1); + expect(keyEvent.secondCall).to.have.been.calledWith(client._sock, + keysym, 0); + + expect(keyEvent.firstCall).to.have.been.calledBefore(pointerEvent.secondCall); + expect(keyEvent.lastCall).to.have.been.calledAfter(pointerEvent.lastCall); + + pointerEvent.resetHistory(); + keyEvent.resetHistory(); + + gestureEnd('pinch', 10, 20); + + expect(pointerEvent).to.not.have.been.called; + expect(keyEvent).to.not.have.been.called; + }); + + it('should handle large gesture pinch', function () { + let keysym = KeyTable.XK_Control_L; + let bmask = 0x10; // Button mask for scroll down + + gestureStart('pinch', 20, 40, 150, 150); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + expect(keyEvent).to.not.have.been.called; + + pointerEvent.resetHistory(); + + gestureMove('pinch', 20, 40, 30, 30); + + expect(pointerEvent).to.have.been.callCount(5); + expect(pointerEvent.getCall(0)).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.getCall(1)).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.getCall(2)).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.getCall(3)).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.getCall(4)).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + + expect(keyEvent).to.have.been.calledTwice; + expect(keyEvent.firstCall).to.have.been.calledWith(client._sock, + keysym, 1); + expect(keyEvent.secondCall).to.have.been.calledWith(client._sock, + keysym, 0); + + expect(keyEvent.firstCall).to.have.been.calledBefore(pointerEvent.secondCall); + expect(keyEvent.lastCall).to.have.been.calledAfter(pointerEvent.lastCall); + + pointerEvent.resetHistory(); + keyEvent.resetHistory(); + + gestureEnd('pinch', 20, 40); + + expect(pointerEvent).to.not.have.been.called; + expect(keyEvent).to.not.have.been.called; + }); + + it('should handle multiple small gesture pinch out events', function () { + let keysym = KeyTable.XK_Control_L; + let bmask = 0x8; // Button mask for scroll down + + gestureStart('pinch', 20, 40, 0, 10); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + expect(keyEvent).to.not.have.been.called; + + pointerEvent.resetHistory(); + + gestureMove('pinch', 20, 40, 0, 30); + clock.tick(50); + + expect(pointerEvent).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + + gestureMove('pinch', 20, 40, 0, 60); + clock.tick(50); + + expect(pointerEvent).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + + pointerEvent.resetHistory(); + keyEvent.resetHistory(); + + gestureMove('pinch', 20, 40, 0, 90); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + + expect(keyEvent).to.have.been.calledTwice; + expect(keyEvent.firstCall).to.have.been.calledWith(client._sock, + keysym, 1); + expect(keyEvent.secondCall).to.have.been.calledWith(client._sock, + keysym, 0); + + expect(keyEvent.firstCall).to.have.been.calledBefore(pointerEvent.secondCall); + expect(keyEvent.lastCall).to.have.been.calledAfter(pointerEvent.lastCall); + + pointerEvent.resetHistory(); + keyEvent.resetHistory(); + + gestureEnd('pinch', 20, 40); + + expect(keyEvent).to.not.have.been.called; + }); + + it('should send correct key control code', function () { + let keysym = KeyTable.XK_Control_L; + let code = 0x1d; + let bmask = 0x10; // Button mask for scroll down + + client._qemuExtKeyEventSupported = true; + + gestureStart('pinch', 20, 40, 90, 90); + + expect(pointerEvent).to.have.been.calledOnceWith(client._sock, + 20, 40, 0x0); + expect(qemuKeyEvent).to.not.have.been.called; + + pointerEvent.resetHistory(); + + gestureMove('pinch', 20, 40, 30, 30); + + expect(pointerEvent).to.have.been.calledThrice; + expect(pointerEvent.firstCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + expect(pointerEvent.secondCall).to.have.been.calledWith(client._sock, + 20, 40, bmask); + expect(pointerEvent.thirdCall).to.have.been.calledWith(client._sock, + 20, 40, 0x0); + + expect(qemuKeyEvent).to.have.been.calledTwice; + expect(qemuKeyEvent.firstCall).to.have.been.calledWith(client._sock, + keysym, + true, + code); + expect(qemuKeyEvent.secondCall).to.have.been.calledWith(client._sock, + keysym, + false, + code); + + expect(qemuKeyEvent.firstCall).to.have.been.calledBefore(pointerEvent.secondCall); + expect(qemuKeyEvent.lastCall).to.have.been.calledAfter(pointerEvent.lastCall); + + pointerEvent.resetHistory(); + qemuKeyEvent.resetHistory(); + + gestureEnd('pinch', 20, 40); + + expect(pointerEvent).to.not.have.been.called; + expect(qemuKeyEvent).to.not.have.been.called; + }); + }); + }); + + describe('WebSocket Events', function () { + // message events + it('should do nothing if we receive an empty message and have nothing in the queue', function () { + client._normalMsg = sinon.spy(); + client._sock._websocket._receiveData(new Uint8Array([])); + expect(client._normalMsg).to.not.have.been.called; + }); + + it('should handle a message in the connected state as a normal message', function () { + client._normalMsg = sinon.spy(); + client._sock._websocket._receiveData(new Uint8Array([1, 2, 3])); + expect(client._normalMsg).to.have.been.called; + }); + + it('should handle a message in any non-disconnected/failed state like an init message', function () { + client._rfbConnectionState = 'connecting'; + client._rfbInitState = 'ProtocolVersion'; + client._initMsg = sinon.spy(); + client._sock._websocket._receiveData(new Uint8Array([1, 2, 3])); + expect(client._initMsg).to.have.been.called; + }); + + it('should process all normal messages directly', function () { + const spy = sinon.spy(); + client.addEventListener("bell", spy); + client._sock._websocket._receiveData(new Uint8Array([0x02, 0x02])); + expect(spy).to.have.been.calledTwice; + }); + + // open events + it('should update the state to ProtocolVersion on open (if the state is "connecting")', function () { + client = new RFB(document.createElement('div'), 'wss://host:8675'); + this.clock.tick(); + client._sock._websocket._open(); + expect(client._rfbInitState).to.equal('ProtocolVersion'); + }); + + it('should fail if we are not currently ready to connect and we get an "open" event', function () { + sinon.spy(client, "_fail"); + client._rfbConnectionState = 'connected'; + client._sock._websocket._open(); + expect(client._fail).to.have.been.calledOnce; + }); + + // close events + it('should transition to "disconnected" from "disconnecting" on a close event', function () { + const real = client._sock._websocket.close; + client._sock._websocket.close = () => {}; + client.disconnect(); + expect(client._rfbConnectionState).to.equal('disconnecting'); + client._sock._websocket.close = real; + client._sock._websocket.close(); + expect(client._rfbConnectionState).to.equal('disconnected'); + }); + + it('should fail if we get a close event while connecting', function () { + sinon.spy(client, "_fail"); + client._rfbConnectionState = 'connecting'; + client._sock._websocket.close(); + expect(client._fail).to.have.been.calledOnce; + }); + + it('should unregister close event handler', function () { + sinon.spy(client._sock, 'off'); + client.disconnect(); + client._sock._websocket.close(); + expect(client._sock.off).to.have.been.calledWith('close'); + }); + + // error events do nothing + }); + }); + + describe('Quality level setting', function () { + const defaultQuality = 6; + + let client; + + beforeEach(function () { + client = makeRFB(); + sinon.spy(RFB.messages, "clientEncodings"); + }); + + afterEach(function () { + RFB.messages.clientEncodings.restore(); + }); + + it(`should equal ${defaultQuality} by default`, function () { + expect(client._qualityLevel).to.equal(defaultQuality); + }); + + it('should ignore non-integers when set', function () { + client.qualityLevel = '1'; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client.qualityLevel = 1.5; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client.qualityLevel = null; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client.qualityLevel = undefined; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client.qualityLevel = {}; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + }); + + it('should ignore integers out of range [0, 9]', function () { + client.qualityLevel = -1; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client.qualityLevel = 10; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + }); + + it('should send clientEncodings with new quality value', function () { + let newQuality; + + newQuality = 8; + client.qualityLevel = newQuality; + expect(client.qualityLevel).to.equal(newQuality); + expect(RFB.messages.clientEncodings).to.have.been.calledOnce; + expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingQualityLevel0 + newQuality); + }); + + it('should not send clientEncodings if quality is the same', function () { + let newQuality; + + newQuality = 2; + client.qualityLevel = newQuality; + expect(RFB.messages.clientEncodings).to.have.been.calledOnce; + expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingQualityLevel0 + newQuality); + + RFB.messages.clientEncodings.resetHistory(); + + client.qualityLevel = newQuality; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + }); + + it('should not send clientEncodings if not in connected state', function () { + let newQuality; + + client._rfbConnectionState = ''; + newQuality = 2; + client.qualityLevel = newQuality; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client._rfbConnectionState = 'connnecting'; + newQuality = 6; + client.qualityLevel = newQuality; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client._rfbConnectionState = 'connected'; + newQuality = 5; + client.qualityLevel = newQuality; + expect(RFB.messages.clientEncodings).to.have.been.calledOnce; + expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingQualityLevel0 + newQuality); + }); + }); + + describe('Compression level setting', function () { + const defaultCompression = 2; + + let client; + + beforeEach(function () { + client = makeRFB(); + sinon.spy(RFB.messages, "clientEncodings"); + }); + + afterEach(function () { + RFB.messages.clientEncodings.restore(); + }); + + it(`should equal ${defaultCompression} by default`, function () { + expect(client._compressionLevel).to.equal(defaultCompression); + }); + + it('should ignore non-integers when set', function () { + client.compressionLevel = '1'; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client.compressionLevel = 1.5; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client.compressionLevel = null; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client.compressionLevel = undefined; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client.compressionLevel = {}; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + }); + + it('should ignore integers out of range [0, 9]', function () { + client.compressionLevel = -1; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client.compressionLevel = 10; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + }); + + it('should send clientEncodings with new compression value', function () { + let newCompression; + + newCompression = 5; + client.compressionLevel = newCompression; + expect(client.compressionLevel).to.equal(newCompression); + expect(RFB.messages.clientEncodings).to.have.been.calledOnce; + expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingCompressLevel0 + newCompression); + }); + + it('should not send clientEncodings if compression is the same', function () { + let newCompression; + + newCompression = 9; + client.compressionLevel = newCompression; + expect(RFB.messages.clientEncodings).to.have.been.calledOnce; + expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingCompressLevel0 + newCompression); + + RFB.messages.clientEncodings.resetHistory(); + + client.compressionLevel = newCompression; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + }); + + it('should not send clientEncodings if not in connected state', function () { + let newCompression; + + client._rfbConnectionState = ''; + newCompression = 7; + client.compressionLevel = newCompression; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client._rfbConnectionState = 'connnecting'; + newCompression = 6; + client.compressionLevel = newCompression; + expect(RFB.messages.clientEncodings).to.not.have.been.called; + + RFB.messages.clientEncodings.resetHistory(); + + client._rfbConnectionState = 'connected'; + newCompression = 5; + client.compressionLevel = newCompression; + expect(RFB.messages.clientEncodings).to.have.been.calledOnce; + expect(RFB.messages.clientEncodings.getCall(0).args[1]).to.include(encodings.pseudoEncodingCompressLevel0 + newCompression); + }); + }); +}); + +describe('RFB messages', function () { + let sock; + + before(function () { + FakeWebSocket.replace(); + sock = new Websock(); + sock.open(); + }); + + after(function () { + FakeWebSocket.restore(); + }); + + describe('Extended Clipboard Handling Send', function () { + beforeEach(function () { + sinon.spy(RFB.messages, 'clientCutText'); + }); + + afterEach(function () { + RFB.messages.clientCutText.restore(); + }); + + it('should call clientCutText with correct Caps data', function () { + let formats = { + 0: 2, + 2: 4121 + }; + let expectedData = new Uint8Array([0x1F, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x10, 0x19]); + let actions = [ + 1 << 24, // Caps + 1 << 25, // Request + 1 << 26, // Peek + 1 << 27, // Notify + 1 << 28 // Provide + ]; + + RFB.messages.extendedClipboardCaps(sock, actions, formats); + expect(RFB.messages.clientCutText).to.have.been.calledOnce; + expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData); + }); + + it('should call clientCutText with correct Request data', function () { + let formats = new Uint8Array([0x01]); + let expectedData = new Uint8Array([0x02, 0x00, 0x00, 0x01]); + + RFB.messages.extendedClipboardRequest(sock, formats); + expect(RFB.messages.clientCutText).to.have.been.calledOnce; + expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData); + }); + + it('should call clientCutText with correct Notify data', function () { + let formats = new Uint8Array([0x01]); + let expectedData = new Uint8Array([0x08, 0x00, 0x00, 0x01]); + + RFB.messages.extendedClipboardNotify(sock, formats); + expect(RFB.messages.clientCutText).to.have.been.calledOnce; + expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData); + }); + + it('should call clientCutText with correct Provide data', function () { + let testText = "Test string"; + let expectedText = encodeUTF8(testText + "\0"); + + let deflatedData = deflateWithSize(expectedText); + + // Build Expected with flags and deflated data + let expectedData = new Uint8Array(4 + deflatedData.length); + expectedData[0] = 0x10; // The client capabilities + expectedData[1] = 0x00; // Reserved flags + expectedData[2] = 0x00; // Reserved flags + expectedData[3] = 0x01; // The formats client supports + expectedData.set(deflatedData, 4); + + RFB.messages.extendedClipboardProvide(sock, [0x01], [testText]); + expect(RFB.messages.clientCutText).to.have.been.calledOnce; + expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData, true); + + }); + + describe('End of line characters', function () { + it('Carriage return', function () { + + let testText = "Hello\rworld\r\r!"; + let expectedText = encodeUTF8("Hello\r\nworld\r\n\r\n!\0"); + + let deflatedData = deflateWithSize(expectedText); + + // Build Expected with flags and deflated data + let expectedData = new Uint8Array(4 + deflatedData.length); + expectedData[0] = 0x10; // The client capabilities + expectedData[1] = 0x00; // Reserved flags + expectedData[2] = 0x00; // Reserved flags + expectedData[3] = 0x01; // The formats client supports + expectedData.set(deflatedData, 4); + + RFB.messages.extendedClipboardProvide(sock, [0x01], [testText]); + expect(RFB.messages.clientCutText).to.have.been.calledOnce; + expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData, true); + }); + + it('Carriage return Line feed', function () { + + let testText = "Hello\r\n\r\nworld\r\n!"; + let expectedText = encodeUTF8(testText + "\0"); + + let deflatedData = deflateWithSize(expectedText); + + // Build Expected with flags and deflated data + let expectedData = new Uint8Array(4 + deflatedData.length); + expectedData[0] = 0x10; // The client capabilities + expectedData[1] = 0x00; // Reserved flags + expectedData[2] = 0x00; // Reserved flags + expectedData[3] = 0x01; // The formats client supports + expectedData.set(deflatedData, 4); + + RFB.messages.extendedClipboardProvide(sock, [0x01], [testText]); + expect(RFB.messages.clientCutText).to.have.been.calledOnce; + expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData, true); + }); + + it('Line feed', function () { + let testText = "Hello\n\n\nworld\n!"; + let expectedText = encodeUTF8("Hello\r\n\r\n\r\nworld\r\n!\0"); + + let deflatedData = deflateWithSize(expectedText); + + // Build Expected with flags and deflated data + let expectedData = new Uint8Array(4 + deflatedData.length); + expectedData[0] = 0x10; // The client capabilities + expectedData[1] = 0x00; // Reserved flags + expectedData[2] = 0x00; // Reserved flags + expectedData[3] = 0x01; // The formats client supports + expectedData.set(deflatedData, 4); + + RFB.messages.extendedClipboardProvide(sock, [0x01], [testText]); + expect(RFB.messages.clientCutText).to.have.been.calledOnce; + expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData, true); + }); + + it('Carriage return and Line feed mixed', function () { + let testText = "\rHello\r\n\rworld\n\n!"; + let expectedText = encodeUTF8("\r\nHello\r\n\r\nworld\r\n\r\n!\0"); + + let deflatedData = deflateWithSize(expectedText); + + // Build Expected with flags and deflated data + let expectedData = new Uint8Array(4 + deflatedData.length); + expectedData[0] = 0x10; // The client capabilities + expectedData[1] = 0x00; // Reserved flags + expectedData[2] = 0x00; // Reserved flags + expectedData[3] = 0x01; // The formats client supports + expectedData.set(deflatedData, 4); + + RFB.messages.extendedClipboardProvide(sock, [0x01], [testText]); + expect(RFB.messages.clientCutText).to.have.been.calledOnce; + expect(RFB.messages.clientCutText).to.have.been.calledWith(sock, expectedData, true); + }); + }); + }); +}); diff --git a/tests/test.rre.js b/tests/test.rre.js new file mode 100644 index 0000000..8e006f8 --- /dev/null +++ b/tests/test.rre.js @@ -0,0 +1,107 @@ +const expect = chai.expect; + +import Websock from '../core/websock.js'; +import Display from '../core/display.js'; + +import RREDecoder from '../core/decoders/rre.js'; + +import FakeWebSocket from './fake.websocket.js'; + +function testDecodeRect(decoder, x, y, width, height, data, display, depth) { + let sock; + + sock = new Websock; + sock.open("ws://example.com"); + + sock.on('message', () => { + decoder.decodeRect(x, y, width, height, sock, display, depth); + }); + + // Empty messages are filtered at multiple layers, so we need to + // do a direct call + if (data.length === 0) { + decoder.decodeRect(x, y, width, height, sock, display, depth); + } else { + sock._websocket._receiveData(new Uint8Array(data)); + } + + display.flip(); +} + +function push16(arr, num) { + arr.push((num >> 8) & 0xFF, + num & 0xFF); +} + +function push32(arr, num) { + arr.push((num >> 24) & 0xFF, + (num >> 16) & 0xFF, + (num >> 8) & 0xFF, + num & 0xFF); +} + +describe('RRE Decoder', function () { + let decoder; + let display; + + before(FakeWebSocket.replace); + after(FakeWebSocket.restore); + + beforeEach(function () { + decoder = new RREDecoder(); + display = new Display(document.createElement('canvas')); + display.resize(4, 4); + }); + + // TODO(directxman12): test rre_chunk_sz? + + it('should handle the RRE encoding', function () { + let data = []; + push32(data, 2); // 2 subrects + push32(data, 0x00ff0000); // becomes 00ff0000 --> #00FF00 bg color + data.push(0x00); // becomes 0000ff00 --> #0000FF fg color + data.push(0x00); + data.push(0xff); + data.push(0x00); + push16(data, 0); // x: 0 + push16(data, 0); // y: 0 + push16(data, 2); // width: 2 + push16(data, 2); // height: 2 + data.push(0x00); // becomes 0000ff00 --> #0000FF fg color + data.push(0x00); + data.push(0xff); + data.push(0x00); + push16(data, 2); // x: 2 + push16(data, 2); // y: 2 + push16(data, 2); // width: 2 + push16(data, 2); // height: 2 + + testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle empty rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, [ 0x00, 0xff, 0xff, 0xff, 0xff ], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); +}); diff --git a/tests/test.tight.js b/tests/test.tight.js new file mode 100644 index 0000000..cc5db36 --- /dev/null +++ b/tests/test.tight.js @@ -0,0 +1,394 @@ +const expect = chai.expect; + +import Websock from '../core/websock.js'; +import Display from '../core/display.js'; + +import TightDecoder from '../core/decoders/tight.js'; + +import FakeWebSocket from './fake.websocket.js'; + +function testDecodeRect(decoder, x, y, width, height, data, display, depth) { + let sock; + + sock = new Websock; + sock.open("ws://example.com"); + + sock.on('message', () => { + decoder.decodeRect(x, y, width, height, sock, display, depth); + }); + + // Empty messages are filtered at multiple layers, so we need to + // do a direct call + if (data.length === 0) { + decoder.decodeRect(x, y, width, height, sock, display, depth); + } else { + sock._websocket._receiveData(new Uint8Array(data)); + } + + display.flip(); +} + +describe('Tight Decoder', function () { + let decoder; + let display; + + before(FakeWebSocket.replace); + after(FakeWebSocket.restore); + + beforeEach(function () { + decoder = new TightDecoder(); + display = new Display(document.createElement('canvas')); + display.resize(4, 4); + }); + + it('should handle fill rects', function () { + testDecodeRect(decoder, 0, 0, 4, 4, + [0x80, 0xff, 0x88, 0x44], + display, 24); + + let targetData = new Uint8Array([ + 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, + 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, + 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, + 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, 0xff, 0x88, 0x44, 255, + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle uncompressed copy rects', function () { + let blueData = [ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff ]; + let greenData = [ 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00 ]; + + testDecodeRect(decoder, 0, 0, 2, 1, blueData, display, 24); + testDecodeRect(decoder, 0, 1, 2, 1, blueData, display, 24); + testDecodeRect(decoder, 2, 0, 2, 1, greenData, display, 24); + testDecodeRect(decoder, 2, 1, 2, 1, greenData, display, 24); + testDecodeRect(decoder, 0, 2, 2, 1, greenData, display, 24); + testDecodeRect(decoder, 0, 3, 2, 1, greenData, display, 24); + testDecodeRect(decoder, 2, 2, 2, 1, blueData, display, 24); + testDecodeRect(decoder, 2, 3, 2, 1, blueData, display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle compressed copy rects', function () { + let data = [ + // Control byte + 0x00, + // Pixels (compressed) + 0x15, + 0x78, 0x9c, 0x63, 0x60, 0xf8, 0xcf, 0x00, 0x44, + 0x60, 0x82, 0x01, 0x99, 0x8d, 0x29, 0x02, 0xa6, + 0x00, 0x7e, 0xbf, 0x0f, 0xf1 ]; + + testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle uncompressed mono rects', function () { + let data = [ + // Control bytes + 0x40, 0x01, + // Palette + 0x01, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, + // Pixels + 0x30, 0x30, 0xc0, 0xc0 ]; + + testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle compressed mono rects', function () { + display.resize(4, 12); + + let data = [ + // Control bytes + 0x40, 0x01, + // Palette + 0x01, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, + // Pixels (compressed) + 0x0e, + 0x78, 0x9c, 0x33, 0x30, 0x38, 0x70, 0xc0, 0x00, + 0x8a, 0x01, 0x21, 0x3c, 0x05, 0xa1 ]; + + testDecodeRect(decoder, 0, 0, 4, 12, data, display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle uncompressed palette rects', function () { + let data1 = [ + // Control bytes + 0x40, 0x01, + // Palette + 0x02, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + // Pixels + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01 ]; + let data2 = [ + // Control bytes + 0x40, 0x01, + // Palette + 0x02, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + // Pixels + 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00 ]; + + testDecodeRect(decoder, 0, 0, 4, 2, data1, display, 24); + testDecodeRect(decoder, 0, 2, 4, 2, data2, display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle compressed palette rects', function () { + let data = [ + // Control bytes + 0x40, 0x01, + // Palette + 0x02, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + // Pixels (compressed) + 0x12, + 0x78, 0x9c, 0x63, 0x60, 0x60, 0x64, 0x64, 0x00, + 0x62, 0x08, 0xc9, 0xc0, 0x00, 0x00, 0x00, 0x54, + 0x00, 0x09 ]; + + testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it.skip('should handle uncompressed gradient rects', function () { + // Not implemented yet + }); + + it.skip('should handle compressed gradient rects', function () { + // Not implemented yet + }); + + it('should handle empty copy rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, [ 0x00 ], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle empty palette rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, + [ 0x40, 0x01, 0x01, + 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff ], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle empty fill rects', function () { + display.fillRect(0, 0, 4, 4, [ 0x00, 0x00, 0xff ]); + display.fillRect(2, 0, 2, 2, [ 0x00, 0xff, 0x00 ]); + display.fillRect(0, 2, 2, 2, [ 0x00, 0xff, 0x00 ]); + + testDecodeRect(decoder, 1, 2, 0, 0, + [ 0x80, 0xff, 0xff, 0xff ], display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0x00, 0xff, 255, 0x00, 0x00, 0xff, 255 + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle JPEG rects', function (done) { + let data = [ + // Control bytes + 0x90, 0xd6, 0x05, + // JPEG data + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, + 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x48, + 0x00, 0x48, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x13, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, + 0x50, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0xdb, + 0x00, 0x43, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0xff, 0xc2, 0x00, 0x11, 0x08, + 0x00, 0x04, 0x00, 0x04, 0x03, 0x01, 0x11, 0x00, + 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, + 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xff, 0xc4, 0x00, 0x14, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, + 0x00, 0x02, 0x10, 0x03, 0x10, 0x00, 0x00, 0x01, + 0x1e, 0x0a, 0xa7, 0x7f, 0xff, 0xc4, 0x00, 0x14, + 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x05, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, + 0x00, 0x01, 0x05, 0x02, 0x5d, 0x74, 0x41, 0x47, + 0xff, 0xc4, 0x00, 0x1f, 0x11, 0x00, 0x01, 0x04, + 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x04, 0x05, + 0x07, 0x08, 0x14, 0x16, 0x03, 0x15, 0x17, 0x25, + 0x26, 0xff, 0xda, 0x00, 0x08, 0x01, 0x03, 0x01, + 0x01, 0x3f, 0x01, 0xad, 0x35, 0xa6, 0x13, 0xb8, + 0x10, 0x98, 0x5d, 0x8a, 0xb1, 0x41, 0x7e, 0x43, + 0x99, 0x24, 0x3d, 0x8f, 0x70, 0x30, 0xd8, 0xcb, + 0x44, 0xbb, 0x7d, 0x48, 0xb5, 0xf8, 0x18, 0x7f, + 0xe7, 0xc1, 0x9f, 0x86, 0x45, 0x9b, 0xfa, 0xf1, + 0x61, 0x96, 0x46, 0xbf, 0x56, 0xc8, 0x8b, 0x2b, + 0x0b, 0x35, 0x6e, 0x4b, 0x8a, 0x95, 0x6a, 0xf9, + 0xff, 0x00, 0xff, 0xc4, 0x00, 0x1f, 0x11, 0x00, + 0x01, 0x04, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x02, 0x04, 0x05, 0x12, 0x13, 0x14, 0x01, 0x06, + 0x11, 0x22, 0x23, 0xff, 0xda, 0x00, 0x08, 0x01, + 0x02, 0x01, 0x01, 0x3f, 0x01, 0x85, 0x85, 0x8c, + 0xec, 0x31, 0x8d, 0xa6, 0x26, 0x1b, 0x6e, 0x48, + 0xbc, 0xcd, 0xb0, 0xe3, 0x33, 0x86, 0xf9, 0x35, + 0xdc, 0x15, 0xa8, 0xbe, 0x4d, 0x4a, 0x10, 0x22, + 0x80, 0x00, 0x91, 0xe8, 0x24, 0xda, 0xb6, 0x57, + 0x95, 0xf2, 0xa5, 0x73, 0xff, 0xc4, 0x00, 0x1e, + 0x10, 0x00, 0x01, 0x04, 0x03, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x01, 0x02, 0x04, 0x12, 0x05, 0x11, + 0x13, 0x14, 0x22, 0x23, 0xff, 0xda, 0x00, 0x08, + 0x01, 0x01, 0x00, 0x06, 0x3f, 0x02, 0x91, 0x89, + 0xc4, 0xc8, 0xf1, 0x60, 0x45, 0xe5, 0xc0, 0x1c, + 0x80, 0x7a, 0x77, 0x00, 0xe4, 0x97, 0xeb, 0x24, + 0x66, 0x33, 0xac, 0x63, 0x11, 0xfe, 0xe4, 0x76, + 0xad, 0x56, 0xe9, 0xa8, 0x88, 0x9f, 0xff, 0xc4, + 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xda, 0x00, 0x08, + 0x01, 0x01, 0x00, 0x01, 0x3f, 0x21, 0x68, 0x3f, + 0x92, 0x17, 0x81, 0x1f, 0x7f, 0xff, 0xda, 0x00, + 0x0c, 0x03, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x10, 0x5f, 0xff, 0xc4, 0x00, 0x14, + 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xda, 0x00, 0x08, 0x01, 0x03, + 0x01, 0x01, 0x3f, 0x10, 0x03, 0xeb, 0x11, 0xe4, + 0xa7, 0xe3, 0xff, 0x00, 0xff, 0xc4, 0x00, 0x14, + 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xda, 0x00, 0x08, 0x01, 0x02, + 0x01, 0x01, 0x3f, 0x10, 0x6b, 0xd3, 0x02, 0xdc, + 0x9a, 0xf4, 0xff, 0x00, 0xff, 0xc4, 0x00, 0x14, + 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, + 0x00, 0x01, 0x3f, 0x10, 0x62, 0x7b, 0x3a, 0xd0, + 0x3f, 0xeb, 0xff, 0x00, 0xff, 0xd9, + ]; + + testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + let targetData = new Uint8Array([ + 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255 + ]); + + // Browsers have rounding errors, so we need an approximate + // comparing function + function almost(a, b) { + let diff = Math.abs(a - b); + return diff < 5; + } + + display.onflush = () => { + expect(display).to.have.displayed(targetData, almost); + done(); + }; + display.flush(); + }); +}); diff --git a/tests/test.tightpng.js b/tests/test.tightpng.js new file mode 100644 index 0000000..253400b --- /dev/null +++ b/tests/test.tightpng.js @@ -0,0 +1,144 @@ +const expect = chai.expect; + +import Websock from '../core/websock.js'; +import Display from '../core/display.js'; + +import TightPngDecoder from '../core/decoders/tightpng.js'; + +import FakeWebSocket from './fake.websocket.js'; + +function testDecodeRect(decoder, x, y, width, height, data, display, depth) { + let sock; + + sock = new Websock; + sock.open("ws://example.com"); + + sock.on('message', () => { + decoder.decodeRect(x, y, width, height, sock, display, depth); + }); + + // Empty messages are filtered at multiple layers, so we need to + // do a direct call + if (data.length === 0) { + decoder.decodeRect(x, y, width, height, sock, display, depth); + } else { + sock._websocket._receiveData(new Uint8Array(data)); + } + + display.flip(); +} + +describe('TightPng Decoder', function () { + let decoder; + let display; + + before(FakeWebSocket.replace); + after(FakeWebSocket.restore); + + beforeEach(function () { + decoder = new TightPngDecoder(); + display = new Display(document.createElement('canvas')); + display.resize(4, 4); + }); + + it('should handle the TightPng encoding', function (done) { + let data = [ + // Control bytes + 0xa0, 0xb4, 0x04, + // PNG data + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, + 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, + 0x08, 0x02, 0x00, 0x00, 0x00, 0x26, 0x93, 0x09, + 0x29, 0x00, 0x00, 0x01, 0x84, 0x69, 0x43, 0x43, + 0x50, 0x49, 0x43, 0x43, 0x20, 0x70, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x00, 0x00, 0x28, 0x91, + 0x7d, 0x91, 0x3d, 0x48, 0xc3, 0x40, 0x18, 0x86, + 0xdf, 0xa6, 0x6a, 0x45, 0x2a, 0x0e, 0x76, 0x10, + 0x71, 0x08, 0x52, 0x9d, 0x2c, 0x88, 0x8a, 0x38, + 0x6a, 0x15, 0x8a, 0x50, 0x21, 0xd4, 0x0a, 0xad, + 0x3a, 0x98, 0x5c, 0xfa, 0x07, 0x4d, 0x1a, 0x92, + 0x14, 0x17, 0x47, 0xc1, 0xb5, 0xe0, 0xe0, 0xcf, + 0x62, 0xd5, 0xc1, 0xc5, 0x59, 0x57, 0x07, 0x57, + 0x41, 0x10, 0xfc, 0x01, 0x71, 0x72, 0x74, 0x52, + 0x74, 0x91, 0x12, 0xbf, 0x4b, 0x0a, 0x2d, 0x62, + 0xbc, 0xe3, 0xb8, 0x87, 0xf7, 0xbe, 0xf7, 0xe5, + 0xee, 0x3b, 0x40, 0xa8, 0x97, 0x99, 0x66, 0x75, + 0x8c, 0x03, 0x9a, 0x6e, 0x9b, 0xa9, 0x44, 0x5c, + 0xcc, 0x64, 0x57, 0xc5, 0xd0, 0x2b, 0xba, 0x68, + 0x86, 0x31, 0x8c, 0x2e, 0x99, 0x59, 0xc6, 0x9c, + 0x24, 0x25, 0xe1, 0x3b, 0xbe, 0xee, 0x11, 0xe0, + 0xfb, 0x5d, 0x8c, 0x67, 0xf9, 0xd7, 0xfd, 0x39, + 0x7a, 0xd5, 0x9c, 0xc5, 0x80, 0x80, 0x48, 0x3c, + 0xcb, 0x0c, 0xd3, 0x26, 0xde, 0x20, 0x9e, 0xde, + 0xb4, 0x0d, 0xce, 0xfb, 0xc4, 0x11, 0x56, 0x94, + 0x55, 0xe2, 0x73, 0xe2, 0x31, 0x93, 0x2e, 0x48, + 0xfc, 0xc8, 0x75, 0xc5, 0xe3, 0x37, 0xce, 0x05, + 0x97, 0x05, 0x9e, 0x19, 0x31, 0xd3, 0xa9, 0x79, + 0xe2, 0x08, 0xb1, 0x58, 0x68, 0x63, 0xa5, 0x8d, + 0x59, 0xd1, 0xd4, 0x88, 0xa7, 0x88, 0xa3, 0xaa, + 0xa6, 0x53, 0xbe, 0x90, 0xf1, 0x58, 0xe5, 0xbc, + 0xc5, 0x59, 0x2b, 0x57, 0x59, 0xf3, 0x9e, 0xfc, + 0x85, 0xe1, 0x9c, 0xbe, 0xb2, 0xcc, 0x75, 0x5a, + 0x43, 0x48, 0x60, 0x11, 0x4b, 0x90, 0x20, 0x42, + 0x41, 0x15, 0x25, 0x94, 0x61, 0x23, 0x46, 0xbb, + 0x4e, 0x8a, 0x85, 0x14, 0x9d, 0xc7, 0x7d, 0xfc, + 0x83, 0xae, 0x5f, 0x22, 0x97, 0x42, 0xae, 0x12, + 0x18, 0x39, 0x16, 0x50, 0x81, 0x06, 0xd9, 0xf5, + 0x83, 0xff, 0xc1, 0xef, 0xde, 0x5a, 0xf9, 0xc9, + 0x09, 0x2f, 0x29, 0x1c, 0x07, 0x3a, 0x5f, 0x1c, + 0xe7, 0x63, 0x04, 0x08, 0xed, 0x02, 0x8d, 0x9a, + 0xe3, 0x7c, 0x1f, 0x3b, 0x4e, 0xe3, 0x04, 0x08, + 0x3e, 0x03, 0x57, 0x7a, 0xcb, 0x5f, 0xa9, 0x03, + 0x33, 0x9f, 0xa4, 0xd7, 0x5a, 0x5a, 0xf4, 0x08, + 0xe8, 0xdb, 0x06, 0x2e, 0xae, 0x5b, 0x9a, 0xb2, + 0x07, 0x5c, 0xee, 0x00, 0x03, 0x4f, 0x86, 0x6c, + 0xca, 0xae, 0x14, 0xa4, 0x25, 0xe4, 0xf3, 0xc0, + 0xfb, 0x19, 0x7d, 0x53, 0x16, 0xe8, 0xbf, 0x05, + 0x7a, 0xd6, 0xbc, 0xbe, 0x35, 0xcf, 0x71, 0xfa, + 0x00, 0xa4, 0xa9, 0x57, 0xc9, 0x1b, 0xe0, 0xe0, + 0x10, 0x18, 0x2d, 0x50, 0xf6, 0xba, 0xcf, 0xbb, + 0xbb, 0xdb, 0xfb, 0xf6, 0x6f, 0x4d, 0xb3, 0x7f, + 0x3f, 0x0a, 0x27, 0x72, 0x7d, 0x49, 0x29, 0x8b, + 0xbb, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, + 0x73, 0x00, 0x00, 0x2e, 0x23, 0x00, 0x00, 0x2e, + 0x23, 0x01, 0x78, 0xa5, 0x3f, 0x76, 0x00, 0x00, + 0x00, 0x07, 0x74, 0x49, 0x4d, 0x45, 0x07, 0xe4, + 0x06, 0x06, 0x0c, 0x23, 0x1d, 0x3f, 0x9f, 0xbb, + 0x94, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, + 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, + 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, + 0x4d, 0x50, 0x57, 0x81, 0x0e, 0x17, 0x00, 0x00, + 0x00, 0x1e, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, + 0x65, 0xc9, 0xb1, 0x0d, 0x00, 0x00, 0x08, 0x03, + 0x20, 0xea, 0xff, 0x3f, 0xd7, 0xd5, 0x44, 0x56, + 0x52, 0x90, 0xc2, 0x38, 0xa2, 0xd0, 0xbc, 0x59, + 0x8a, 0x9f, 0x04, 0x05, 0x6b, 0x38, 0x7b, 0xb2, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, + 0xae, 0x42, 0x60, 0x82, + ]; + + testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24); + + let targetData = new Uint8Array([ + 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255, + 0x00, 0xff, 0x00, 255, 0x00, 0xff, 0x00, 255, 0xff, 0x00, 0x00, 255, 0xff, 0x00, 0x00, 255 + ]); + + // Firefox currently has some very odd rounding bug: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1667747 + function almost(a, b) { + let diff = Math.abs(a - b); + return diff < 30; + } + + display.onflush = () => { + expect(display).to.have.displayed(targetData, almost); + done(); + }; + display.flush(); + }); +}); diff --git a/tests/test.util.js b/tests/test.util.js new file mode 100644 index 0000000..cd61f24 --- /dev/null +++ b/tests/test.util.js @@ -0,0 +1,89 @@ +/* eslint-disable no-console */ +const expect = chai.expect; + +import * as Log from '../core/util/logging.js'; +import { encodeUTF8, decodeUTF8 } from '../core/util/strings.js'; + +describe('Utils', function () { + "use strict"; + + describe('logging functions', function () { + beforeEach(function () { + sinon.spy(console, 'log'); + sinon.spy(console, 'debug'); + sinon.spy(console, 'warn'); + sinon.spy(console, 'error'); + sinon.spy(console, 'info'); + }); + + afterEach(function () { + console.log.restore(); + console.debug.restore(); + console.warn.restore(); + console.error.restore(); + console.info.restore(); + Log.initLogging(); + }); + + it('should use noop for levels lower than the min level', function () { + Log.initLogging('warn'); + Log.Debug('hi'); + Log.Info('hello'); + expect(console.log).to.not.have.been.called; + }); + + it('should use console.debug for Debug', function () { + Log.initLogging('debug'); + Log.Debug('dbg'); + expect(console.debug).to.have.been.calledWith('dbg'); + }); + + it('should use console.info for Info', function () { + Log.initLogging('debug'); + Log.Info('inf'); + expect(console.info).to.have.been.calledWith('inf'); + }); + + it('should use console.warn for Warn', function () { + Log.initLogging('warn'); + Log.Warn('wrn'); + expect(console.warn).to.have.been.called; + expect(console.warn).to.have.been.calledWith('wrn'); + }); + + it('should use console.error for Error', function () { + Log.initLogging('error'); + Log.Error('err'); + expect(console.error).to.have.been.called; + expect(console.error).to.have.been.calledWith('err'); + }); + }); + + describe('string functions', function () { + it('should decode UTF-8 to DOMString correctly', function () { + const utf8string = '\xd0\x9f'; + const domstring = decodeUTF8(utf8string); + expect(domstring).to.equal("П"); + }); + + it('should encode DOMString to UTF-8 correctly', function () { + const domstring = "åäöa"; + const utf8string = encodeUTF8(domstring); + expect(utf8string).to.equal('\xc3\xa5\xc3\xa4\xc3\xb6\x61'); + }); + + it('should allow Latin-1 strings if allowLatin1 is set when decoding', function () { + const latin1string = '\xe5\xe4\xf6'; + expect(() => decodeUTF8(latin1string)).to.throw(Error); + expect(decodeUTF8(latin1string, true)).to.equal('åäö'); + }); + }); + + // TODO(directxman12): test the conf_default and conf_defaults methods + // TODO(directxman12): test the event methods (addEvent, removeEvent, stopEvent) + // TODO(directxman12): figure out a good way to test getPosition and getEventPosition + // TODO(directxman12): figure out how to test the browser detection functions properly + // (we can't really test them against the browsers, except for Gecko + // via PhantomJS, the default test driver) +}); +/* eslint-enable no-console */ diff --git a/tests/test.websock.js b/tests/test.websock.js new file mode 100644 index 0000000..857fdca --- /dev/null +++ b/tests/test.websock.js @@ -0,0 +1,552 @@ +const expect = chai.expect; + +import Websock from '../core/websock.js'; +import FakeWebSocket from './fake.websocket.js'; + +describe('Websock', function () { + "use strict"; + + describe('Queue methods', function () { + let sock; + const RQ_TEMPLATE = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]); + + beforeEach(function () { + sock = new Websock(); + // skip init + sock._allocateBuffers(); + sock._rQ.set(RQ_TEMPLATE); + sock._rQlen = RQ_TEMPLATE.length; + }); + describe('rQlen', function () { + it('should return the length of the receive queue', function () { + sock.rQi = 0; + + expect(sock.rQlen).to.equal(RQ_TEMPLATE.length); + }); + + it("should return the proper length if we read some from the receive queue", function () { + sock.rQi = 1; + + expect(sock.rQlen).to.equal(RQ_TEMPLATE.length - 1); + }); + }); + + describe('rQpeek8', function () { + it('should peek at the next byte without poping it off the queue', function () { + const befLen = sock.rQlen; + const peek = sock.rQpeek8(); + expect(sock.rQpeek8()).to.equal(peek); + expect(sock.rQlen).to.equal(befLen); + }); + }); + + describe('rQshift8()', function () { + it('should pop a single byte from the receive queue', function () { + const peek = sock.rQpeek8(); + const befLen = sock.rQlen; + expect(sock.rQshift8()).to.equal(peek); + expect(sock.rQlen).to.equal(befLen - 1); + }); + }); + + describe('rQshift16()', function () { + it('should pop two bytes from the receive queue and return a single number', function () { + const befLen = sock.rQlen; + const expected = (RQ_TEMPLATE[0] << 8) + RQ_TEMPLATE[1]; + expect(sock.rQshift16()).to.equal(expected); + expect(sock.rQlen).to.equal(befLen - 2); + }); + }); + + describe('rQshift32()', function () { + it('should pop four bytes from the receive queue and return a single number', function () { + const befLen = sock.rQlen; + const expected = (RQ_TEMPLATE[0] << 24) + + (RQ_TEMPLATE[1] << 16) + + (RQ_TEMPLATE[2] << 8) + + RQ_TEMPLATE[3]; + expect(sock.rQshift32()).to.equal(expected); + expect(sock.rQlen).to.equal(befLen - 4); + }); + }); + + describe('rQshiftStr', function () { + it('should shift the given number of bytes off of the receive queue and return a string', function () { + const befLen = sock.rQlen; + const befRQi = sock.rQi; + const shifted = sock.rQshiftStr(3); + expect(shifted).to.be.a('string'); + expect(shifted).to.equal(String.fromCharCode.apply(null, Array.prototype.slice.call(new Uint8Array(RQ_TEMPLATE.buffer, befRQi, 3)))); + expect(sock.rQlen).to.equal(befLen - 3); + }); + + it('should shift the entire rest of the queue off if no length is given', function () { + sock.rQshiftStr(); + expect(sock.rQlen).to.equal(0); + }); + + it('should be able to handle very large strings', function () { + const BIG_LEN = 500000; + const RQ_BIG = new Uint8Array(BIG_LEN); + let expected = ""; + let letterCode = 'a'.charCodeAt(0); + for (let i = 0; i < BIG_LEN; i++) { + RQ_BIG[i] = letterCode; + expected += String.fromCharCode(letterCode); + + if (letterCode < 'z'.charCodeAt(0)) { + letterCode++; + } else { + letterCode = 'a'.charCodeAt(0); + } + } + sock._rQ.set(RQ_BIG); + sock._rQlen = RQ_BIG.length; + + const shifted = sock.rQshiftStr(); + + expect(shifted).to.be.equal(expected); + expect(sock.rQlen).to.equal(0); + }); + }); + + describe('rQshiftBytes', function () { + it('should shift the given number of bytes of the receive queue and return an array', function () { + const befLen = sock.rQlen; + const befRQi = sock.rQi; + const shifted = sock.rQshiftBytes(3); + expect(shifted).to.be.an.instanceof(Uint8Array); + expect(shifted).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, befRQi, 3)); + expect(sock.rQlen).to.equal(befLen - 3); + }); + + it('should shift the entire rest of the queue off if no length is given', function () { + sock.rQshiftBytes(); + expect(sock.rQlen).to.equal(0); + }); + }); + + describe('rQslice', function () { + beforeEach(function () { + sock.rQi = 0; + }); + + it('should not modify the receive queue', function () { + const befLen = sock.rQlen; + sock.rQslice(0, 2); + expect(sock.rQlen).to.equal(befLen); + }); + + it('should return an array containing the given slice of the receive queue', function () { + const sl = sock.rQslice(0, 2); + expect(sl).to.be.an.instanceof(Uint8Array); + expect(sl).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 0, 2)); + }); + + it('should use the rest of the receive queue if no end is given', function () { + const sl = sock.rQslice(1); + expect(sl).to.have.length(RQ_TEMPLATE.length - 1); + expect(sl).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 1)); + }); + + it('should take the current rQi in to account', function () { + sock.rQi = 1; + expect(sock.rQslice(0, 2)).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 1, 2)); + }); + }); + + describe('rQwait', function () { + beforeEach(function () { + sock.rQi = 0; + }); + + it('should return true if there are not enough bytes in the receive queue', function () { + expect(sock.rQwait('hi', RQ_TEMPLATE.length + 1)).to.be.true; + }); + + it('should return false if there are enough bytes in the receive queue', function () { + expect(sock.rQwait('hi', RQ_TEMPLATE.length)).to.be.false; + }); + + it('should return true and reduce rQi by "goback" if there are not enough bytes', function () { + sock.rQi = 5; + expect(sock.rQwait('hi', RQ_TEMPLATE.length, 4)).to.be.true; + expect(sock.rQi).to.equal(1); + }); + + it('should raise an error if we try to go back more than possible', function () { + sock.rQi = 5; + expect(() => sock.rQwait('hi', RQ_TEMPLATE.length, 6)).to.throw(Error); + }); + + it('should not reduce rQi if there are enough bytes', function () { + sock.rQi = 5; + sock.rQwait('hi', 1, 6); + expect(sock.rQi).to.equal(5); + }); + }); + + describe('flush', function () { + beforeEach(function () { + sock._websocket = { + send: sinon.spy() + }; + }); + + it('should actually send on the websocket', function () { + sock._websocket.bufferedAmount = 8; + sock._websocket.readyState = WebSocket.OPEN; + sock._sQ = new Uint8Array([1, 2, 3]); + sock._sQlen = 3; + const encoded = sock._encodeMessage(); + + sock.flush(); + expect(sock._websocket.send).to.have.been.calledOnce; + expect(sock._websocket.send).to.have.been.calledWith(encoded); + }); + + it('should not call send if we do not have anything queued up', function () { + sock._sQlen = 0; + sock._websocket.bufferedAmount = 8; + + sock.flush(); + + expect(sock._websocket.send).not.to.have.been.called; + }); + }); + + describe('send', function () { + beforeEach(function () { + sock.flush = sinon.spy(); + }); + + it('should add to the send queue', function () { + sock.send([1, 2, 3]); + const sq = sock.sQ; + expect(new Uint8Array(sq.buffer, sock._sQlen - 3, 3)).to.array.equal(new Uint8Array([1, 2, 3])); + }); + + it('should call flush', function () { + sock.send([1, 2, 3]); + expect(sock.flush).to.have.been.calledOnce; + }); + }); + + describe('sendString', function () { + beforeEach(function () { + sock.send = sinon.spy(); + }); + + it('should call send after converting the string to an array', function () { + sock.sendString("\x01\x02\x03"); + expect(sock.send).to.have.been.calledWith([1, 2, 3]); + }); + }); + }); + + describe('lifecycle methods', function () { + let oldWS; + before(function () { + oldWS = WebSocket; + }); + + let sock; + beforeEach(function () { + sock = new Websock(); + // eslint-disable-next-line no-global-assign + WebSocket = sinon.spy(FakeWebSocket); + }); + + describe('opening', function () { + it('should pick the correct protocols if none are given', function () { + + }); + + it('should open the actual websocket', function () { + sock.open('ws://localhost:8675', 'binary'); + expect(WebSocket).to.have.been.calledWith('ws://localhost:8675', 'binary'); + }); + + // it('should initialize the event handlers')? + }); + + describe('attaching', function () { + it('should attach to an existing websocket', function () { + let ws = new FakeWebSocket('ws://localhost:8675'); + sock.attach(ws); + expect(WebSocket).to.not.have.been.called; + }); + }); + + describe('closing', function () { + beforeEach(function () { + sock.open('ws://localhost'); + sock._websocket.close = sinon.spy(); + }); + + it('should close the actual websocket if it is open', function () { + sock._websocket.readyState = WebSocket.OPEN; + sock.close(); + expect(sock._websocket.close).to.have.been.calledOnce; + }); + + it('should close the actual websocket if it is connecting', function () { + sock._websocket.readyState = WebSocket.CONNECTING; + sock.close(); + expect(sock._websocket.close).to.have.been.calledOnce; + }); + + it('should not try to close the actual websocket if closing', function () { + sock._websocket.readyState = WebSocket.CLOSING; + sock.close(); + expect(sock._websocket.close).not.to.have.been.called; + }); + + it('should not try to close the actual websocket if closed', function () { + sock._websocket.readyState = WebSocket.CLOSED; + sock.close(); + expect(sock._websocket.close).not.to.have.been.called; + }); + + it('should reset onmessage to not call _recvMessage', function () { + sinon.spy(sock, '_recvMessage'); + sock.close(); + sock._websocket.onmessage(null); + try { + expect(sock._recvMessage).not.to.have.been.called; + } finally { + sock._recvMessage.restore(); + } + }); + }); + + describe('event handlers', function () { + beforeEach(function () { + sock._recvMessage = sinon.spy(); + sock.on('open', sinon.spy()); + sock.on('close', sinon.spy()); + sock.on('error', sinon.spy()); + sock.open('ws://localhost'); + }); + + it('should call _recvMessage on a message', function () { + sock._websocket.onmessage(null); + expect(sock._recvMessage).to.have.been.calledOnce; + }); + + it('should call the open event handler on opening', function () { + sock._websocket.onopen(); + expect(sock._eventHandlers.open).to.have.been.calledOnce; + }); + + it('should call the close event handler on closing', function () { + sock._websocket.onclose(); + expect(sock._eventHandlers.close).to.have.been.calledOnce; + }); + + it('should call the error event handler on error', function () { + sock._websocket.onerror(); + expect(sock._eventHandlers.error).to.have.been.calledOnce; + }); + }); + + describe('ready state', function () { + it('should be "unused" after construction', function () { + let sock = new Websock(); + expect(sock.readyState).to.equal('unused'); + }); + + it('should be "connecting" if WebSocket is connecting', function () { + let sock = new Websock(); + let ws = new FakeWebSocket(); + ws.readyState = WebSocket.CONNECTING; + sock.attach(ws); + expect(sock.readyState).to.equal('connecting'); + }); + + it('should be "open" if WebSocket is open', function () { + let sock = new Websock(); + let ws = new FakeWebSocket(); + ws.readyState = WebSocket.OPEN; + sock.attach(ws); + expect(sock.readyState).to.equal('open'); + }); + + it('should be "closing" if WebSocket is closing', function () { + let sock = new Websock(); + let ws = new FakeWebSocket(); + ws.readyState = WebSocket.CLOSING; + sock.attach(ws); + expect(sock.readyState).to.equal('closing'); + }); + + it('should be "closed" if WebSocket is closed', function () { + let sock = new Websock(); + let ws = new FakeWebSocket(); + ws.readyState = WebSocket.CLOSED; + sock.attach(ws); + expect(sock.readyState).to.equal('closed'); + }); + + it('should be "unknown" if WebSocket state is unknown', function () { + let sock = new Websock(); + let ws = new FakeWebSocket(); + ws.readyState = 666; + sock.attach(ws); + expect(sock.readyState).to.equal('unknown'); + }); + + it('should be "connecting" if RTCDataChannel is connecting', function () { + let sock = new Websock(); + let ws = new FakeWebSocket(); + ws.readyState = 'connecting'; + sock.attach(ws); + expect(sock.readyState).to.equal('connecting'); + }); + + it('should be "open" if RTCDataChannel is open', function () { + let sock = new Websock(); + let ws = new FakeWebSocket(); + ws.readyState = 'open'; + sock.attach(ws); + expect(sock.readyState).to.equal('open'); + }); + + it('should be "closing" if RTCDataChannel is closing', function () { + let sock = new Websock(); + let ws = new FakeWebSocket(); + ws.readyState = 'closing'; + sock.attach(ws); + expect(sock.readyState).to.equal('closing'); + }); + + it('should be "closed" if RTCDataChannel is closed', function () { + let sock = new Websock(); + let ws = new FakeWebSocket(); + ws.readyState = 'closed'; + sock.attach(ws); + expect(sock.readyState).to.equal('closed'); + }); + + it('should be "unknown" if RTCDataChannel state is unknown', function () { + let sock = new Websock(); + let ws = new FakeWebSocket(); + ws.readyState = 'foobar'; + sock.attach(ws); + expect(sock.readyState).to.equal('unknown'); + }); + }); + + after(function () { + // eslint-disable-next-line no-global-assign + WebSocket = oldWS; + }); + }); + + describe('WebSocket Receiving', function () { + let sock; + beforeEach(function () { + sock = new Websock(); + sock._allocateBuffers(); + }); + + it('should support adding binary Uint8Array data to the receive queue', function () { + const msg = { data: new Uint8Array([1, 2, 3]) }; + sock._mode = 'binary'; + sock._recvMessage(msg); + expect(sock.rQshiftStr(3)).to.equal('\x01\x02\x03'); + }); + + it('should call the message event handler if present', function () { + sock._eventHandlers.message = sinon.spy(); + const msg = { data: new Uint8Array([1, 2, 3]).buffer }; + sock._mode = 'binary'; + sock._recvMessage(msg); + expect(sock._eventHandlers.message).to.have.been.calledOnce; + }); + + it('should not call the message event handler if there is nothing in the receive queue', function () { + sock._eventHandlers.message = sinon.spy(); + const msg = { data: new Uint8Array([]).buffer }; + sock._mode = 'binary'; + sock._recvMessage(msg); + expect(sock._eventHandlers.message).not.to.have.been.called; + }); + + it('should compact the receive queue when a message handler empties it', function () { + sock._eventHandlers.message = () => { sock.rQi = sock._rQlen; }; + sock._rQ = new Uint8Array([0, 1, 2, 3, 4, 5, 0, 0, 0, 0]); + sock._rQlen = 6; + sock.rQi = 6; + const msg = { data: new Uint8Array([1, 2, 3]).buffer }; + sock._mode = 'binary'; + sock._recvMessage(msg); + expect(sock._rQlen).to.equal(0); + expect(sock.rQi).to.equal(0); + }); + + it('should compact the receive queue when we reach the end of the buffer', function () { + sock._rQ = new Uint8Array(20); + sock._rQbufferSize = 20; + sock._rQlen = 20; + sock.rQi = 10; + const msg = { data: new Uint8Array([1, 2]).buffer }; + sock._mode = 'binary'; + sock._recvMessage(msg); + expect(sock._rQlen).to.equal(12); + expect(sock.rQi).to.equal(0); + }); + + it('should automatically resize the receive queue if the incoming message is larger than the buffer', function () { + sock._rQ = new Uint8Array(20); + sock._rQlen = 0; + sock.rQi = 0; + sock._rQbufferSize = 20; + const msg = { data: new Uint8Array(30).buffer }; + sock._mode = 'binary'; + sock._recvMessage(msg); + expect(sock._rQlen).to.equal(30); + expect(sock.rQi).to.equal(0); + expect(sock._rQ.length).to.equal(240); // keep the invariant that rQbufferSize / 8 >= rQlen + }); + + it('should automatically resize the receive queue if the incoming message is larger than 1/8th of the buffer and we reach the end of the buffer', function () { + sock._rQ = new Uint8Array(20); + sock._rQlen = 16; + sock.rQi = 16; + sock._rQbufferSize = 20; + const msg = { data: new Uint8Array(6).buffer }; + sock._mode = 'binary'; + sock._recvMessage(msg); + expect(sock._rQlen).to.equal(6); + expect(sock.rQi).to.equal(0); + expect(sock._rQ.length).to.equal(48); + }); + }); + + describe('Data encoding', function () { + before(function () { FakeWebSocket.replace(); }); + after(function () { FakeWebSocket.restore(); }); + + describe('as binary data', function () { + let sock; + beforeEach(function () { + sock = new Websock(); + sock.open('ws://', 'binary'); + sock._websocket._open(); + }); + + it('should only send the send queue up to the send queue length', function () { + sock._sQ = new Uint8Array([1, 2, 3, 4, 5]); + sock._sQlen = 3; + const res = sock._encodeMessage(); + expect(res).to.array.equal(new Uint8Array([1, 2, 3])); + }); + + it('should properly pass the encoded data off to the actual WebSocket', function () { + sock.send([1, 2, 3]); + expect(sock._websocket._getSentData()).to.array.equal(new Uint8Array([1, 2, 3])); + }); + }); + }); +}); diff --git a/tests/test.webutil.js b/tests/test.webutil.js new file mode 100644 index 0000000..6681b3c --- /dev/null +++ b/tests/test.webutil.js @@ -0,0 +1,223 @@ +/* jshint expr: true */ + +const expect = chai.expect; + +import * as WebUtil from '../app/webutil.js'; + +describe('WebUtil', function () { + "use strict"; + + describe('config variables', function () { + it('should parse query string variables', function () { + // history.pushState() will not cause the browser to attempt loading + // the URL, this is exactly what we want here for the tests. + history.pushState({}, '', "test?myvar=myval"); + expect(WebUtil.getConfigVar("myvar")).to.be.equal("myval"); + }); + it('should return default value when no query match', function () { + history.pushState({}, '', "test?myvar=myval"); + expect(WebUtil.getConfigVar("other", "def")).to.be.equal("def"); + }); + it('should handle no query match and no default value', function () { + history.pushState({}, '', "test?myvar=myval"); + expect(WebUtil.getConfigVar("other")).to.be.equal(null); + }); + it('should parse fragment variables', function () { + history.pushState({}, '', "test#myvar=myval"); + expect(WebUtil.getConfigVar("myvar")).to.be.equal("myval"); + }); + it('should return default value when no fragment match', function () { + history.pushState({}, '', "test#myvar=myval"); + expect(WebUtil.getConfigVar("other", "def")).to.be.equal("def"); + }); + it('should handle no fragment match and no default value', function () { + history.pushState({}, '', "test#myvar=myval"); + expect(WebUtil.getConfigVar("other")).to.be.equal(null); + }); + it('should handle both query and fragment', function () { + history.pushState({}, '', "test?myquery=1#myhash=2"); + expect(WebUtil.getConfigVar("myquery")).to.be.equal("1"); + expect(WebUtil.getConfigVar("myhash")).to.be.equal("2"); + }); + it('should prioritize fragment if both provide same var', function () { + history.pushState({}, '', "test?myvar=1#myvar=2"); + expect(WebUtil.getConfigVar("myvar")).to.be.equal("2"); + }); + }); + + describe('cookies', function () { + // TODO + }); + + describe('settings', function () { + + describe('localStorage', function () { + let chrome = window.chrome; + before(function () { + chrome = window.chrome; + window.chrome = null; + }); + after(function () { + window.chrome = chrome; + }); + + let origLocalStorage; + beforeEach(function () { + origLocalStorage = Object.getOwnPropertyDescriptor(window, "localStorage"); + + Object.defineProperty(window, "localStorage", {value: {}}); + if (window.localStorage.setItem !== undefined) { + // Object.defineProperty() doesn't work properly in old + // versions of Chrome + this.skip(); + } + + window.localStorage.setItem = sinon.stub(); + window.localStorage.getItem = sinon.stub(); + window.localStorage.removeItem = sinon.stub(); + + return WebUtil.initSettings(); + }); + afterEach(function () { + if (origLocalStorage !== undefined) { + Object.defineProperty(window, "localStorage", origLocalStorage); + } + }); + + describe('writeSetting', function () { + it('should save the setting value to local storage', function () { + WebUtil.writeSetting('test', 'value'); + expect(window.localStorage.setItem).to.have.been.calledWithExactly('test', 'value'); + expect(WebUtil.readSetting('test')).to.equal('value'); + }); + }); + + describe('setSetting', function () { + it('should update the setting but not save to local storage', function () { + WebUtil.setSetting('test', 'value'); + expect(window.localStorage.setItem).to.not.have.been.called; + expect(WebUtil.readSetting('test')).to.equal('value'); + }); + }); + + describe('readSetting', function () { + it('should read the setting value from local storage', function () { + localStorage.getItem.returns('value'); + expect(WebUtil.readSetting('test')).to.equal('value'); + }); + + it('should return the default value when not in local storage', function () { + expect(WebUtil.readSetting('test', 'default')).to.equal('default'); + }); + + it('should return the cached value even if local storage changed', function () { + localStorage.getItem.returns('value'); + expect(WebUtil.readSetting('test')).to.equal('value'); + localStorage.getItem.returns('something else'); + expect(WebUtil.readSetting('test')).to.equal('value'); + }); + + it('should cache the value even if it is not initially in local storage', function () { + expect(WebUtil.readSetting('test')).to.be.null; + localStorage.getItem.returns('value'); + expect(WebUtil.readSetting('test')).to.be.null; + }); + + it('should return the default value always if the first read was not in local storage', function () { + expect(WebUtil.readSetting('test', 'default')).to.equal('default'); + localStorage.getItem.returns('value'); + expect(WebUtil.readSetting('test', 'another default')).to.equal('another default'); + }); + + it('should return the last local written value', function () { + localStorage.getItem.returns('value'); + expect(WebUtil.readSetting('test')).to.equal('value'); + WebUtil.writeSetting('test', 'something else'); + expect(WebUtil.readSetting('test')).to.equal('something else'); + }); + }); + + // this doesn't appear to be used anywhere + describe('eraseSetting', function () { + it('should remove the setting from local storage', function () { + WebUtil.eraseSetting('test'); + expect(window.localStorage.removeItem).to.have.been.calledWithExactly('test'); + }); + }); + }); + + describe('chrome.storage', function () { + let chrome = window.chrome; + let settings = {}; + before(function () { + chrome = window.chrome; + window.chrome = { + storage: { + sync: { + get(cb) { cb(settings); }, + set() {}, + remove() {} + } + } + }; + }); + after(function () { + window.chrome = chrome; + }); + + const csSandbox = sinon.createSandbox(); + + beforeEach(function () { + settings = {}; + csSandbox.spy(window.chrome.storage.sync, 'set'); + csSandbox.spy(window.chrome.storage.sync, 'remove'); + return WebUtil.initSettings(); + }); + afterEach(function () { + csSandbox.restore(); + }); + + describe('writeSetting', function () { + it('should save the setting value to chrome storage', function () { + WebUtil.writeSetting('test', 'value'); + expect(window.chrome.storage.sync.set).to.have.been.calledWithExactly(sinon.match({ test: 'value' })); + expect(WebUtil.readSetting('test')).to.equal('value'); + }); + }); + + describe('setSetting', function () { + it('should update the setting but not save to chrome storage', function () { + WebUtil.setSetting('test', 'value'); + expect(window.chrome.storage.sync.set).to.not.have.been.called; + expect(WebUtil.readSetting('test')).to.equal('value'); + }); + }); + + describe('readSetting', function () { + it('should read the setting value from chrome storage', function () { + settings.test = 'value'; + expect(WebUtil.readSetting('test')).to.equal('value'); + }); + + it('should return the default value when not in chrome storage', function () { + expect(WebUtil.readSetting('test', 'default')).to.equal('default'); + }); + + it('should return the last local written value', function () { + settings.test = 'value'; + expect(WebUtil.readSetting('test')).to.equal('value'); + WebUtil.writeSetting('test', 'something else'); + expect(WebUtil.readSetting('test')).to.equal('something else'); + }); + }); + + // this doesn't appear to be used anywhere + describe('eraseSetting', function () { + it('should remove the setting from chrome storage', function () { + WebUtil.eraseSetting('test'); + expect(window.chrome.storage.sync.remove).to.have.been.calledWithExactly('test'); + }); + }); + }); + }); +}); diff --git a/tests/test.zrle.js b/tests/test.zrle.js new file mode 100644 index 0000000..e09d208 --- /dev/null +++ b/tests/test.zrle.js @@ -0,0 +1,124 @@ +const expect = chai.expect; + +import Websock from '../core/websock.js'; +import Display from '../core/display.js'; + +import ZRLEDecoder from '../core/decoders/zrle.js'; + +import FakeWebSocket from './fake.websocket.js'; + +function testDecodeRect(decoder, x, y, width, height, data, display, depth) { + let sock; + + sock = new Websock; + sock.open("ws://example.com"); + + sock.on('message', () => { + decoder.decodeRect(x, y, width, height, sock, display, depth); + }); + + // Empty messages are filtered at multiple layers, so we need to + // do a direct call + if (data.length === 0) { + decoder.decodeRect(x, y, width, height, sock, display, depth); + } else { + sock._websocket._receiveData(new Uint8Array(data)); + } + + display.flip(); +} + +describe('ZRLE Decoder', function () { + let decoder; + let display; + + before(FakeWebSocket.replace); + after(FakeWebSocket.restore); + + beforeEach(function () { + decoder = new ZRLEDecoder(); + display = new Display(document.createElement('canvas')); + display.resize(4, 4); + }); + + it('should handle the Raw subencoding', function () { + testDecodeRect(decoder, 0, 0, 4, 4, + [0x00, 0x00, 0x00, 0x0e, 0x78, 0x5e, 0x62, 0x60, 0x60, 0xf8, 0x4f, 0x12, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff], + display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle the Solid subencoding', function () { + testDecodeRect(decoder, 0, 0, 4, 4, + [0x00, 0x00, 0x00, 0x0c, 0x78, 0x5e, 0x62, 0x64, 0x60, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0xff, 0xff], + display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff + ]); + + expect(display).to.have.displayed(targetData); + }); + + + it('should handle the Palette Tile subencoding', function () { + testDecodeRect(decoder, 0, 0, 4, 4, + [0x00, 0x00, 0x00, 0x12, 0x78, 0x5E, 0x62, 0x62, 0x60, 248, 0xff, 0x9F, 0x01, 0x08, 0x3E, 0x7C, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff], + display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, + 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle the RLE Tile subencoding', function () { + testDecodeRect(decoder, 0, 0, 4, 4, + [0x00, 0x00, 0x00, 0x0d, 0x78, 0x5e, 0x6a, 0x60, 0x60, 0xf8, 0x2f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff], + display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should handle the RLE Palette Tile subencoding', function () { + testDecodeRect(decoder, 0, 0, 4, 4, + [0x00, 0x00, 0x00, 0x11, 0x78, 0x5e, 0x6a, 0x62, 0x60, 0xf8, 0xff, 0x9f, 0x81, 0xa1, 0x81, 0x1f, 0x00, 0x00, 0x00, 0xff, 0xff], + display, 24); + + let targetData = new Uint8Array([ + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff + ]); + + expect(display).to.have.displayed(targetData); + }); + + it('should fail on an invalid subencoding', function () { + let data = [0x00, 0x00, 0x00, 0x0c, 0x78, 0x5e, 0x6a, 0x64, 0x60, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0xff, 0xff]; + expect(() => testDecodeRect(decoder, 0, 0, 4, 4, data, display, 24)).to.throw(); + }); +}); diff --git a/tests/vnc_playback.html b/tests/vnc_playback.html new file mode 100644 index 0000000..148e292 --- /dev/null +++ b/tests/vnc_playback.html @@ -0,0 +1,36 @@ + + + + VNC Playback + + + + + Iterations:   + Perftest:  + Realtime:   + +   + +

+ + Results:
+ + +

+ + +
+ + +
+ +
+
Loading
+
+ + diff --git a/utils/.eslintrc b/utils/.eslintrc new file mode 100644 index 0000000..b7dc129 --- /dev/null +++ b/utils/.eslintrc @@ -0,0 +1,8 @@ +{ + "env": { + "node": true + }, + "rules": { + "no-console": 0 + } +} \ No newline at end of file diff --git a/utils/README.md b/utils/README.md new file mode 100644 index 0000000..32582e6 --- /dev/null +++ b/utils/README.md @@ -0,0 +1,14 @@ +## WebSockets Proxy/Bridge + +Websockify has been forked out into its own project. `launch.sh` wil +automatically download it here if it is not already present and not +installed as system-wide. + +For more detailed description and usage information please refer to +the [websockify README](https://github.com/novnc/websockify/blob/master/README.md). + +The other versions of websockify (C, Node.js) and the associated test +programs have been moved to +[websockify](https://github.com/novnc/websockify). Websockify was +formerly named wsproxy. + diff --git a/utils/b64-to-binary.pl b/utils/b64-to-binary.pl new file mode 100755 index 0000000..280e28c --- /dev/null +++ b/utils/b64-to-binary.pl @@ -0,0 +1,17 @@ +#!/usr/bin/env perl +use MIME::Base64; + +for (<>) { + unless (/^'([{}])(\d+)\1(.+?)',$/) { + print; + next; + } + + my ($dir, $amt, $b64) = ($1, $2, $3); + + my $decoded = MIME::Base64::decode($b64) or die "Could not base64-decode line `$_`"; + + my $decoded_escaped = join "", map { "\\x$_" } unpack("(H2)*", $decoded); + + print "'${dir}${amt}${dir}${decoded_escaped}',\n"; +} diff --git a/utils/genkeysymdef.js b/utils/genkeysymdef.js new file mode 100755 index 0000000..f539a0b --- /dev/null +++ b/utils/genkeysymdef.js @@ -0,0 +1,127 @@ +#!/usr/bin/env node +/* + * genkeysymdef: X11 keysymdef.h to JavaScript converter + * Copyright (C) 2018 The noVNC Authors + * Licensed under MPL 2.0 (see LICENSE.txt) + */ + +"use strict"; + +const fs = require('fs'); + +let showHelp = process.argv.length === 2; +let filename; + +for (let i = 2; i < process.argv.length; ++i) { + switch (process.argv[i]) { + case "--help": + case "-h": + showHelp = true; + break; + case "--file": + case "-f": + default: + filename = process.argv[i]; + } +} + +if (!filename) { + showHelp = true; + console.log("Error: No filename specified\n"); +} + +if (showHelp) { + console.log("Parses a *nix keysymdef.h to generate Unicode code point mappings"); + console.log("Usage: node parse.js [options] filename:"); + console.log(" -h [ --help ] Produce this help message"); + console.log(" filename The keysymdef.h file to parse"); + process.exit(0); +} + +const buf = fs.readFileSync(filename); +const str = buf.toString('utf8'); + +const re = /^#define XK_([a-zA-Z_0-9]+)\s+0x([0-9a-fA-F]+)\s*(\/\*\s*(.*)\s*\*\/)?\s*$/m; + +const arr = str.split('\n'); + +const codepoints = {}; + +for (let i = 0; i < arr.length; ++i) { + const result = re.exec(arr[i]); + if (result) { + const keyname = result[1]; + const keysym = parseInt(result[2], 16); + const remainder = result[3]; + + const unicodeRes = /U\+([0-9a-fA-F]+)/.exec(remainder); + if (unicodeRes) { + const unicode = parseInt(unicodeRes[1], 16); + // The first entry is the preferred one + if (!codepoints[unicode]) { + codepoints[unicode] = { keysym: keysym, name: keyname }; + } + } + } +} + +let out = +"/*\n" + +" * Mapping from Unicode codepoints to X11/RFB keysyms\n" + +" *\n" + +" * This file was automatically generated from keysymdef.h\n" + +" * DO NOT EDIT!\n" + +" */\n" + +"\n" + +"/* Functions at the bottom */\n" + +"\n" + +"const codepoints = {\n"; + +function toHex(num) { + let s = num.toString(16); + if (s.length < 4) { + s = ("0000" + s).slice(-4); + } + return "0x" + s; +} + +for (let codepoint in codepoints) { + codepoint = parseInt(codepoint); + + // Latin-1? + if ((codepoint >= 0x20) && (codepoint <= 0xff)) { + continue; + } + + // Handled by the general Unicode mapping? + if ((codepoint | 0x01000000) === codepoints[codepoint].keysym) { + continue; + } + + out += " " + toHex(codepoint) + ": " + + toHex(codepoints[codepoint].keysym) + + ", // XK_" + codepoints[codepoint].name + "\n"; +} + +out += +"};\n" + +"\n" + +"export default {\n" + +" lookup(u) {\n" + +" // Latin-1 is one-to-one mapping\n" + +" if ((u >= 0x20) && (u <= 0xff)) {\n" + +" return u;\n" + +" }\n" + +"\n" + +" // Lookup table (fairly random)\n" + +" const keysym = codepoints[u];\n" + +" if (keysym !== undefined) {\n" + +" return keysym;\n" + +" }\n" + +"\n" + +" // General mapping as final fallback\n" + +" return 0x01000000 | u;\n" + +" },\n" + +"};"; + +console.log(out); diff --git a/utils/launch.sh b/utils/launch.sh new file mode 100755 index 0000000..0900f7e --- /dev/null +++ b/utils/launch.sh @@ -0,0 +1,198 @@ +#!/usr/bin/env bash + +# Copyright (C) 2018 The noVNC Authors +# Licensed under MPL 2.0 or any later version (see LICENSE.txt) + +usage() { + if [ "$*" ]; then + echo "$*" + echo + fi + echo "Usage: ${NAME} [--listen PORT] [--vnc VNC_HOST:PORT] [--cert CERT] [--ssl-only]" + echo + echo "Starts the WebSockets proxy and a mini-webserver and " + echo "provides a cut-and-paste URL to go to." + echo + echo " --listen PORT Port for proxy/webserver to listen on" + echo " Default: 6080" + echo " --vnc VNC_HOST:PORT VNC server host:port proxy target" + echo " Default: localhost:5900" + echo " --cert CERT Path to combined cert/key file, or just" + echo " the cert file if used with --key" + echo " Default: self.pem" + echo " --key KEY Path to key file, when not combined with cert" + echo " --web WEB Path to web files (e.g. vnc.html)" + echo " Default: ./" + echo " --ssl-only Disable non-https connections." + echo " " + echo " --record FILE Record traffic to FILE.session.js" + echo " " + echo " --syslog SERVER Can be local socket such as /dev/log, or a UDP host:port pair." + echo " " + echo " --heartbeat SEC send a ping to the client every SEC seconds" + echo " --timeout SEC after SEC seconds exit when not connected" + echo " --idle-timeout SEC server exits after SEC seconds if there are no" + echo " active connections" + echo " " + exit 2 +} + +NAME="$(basename $0)" +REAL_NAME="$(readlink -f $0)" +HERE="$(cd "$(dirname "$REAL_NAME")" && pwd)" +PORT="6080" +VNC_DEST="localhost:5900" +CERT="" +KEY="" +WEB="" +proxy_pid="" +SSLONLY="" +RECORD_ARG="" +SYSLOG_ARG="" +HEARTBEAT_ARG="" +IDLETIMEOUT_ARG="" +TIMEOUT_ARG="" + +die() { + echo "$*" + exit 1 +} + +cleanup() { + trap - TERM QUIT INT EXIT + trap "true" CHLD # Ignore cleanup messages + echo + if [ -n "${proxy_pid}" ]; then + echo "Terminating WebSockets proxy (${proxy_pid})" + kill ${proxy_pid} + fi +} + +# Process Arguments + +# Arguments that only apply to chrooter itself +while [ "$*" ]; do + param=$1; shift; OPTARG=$1 + case $param in + --listen) PORT="${OPTARG}"; shift ;; + --vnc) VNC_DEST="${OPTARG}"; shift ;; + --cert) CERT="${OPTARG}"; shift ;; + --key) KEY="${OPTARG}"; shift ;; + --web) WEB="${OPTARG}"; shift ;; + --ssl-only) SSLONLY="--ssl-only" ;; + --record) RECORD_ARG="--record ${OPTARG}"; shift ;; + --syslog) SYSLOG_ARG="--syslog ${OPTARG}"; shift ;; + --heartbeat) HEARTBEAT_ARG="--heartbeat ${OPTARG}"; shift ;; + --idle-timeout) IDLETIMEOUT_ARG="--idle-timeout ${OPTARG}"; shift ;; + --timeout) TIMEOUT_ARG="--timeout ${OPTARG}"; shift ;; + -h|--help) usage ;; + -*) usage "Unknown chrooter option: ${param}" ;; + *) break ;; + esac +done + +# Sanity checks +if bash -c "exec 7<>/dev/tcp/localhost/${PORT}" &> /dev/null; then + exec 7<&- + exec 7>&- + die "Port ${PORT} in use. Try --listen PORT" +else + exec 7<&- + exec 7>&- +fi + +trap "cleanup" TERM QUIT INT EXIT + +# Find vnc.html +if [ -n "${WEB}" ]; then + if [ ! -e "${WEB}/vnc.html" ]; then + die "Could not find ${WEB}/vnc.html" + fi +elif [ -e "$(pwd)/vnc.html" ]; then + WEB=$(pwd) +elif [ -e "${HERE}/../vnc.html" ]; then + WEB=${HERE}/../ +elif [ -e "${HERE}/vnc.html" ]; then + WEB=${HERE} +elif [ -e "${HERE}/../share/novnc/vnc.html" ]; then + WEB=${HERE}/../share/novnc/ +else + die "Could not find vnc.html" +fi + +# Find self.pem +if [ -n "${CERT}" ]; then + if [ ! -e "${CERT}" ]; then + die "Could not find ${CERT}" + fi +elif [ -e "$(pwd)/self.pem" ]; then + CERT="$(pwd)/self.pem" +elif [ -e "${HERE}/../self.pem" ]; then + CERT="${HERE}/../self.pem" +elif [ -e "${HERE}/self.pem" ]; then + CERT="${HERE}/self.pem" +else + echo "Warning: could not find self.pem" +fi + +# Check key file +if [ -n "${KEY}" ]; then + if [ ! -e "${KEY}" ]; then + die "Could not find ${KEY}" + fi +fi + +# try to find websockify (prefer local, try global, then download local) +if [[ -d ${HERE}/websockify ]]; then + WEBSOCKIFY=${HERE}/websockify/run + + if [[ ! -x $WEBSOCKIFY ]]; then + echo "The path ${HERE}/websockify exists, but $WEBSOCKIFY either does not exist or is not executable." + echo "If you intended to use an installed websockify package, please remove ${HERE}/websockify." + exit 1 + fi + + echo "Using local websockify at $WEBSOCKIFY" +else + WEBSOCKIFY_FROMSYSTEM=$(which websockify 2>/dev/null) + WEBSOCKIFY_FROMSNAP=${HERE}/../usr/bin/python2-websockify + [ -f $WEBSOCKIFY_FROMSYSTEM ] && WEBSOCKIFY=$WEBSOCKIFY_FROMSYSTEM + [ -f $WEBSOCKIFY_FROMSNAP ] && WEBSOCKIFY=$WEBSOCKIFY_FROMSNAP + + if [ ! -f "$WEBSOCKIFY" ]; then + echo "No installed websockify, attempting to clone websockify..." + WEBSOCKIFY=${HERE}/websockify/run + git clone https://github.com/novnc/websockify ${HERE}/websockify + + if [[ ! -e $WEBSOCKIFY ]]; then + echo "Unable to locate ${HERE}/websockify/run after downloading" + exit 1 + fi + + echo "Using local websockify at $WEBSOCKIFY" + else + echo "Using installed websockify at $WEBSOCKIFY" + fi +fi + +echo "Starting webserver and WebSockets proxy on port ${PORT}" +#${HERE}/websockify --web ${WEB} ${CERT:+--cert ${CERT}} ${PORT} ${VNC_DEST} & +${WEBSOCKIFY} ${SYSLOG_ARG} ${SSLONLY} --web ${WEB} ${CERT:+--cert ${CERT}} ${KEY:+--key ${KEY}} ${PORT} ${VNC_DEST} ${HEARTBEAT_ARG} ${IDLETIMEOUT_ARG} ${RECORD_ARG} ${TIMEOUT_ARG} & +proxy_pid="$!" +sleep 1 +if ! ps -p ${proxy_pid} >/dev/null; then + proxy_pid= + echo "Failed to start WebSockets proxy" + exit 1 +fi + +echo -e "\n\nNavigate to this URL:\n" +if [ "x$SSLONLY" == "x" ]; then + echo -e " http://$(hostname):${PORT}/vnc.html?host=$(hostname)&port=${PORT}\n" +else + echo -e " https://$(hostname):${PORT}/vnc.html?host=$(hostname)&port=${PORT}\n" +fi + +echo -e "Press Ctrl-C to exit\n\n" + +wait ${proxy_pid} diff --git a/utils/u2x11 b/utils/u2x11 new file mode 100755 index 0000000..fd3e4ba --- /dev/null +++ b/utils/u2x11 @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# +# Convert "U+..." commented entries in /usr/include/X11/keysymdef.h +# into JavaScript for use by noVNC. Note this is likely to produce +# a few duplicate properties with clashing values, that will need +# resolving manually. +# +# Colin Dean +# + +regex="^#define[ \t]+XK_[A-Za-z0-9_]+[ \t]+0x([0-9a-fA-F]+)[ \t]+\/\*[ \t]+U\+([0-9a-fA-F]+)[ \t]+[^*]+.[ \t]+\*\/[ \t]*$" +echo "unicodeTable = {" +while read line; do + if echo "${line}" | egrep -qs "${regex}"; then + + x11=$(echo "${line}" | sed -r "s/${regex}/\1/") + vnc=$(echo "${line}" | sed -r "s/${regex}/\2/") + + if echo "${vnc}" | egrep -qs "^00[2-9A-F][0-9A-F]$"; then + : # skip ISO Latin-1 (U+0020 to U+00FF) as 1-to-1 mapping + else + # note 1-to-1 is possible (e.g. for Euro symbol, U+20AC) + echo " 0x${vnc} : 0x${x11}," + fi + fi +done < /usr/include/X11/keysymdef.h | uniq +echo "};" + diff --git a/utils/use_require.js b/utils/use_require.js new file mode 100755 index 0000000..5dd900a --- /dev/null +++ b/utils/use_require.js @@ -0,0 +1,138 @@ +#!/usr/bin/env node + +const path = require('path'); +const program = require('commander'); +const fs = require('fs'); +const fse = require('fs-extra'); +const babel = require('@babel/core'); + +program + .option('-m, --with-source-maps [type]', 'output source maps when not generating a bundled app (type may be empty for external source maps, inline for inline source maps, or both) ') + .option('--clean', 'clear the lib folder before building') + .parse(process.argv); + +// the various important paths +const paths = { + main: path.resolve(__dirname, '..'), + core: path.resolve(__dirname, '..', 'core'), + vendor: path.resolve(__dirname, '..', 'vendor'), + libDirBase: path.resolve(__dirname, '..', 'lib'), +}; + +// util.promisify requires Node.js 8.x, so we have our own +function promisify(original) { + return function promiseWrap() { + const args = Array.prototype.slice.call(arguments); + return new Promise((resolve, reject) => { + original.apply(this, args.concat((err, value) => { + if (err) return reject(err); + resolve(value); + })); + }); + }; +} + +const writeFile = promisify(fs.writeFile); + +const readdir = promisify(fs.readdir); +const lstat = promisify(fs.lstat); + +const ensureDir = promisify(fse.ensureDir); + +const babelTransformFile = promisify(babel.transformFile); + +// walkDir *recursively* walks directories trees, +// calling the callback for all normal files found. +function walkDir(basePath, cb, filter) { + return readdir(basePath) + .then((files) => { + const paths = files.map(filename => path.join(basePath, filename)); + return Promise.all(paths.map(filepath => lstat(filepath) + .then((stats) => { + if (filter !== undefined && !filter(filepath, stats)) return; + + if (stats.isSymbolicLink()) return; + if (stats.isFile()) return cb(filepath); + if (stats.isDirectory()) return walkDir(filepath, cb, filter); + }))); + }); +} + +function makeLibFiles(sourceMaps) { + // NB: we need to make a copy of babelOpts, since babel sets some defaults on it + const babelOpts = () => ({ + plugins: [], + presets: [ + [ '@babel/preset-env', + { modules: 'commonjs' } ] + ], + ast: false, + sourceMaps: sourceMaps, + }); + + fse.ensureDirSync(paths.libDirBase); + + const outFiles = []; + + const handleDir = (vendorRewrite, inPathBase, filename) => Promise.resolve() + .then(() => { + const outPath = path.join(paths.libDirBase, path.relative(inPathBase, filename)); + + if (path.extname(filename) !== '.js') { + return; // skip non-javascript files + } + return Promise.resolve() + .then(() => ensureDir(path.dirname(outPath))) + .then(() => { + const opts = babelOpts(); + // Adjust for the fact that we move the core files relative + // to the vendor directory + if (vendorRewrite) { + opts.plugins.push(["import-redirect", + {"root": paths.libDirBase, + "redirect": { "vendor/(.+)": "./vendor/$1"}}]); + } + + return babelTransformFile(filename, opts) + .then((res) => { + console.log(`Writing ${outPath}`); + const {map} = res; + let {code} = res; + if (sourceMaps === true) { + // append URL for external source map + code += `\n//# sourceMappingURL=${path.basename(outPath)}.map\n`; + } + outFiles.push(`${outPath}`); + return writeFile(outPath, code) + .then(() => { + if (sourceMaps === true || sourceMaps === 'both') { + console.log(` and ${outPath}.map`); + outFiles.push(`${outPath}.map`); + return writeFile(`${outPath}.map`, JSON.stringify(map)); + } + }); + }); + }); + }); + + Promise.resolve() + .then(() => { + const handler = handleDir.bind(null, false, paths.main); + return walkDir(paths.vendor, handler); + }) + .then(() => { + const handler = handleDir.bind(null, true, paths.core); + return walkDir(paths.core, handler); + }) + .catch((err) => { + console.error(`Failure converting modules: ${err}`); + process.exit(1); + }); +} + +if (program.clean) { + console.log(`Removing ${paths.libDirBase}`); + fse.removeSync(paths.libDirBase); +} + +makeLibFiles(program.withSourceMaps); diff --git a/utils/validate b/utils/validate new file mode 100755 index 0000000..a6b5507 --- /dev/null +++ b/utils/validate @@ -0,0 +1,45 @@ +#!/bin/bash + +set -e + +RET=0 + +OUT=`mktemp` + +for fn in "$@"; do + echo "Validating $fn..." + echo + + case $fn in + *.html) + type="text/html" + ;; + *.css) + type="text/css" + ;; + *) + echo "Unknown format!" + echo + RET=1 + continue + ;; + esac + + curl --silent \ + --header "Content-Type: ${type}; charset=utf-8" \ + --data-binary @${fn} \ + https://validator.w3.org/nu/?out=text > $OUT + cat $OUT + echo + + # We don't fail the check for warnings as some warnings are + # not relevant for us, and we don't currently have a way to + # ignore just those + if grep -q -s -E "^Error:" $OUT; then + RET=1 + fi +done + +rm $OUT + +exit $RET diff --git a/vendor/interact.min.js b/vendor/interact.min.js new file mode 100644 index 0000000..442e0e7 --- /dev/null +++ b/vendor/interact.min.js @@ -0,0 +1,3 @@ +/* interact.js 1.10.11 | https://interactjs.io/license */ +!function(t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).interact=t()}((function(){var t={};Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0,t.default=function(t){return!(!t||!t.Window)&&t instanceof t.Window};var e={};Object.defineProperty(e,"__esModule",{value:!0}),e.init=o,e.getWindow=function(e){return(0,t.default)(e)?e:(e.ownerDocument||e).defaultView||r.window},e.window=e.realWindow=void 0;var n=void 0;e.realWindow=n;var r=void 0;function o(t){e.realWindow=n=t;var o=t.document.createTextNode("");o.ownerDocument!==t.document&&"function"==typeof t.wrap&&t.wrap(o)===o&&(t=t.wrap(t)),e.window=r=t}e.window=r,"undefined"!=typeof window&&window&&o(window);var i={};function a(t){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}Object.defineProperty(i,"__esModule",{value:!0}),i.default=void 0;var s=function(t){return!!t&&"object"===a(t)},l=function(t){return"function"==typeof t},u={window:function(n){return n===e.window||(0,t.default)(n)},docFrag:function(t){return s(t)&&11===t.nodeType},object:s,func:l,number:function(t){return"number"==typeof t},bool:function(t){return"boolean"==typeof t},string:function(t){return"string"==typeof t},element:function(t){if(!t||"object"!==a(t))return!1;var n=e.getWindow(t)||e.window;return/object|function/.test(a(n.Element))?t instanceof n.Element:1===t.nodeType&&"string"==typeof t.nodeName},plainObject:function(t){return s(t)&&!!t.constructor&&/function Object\b/.test(t.constructor.toString())},array:function(t){return s(t)&&void 0!==t.length&&l(t.splice)}};i.default=u;var c={};function f(t){var e=t.interaction;if("drag"===e.prepared.name){var n=e.prepared.axis;"x"===n?(e.coords.cur.page.y=e.coords.start.page.y,e.coords.cur.client.y=e.coords.start.client.y,e.coords.velocity.client.y=0,e.coords.velocity.page.y=0):"y"===n&&(e.coords.cur.page.x=e.coords.start.page.x,e.coords.cur.client.x=e.coords.start.client.x,e.coords.velocity.client.x=0,e.coords.velocity.page.x=0)}}function d(t){var e=t.iEvent,n=t.interaction;if("drag"===n.prepared.name){var r=n.prepared.axis;if("x"===r||"y"===r){var o="x"===r?"y":"x";e.page[o]=n.coords.start.page[o],e.client[o]=n.coords.start.client[o],e.delta[o]=0}}}Object.defineProperty(c,"__esModule",{value:!0}),c.default=void 0;var p={id:"actions/drag",install:function(t){var e=t.actions,n=t.Interactable,r=t.defaults;n.prototype.draggable=p.draggable,e.map.drag=p,e.methodDict.drag="draggable",r.actions.drag=p.defaults},listeners:{"interactions:before-action-move":f,"interactions:action-resume":f,"interactions:action-move":d,"auto-start:check":function(t){var e=t.interaction,n=t.interactable,r=t.buttons,o=n.options.drag;if(o&&o.enabled&&(!e.pointerIsDown||!/mouse|pointer/.test(e.pointerType)||0!=(r&n.options.drag.mouseButtons)))return t.action={name:"drag",axis:"start"===o.lockAxis?o.startAxis:o.lockAxis},!1}},draggable:function(t){return i.default.object(t)?(this.options.drag.enabled=!1!==t.enabled,this.setPerAction("drag",t),this.setOnEvents("drag",t),/^(xy|x|y|start)$/.test(t.lockAxis)&&(this.options.drag.lockAxis=t.lockAxis),/^(xy|x|y)$/.test(t.startAxis)&&(this.options.drag.startAxis=t.startAxis),this):i.default.bool(t)?(this.options.drag.enabled=t,this):this.options.drag},beforeMove:f,move:d,defaults:{startAxis:"xy",lockAxis:"xy"},getCursor:function(){return"move"}},v=p;c.default=v;var h={};Object.defineProperty(h,"__esModule",{value:!0}),h.default=void 0;var g={init:function(t){var e=t;g.document=e.document,g.DocumentFragment=e.DocumentFragment||y,g.SVGElement=e.SVGElement||y,g.SVGSVGElement=e.SVGSVGElement||y,g.SVGElementInstance=e.SVGElementInstance||y,g.Element=e.Element||y,g.HTMLElement=e.HTMLElement||g.Element,g.Event=e.Event,g.Touch=e.Touch||y,g.PointerEvent=e.PointerEvent||e.MSPointerEvent},document:null,DocumentFragment:null,SVGElement:null,SVGSVGElement:null,SVGElementInstance:null,Element:null,HTMLElement:null,Event:null,Touch:null,PointerEvent:null};function y(){}var m=g;h.default=m;var b={};Object.defineProperty(b,"__esModule",{value:!0}),b.default=void 0;var x={init:function(t){var e=h.default.Element,n=t.navigator||{};x.supportsTouch="ontouchstart"in t||i.default.func(t.DocumentTouch)&&h.default.document instanceof t.DocumentTouch,x.supportsPointerEvent=!1!==n.pointerEnabled&&!!h.default.PointerEvent,x.isIOS=/iP(hone|od|ad)/.test(n.platform),x.isIOS7=/iP(hone|od|ad)/.test(n.platform)&&/OS 7[^\d]/.test(n.appVersion),x.isIe9=/MSIE 9/.test(n.userAgent),x.isOperaMobile="Opera"===n.appName&&x.supportsTouch&&/Presto/.test(n.userAgent),x.prefixedMatchesSelector="matches"in e.prototype?"matches":"webkitMatchesSelector"in e.prototype?"webkitMatchesSelector":"mozMatchesSelector"in e.prototype?"mozMatchesSelector":"oMatchesSelector"in e.prototype?"oMatchesSelector":"msMatchesSelector",x.pEventTypes=x.supportsPointerEvent?h.default.PointerEvent===t.MSPointerEvent?{up:"MSPointerUp",down:"MSPointerDown",over:"mouseover",out:"mouseout",move:"MSPointerMove",cancel:"MSPointerCancel"}:{up:"pointerup",down:"pointerdown",over:"pointerover",out:"pointerout",move:"pointermove",cancel:"pointercancel"}:null,x.wheelEvent=h.default.document&&"onmousewheel"in h.default.document?"mousewheel":"wheel"},supportsTouch:null,supportsPointerEvent:null,isIOS7:null,isIOS:null,isIe9:null,isOperaMobile:null,prefixedMatchesSelector:null,pEventTypes:null,wheelEvent:null},w=x;b.default=w;var _={};function P(t){var e=t.parentNode;if(i.default.docFrag(e)){for(;(e=e.host)&&i.default.docFrag(e););return e}return e}function O(t,n){return e.window!==e.realWindow&&(n=n.replace(/\/deep\//g," ")),t[b.default.prefixedMatchesSelector](n)}Object.defineProperty(_,"__esModule",{value:!0}),_.nodeContains=function(t,e){if(t.contains)return t.contains(e);for(;e;){if(e===t)return!0;e=e.parentNode}return!1},_.closest=function(t,e){for(;i.default.element(t);){if(O(t,e))return t;t=P(t)}return null},_.parentNode=P,_.matchesSelector=O,_.indexOfDeepestElement=function(t){for(var n,r=[],o=0;o=(parseInt(e.getWindow(g).getComputedStyle(g).zIndex,10)||0)&&(n=o);else n=o}else n=o}var v,g;return n},_.matchesUpTo=function(t,e,n){for(;i.default.element(t);){if(O(t,e))return!0;if((t=P(t))===n)return O(t,e)}return!1},_.getActualElement=function(t){return t.correspondingUseElement||t},_.getScrollXY=T,_.getElementClientRect=M,_.getElementRect=function(t){var n=M(t);if(!b.default.isIOS7&&n){var r=T(e.getWindow(t));n.left+=r.x,n.right+=r.x,n.top+=r.y,n.bottom+=r.y}return n},_.getPath=function(t){for(var e=[];t;)e.push(t),t=P(t);return e},_.trySelector=function(t){return!!i.default.string(t)&&(h.default.document.querySelector(t),!0)};var S=function(t){return t.parentNode||t.host};function E(t,e){for(var n,r=[],o=t;(n=S(o))&&o!==e&&n!==o.ownerDocument;)r.unshift(o),o=n;return r}function T(t){return{x:(t=t||e.window).scrollX||t.document.documentElement.scrollLeft,y:t.scrollY||t.document.documentElement.scrollTop}}function M(t){var e=t instanceof h.default.SVGElement?t.getBoundingClientRect():t.getClientRects()[0];return e&&{left:e.left,right:e.right,top:e.top,bottom:e.bottom,width:e.width||e.right-e.left,height:e.height||e.bottom-e.top}}var j={};Object.defineProperty(j,"__esModule",{value:!0}),j.default=function(t,e){for(var n in e)t[n]=e[n];return t};var k={};function I(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=Array(e);n1?q(e):e[0];U(r,t.page),V(r,t.client),t.timeStamp=n},B.getTouchPair=N,B.pointerAverage=q,B.touchBBox=function(t){if(!t.length)return null;var e=N(t),n=Math.min(e[0].pageX,e[1].pageX),r=Math.min(e[0].pageY,e[1].pageY),o=Math.max(e[0].pageX,e[1].pageX),i=Math.max(e[0].pageY,e[1].pageY);return{x:n,y:r,left:n,top:r,right:o,bottom:i,width:o-n,height:i-r}},B.touchDistance=function(t,e){var n=e+"X",r=e+"Y",o=N(t),i=o[0][n]-o[1][n],a=o[0][r]-o[1][r];return(0,C.default)(i,a)},B.touchAngle=function(t,e){var n=e+"X",r=e+"Y",o=N(t),i=o[1][n]-o[0][n],a=o[1][r]-o[0][r];return 180*Math.atan2(a,i)/Math.PI},B.getPointerType=function(t){return i.default.string(t.pointerType)?t.pointerType:i.default.number(t.pointerType)?[void 0,void 0,"touch","pen","mouse"][t.pointerType]:/touch/.test(t.type||"")||t instanceof h.default.Touch?"touch":"mouse"},B.getEventTargets=function(t){var e=i.default.func(t.composedPath)?t.composedPath():t.path;return[_.getActualElement(e?e[0]:t.target),_.getActualElement(t.currentTarget)]},B.newCoords=function(){return{page:{x:0,y:0},client:{x:0,y:0},timeStamp:0}},B.coordsToEvent=function(t){return{coords:t,get page(){return this.coords.page},get client(){return this.coords.client},get timeStamp(){return this.coords.timeStamp},get pageX(){return this.coords.page.x},get pageY(){return this.coords.page.y},get clientX(){return this.coords.client.x},get clientY(){return this.coords.client.y},get pointerId(){return this.coords.pointerId},get target(){return this.coords.target},get type(){return this.coords.type},get pointerType(){return this.coords.pointerType},get buttons(){return this.coords.buttons},preventDefault:function(){}}},Object.defineProperty(B,"pointerExtend",{enumerable:!0,get:function(){return F.default}});var $={};function G(t,e){for(var n=0;ns.left&&f.xs.top&&f.y=s.left&&h<=s.right&&g>=s.top&&g<=s.bottom}return v&&i.default.number(u)&&(l=Math.max(0,Math.min(s.right,v.right)-Math.max(s.left,v.left))*Math.max(0,Math.min(s.bottom,v.bottom)-Math.max(s.top,v.top))/(v.width*v.height)>=u),t.options.drop.checker&&(l=t.options.drop.checker(e,n,l,t,a,r,o)),l}(this,t,e,n,r,o,a)},n.dynamicDrop=function(e){return i.default.bool(e)?(t.dynamicDrop=e,n):t.dynamicDrop},(0,j.default)(e.phaselessTypes,{dragenter:!0,dragleave:!0,dropactivate:!0,dropdeactivate:!0,dropmove:!0,drop:!0}),e.methodDict.drop="dropzone",t.dynamicDrop=!1,o.actions.drop=gt.defaults},listeners:{"interactions:before-action-start":function(t){var e=t.interaction;"drag"===e.prepared.name&&(e.dropState={cur:{dropzone:null,element:null},prev:{dropzone:null,element:null},rejected:null,events:null,activeDrops:[]})},"interactions:after-action-start":function(t,e){var n=t.interaction,r=(t.event,t.iEvent);if("drag"===n.prepared.name){var o=n.dropState;o.activeDrops=null,o.events=null,o.activeDrops=ft(e,n.element),o.events=pt(n,0,r),o.events.activate&&(ct(o.activeDrops,o.events.activate),e.fire("actions/drop:start",{interaction:n,dragEvent:r}))}},"interactions:action-move":ht,"interactions:after-action-move":function(t,e){var n=t.interaction,r=t.iEvent;"drag"===n.prepared.name&&(vt(n,n.dropState.events),e.fire("actions/drop:move",{interaction:n,dragEvent:r}),n.dropState.events={})},"interactions:action-end":function(t,e){if("drag"===t.interaction.prepared.name){var n=t.interaction,r=t.iEvent;ht(t,e),vt(n,n.dropState.events),e.fire("actions/drop:end",{interaction:n,dragEvent:r})}},"interactions:stop":function(t){var e=t.interaction;if("drag"===e.prepared.name){var n=e.dropState;n&&(n.activeDrops=null,n.events=null,n.cur.dropzone=null,n.cur.element=null,n.prev.dropzone=null,n.prev.element=null,n.rejected=!1)}}},getActiveDrops:ft,getDrop:dt,getDropEvents:pt,fireDropEvents:vt,defaults:{enabled:!1,accept:null,overlap:"pointer"}},yt=gt;ut.default=yt;var mt={};function bt(t){var e=t.interaction,n=t.iEvent,r=t.phase;if("gesture"===e.prepared.name){var o=e.pointers.map((function(t){return t.pointer})),a="start"===r,s="end"===r,l=e.interactable.options.deltaSource;if(n.touches=[o[0],o[1]],a)n.distance=B.touchDistance(o,l),n.box=B.touchBBox(o),n.scale=1,n.ds=0,n.angle=B.touchAngle(o,l),n.da=0,e.gesture.startDistance=n.distance,e.gesture.startAngle=n.angle;else if(s){var u=e.prevEvent;n.distance=u.distance,n.box=u.box,n.scale=u.scale,n.ds=0,n.angle=u.angle,n.da=0}else n.distance=B.touchDistance(o,l),n.box=B.touchBBox(o),n.scale=n.distance/e.gesture.startDistance,n.angle=B.touchAngle(o,l),n.ds=n.scale-e.gesture.scale,n.da=n.angle-e.gesture.angle;e.gesture.distance=n.distance,e.gesture.angle=n.angle,i.default.number(n.scale)&&n.scale!==1/0&&!isNaN(n.scale)&&(e.gesture.scale=n.scale)}}Object.defineProperty(mt,"__esModule",{value:!0}),mt.default=void 0;var xt={id:"actions/gesture",before:["actions/drag","actions/resize"],install:function(t){var e=t.actions,n=t.Interactable,r=t.defaults;n.prototype.gesturable=function(t){return i.default.object(t)?(this.options.gesture.enabled=!1!==t.enabled,this.setPerAction("gesture",t),this.setOnEvents("gesture",t),this):i.default.bool(t)?(this.options.gesture.enabled=t,this):this.options.gesture},e.map.gesture=xt,e.methodDict.gesture="gesturable",r.actions.gesture=xt.defaults},listeners:{"interactions:action-start":bt,"interactions:action-move":bt,"interactions:action-end":bt,"interactions:new":function(t){t.interaction.gesture={angle:0,distance:0,scale:1,startAngle:0,startDistance:0}},"auto-start:check":function(t){if(!(t.interaction.pointers.length<2)){var e=t.interactable.options.gesture;if(e&&e.enabled)return t.action={name:"gesture"},!1}}},defaults:{},getCursor:function(){return""}},wt=xt;mt.default=wt;var _t={};function Pt(t,e,n,r,o,a,s){if(!e)return!1;if(!0===e){var l=i.default.number(a.width)?a.width:a.right-a.left,u=i.default.number(a.height)?a.height:a.bottom-a.top;if(s=Math.min(s,Math.abs(("left"===t||"right"===t?l:u)/2)),l<0&&("left"===t?t="right":"right"===t&&(t="left")),u<0&&("top"===t?t="bottom":"bottom"===t&&(t="top")),"left"===t)return n.x<(l>=0?a.left:a.right)+s;if("top"===t)return n.y<(u>=0?a.top:a.bottom)+s;if("right"===t)return n.x>(l>=0?a.right:a.left)-s;if("bottom"===t)return n.y>(u>=0?a.bottom:a.top)-s}return!!i.default.element(r)&&(i.default.element(e)?e===r:_.matchesUpTo(r,e,o))}function Ot(t){var e=t.iEvent,n=t.interaction;if("resize"===n.prepared.name&&n.resizeAxes){var r=e;n.interactable.options.resize.square?("y"===n.resizeAxes?r.delta.x=r.delta.y:r.delta.y=r.delta.x,r.axes="xy"):(r.axes=n.resizeAxes,"x"===n.resizeAxes?r.delta.y=0:"y"===n.resizeAxes&&(r.delta.x=0))}}Object.defineProperty(_t,"__esModule",{value:!0}),_t.default=void 0;var St={id:"actions/resize",before:["actions/drag"],install:function(t){var e=t.actions,n=t.browser,r=t.Interactable,o=t.defaults;St.cursors=function(t){return t.isIe9?{x:"e-resize",y:"s-resize",xy:"se-resize",top:"n-resize",left:"w-resize",bottom:"s-resize",right:"e-resize",topleft:"se-resize",bottomright:"se-resize",topright:"ne-resize",bottomleft:"ne-resize"}:{x:"ew-resize",y:"ns-resize",xy:"nwse-resize",top:"ns-resize",left:"ew-resize",bottom:"ns-resize",right:"ew-resize",topleft:"nwse-resize",bottomright:"nwse-resize",topright:"nesw-resize",bottomleft:"nesw-resize"}}(n),St.defaultMargin=n.supportsTouch||n.supportsPointerEvent?20:10,r.prototype.resizable=function(e){return function(t,e,n){return i.default.object(e)?(t.options.resize.enabled=!1!==e.enabled,t.setPerAction("resize",e),t.setOnEvents("resize",e),i.default.string(e.axis)&&/^x$|^y$|^xy$/.test(e.axis)?t.options.resize.axis=e.axis:null===e.axis&&(t.options.resize.axis=n.defaults.actions.resize.axis),i.default.bool(e.preserveAspectRatio)?t.options.resize.preserveAspectRatio=e.preserveAspectRatio:i.default.bool(e.square)&&(t.options.resize.square=e.square),t):i.default.bool(e)?(t.options.resize.enabled=e,t):t.options.resize}(this,e,t)},e.map.resize=St,e.methodDict.resize="resizable",o.actions.resize=St.defaults},listeners:{"interactions:new":function(t){t.interaction.resizeAxes="xy"},"interactions:action-start":function(t){!function(t){var e=t.iEvent,n=t.interaction;if("resize"===n.prepared.name&&n.prepared.edges){var r=e,o=n.rect;n._rects={start:(0,j.default)({},o),corrected:(0,j.default)({},o),previous:(0,j.default)({},o),delta:{left:0,right:0,width:0,top:0,bottom:0,height:0}},r.edges=n.prepared.edges,r.rect=n._rects.corrected,r.deltaRect=n._rects.delta}}(t),Ot(t)},"interactions:action-move":function(t){!function(t){var e=t.iEvent,n=t.interaction;if("resize"===n.prepared.name&&n.prepared.edges){var r=e,o=n.interactable.options.resize.invert,i="reposition"===o||"negate"===o,a=n.rect,s=n._rects,l=s.start,u=s.corrected,c=s.delta,f=s.previous;if((0,j.default)(f,u),i){if((0,j.default)(u,a),"reposition"===o){if(u.top>u.bottom){var d=u.top;u.top=u.bottom,u.bottom=d}if(u.left>u.right){var p=u.left;u.left=u.right,u.right=p}}}else u.top=Math.min(a.top,l.bottom),u.bottom=Math.max(a.bottom,l.top),u.left=Math.min(a.left,l.right),u.right=Math.max(a.right,l.left);for(var v in u.width=u.right-u.left,u.height=u.bottom-u.top,u)c[v]=u[v]-f[v];r.edges=n.prepared.edges,r.rect=u,r.deltaRect=c}}(t),Ot(t)},"interactions:action-end":function(t){var e=t.iEvent,n=t.interaction;if("resize"===n.prepared.name&&n.prepared.edges){var r=e;r.edges=n.prepared.edges,r.rect=n._rects.corrected,r.deltaRect=n._rects.delta}},"auto-start:check":function(t){var e=t.interaction,n=t.interactable,r=t.element,o=t.rect,a=t.buttons;if(o){var s=(0,j.default)({},e.coords.cur.page),l=n.options.resize;if(l&&l.enabled&&(!e.pointerIsDown||!/mouse|pointer/.test(e.pointerType)||0!=(a&l.mouseButtons))){if(i.default.object(l.edges)){var u={left:!1,right:!1,top:!1,bottom:!1};for(var c in u)u[c]=Pt(c,l.edges[c],s,e._latestPointer.eventTarget,r,o,l.margin||St.defaultMargin);u.left=u.left&&!u.right,u.top=u.top&&!u.bottom,(u.left||u.right||u.top||u.bottom)&&(t.action={name:"resize",edges:u})}else{var f="y"!==l.axis&&s.x>o.right-St.defaultMargin,d="x"!==l.axis&&s.y>o.bottom-St.defaultMargin;(f||d)&&(t.action={name:"resize",axes:(f?"x":"")+(d?"y":"")})}return!t.action&&void 0}}}},defaults:{square:!1,preserveAspectRatio:!1,axis:"xy",margin:NaN,edges:null,invert:"none"},cursors:null,getCursor:function(t){var e=t.edges,n=t.axis,r=t.name,o=St.cursors,i=null;if(n)i=o[r+n];else if(e){for(var a="",s=["top","bottom","left","right"],l=0;l=1){var c={x:zt.x*u,y:zt.y*u};if(c.x||c.y){var f=Ft(a);i.default.window(a)?a.scrollBy(c.x,c.y):a&&(a.scrollLeft+=c.x,a.scrollTop+=c.y);var d=Ft(a),p={x:d.x-f.x,y:d.y-f.y};(p.x||p.y)&&e.fire({type:"autoscroll",target:n,interactable:e,delta:p,interaction:t,container:a})}zt.prevTime=s}zt.isScrolling&&(jt.default.cancel(zt.i),zt.i=jt.default.request(zt.scroll))},check:function(t,e){var n;return null==(n=t.options[e].autoScroll)?void 0:n.enabled},onInteractionMove:function(t){var e=t.interaction,n=t.pointer;if(e.interacting()&&zt.check(e.interactable,e.prepared.name))if(e.simulation)zt.x=zt.y=0;else{var r,o,a,s,l=e.interactable,u=e.element,c=e.prepared.name,f=l.options[c].autoScroll,d=Ct(f.container,l,u);if(i.default.window(d))s=n.clientXd.innerWidth-zt.margin,a=n.clientY>d.innerHeight-zt.margin;else{var p=_.getElementClientRect(d);s=n.clientXp.right-zt.margin,a=n.clientY>p.bottom-zt.margin}zt.x=o?1:s?-1:0,zt.y=a?1:r?-1:0,zt.isScrolling||(zt.margin=f.margin,zt.speed=f.speed,zt.start(e))}}};function Ct(t,n,r){return(i.default.string(t)?(0,k.getStringOptionResult)(t,n,r):t)||(0,e.getWindow)(r)}function Ft(t){return i.default.window(t)&&(t=window.document.body),{x:t.scrollLeft,y:t.scrollTop}}var Xt={id:"auto-scroll",install:function(t){var e=t.defaults,n=t.actions;t.autoScroll=zt,zt.now=function(){return t.now()},n.phaselessTypes.autoscroll=!0,e.perAction.autoScroll=zt.defaults},listeners:{"interactions:new":function(t){t.interaction.autoScroll=null},"interactions:destroy":function(t){t.interaction.autoScroll=null,zt.stop(),zt.interaction&&(zt.interaction=null)},"interactions:stop":zt.stop,"interactions:action-move":function(t){return zt.onInteractionMove(t)}}};Rt.default=Xt;var Yt={};Object.defineProperty(Yt,"__esModule",{value:!0}),Yt.warnOnce=function(t,n){var r=!1;return function(){return r||(e.window.console.warn(n),r=!0),t.apply(this,arguments)}},Yt.copyAction=function(t,e){return t.name=e.name,t.axis=e.axis,t.edges=e.edges,t},Yt.sign=void 0,Yt.sign=function(t){return t>=0?1:-1};var Bt={};function Wt(t){return i.default.bool(t)?(this.options.styleCursor=t,this):null===t?(delete this.options.styleCursor,this):this.options.styleCursor}function Lt(t){return i.default.func(t)?(this.options.actionChecker=t,this):null===t?(delete this.options.actionChecker,this):this.options.actionChecker}Object.defineProperty(Bt,"__esModule",{value:!0}),Bt.default=void 0;var Ut={id:"auto-start/interactableMethods",install:function(t){var e=t.Interactable;e.prototype.getAction=function(e,n,r,o){var i=function(t,e,n,r,o){var i=t.getRect(r),a={action:null,interactable:t,interaction:n,element:r,rect:i,buttons:e.buttons||{0:1,1:4,3:8,4:16}[e.button]};return o.fire("auto-start:check",a),a.action}(this,n,r,o,t);return this.options.actionChecker?this.options.actionChecker(e,n,i,this,o,r):i},e.prototype.ignoreFrom=(0,Yt.warnOnce)((function(t){return this._backCompatOption("ignoreFrom",t)}),"Interactable.ignoreFrom() has been deprecated. Use Interactble.draggable({ignoreFrom: newValue})."),e.prototype.allowFrom=(0,Yt.warnOnce)((function(t){return this._backCompatOption("allowFrom",t)}),"Interactable.allowFrom() has been deprecated. Use Interactble.draggable({allowFrom: newValue})."),e.prototype.actionChecker=Lt,e.prototype.styleCursor=Wt}};Bt.default=Ut;var Vt={};function Nt(t,e,n,r,o){return e.testIgnoreAllow(e.options[t.name],n,r)&&e.options[t.name].enabled&&Ht(e,n,t,o)?t:null}function qt(t,e,n,r,o,i,a){for(var s=0,l=r.length;s=s)return!1;if(d.interactable===t){if((u+=p===n.name?1:0)>=i)return!1;if(d.element===e&&(c++,p===n.name&&c>=a))return!1}}}return s>0}function Kt(t,e){return i.default.number(t)?(e.autoStart.maxInteractions=t,this):e.autoStart.maxInteractions}function Zt(t,e,n){var r=n.autoStart.cursorElement;r&&r!==t&&(r.style.cursor=""),t.ownerDocument.documentElement.style.cursor=e,t.style.cursor=e,n.autoStart.cursorElement=e?t:null}function Jt(t,e){var n=t.interactable,r=t.element,o=t.prepared;if("mouse"===t.pointerType&&n&&n.options.styleCursor){var a="";if(o.name){var s=n.options[o.name].cursorChecker;a=i.default.func(s)?s(o,n,r,t._interacting):e.actions.map[o.name].getCursor(o)}Zt(t.element,a||"",e)}else e.autoStart.cursorElement&&Zt(e.autoStart.cursorElement,"",e)}Object.defineProperty(Vt,"__esModule",{value:!0}),Vt.default=void 0;var Qt={id:"auto-start/base",before:["actions"],install:function(t){var e=t.interactStatic,n=t.defaults;t.usePlugin(Bt.default),n.base.actionChecker=null,n.base.styleCursor=!0,(0,j.default)(n.perAction,{manualStart:!1,max:1/0,maxPerElement:1,allowFrom:null,ignoreFrom:null,mouseButtons:1}),e.maxInteractions=function(e){return Kt(e,t)},t.autoStart={maxInteractions:1/0,withinInteractionLimit:Ht,cursorElement:null}},listeners:{"interactions:down":function(t,e){var n=t.interaction,r=t.pointer,o=t.event,i=t.eventTarget;n.interacting()||Gt(n,$t(n,r,o,i,e),e)},"interactions:move":function(t,e){!function(t,e){var n=t.interaction,r=t.pointer,o=t.event,i=t.eventTarget;"mouse"!==n.pointerType||n.pointerIsDown||n.interacting()||Gt(n,$t(n,r,o,i,e),e)}(t,e),function(t,e){var n=t.interaction;if(n.pointerIsDown&&!n.interacting()&&n.pointerWasMoved&&n.prepared.name){e.fire("autoStart:before-start",t);var r=n.interactable,o=n.prepared.name;o&&r&&(r.options[o].manualStart||!Ht(r,n.element,n.prepared,e)?n.stop():(n.start(n.prepared,r,n.element),Jt(n,e)))}}(t,e)},"interactions:stop":function(t,e){var n=t.interaction,r=n.interactable;r&&r.options.styleCursor&&Zt(n.element,"",e)}},maxInteractions:Kt,withinInteractionLimit:Ht,validateAction:Nt};Vt.default=Qt;var te={};Object.defineProperty(te,"__esModule",{value:!0}),te.default=void 0;var ee={id:"auto-start/dragAxis",listeners:{"autoStart:before-start":function(t,e){var n=t.interaction,r=t.eventTarget,o=t.dx,a=t.dy;if("drag"===n.prepared.name){var s=Math.abs(o),l=Math.abs(a),u=n.interactable.options.drag,c=u.startAxis,f=s>l?"x":s0&&(e.autoStartHoldTimer=setTimeout((function(){e.start(e.prepared,e.interactable,e.element)}),n))},"interactions:move":function(t){var e=t.interaction,n=t.duplicate;e.autoStartHoldTimer&&e.pointerWasMoved&&!n&&(clearTimeout(e.autoStartHoldTimer),e.autoStartHoldTimer=null)},"autoStart:before-start":function(t){var e=t.interaction;re(e)>0&&(e.prepared.name=null)}},getHoldDuration:re};ne.default=oe;var ie={};Object.defineProperty(ie,"__esModule",{value:!0}),ie.default=void 0;var ae={id:"auto-start",install:function(t){t.usePlugin(Vt.default),t.usePlugin(ne.default),t.usePlugin(te.default)}};ie.default=ae;var se={};function le(t){return/^(always|never|auto)$/.test(t)?(this.options.preventDefault=t,this):i.default.bool(t)?(this.options.preventDefault=t?"always":"never",this):this.options.preventDefault}function ue(t){var e=t.interaction,n=t.event;e.interactable&&e.interactable.checkAndPreventDefault(n)}function ce(t){var n=t.Interactable;n.prototype.preventDefault=le,n.prototype.checkAndPreventDefault=function(n){return function(t,n,r){var o=t.options.preventDefault;if("never"!==o)if("always"!==o){if(n.events.supportsPassive&&/^touch(start|move)$/.test(r.type)){var a=(0,e.getWindow)(r.target).document,s=n.getDocOptions(a);if(!s||!s.events||!1!==s.events.passive)return}/^(mouse|pointer|touch)*(down|start)/i.test(r.type)||i.default.element(r.target)&&(0,_.matchesSelector)(r.target,"input,select,textarea,[contenteditable=true],[contenteditable=true] *")||r.preventDefault()}else r.preventDefault()}(this,t,n)},t.interactions.docEvents.push({type:"dragstart",listener:function(e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=Array(e);n150)return null;var e=180*Math.atan2(t.prevEvent.velocityY,t.prevEvent.velocityX)/Math.PI;e<0&&(e+=360);var n=112.5<=e&&e<247.5,r=202.5<=e&&e<337.5;return{up:r,down:!r&&22.5<=e&&e<157.5,left:n,right:!n&&(292.5<=e||e<67.5),angle:e,speed:t.prevEvent.speed,velocity:{x:t.prevEvent.velocityX,y:t.prevEvent.velocityY}}}},{key:"preventDefault",value:function(){}},{key:"stopImmediatePropagation",value:function(){this.immediatePropagationStopped=this.propagationStopped=!0}},{key:"stopPropagation",value:function(){this.propagationStopped=!0}}])&&Ie(e.prototype,n),a}($.BaseEvent);je.InteractEvent=Fe,Object.defineProperties(Fe.prototype,{pageX:{get:function(){return this.page.x},set:function(t){this.page.x=t}},pageY:{get:function(){return this.page.y},set:function(t){this.page.y=t}},clientX:{get:function(){return this.client.x},set:function(t){this.client.x=t}},clientY:{get:function(){return this.client.y},set:function(t){this.client.y=t}},dx:{get:function(){return this.delta.x},set:function(t){this.delta.x=t}},dy:{get:function(){return this.delta.y},set:function(t){this.delta.y=t}},velocityX:{get:function(){return this.velocity.x},set:function(t){this.velocity.x=t}},velocityY:{get:function(){return this.velocity.y},set:function(t){this.velocity.y=t}}});var Xe={};function Ye(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}Object.defineProperty(Xe,"__esModule",{value:!0}),Xe.PointerInfo=void 0,Xe.PointerInfo=function t(e,n,r,o,i){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),Ye(this,"id",void 0),Ye(this,"pointer",void 0),Ye(this,"event",void 0),Ye(this,"downTime",void 0),Ye(this,"downTarget",void 0),this.id=e,this.pointer=n,this.event=r,this.downTime=o,this.downTarget=i};var Be,We,Le={};function Ue(t,e){for(var n=0;nthis.pointerMoveTolerance);var a=this.getPointerIndex(t),s={pointer:t,pointerIndex:a,pointerInfo:this.pointers[a],event:e,type:"move",eventTarget:n,dx:r,dy:o,duplicate:i,interaction:this};i||B.setCoordVelocity(this.coords.velocity,this.coords.delta),this._scopeFire("interactions:move",s),i||this.simulation||(this.interacting()&&(s.type=null,this.move(s)),this.pointerWasMoved&&B.copyCoords(this.coords.prev,this.coords.cur))}},{key:"move",value:function(t){t&&t.event||B.setZeroCoords(this.coords.delta),(t=(0,j.default)({pointer:this._latestPointer.pointer,event:this._latestPointer.event,eventTarget:this._latestPointer.eventTarget,interaction:this},t||{})).phase="move",this._doPhase(t)}},{key:"pointerUp",value:function(t,e,n,r){var o=this.getPointerIndex(t);-1===o&&(o=this.updatePointer(t,e,n,!1));var i=/cancel$/i.test(e.type)?"cancel":"up";this._scopeFire("interactions:".concat(i),{pointer:t,pointerIndex:o,pointerInfo:this.pointers[o],event:e,eventTarget:n,type:i,curEventTarget:r,interaction:this}),this.simulation||this.end(e),this.removePointer(t,e)}},{key:"documentBlur",value:function(t){this.end(t),this._scopeFire("interactions:blur",{event:t,type:"blur",interaction:this})}},{key:"end",value:function(t){var e;this._ending=!0,t=t||this._latestPointer.event,this.interacting()&&(e=this._doPhase({event:t,interaction:this,phase:"end"})),this._ending=!1,!0===e&&this.stop()}},{key:"currentAction",value:function(){return this._interacting?this.prepared.name:null}},{key:"interacting",value:function(){return this._interacting}},{key:"stop",value:function(){this._scopeFire("interactions:stop",{interaction:this}),this.interactable=this.element=null,this._interacting=!1,this._stopped=!0,this.prepared.name=this.prevEvent=null}},{key:"getPointerIndex",value:function(t){var e=B.getPointerId(t);return"mouse"===this.pointerType||"pen"===this.pointerType?this.pointers.length-1:Z.findIndex(this.pointers,(function(t){return t.id===e}))}},{key:"getPointerInfo",value:function(t){return this.pointers[this.getPointerIndex(t)]}},{key:"updatePointer",value:function(t,e,n,r){var o=B.getPointerId(t),i=this.getPointerIndex(t),a=this.pointers[i];return r=!1!==r&&(r||/(down|start)$/i.test(e.type)),a?a.pointer=t:(a=new Xe.PointerInfo(o,t,e,null,null),i=this.pointers.length,this.pointers.push(a)),B.setCoords(this.coords.cur,this.pointers.map((function(t){return t.pointer})),this._now()),B.setCoordDeltas(this.coords.delta,this.coords.prev,this.coords.cur),r&&(this.pointerIsDown=!0,a.downTime=this.coords.cur.timeStamp,a.downTarget=n,B.pointerExtend(this.downPointer,t),this.interacting()||(B.copyCoords(this.coords.start,this.coords.cur),B.copyCoords(this.coords.prev,this.coords.cur),this.downEvent=e,this.pointerWasMoved=!1)),this._updateLatestPointer(t,e,n),this._scopeFire("interactions:update-pointer",{pointer:t,event:e,eventTarget:n,down:r,pointerInfo:a,pointerIndex:i,interaction:this}),i}},{key:"removePointer",value:function(t,e){var n=this.getPointerIndex(t);if(-1!==n){var r=this.pointers[n];this._scopeFire("interactions:remove-pointer",{pointer:t,event:e,eventTarget:null,pointerIndex:n,pointerInfo:r,interaction:this}),this.pointers.splice(n,1),this.pointerIsDown=!1}}},{key:"_updateLatestPointer",value:function(t,e,n){this._latestPointer.pointer=t,this._latestPointer.event=e,this._latestPointer.eventTarget=n}},{key:"destroy",value:function(){this._latestPointer.pointer=null,this._latestPointer.event=null,this._latestPointer.eventTarget=null}},{key:"_createPreparedEvent",value:function(t,e,n,r){return new je.InteractEvent(this,t,this.prepared.name,e,this.element,n,r)}},{key:"_fireEvent",value:function(t){this.interactable.fire(t),(!this.prevEvent||t.timeStamp>=this.prevEvent.timeStamp)&&(this.prevEvent=t)}},{key:"_doPhase",value:function(t){var e=t.event,n=t.phase,r=t.preEnd,o=t.type,i=this.rect;if(i&&"move"===n&&(k.addEdges(this.edges,i,this.coords.delta[this.interactable.options.deltaSource]),i.width=i.right-i.left,i.height=i.bottom-i.top),!1===this._scopeFire("interactions:before-action-".concat(n),t))return!1;var a=t.iEvent=this._createPreparedEvent(e,n,r,o);return this._scopeFire("interactions:action-".concat(n),t),"start"===n&&(this.prevEvent=a),this._fireEvent(a),this._scopeFire("interactions:after-action-".concat(n),t),!0}},{key:"_now",value:function(){return Date.now()}}])&&Ue(e.prototype,n),t}();Le.Interaction=qe;var $e=qe;Le.default=$e;var Ge={};function He(t){t.pointerIsDown&&(Qe(t.coords.cur,t.offset.total),t.offset.pending.x=0,t.offset.pending.y=0)}function Ke(t){Ze(t.interaction)}function Ze(t){if(!function(t){return!(!t.offset.pending.x&&!t.offset.pending.y)}(t))return!1;var e=t.offset.pending;return Qe(t.coords.cur,e),Qe(t.coords.delta,e),k.addEdges(t.edges,t.rect,e),e.x=0,e.y=0,!0}function Je(t){var e=t.x,n=t.y;this.offset.pending.x+=e,this.offset.pending.y+=n,this.offset.total.x+=e,this.offset.total.y+=n}function Qe(t,e){var n=t.page,r=t.client,o=e.x,i=e.y;n.x+=o,n.y+=i,r.x+=o,r.y+=i}Object.defineProperty(Ge,"__esModule",{value:!0}),Ge.addTotal=He,Ge.applyPending=Ze,Ge.default=void 0,Le._ProxyMethods.offsetBy="";var tn={id:"offset",before:["modifiers","pointer-events","actions","inertia"],install:function(t){t.Interaction.prototype.offsetBy=Je},listeners:{"interactions:new":function(t){t.interaction.offset={total:{x:0,y:0},pending:{x:0,y:0}}},"interactions:update-pointer":function(t){return He(t.interaction)},"interactions:before-action-start":Ke,"interactions:before-action-move":Ke,"interactions:before-action-end":function(t){var e=t.interaction;if(Ze(e))return e.move({offset:!0}),e.end(),!1},"interactions:stop":function(t){var e=t.interaction;e.offset.total.x=0,e.offset.total.y=0,e.offset.pending.x=0,e.offset.pending.y=0}}};Ge.default=tn;var en={};function nn(t,e){for(var n=0;nn.minSpeed&&o>n.endSpeed)this.startInertia();else{if(i.result=i.setAll(this.modifierArg),!i.result.changed)return!1;this.startSmoothEnd()}return e.modification.result.rect=null,e.offsetBy(this.targetOffset),e._doPhase({interaction:e,event:t,phase:"inertiastart"}),e.offsetBy({x:-this.targetOffset.x,y:-this.targetOffset.y}),e.modification.result.rect=null,this.active=!0,e.simulation=this,!0}},{key:"startInertia",value:function(){var t=this,e=this.interaction.coords.velocity.client,n=an(this.interaction),r=n.resistance,o=-Math.log(n.endSpeed/this.v0)/r;this.targetOffset={x:(e.x-o)/r,y:(e.y-o)/r},this.te=o,this.lambda_v0=r/this.v0,this.one_ve_v0=1-n.endSpeed/this.v0;var i=this.modification,a=this.modifierArg;a.pageCoords={x:this.startCoords.x+this.targetOffset.x,y:this.startCoords.y+this.targetOffset.y},i.result=i.setAll(a),i.result.changed&&(this.isModified=!0,this.modifiedOffset={x:this.targetOffset.x+i.result.delta.x,y:this.targetOffset.y+i.result.delta.y}),this.onNextFrame((function(){return t.inertiaTick()}))}},{key:"startSmoothEnd",value:function(){var t=this;this.smoothEnd=!0,this.isModified=!0,this.targetOffset={x:this.modification.result.delta.x,y:this.modification.result.delta.y},this.onNextFrame((function(){return t.smoothEndTick()}))}},{key:"onNextFrame",value:function(t){var e=this;this.timeout=jt.default.request((function(){e.active&&t()}))}},{key:"inertiaTick",value:function(){var t,e,n,r,o,i=this,a=this.interaction,s=an(a).resistance,l=(a._now()-this.t0)/1e3;if(l=0;n--){var r=e[n],o=r.selector,a=r.context,s=r.listeners;o===this.target&&a===this._context&&e.splice(n,1);for(var l=s.length-1;l>=0;l--)this._scopeEvents.removeDelegate(this.target,this._context,t,s[l][0],s[l][1])}else this._scopeEvents.remove(this.target,"all")}}])&&mn(n.prototype,r),t}();yn.Interactable=xn;var wn={};function _n(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=Array(e);n=0;a--){var p=f[a];if(p.selector===t&&p.context===e){for(var v=p.listeners,h=v.length-1;h>=0;h--){var g=Mn(v[h],2),y=g[0],m=g[1],b=m.capture,x=m.passive;if(y===o&&b===s.capture&&x===s.passive){v.splice(h,1),v.length||(f.splice(a,1),l(e,n,u),l(e,n,c,!0)),d=!0;break}}if(d)break}}},delegateListener:u,delegateUseCapture:c,delegatedEvents:r,documents:o,targets:n,supportsOptions:!1,supportsPassive:!1};function s(t,e,r,o){var i=In(o),s=Z.find(n,(function(e){return e.eventTarget===t}));s||(s={eventTarget:t,events:{}},n.push(s)),s.events[e]||(s.events[e]=[]),t.addEventListener&&!Z.contains(s.events[e],r)&&(t.addEventListener(e,r,a.supportsOptions?i:i.capture),s.events[e].push(r))}function l(t,e,r,o){var i=In(o),s=Z.findIndex(n,(function(e){return e.eventTarget===t})),u=n[s];if(u&&u.events)if("all"!==e){var c=!1,f=u.events[e];if(f){if("all"===r){for(var d=f.length-1;d>=0;d--)l(t,e,f[d],i);return}for(var p=0;p=2)continue;if(!o.interacting()&&e===o.pointerType)return o}return null}};function zn(t,e){return t.pointers.some((function(t){return t.id===e}))}var Cn=Rn;An.default=Cn;var Fn={};function Xn(t){return(Xn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function Yn(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(t)){var n=[],r=!0,o=!1,i=void 0;try{for(var a,s=t[Symbol.iterator]();!(r=(a=s.next()).done)&&(n.push(a.value),!e||n.length!==e);r=!0);}catch(t){o=!0,i=t}finally{try{r||null==s.return||s.return()}finally{if(o)throw i}}return n}}(t,e)||function(t,e){if(t){if("string"==typeof t)return Bn(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Bn(t,e):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Bn(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=Array(e);n=0;r--){var o=e.interactions.list[r];o.interactable===n&&(o.stop(),e.fire("interactions:destroy",{interaction:o}),o.destroy(),e.interactions.list.length>2&&e.interactions.list.splice(r,1))}}},onDocSignal:Hn,doOnInteractions:$n,methodNames:qn};Fn.default=Kn;var Zn={};function Jn(t){return(Jn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function Qn(t,e,n){return(Qn="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(t,e,n){var r=function(t,e){for(;!Object.prototype.hasOwnProperty.call(t,e)&&null!==(t=nr(t)););return t}(t,e);if(r){var o=Object.getOwnPropertyDescriptor(r,e);return o.get?o.get.call(n):o.value}})(t,e,n||t)}function tr(t,e){return(tr=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function er(t,e){return!e||"object"!==Jn(e)&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function nr(t){return(nr=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function rr(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function or(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=Array(e);nMath.abs(l.y),s.coords,s.rect),(0,j.default)(r,s.coords)),s.eventProps},defaults:{ratio:"preserve",equalDelta:!1,modifiers:[],enabled:!1}};function Tr(t,e,n){var r=t.startCoords,o=t.edgeSign;e?n.y=r.y+(n.x-r.x)*o:n.x=r.x+(n.y-r.y)*o}function Mr(t,e,n,r){var o=t.startRect,i=t.startCoords,a=t.ratio,s=t.edgeSign;if(e){var l=r.width/a;n.y=i.y+(l-o.height)*s}else{var u=r.height*a;n.x=i.x+(u-o.width)*s}}_r.aspectRatio=Er;var jr=(0,Se.makeModifier)(Er,"aspectRatio");_r.default=jr;var kr={};Object.defineProperty(kr,"__esModule",{value:!0}),kr.default=void 0;var Ir=function(){};Ir._defaults={};var Dr=Ir;kr.default=Dr;var Ar={};Object.defineProperty(Ar,"__esModule",{value:!0}),Object.defineProperty(Ar,"default",{enumerable:!0,get:function(){return kr.default}});var Rr={};function zr(t,e,n){return i.default.func(t)?k.resolveRectLike(t,e.interactable,e.element,[n.x,n.y,e]):k.resolveRectLike(t,e.interactable,e.element)}Object.defineProperty(Rr,"__esModule",{value:!0}),Rr.getRestrictionRect=zr,Rr.restrict=Rr.default=void 0;var Cr={start:function(t){var e=t.rect,n=t.startOffset,r=t.state,o=t.interaction,i=t.pageCoords,a=r.options,s=a.elementRect,l=(0,j.default)({left:0,top:0,right:0,bottom:0},a.offset||{});if(e&&s){var u=zr(a.restriction,o,i);if(u){var c=u.right-u.left-e.width,f=u.bottom-u.top-e.height;c<0&&(l.left+=c,l.right+=c),f<0&&(l.top+=f,l.bottom+=f)}l.left+=n.left-e.width*s.left,l.top+=n.top-e.height*s.top,l.right+=n.right-e.width*(1-s.right),l.bottom+=n.bottom-e.height*(1-s.bottom)}r.offset=l},set:function(t){var e=t.coords,n=t.interaction,r=t.state,o=r.options,i=r.offset,a=zr(o.restriction,n,e);if(a){var s=k.xywhToTlbr(a);e.x=Math.max(Math.min(s.right-i.right,e.x),s.left+i.left),e.y=Math.max(Math.min(s.bottom-i.bottom,e.y),s.top+i.top)}},defaults:{restriction:null,elementRect:null,offset:null,endOnly:!1,enabled:!1}};Rr.restrict=Cr;var Fr=(0,Se.makeModifier)(Cr,"restrict");Rr.default=Fr;var Xr={};Object.defineProperty(Xr,"__esModule",{value:!0}),Xr.restrictEdges=Xr.default=void 0;var Yr={top:1/0,left:1/0,bottom:-1/0,right:-1/0},Br={top:-1/0,left:-1/0,bottom:1/0,right:1/0};function Wr(t,e){for(var n=["top","left","bottom","right"],r=0;rt.length)&&(e=t.length);for(var n=0,r=Array(e);n>> 16) & 0xffff) |0, + n = 0; + + while (len !== 0) { + // Set limit ~ twice less than 5552, to keep + // s2 in 31-bits, because we force signed ints. + // in other case %= will fail. + n = len > 2000 ? 2000 : len; + len -= n; + + do { + s1 = (s1 + buf[pos++]) |0; + s2 = (s2 + s1) |0; + } while (--n); + + s1 %= 65521; + s2 %= 65521; + } + + return (s1 | (s2 << 16)) |0; +} diff --git a/vendor/pako/lib/zlib/constants.js b/vendor/pako/lib/zlib/constants.js new file mode 100644 index 0000000..7d80502 --- /dev/null +++ b/vendor/pako/lib/zlib/constants.js @@ -0,0 +1,47 @@ +export default { + + /* Allowed flush values; see deflate() and inflate() below for details */ + Z_NO_FLUSH: 0, + Z_PARTIAL_FLUSH: 1, + Z_SYNC_FLUSH: 2, + Z_FULL_FLUSH: 3, + Z_FINISH: 4, + Z_BLOCK: 5, + Z_TREES: 6, + + /* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + Z_OK: 0, + Z_STREAM_END: 1, + Z_NEED_DICT: 2, + Z_ERRNO: -1, + Z_STREAM_ERROR: -2, + Z_DATA_ERROR: -3, + //Z_MEM_ERROR: -4, + Z_BUF_ERROR: -5, + //Z_VERSION_ERROR: -6, + + /* compression levels */ + Z_NO_COMPRESSION: 0, + Z_BEST_SPEED: 1, + Z_BEST_COMPRESSION: 9, + Z_DEFAULT_COMPRESSION: -1, + + + Z_FILTERED: 1, + Z_HUFFMAN_ONLY: 2, + Z_RLE: 3, + Z_FIXED: 4, + Z_DEFAULT_STRATEGY: 0, + + /* Possible values of the data_type field (though see inflate()) */ + Z_BINARY: 0, + Z_TEXT: 1, + //Z_ASCII: 1, // = Z_TEXT (deprecated) + Z_UNKNOWN: 2, + + /* The deflate compression method */ + Z_DEFLATED: 8 + //Z_NULL: null // Use -1 or null inline, depending on var type +}; diff --git a/vendor/pako/lib/zlib/crc32.js b/vendor/pako/lib/zlib/crc32.js new file mode 100644 index 0000000..611ffb2 --- /dev/null +++ b/vendor/pako/lib/zlib/crc32.js @@ -0,0 +1,36 @@ +// Note: we can't get significant speed boost here. +// So write code to minimize size - no pregenerated tables +// and array tools dependencies. + + +// Use ordinary array, since untyped makes no boost here +export default function makeTable() { + var c, table = []; + + for (var n = 0; n < 256; n++) { + c = n; + for (var k = 0; k < 8; k++) { + c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); + } + table[n] = c; + } + + return table; +} + +// Create table on load. Just 255 signed longs. Not a problem. +var crcTable = makeTable(); + + +function crc32(crc, buf, len, pos) { + var t = crcTable, + end = pos + len; + + crc ^= -1; + + for (var i = pos; i < end; i++) { + crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; + } + + return (crc ^ (-1)); // >>> 0; +} diff --git a/vendor/pako/lib/zlib/deflate.js b/vendor/pako/lib/zlib/deflate.js new file mode 100644 index 0000000..c3a5ba4 --- /dev/null +++ b/vendor/pako/lib/zlib/deflate.js @@ -0,0 +1,1846 @@ +import * as utils from "../utils/common.js"; +import * as trees from "./trees.js"; +import adler32 from "./adler32.js"; +import crc32 from "./crc32.js"; +import msg from "./messages.js"; + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +/* Allowed flush values; see deflate() and inflate() below for details */ +export const Z_NO_FLUSH = 0; +export const Z_PARTIAL_FLUSH = 1; +//export const Z_SYNC_FLUSH = 2; +export const Z_FULL_FLUSH = 3; +export const Z_FINISH = 4; +export const Z_BLOCK = 5; +//export const Z_TREES = 6; + + +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ +export const Z_OK = 0; +export const Z_STREAM_END = 1; +//export const Z_NEED_DICT = 2; +//export const Z_ERRNO = -1; +export const Z_STREAM_ERROR = -2; +export const Z_DATA_ERROR = -3; +//export const Z_MEM_ERROR = -4; +export const Z_BUF_ERROR = -5; +//export const Z_VERSION_ERROR = -6; + + +/* compression levels */ +//export const Z_NO_COMPRESSION = 0; +//export const Z_BEST_SPEED = 1; +//export const Z_BEST_COMPRESSION = 9; +export const Z_DEFAULT_COMPRESSION = -1; + + +export const Z_FILTERED = 1; +export const Z_HUFFMAN_ONLY = 2; +export const Z_RLE = 3; +export const Z_FIXED = 4; +export const Z_DEFAULT_STRATEGY = 0; + +/* Possible values of the data_type field (though see inflate()) */ +//export const Z_BINARY = 0; +//export const Z_TEXT = 1; +//export const Z_ASCII = 1; // = Z_TEXT +export const Z_UNKNOWN = 2; + + +/* The deflate compression method */ +export const Z_DEFLATED = 8; + +/*============================================================================*/ + + +var MAX_MEM_LEVEL = 9; +/* Maximum value for memLevel in deflateInit2 */ +var MAX_WBITS = 15; +/* 32K LZ77 window */ +var DEF_MEM_LEVEL = 8; + + +var LENGTH_CODES = 29; +/* number of length codes, not counting the special END_BLOCK code */ +var LITERALS = 256; +/* number of literal bytes 0..255 */ +var L_CODES = LITERALS + 1 + LENGTH_CODES; +/* number of Literal or Length codes, including the END_BLOCK code */ +var D_CODES = 30; +/* number of distance codes */ +var BL_CODES = 19; +/* number of codes used to transfer the bit lengths */ +var HEAP_SIZE = 2 * L_CODES + 1; +/* maximum heap size */ +var MAX_BITS = 15; +/* All codes must not exceed MAX_BITS bits */ + +var MIN_MATCH = 3; +var MAX_MATCH = 258; +var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); + +var PRESET_DICT = 0x20; + +var INIT_STATE = 42; +var EXTRA_STATE = 69; +var NAME_STATE = 73; +var COMMENT_STATE = 91; +var HCRC_STATE = 103; +var BUSY_STATE = 113; +var FINISH_STATE = 666; + +var BS_NEED_MORE = 1; /* block not completed, need more input or more output */ +var BS_BLOCK_DONE = 2; /* block flush performed */ +var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ +var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ + +var OS_CODE = 0x03; // Unix :) . Don't detect, use this default. + +function err(strm, errorCode) { + strm.msg = msg[errorCode]; + return errorCode; +} + +function rank(f) { + return ((f) << 1) - ((f) > 4 ? 9 : 0); +} + +function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } + + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->output buffer and copying into it. + * (See also read_buf()). + */ +function flush_pending(strm) { + var s = strm.state; + + //_tr_flush_bits(s); + var len = s.pending; + if (len > strm.avail_out) { + len = strm.avail_out; + } + if (len === 0) { return; } + + utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out); + strm.next_out += len; + s.pending_out += len; + strm.total_out += len; + strm.avail_out -= len; + s.pending -= len; + if (s.pending === 0) { + s.pending_out = 0; + } +} + + +function flush_block_only(s, last) { + trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last); + s.block_start = s.strstart; + flush_pending(s.strm); +} + + +function put_byte(s, b) { + s.pending_buf[s.pending++] = b; +} + + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +function putShortMSB(s, b) { +// put_byte(s, (Byte)(b >> 8)); +// put_byte(s, (Byte)(b & 0xff)); + s.pending_buf[s.pending++] = (b >>> 8) & 0xff; + s.pending_buf[s.pending++] = b & 0xff; +} + + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->input buffer and copying from it. + * (See also flush_pending()). + */ +function read_buf(strm, buf, start, size) { + var len = strm.avail_in; + + if (len > size) { len = size; } + if (len === 0) { return 0; } + + strm.avail_in -= len; + + // zmemcpy(buf, strm->next_in, len); + utils.arraySet(buf, strm.input, strm.next_in, len, start); + if (strm.state.wrap === 1) { + strm.adler = adler32(strm.adler, buf, len, start); + } + + else if (strm.state.wrap === 2) { + strm.adler = crc32(strm.adler, buf, len, start); + } + + strm.next_in += len; + strm.total_in += len; + + return len; +} + + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +function longest_match(s, cur_match) { + var chain_length = s.max_chain_length; /* max hash chain length */ + var scan = s.strstart; /* current string */ + var match; /* matched string */ + var len; /* length of current match */ + var best_len = s.prev_length; /* best match length so far */ + var nice_match = s.nice_match; /* stop if match long enough */ + var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ? + s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/; + + var _win = s.window; // shortcut + + var wmask = s.w_mask; + var prev = s.prev; + + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + + var strend = s.strstart + MAX_MATCH; + var scan_end1 = _win[scan + best_len - 1]; + var scan_end = _win[scan + best_len]; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s.prev_length >= s.good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if (nice_match > s.lookahead) { nice_match = s.lookahead; } + + // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + // Assert(cur_match < s->strstart, "no future"); + match = cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ + + if (_win[match + best_len] !== scan_end || + _win[match + best_len - 1] !== scan_end1 || + _win[match] !== _win[scan] || + _win[++match] !== _win[scan + 1]) { + continue; + } + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2; + match++; + // Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + // Do nothing + } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + scan < strend); + + // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (strend - scan); + scan = strend - MAX_MATCH; + + if (len > best_len) { + s.match_start = cur_match; + best_len = len; + if (len >= nice_match) { + break; + } + scan_end1 = _win[scan + best_len - 1]; + scan_end = _win[scan + best_len]; + } + } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); + + if (best_len <= s.lookahead) { + return best_len; + } + return s.lookahead; +} + + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +function fill_window(s) { + var _w_size = s.w_size; + var p, n, m, more, str; + + //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = s.window_size - s.lookahead - s.strstart; + + // JS ints have 32 bit, block below not needed + /* Deal with !@#$% 64K limit: */ + //if (sizeof(int) <= 2) { + // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + // more = wsize; + // + // } else if (more == (unsigned)(-1)) { + // /* Very unlikely, but possible on 16 bit machine if + // * strstart == 0 && lookahead == 1 (input done a byte at time) + // */ + // more--; + // } + //} + + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { + + utils.arraySet(s.window, s.window, _w_size, _w_size, 0); + s.match_start -= _w_size; + s.strstart -= _w_size; + /* we now have strstart >= MAX_DIST */ + s.block_start -= _w_size; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + + n = s.hash_size; + p = n; + do { + m = s.head[--p]; + s.head[p] = (m >= _w_size ? m - _w_size : 0); + } while (--n); + + n = _w_size; + p = n; + do { + m = s.prev[--p]; + s.prev[p] = (m >= _w_size ? m - _w_size : 0); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + + more += _w_size; + } + if (s.strm.avail_in === 0) { + break; + } + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + //Assert(more >= 2, "more < 2"); + n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); + s.lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s.lookahead + s.insert >= MIN_MATCH) { + str = s.strstart - s.insert; + s.ins_h = s.window[str]; + + /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask; +//#if MIN_MATCH != 3 +// Call update_hash() MIN_MATCH-3 more times +//#endif + while (s.insert) { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask; + + s.prev[str & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = str; + str++; + s.insert--; + if (s.lookahead + s.insert < MIN_MATCH) { + break; + } + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ +// if (s.high_water < s.window_size) { +// var curr = s.strstart + s.lookahead; +// var init = 0; +// +// if (s.high_water < curr) { +// /* Previous high water mark below current data -- zero WIN_INIT +// * bytes or up to end of window, whichever is less. +// */ +// init = s.window_size - curr; +// if (init > WIN_INIT) +// init = WIN_INIT; +// zmemzero(s->window + curr, (unsigned)init); +// s->high_water = curr + init; +// } +// else if (s->high_water < (ulg)curr + WIN_INIT) { +// /* High water mark at or above current data, but below current data +// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up +// * to end of window, whichever is less. +// */ +// init = (ulg)curr + WIN_INIT - s->high_water; +// if (init > s->window_size - s->high_water) +// init = s->window_size - s->high_water; +// zmemzero(s->window + s->high_water, (unsigned)init); +// s->high_water += init; +// } +// } +// +// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, +// "not enough room for search"); +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +function deflate_stored(s, flush) { + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + var max_block_size = 0xffff; + + if (max_block_size > s.pending_buf_size - 5) { + max_block_size = s.pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s.lookahead <= 1) { + + //Assert(s->strstart < s->w_size+MAX_DIST(s) || + // s->block_start >= (long)s->w_size, "slide too late"); +// if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || +// s.block_start >= s.w_size)) { +// throw new Error("slide too late"); +// } + + fill_window(s); + if (s.lookahead === 0 && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + + if (s.lookahead === 0) { + break; + } + /* flush the current block */ + } + //Assert(s->block_start >= 0L, "block gone"); +// if (s.block_start < 0) throw new Error("block gone"); + + s.strstart += s.lookahead; + s.lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + var max_start = s.block_start + max_block_size; + + if (s.strstart === 0 || s.strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s.lookahead = s.strstart - max_start; + s.strstart = max_start; + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + + s.insert = 0; + + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + + if (s.strstart > s.block_start) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_NEED_MORE; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +function deflate_fast(s, flush) { + var hash_head; /* head of the hash chain */ + var bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { + break; /* flush the current block */ + } + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + } + if (s.match_length >= MIN_MATCH) { + // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only + + /*** _tr_tally_dist(s, s.strstart - s.match_start, + s.match_length - MIN_MATCH, bflush); ***/ + bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) { + s.match_length--; /* string at strstart already in table */ + do { + s.strstart++; + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s.match_length !== 0); + s.strstart++; + } else + { + s.strstart += s.match_length; + s.match_length = 0; + s.ins_h = s.window[s.strstart]; + /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask; + +//#if MIN_MATCH != 3 +// Call UPDATE_HASH() MIN_MATCH-3 more times +//#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s.window[s.strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1); + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +function deflate_slow(s, flush) { + var hash_head; /* head of hash chain */ + var bflush; /* set if current block must be flushed */ + + var max_insert; + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + */ + s.prev_length = s.match_length; + s.prev_match = s.match_start; + s.match_length = MIN_MATCH - 1; + + if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match && + s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + + if (s.match_length <= 5 && + (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s.match_length = MIN_MATCH - 1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { + max_insert = s.strstart + s.lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + //check_match(s, s.strstart-1, s.prev_match, s.prev_length); + + /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, + s.prev_length - MIN_MATCH, bflush);***/ + bflush = trees._tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH); + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s.lookahead -= s.prev_length - 1; + s.prev_length -= 2; + do { + if (++s.strstart <= max_insert) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + } while (--s.prev_length !== 0); + s.match_available = 0; + s.match_length = MIN_MATCH - 1; + s.strstart++; + + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + } else if (s.match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]); + + if (bflush) { + /*** FLUSH_BLOCK_ONLY(s, 0) ***/ + flush_block_only(s, false); + /***/ + } + s.strstart++; + s.lookahead--; + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s.match_available = 1; + s.strstart++; + s.lookahead--; + } + } + //Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s.match_available) { + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]); + + s.match_available = 0; + } + s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_BLOCK_DONE; +} + + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +function deflate_rle(s, flush) { + var bflush; /* set if current block must be flushed */ + var prev; /* byte at distance one to match */ + var scan, strend; /* scan goes up to strend for length of run */ + + var _win = s.window; + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s.lookahead <= MAX_MATCH) { + fill_window(s); + if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s.match_length = 0; + if (s.lookahead >= MIN_MATCH && s.strstart > 0) { + scan = s.strstart - 1; + prev = _win[scan]; + if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { + strend = s.strstart + MAX_MATCH; + do { + // Do nothing + } while (prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + scan < strend); + s.match_length = MAX_MATCH - (strend - scan); + if (s.match_length > s.lookahead) { + s.match_length = s.lookahead; + } + } + //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s.match_length >= MIN_MATCH) { + //check_match(s, s.strstart, s.strstart - 1, s.match_length); + + /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ + bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + s.strstart += s.match_length; + s.match_length = 0; + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +function deflate_huff(s, flush) { + var bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s.lookahead === 0) { + fill_window(s); + if (s.lookahead === 0) { + if (flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s.match_length = 0; + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + s.lookahead--; + s.strstart++; + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; +} + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +function Config(good_length, max_lazy, nice_length, max_chain, func) { + this.good_length = good_length; + this.max_lazy = max_lazy; + this.nice_length = nice_length; + this.max_chain = max_chain; + this.func = func; +} + +var configuration_table; + +configuration_table = [ + /* good lazy nice chain */ + new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ + new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ + new Config(4, 5, 16, 8, deflate_fast), /* 2 */ + new Config(4, 6, 32, 32, deflate_fast), /* 3 */ + + new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ + new Config(8, 16, 32, 32, deflate_slow), /* 5 */ + new Config(8, 16, 128, 128, deflate_slow), /* 6 */ + new Config(8, 32, 128, 256, deflate_slow), /* 7 */ + new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ + new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ +]; + + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +function lm_init(s) { + s.window_size = 2 * s.w_size; + + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + + /* Set the default configuration parameters: + */ + s.max_lazy_match = configuration_table[s.level].max_lazy; + s.good_match = configuration_table[s.level].good_length; + s.nice_match = configuration_table[s.level].nice_length; + s.max_chain_length = configuration_table[s.level].max_chain; + + s.strstart = 0; + s.block_start = 0; + s.lookahead = 0; + s.insert = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + s.ins_h = 0; +} + + +function DeflateState() { + this.strm = null; /* pointer back to this zlib stream */ + this.status = 0; /* as the name implies */ + this.pending_buf = null; /* output still pending */ + this.pending_buf_size = 0; /* size of pending_buf */ + this.pending_out = 0; /* next pending byte to output to the stream */ + this.pending = 0; /* nb of bytes in the pending buffer */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.gzhead = null; /* gzip header information to write */ + this.gzindex = 0; /* where in extra, name, or comment */ + this.method = Z_DEFLATED; /* can only be DEFLATED */ + this.last_flush = -1; /* value of flush param for previous deflate call */ + + this.w_size = 0; /* LZ77 window size (32K by default) */ + this.w_bits = 0; /* log2(w_size) (8..16) */ + this.w_mask = 0; /* w_size - 1 */ + + this.window = null; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. + */ + + this.window_size = 0; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + this.prev = null; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + this.head = null; /* Heads of the hash chains or NIL. */ + + this.ins_h = 0; /* hash index of string to be inserted */ + this.hash_size = 0; /* number of elements in hash table */ + this.hash_bits = 0; /* log2(hash_size) */ + this.hash_mask = 0; /* hash_size-1 */ + + this.hash_shift = 0; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + this.block_start = 0; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + this.match_length = 0; /* length of best match */ + this.prev_match = 0; /* previous match */ + this.match_available = 0; /* set if previous match exists */ + this.strstart = 0; /* start of string to insert */ + this.match_start = 0; /* start of matching string */ + this.lookahead = 0; /* number of valid bytes ahead in window */ + + this.prev_length = 0; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + this.max_chain_length = 0; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + this.max_lazy_match = 0; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ + // That's alias to max_lazy_match, don't use directly + //this.max_insert_length = 0; + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + this.level = 0; /* compression level (1..9) */ + this.strategy = 0; /* favor or force Huffman coding*/ + + this.good_match = 0; + /* Use a faster search when the previous match is longer than this */ + + this.nice_match = 0; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + + /* Didn't use ct_data typedef below to suppress compiler warning */ + + // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + // Use flat array of DOUBLE size, with interleaved fata, + // because JS does not support effective + this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2); + this.dyn_dtree = new utils.Buf16((2 * D_CODES + 1) * 2); + this.bl_tree = new utils.Buf16((2 * BL_CODES + 1) * 2); + zero(this.dyn_ltree); + zero(this.dyn_dtree); + zero(this.bl_tree); + + this.l_desc = null; /* desc. for literal tree */ + this.d_desc = null; /* desc. for distance tree */ + this.bl_desc = null; /* desc. for bit length tree */ + + //ush bl_count[MAX_BITS+1]; + this.bl_count = new utils.Buf16(MAX_BITS + 1); + /* number of codes at each bit length for an optimal tree */ + + //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + this.heap = new utils.Buf16(2 * L_CODES + 1); /* heap used to build the Huffman trees */ + zero(this.heap); + + this.heap_len = 0; /* number of elements in the heap */ + this.heap_max = 0; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + this.depth = new utils.Buf16(2 * L_CODES + 1); //uch depth[2*L_CODES+1]; + zero(this.depth); + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + this.l_buf = 0; /* buffer index for literals or lengths */ + + this.lit_bufsize = 0; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + this.last_lit = 0; /* running index in l_buf */ + + this.d_buf = 0; + /* Buffer index for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + this.opt_len = 0; /* bit length of current block with optimal trees */ + this.static_len = 0; /* bit length of current block with static trees */ + this.matches = 0; /* number of string matches in current block */ + this.insert = 0; /* bytes at end of window left to insert */ + + + this.bi_buf = 0; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + this.bi_valid = 0; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + // Used for window memory init. We safely ignore it for JS. That makes + // sense only for pointers and memory check tools. + //this.high_water = 0; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ +} + + +function deflateResetKeep(strm) { + var s; + + if (!strm || !strm.state) { + return err(strm, Z_STREAM_ERROR); + } + + strm.total_in = strm.total_out = 0; + strm.data_type = Z_UNKNOWN; + + s = strm.state; + s.pending = 0; + s.pending_out = 0; + + if (s.wrap < 0) { + s.wrap = -s.wrap; + /* was made negative by deflate(..., Z_FINISH); */ + } + s.status = (s.wrap ? INIT_STATE : BUSY_STATE); + strm.adler = (s.wrap === 2) ? + 0 // crc32(0, Z_NULL, 0) + : + 1; // adler32(0, Z_NULL, 0) + s.last_flush = Z_NO_FLUSH; + trees._tr_init(s); + return Z_OK; +} + + +function deflateReset(strm) { + var ret = deflateResetKeep(strm); + if (ret === Z_OK) { + lm_init(strm.state); + } + return ret; +} + + +function deflateSetHeader(strm, head) { + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; } + strm.state.gzhead = head; + return Z_OK; +} + + +function deflateInit2(strm, level, method, windowBits, memLevel, strategy) { + if (!strm) { // === Z_NULL + return Z_STREAM_ERROR; + } + var wrap = 1; + + if (level === Z_DEFAULT_COMPRESSION) { + level = 6; + } + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } + + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } + + + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return err(strm, Z_STREAM_ERROR); + } + + + if (windowBits === 8) { + windowBits = 9; + } + /* until 256-byte window bug fixed */ + + var s = new DeflateState(); + + strm.state = s; + s.strm = strm; + + s.wrap = wrap; + s.gzhead = null; + s.w_bits = windowBits; + s.w_size = 1 << s.w_bits; + s.w_mask = s.w_size - 1; + + s.hash_bits = memLevel + 7; + s.hash_size = 1 << s.hash_bits; + s.hash_mask = s.hash_size - 1; + s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); + + s.window = new utils.Buf8(s.w_size * 2); + s.head = new utils.Buf16(s.hash_size); + s.prev = new utils.Buf16(s.w_size); + + // Don't need mem init magic for JS. + //s.high_water = 0; /* nothing written to s->window yet */ + + s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + s.pending_buf_size = s.lit_bufsize * 4; + + //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + //s->pending_buf = (uchf *) overlay; + s.pending_buf = new utils.Buf8(s.pending_buf_size); + + // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`) + //s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s.d_buf = 1 * s.lit_bufsize; + + //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + s.l_buf = (1 + 2) * s.lit_bufsize; + + s.level = level; + s.strategy = strategy; + s.method = method; + + return deflateReset(strm); +} + +function deflateInit(strm, level) { + return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); +} + + +function deflate(strm, flush) { + var old_flush, s; + var beg, val; // for gzip header write only + + if (!strm || !strm.state || + flush > Z_BLOCK || flush < 0) { + return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR; + } + + s = strm.state; + + if (!strm.output || + (!strm.input && strm.avail_in !== 0) || + (s.status === FINISH_STATE && flush !== Z_FINISH)) { + return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR); + } + + s.strm = strm; /* just in case */ + old_flush = s.last_flush; + s.last_flush = flush; + + /* Write the header */ + if (s.status === INIT_STATE) { + + if (s.wrap === 2) { // GZIP header + strm.adler = 0; //crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (!s.gzhead) { // s->gzhead == Z_NULL + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s.status = BUSY_STATE; + } + else { + put_byte(s, (s.gzhead.text ? 1 : 0) + + (s.gzhead.hcrc ? 2 : 0) + + (!s.gzhead.extra ? 0 : 4) + + (!s.gzhead.name ? 0 : 8) + + (!s.gzhead.comment ? 0 : 16) + ); + put_byte(s, s.gzhead.time & 0xff); + put_byte(s, (s.gzhead.time >> 8) & 0xff); + put_byte(s, (s.gzhead.time >> 16) & 0xff); + put_byte(s, (s.gzhead.time >> 24) & 0xff); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, s.gzhead.os & 0xff); + if (s.gzhead.extra && s.gzhead.extra.length) { + put_byte(s, s.gzhead.extra.length & 0xff); + put_byte(s, (s.gzhead.extra.length >> 8) & 0xff); + } + if (s.gzhead.hcrc) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0); + } + s.gzindex = 0; + s.status = EXTRA_STATE; + } + } + else // DEFLATE header + { + var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8; + var level_flags = -1; + + if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { + level_flags = 0; + } else if (s.level < 6) { + level_flags = 1; + } else if (s.level === 6) { + level_flags = 2; + } else { + level_flags = 3; + } + header |= (level_flags << 6); + if (s.strstart !== 0) { header |= PRESET_DICT; } + header += 31 - (header % 31); + + s.status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s.strstart !== 0) { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + strm.adler = 1; // adler32(0L, Z_NULL, 0); + } + } + +//#ifdef GZIP + if (s.status === EXTRA_STATE) { + if (s.gzhead.extra/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + + while (s.gzindex < (s.gzhead.extra.length & 0xffff)) { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + break; + } + } + put_byte(s, s.gzhead.extra[s.gzindex] & 0xff); + s.gzindex++; + } + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (s.gzindex === s.gzhead.extra.length) { + s.gzindex = 0; + s.status = NAME_STATE; + } + } + else { + s.status = NAME_STATE; + } + } + if (s.status === NAME_STATE) { + if (s.gzhead.name/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.name.length) { + val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (val === 0) { + s.gzindex = 0; + s.status = COMMENT_STATE; + } + } + else { + s.status = COMMENT_STATE; + } + } + if (s.status === COMMENT_STATE) { + if (s.gzhead.comment/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.comment.length) { + val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (val === 0) { + s.status = HCRC_STATE; + } + } + else { + s.status = HCRC_STATE; + } + } + if (s.status === HCRC_STATE) { + if (s.gzhead.hcrc) { + if (s.pending + 2 > s.pending_buf_size) { + flush_pending(strm); + } + if (s.pending + 2 <= s.pending_buf_size) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + strm.adler = 0; //crc32(0L, Z_NULL, 0); + s.status = BUSY_STATE; + } + } + else { + s.status = BUSY_STATE; + } + } +//#endif + + /* Flush as much pending output as possible */ + if (s.pending !== 0) { + flush_pending(strm); + if (strm.avail_out === 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s.last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && + flush !== Z_FINISH) { + return err(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s.status === FINISH_STATE && strm.avail_in !== 0) { + return err(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm.avail_in !== 0 || s.lookahead !== 0 || + (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) { + var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) : + (s.strategy === Z_RLE ? deflate_rle(s, flush) : + configuration_table[s.level].func(s, flush)); + + if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { + s.status = FINISH_STATE; + } + if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { + if (strm.avail_out === 0) { + s.last_flush = -1; + /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate === BS_BLOCK_DONE) { + if (flush === Z_PARTIAL_FLUSH) { + trees._tr_align(s); + } + else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + + trees._tr_stored_block(s, 0, 0, false); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush === Z_FULL_FLUSH) { + /*** CLEAR_HASH(s); ***/ /* forget history */ + zero(s.head); // Fill with NIL (= 0); + + if (s.lookahead === 0) { + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + } + } + flush_pending(strm); + if (strm.avail_out === 0) { + s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + //Assert(strm->avail_out > 0, "bug2"); + //if (strm.avail_out <= 0) { throw new Error("bug2");} + + if (flush !== Z_FINISH) { return Z_OK; } + if (s.wrap <= 0) { return Z_STREAM_END; } + + /* Write the trailer */ + if (s.wrap === 2) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + put_byte(s, (strm.adler >> 16) & 0xff); + put_byte(s, (strm.adler >> 24) & 0xff); + put_byte(s, strm.total_in & 0xff); + put_byte(s, (strm.total_in >> 8) & 0xff); + put_byte(s, (strm.total_in >> 16) & 0xff); + put_byte(s, (strm.total_in >> 24) & 0xff); + } + else + { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s.wrap > 0) { s.wrap = -s.wrap; } + /* write the trailer only once! */ + return s.pending !== 0 ? Z_OK : Z_STREAM_END; +} + +function deflateEnd(strm) { + var status; + + if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { + return Z_STREAM_ERROR; + } + + status = strm.state.status; + if (status !== INIT_STATE && + status !== EXTRA_STATE && + status !== NAME_STATE && + status !== COMMENT_STATE && + status !== HCRC_STATE && + status !== BUSY_STATE && + status !== FINISH_STATE + ) { + return err(strm, Z_STREAM_ERROR); + } + + strm.state = null; + + return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK; +} + + +/* ========================================================================= + * Initializes the compression dictionary from the given byte + * sequence without producing any compressed output. + */ +function deflateSetDictionary(strm, dictionary) { + var dictLength = dictionary.length; + + var s; + var str, n; + var wrap; + var avail; + var next; + var input; + var tmpDict; + + if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { + return Z_STREAM_ERROR; + } + + s = strm.state; + wrap = s.wrap; + + if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) { + return Z_STREAM_ERROR; + } + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap === 1) { + /* adler32(strm->adler, dictionary, dictLength); */ + strm.adler = adler32(strm.adler, dictionary, dictLength, 0); + } + + s.wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s.w_size) { + if (wrap === 0) { /* already empty otherwise */ + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + /* use the tail */ + // dictionary = dictionary.slice(dictLength - s.w_size); + tmpDict = new utils.Buf8(s.w_size); + utils.arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0); + dictionary = tmpDict; + dictLength = s.w_size; + } + /* insert dictionary into window and hash */ + avail = strm.avail_in; + next = strm.next_in; + input = strm.input; + strm.avail_in = dictLength; + strm.next_in = 0; + strm.input = dictionary; + fill_window(s); + while (s.lookahead >= MIN_MATCH) { + str = s.strstart; + n = s.lookahead - (MIN_MATCH - 1); + do { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask; + + s.prev[str & s.w_mask] = s.head[s.ins_h]; + + s.head[s.ins_h] = str; + str++; + } while (--n); + s.strstart = str; + s.lookahead = MIN_MATCH - 1; + fill_window(s); + } + s.strstart += s.lookahead; + s.block_start = s.strstart; + s.insert = s.lookahead; + s.lookahead = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + strm.next_in = next; + strm.input = input; + strm.avail_in = avail; + s.wrap = wrap; + return Z_OK; +} + + +export { deflateInit, deflateInit2, deflateReset, deflateResetKeep, deflateSetHeader, deflate, deflateEnd, deflateSetDictionary }; +export var deflateInfo = 'pako deflate (from Nodeca project)'; + +/* Not implemented +exports.deflateBound = deflateBound; +exports.deflateCopy = deflateCopy; +exports.deflateParams = deflateParams; +exports.deflatePending = deflatePending; +exports.deflatePrime = deflatePrime; +exports.deflateTune = deflateTune; +*/ diff --git a/vendor/pako/lib/zlib/gzheader.js b/vendor/pako/lib/zlib/gzheader.js new file mode 100644 index 0000000..2ec586d --- /dev/null +++ b/vendor/pako/lib/zlib/gzheader.js @@ -0,0 +1,35 @@ +export default function GZheader() { + /* true if compressed data believed to be text */ + this.text = 0; + /* modification time */ + this.time = 0; + /* extra flags (not used when writing a gzip file) */ + this.xflags = 0; + /* operating system */ + this.os = 0; + /* pointer to extra field or Z_NULL if none */ + this.extra = null; + /* extra field length (valid if extra != Z_NULL) */ + this.extra_len = 0; // Actually, we don't need it in JS, + // but leave for few code modifications + + // + // Setup limits is not necessary because in js we should not preallocate memory + // for inflate use constant limit in 65536 bytes + // + + /* space at extra (only when reading header) */ + // this.extra_max = 0; + /* pointer to zero-terminated file name or Z_NULL */ + this.name = ''; + /* space at name (only when reading header) */ + // this.name_max = 0; + /* pointer to zero-terminated comment or Z_NULL */ + this.comment = ''; + /* space at comment (only when reading header) */ + // this.comm_max = 0; + /* true if there was or will be a header crc */ + this.hcrc = 0; + /* true when done reading gzip header (not used when writing a gzip file) */ + this.done = false; +} diff --git a/vendor/pako/lib/zlib/inffast.js b/vendor/pako/lib/zlib/inffast.js new file mode 100644 index 0000000..889dcc7 --- /dev/null +++ b/vendor/pako/lib/zlib/inffast.js @@ -0,0 +1,324 @@ +// See state defs from inflate.js +var BAD = 30; /* got a data error -- remain here until reset */ +var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state.mode === LEN + strm.avail_in >= 6 + strm.avail_out >= 258 + start >= strm.avail_out + state.bits < 8 + + On return, state.mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm.avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm.avail_out >= 258 for each loop to avoid checking for + output space. + */ +export default function inflate_fast(strm, start) { + var state; + var _in; /* local strm.input */ + var last; /* have enough input while in < last */ + var _out; /* local strm.output */ + var beg; /* inflate()'s initial strm.output */ + var end; /* while out < end, enough space available */ +//#ifdef INFLATE_STRICT + var dmax; /* maximum distance from zlib header */ +//#endif + var wsize; /* window size or zero if not using window */ + var whave; /* valid bytes in the window */ + var wnext; /* window write index */ + // Use `s_window` instead `window`, avoid conflict with instrumentation tools + var s_window; /* allocated sliding window, if wsize != 0 */ + var hold; /* local strm.hold */ + var bits; /* local strm.bits */ + var lcode; /* local strm.lencode */ + var dcode; /* local strm.distcode */ + var lmask; /* mask for first level of length codes */ + var dmask; /* mask for first level of distance codes */ + var here; /* retrieved table entry */ + var op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + var len; /* match length, unused bytes */ + var dist; /* match distance */ + var from; /* where to copy match from */ + var from_source; + + + var input, output; // JS specific, because we have no pointers + + /* copy state to local variables */ + state = strm.state; + //here = state.here; + _in = strm.next_in; + input = strm.input; + last = _in + (strm.avail_in - 5); + _out = strm.next_out; + output = strm.output; + beg = _out - (start - strm.avail_out); + end = _out + (strm.avail_out - 257); +//#ifdef INFLATE_STRICT + dmax = state.dmax; +//#endif + wsize = state.wsize; + whave = state.whave; + wnext = state.wnext; + s_window = state.window; + hold = state.hold; + bits = state.bits; + lcode = state.lencode; + dcode = state.distcode; + lmask = (1 << state.lenbits) - 1; + dmask = (1 << state.distbits) - 1; + + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + top: + do { + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + + here = lcode[hold & lmask]; + + dolen: + for (;;) { // Goto emulation + op = here >>> 24/*here.bits*/; + hold >>>= op; + bits -= op; + op = (here >>> 16) & 0xff/*here.op*/; + if (op === 0) { /* literal */ + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + output[_out++] = here & 0xffff/*here.val*/; + } + else if (op & 16) { /* length base */ + len = here & 0xffff/*here.val*/; + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + len += hold & ((1 << op) - 1); + hold >>>= op; + bits -= op; + } + //Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + here = dcode[hold & dmask]; + + dodist: + for (;;) { // goto emulation + op = here >>> 24/*here.bits*/; + hold >>>= op; + bits -= op; + op = (here >>> 16) & 0xff/*here.op*/; + + if (op & 16) { /* distance base */ + dist = here & 0xffff/*here.val*/; + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + } + dist += hold & ((1 << op) - 1); +//#ifdef INFLATE_STRICT + if (dist > dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break top; + } +//#endif + hold >>>= op; + bits -= op; + //Tracevv((stderr, "inflate: distance %u\n", dist)); + op = _out - beg; /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break top; + } + +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility +//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR +// if (len <= op - whave) { +// do { +// output[_out++] = 0; +// } while (--len); +// continue top; +// } +// len -= op - whave; +// do { +// output[_out++] = 0; +// } while (--op > whave); +// if (op === 0) { +// from = _out - dist; +// do { +// output[_out++] = output[from++]; +// } while (--len); +// continue top; +// } +//#endif + } + from = 0; // window index + from_source = s_window; + if (wnext === 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + output[_out++] = s_window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + output[_out++] = s_window[from++]; + } while (--op); + from = 0; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + output[_out++] = s_window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + output[_out++] = s_window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + while (len > 2) { + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + len -= 3; + } + if (len) { + output[_out++] = from_source[from++]; + if (len > 1) { + output[_out++] = from_source[from++]; + } + } + } + else { + from = _out - dist; /* copy direct from output */ + do { /* minimum length is three */ + output[_out++] = output[from++]; + output[_out++] = output[from++]; + output[_out++] = output[from++]; + len -= 3; + } while (len > 2); + if (len) { + output[_out++] = output[from++]; + if (len > 1) { + output[_out++] = output[from++]; + } + } + } + } + else if ((op & 64) === 0) { /* 2nd level distance code */ + here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; + continue dodist; + } + else { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break top; + } + + break; // need to emulate goto via "continue" + } + } + else if ((op & 64) === 0) { /* 2nd level length code */ + here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; + continue dolen; + } + else if (op & 32) { /* end-of-block */ + //Tracevv((stderr, "inflate: end of block\n")); + state.mode = TYPE; + break top; + } + else { + strm.msg = 'invalid literal/length code'; + state.mode = BAD; + break top; + } + + break; // need to emulate goto via "continue" + } + } while (_in < last && _out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + _in -= len; + bits -= len << 3; + hold &= (1 << bits) - 1; + + /* update state and return */ + strm.next_in = _in; + strm.next_out = _out; + strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last)); + strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end)); + state.hold = hold; + state.bits = bits; + return; +}; diff --git a/vendor/pako/lib/zlib/inflate.js b/vendor/pako/lib/zlib/inflate.js new file mode 100644 index 0000000..1d2063b --- /dev/null +++ b/vendor/pako/lib/zlib/inflate.js @@ -0,0 +1,1527 @@ +import * as utils from "../utils/common.js"; +import adler32 from "./adler32.js"; +import crc32 from "./crc32.js"; +import inflate_fast from "./inffast.js"; +import inflate_table from "./inftrees.js"; + +var CODES = 0; +var LENS = 1; +var DISTS = 2; + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +/* Allowed flush values; see deflate() and inflate() below for details */ +//export const Z_NO_FLUSH = 0; +//export const Z_PARTIAL_FLUSH = 1; +//export const Z_SYNC_FLUSH = 2; +//export const Z_FULL_FLUSH = 3; +export const Z_FINISH = 4; +export const Z_BLOCK = 5; +export const Z_TREES = 6; + + +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ +export const Z_OK = 0; +export const Z_STREAM_END = 1; +export const Z_NEED_DICT = 2; +//export const Z_ERRNO = -1; +export const Z_STREAM_ERROR = -2; +export const Z_DATA_ERROR = -3; +export const Z_MEM_ERROR = -4; +export const Z_BUF_ERROR = -5; +//export const Z_VERSION_ERROR = -6; + +/* The deflate compression method */ +export const Z_DEFLATED = 8; + + +/* STATES ====================================================================*/ +/* ===========================================================================*/ + + +var HEAD = 1; /* i: waiting for magic header */ +var FLAGS = 2; /* i: waiting for method and flags (gzip) */ +var TIME = 3; /* i: waiting for modification time (gzip) */ +var OS = 4; /* i: waiting for extra flags and operating system (gzip) */ +var EXLEN = 5; /* i: waiting for extra length (gzip) */ +var EXTRA = 6; /* i: waiting for extra bytes (gzip) */ +var NAME = 7; /* i: waiting for end of file name (gzip) */ +var COMMENT = 8; /* i: waiting for end of comment (gzip) */ +var HCRC = 9; /* i: waiting for header crc (gzip) */ +var DICTID = 10; /* i: waiting for dictionary check value */ +var DICT = 11; /* waiting for inflateSetDictionary() call */ +var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ +var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */ +var STORED = 14; /* i: waiting for stored size (length and complement) */ +var COPY_ = 15; /* i/o: same as COPY below, but only first time in */ +var COPY = 16; /* i/o: waiting for input or output to copy stored block */ +var TABLE = 17; /* i: waiting for dynamic block table lengths */ +var LENLENS = 18; /* i: waiting for code length code lengths */ +var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */ +var LEN_ = 20; /* i: same as LEN below, but only first time in */ +var LEN = 21; /* i: waiting for length/lit/eob code */ +var LENEXT = 22; /* i: waiting for length extra bits */ +var DIST = 23; /* i: waiting for distance code */ +var DISTEXT = 24; /* i: waiting for distance extra bits */ +var MATCH = 25; /* o: waiting for output space to copy string */ +var LIT = 26; /* o: waiting for output space to write literal */ +var CHECK = 27; /* i: waiting for 32-bit check value */ +var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */ +var DONE = 29; /* finished check, done -- remain here until reset */ +var BAD = 30; /* got a data error -- remain here until reset */ +var MEM = 31; /* got an inflate() memory error -- remain here until reset */ +var SYNC = 32; /* looking for synchronization bytes to restart inflate() */ + +/* ===========================================================================*/ + + + +var ENOUGH_LENS = 852; +var ENOUGH_DISTS = 592; +//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + +var MAX_WBITS = 15; +/* 32K LZ77 window */ +var DEF_WBITS = MAX_WBITS; + + +function zswap32(q) { + return (((q >>> 24) & 0xff) + + ((q >>> 8) & 0xff00) + + ((q & 0xff00) << 8) + + ((q & 0xff) << 24)); +} + + +function InflateState() { + this.mode = 0; /* current inflate mode */ + this.last = false; /* true if processing last block */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.havedict = false; /* true if dictionary provided */ + this.flags = 0; /* gzip header method and flags (0 if zlib) */ + this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */ + this.check = 0; /* protected copy of check value */ + this.total = 0; /* protected copy of output count */ + // TODO: may be {} + this.head = null; /* where to save gzip header information */ + + /* sliding window */ + this.wbits = 0; /* log base 2 of requested window size */ + this.wsize = 0; /* window size or zero if not using window */ + this.whave = 0; /* valid bytes in the window */ + this.wnext = 0; /* window write index */ + this.window = null; /* allocated sliding window, if needed */ + + /* bit accumulator */ + this.hold = 0; /* input bit accumulator */ + this.bits = 0; /* number of bits in "in" */ + + /* for string and stored block copying */ + this.length = 0; /* literal or length of data to copy */ + this.offset = 0; /* distance back to copy string from */ + + /* for table and code decoding */ + this.extra = 0; /* extra bits needed */ + + /* fixed and dynamic code tables */ + this.lencode = null; /* starting table for length/literal codes */ + this.distcode = null; /* starting table for distance codes */ + this.lenbits = 0; /* index bits for lencode */ + this.distbits = 0; /* index bits for distcode */ + + /* dynamic table building */ + this.ncode = 0; /* number of code length code lengths */ + this.nlen = 0; /* number of length code lengths */ + this.ndist = 0; /* number of distance code lengths */ + this.have = 0; /* number of code lengths in lens[] */ + this.next = null; /* next available space in codes[] */ + + this.lens = new utils.Buf16(320); /* temporary storage for code lengths */ + this.work = new utils.Buf16(288); /* work area for code table building */ + + /* + because we don't have pointers in js, we use lencode and distcode directly + as buffers so we don't need codes + */ + //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */ + this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */ + this.distdyn = null; /* dynamic table for distance codes (JS specific) */ + this.sane = 0; /* if false, allow invalid distance too far */ + this.back = 0; /* bits back of last unprocessed length/lit */ + this.was = 0; /* initial length of match */ +} + +function inflateResetKeep(strm) { + var state; + + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + strm.total_in = strm.total_out = state.total = 0; + strm.msg = ''; /*Z_NULL*/ + if (state.wrap) { /* to support ill-conceived Java test suite */ + strm.adler = state.wrap & 1; + } + state.mode = HEAD; + state.last = 0; + state.havedict = 0; + state.dmax = 32768; + state.head = null/*Z_NULL*/; + state.hold = 0; + state.bits = 0; + //state.lencode = state.distcode = state.next = state.codes; + state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS); + state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS); + + state.sane = 1; + state.back = -1; + //Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +function inflateReset(strm) { + var state; + + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + state.wsize = 0; + state.whave = 0; + state.wnext = 0; + return inflateResetKeep(strm); + +} + +function inflateReset2(strm, windowBits) { + var wrap; + var state; + + /* get the state */ + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 1; + if (windowBits < 48) { + windowBits &= 15; + } + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) { + return Z_STREAM_ERROR; + } + if (state.window !== null && state.wbits !== windowBits) { + state.window = null; + } + + /* update state and reset the rest of it */ + state.wrap = wrap; + state.wbits = windowBits; + return inflateReset(strm); +} + +function inflateInit2(strm, windowBits) { + var ret; + var state; + + if (!strm) { return Z_STREAM_ERROR; } + //strm.msg = Z_NULL; /* in case we return an error */ + + state = new InflateState(); + + //if (state === Z_NULL) return Z_MEM_ERROR; + //Tracev((stderr, "inflate: allocated\n")); + strm.state = state; + state.window = null/*Z_NULL*/; + ret = inflateReset2(strm, windowBits); + if (ret !== Z_OK) { + strm.state = null/*Z_NULL*/; + } + return ret; +} + +function inflateInit(strm) { + return inflateInit2(strm, DEF_WBITS); +} + + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +var virgin = true; + +var lenfix, distfix; // We have no pointers in JS, so keep tables separate + +function fixedtables(state) { + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + var sym; + + lenfix = new utils.Buf32(512); + distfix = new utils.Buf32(32); + + /* literal/length table */ + sym = 0; + while (sym < 144) { state.lens[sym++] = 8; } + while (sym < 256) { state.lens[sym++] = 9; } + while (sym < 280) { state.lens[sym++] = 7; } + while (sym < 288) { state.lens[sym++] = 8; } + + inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 }); + + /* distance table */ + sym = 0; + while (sym < 32) { state.lens[sym++] = 5; } + + inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 }); + + /* do this just once */ + virgin = false; + } + + state.lencode = lenfix; + state.lenbits = 9; + state.distcode = distfix; + state.distbits = 5; +} + + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +function updatewindow(strm, src, end, copy) { + var dist; + var state = strm.state; + + /* if it hasn't been done already, allocate space for the window */ + if (state.window === null) { + state.wsize = 1 << state.wbits; + state.wnext = 0; + state.whave = 0; + + state.window = new utils.Buf8(state.wsize); + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state.wsize) { + utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0); + state.wnext = 0; + state.whave = state.wsize; + } + else { + dist = state.wsize - state.wnext; + if (dist > copy) { + dist = copy; + } + //zmemcpy(state->window + state->wnext, end - copy, dist); + utils.arraySet(state.window, src, end - copy, dist, state.wnext); + copy -= dist; + if (copy) { + //zmemcpy(state->window, end - copy, copy); + utils.arraySet(state.window, src, end - copy, copy, 0); + state.wnext = copy; + state.whave = state.wsize; + } + else { + state.wnext += dist; + if (state.wnext === state.wsize) { state.wnext = 0; } + if (state.whave < state.wsize) { state.whave += dist; } + } + } + return 0; +} + +function inflate(strm, flush) { + var state; + var input, output; // input/output buffers + var next; /* next input INDEX */ + var put; /* next output INDEX */ + var have, left; /* available input and output */ + var hold; /* bit buffer */ + var bits; /* bits in bit buffer */ + var _in, _out; /* save starting available input and output */ + var copy; /* number of stored or match bytes to copy */ + var from; /* where to copy match bytes from */ + var from_source; + var here = 0; /* current decoding table entry */ + var here_bits, here_op, here_val; // paked "here" denormalized (JS specific) + //var last; /* parent table entry */ + var last_bits, last_op, last_val; // paked "last" denormalized (JS specific) + var len; /* length to copy for repeats, bits to drop */ + var ret; /* return code */ + var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */ + var opts; + + var n; // temporary var for NEED_BITS + + var order = /* permutation of code lengths */ + [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]; + + + if (!strm || !strm.state || !strm.output || + (!strm.input && strm.avail_in !== 0)) { + return Z_STREAM_ERROR; + } + + state = strm.state; + if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */ + + + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + _in = have; + _out = left; + ret = Z_OK; + + inf_leave: // goto emulation + for (;;) { + switch (state.mode) { + case HEAD: + if (state.wrap === 0) { + state.mode = TYPEDO; + break; + } + //=== NEEDBITS(16); + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */ + state.check = 0/*crc32(0L, Z_NULL, 0)*/; + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = FLAGS; + break; + } + state.flags = 0; /* expect zlib header */ + if (state.head) { + state.head.done = false; + } + if (!(state.wrap & 1) || /* check if zlib header allowed */ + (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) { + strm.msg = 'incorrect header check'; + state.mode = BAD; + break; + } + if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// + len = (hold & 0x0f)/*BITS(4)*/ + 8; + if (state.wbits === 0) { + state.wbits = len; + } + else if (len > state.wbits) { + strm.msg = 'invalid window size'; + state.mode = BAD; + break; + } + state.dmax = 1 << len; + //Tracev((stderr, "inflate: zlib header ok\n")); + strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; + state.mode = hold & 0x200 ? DICTID : TYPE; + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + break; + case FLAGS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.flags = hold; + if ((state.flags & 0xff) !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + if (state.flags & 0xe000) { + strm.msg = 'unknown header flags set'; + state.mode = BAD; + break; + } + if (state.head) { + state.head.text = ((hold >> 8) & 1); + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = TIME; + /* falls through */ + case TIME: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (state.head) { + state.head.time = hold; + } + if (state.flags & 0x0200) { + //=== CRC4(state.check, hold) + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + hbuf[2] = (hold >>> 16) & 0xff; + hbuf[3] = (hold >>> 24) & 0xff; + state.check = crc32(state.check, hbuf, 4, 0); + //=== + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = OS; + /* falls through */ + case OS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (state.head) { + state.head.xflags = (hold & 0xff); + state.head.os = (hold >> 8); + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = EXLEN; + /* falls through */ + case EXLEN: + if (state.flags & 0x0400) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.length = hold; + if (state.head) { + state.head.extra_len = hold; + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } + else if (state.head) { + state.head.extra = null/*Z_NULL*/; + } + state.mode = EXTRA; + /* falls through */ + case EXTRA: + if (state.flags & 0x0400) { + copy = state.length; + if (copy > have) { copy = have; } + if (copy) { + if (state.head) { + len = state.head.extra_len - state.length; + if (!state.head.extra) { + // Use untyped array for more conveniend processing later + state.head.extra = new Array(state.head.extra_len); + } + utils.arraySet( + state.head.extra, + input, + next, + // extra field is limited to 65536 bytes + // - no need for additional size check + copy, + /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ + len + ); + //zmemcpy(state.head.extra + len, next, + // len + copy > state.head.extra_max ? + // state.head.extra_max - len : copy); + } + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + state.length -= copy; + } + if (state.length) { break inf_leave; } + } + state.length = 0; + state.mode = NAME; + /* falls through */ + case NAME: + if (state.flags & 0x0800) { + if (have === 0) { break inf_leave; } + copy = 0; + do { + // TODO: 2 or 1 bytes? + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + if (state.head && len && + (state.length < 65536 /*state.head.name_max*/)) { + state.head.name += String.fromCharCode(len); + } + } while (len && copy < have); + + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + if (len) { break inf_leave; } + } + else if (state.head) { + state.head.name = null; + } + state.length = 0; + state.mode = COMMENT; + /* falls through */ + case COMMENT: + if (state.flags & 0x1000) { + if (have === 0) { break inf_leave; } + copy = 0; + do { + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + if (state.head && len && + (state.length < 65536 /*state.head.comm_max*/)) { + state.head.comment += String.fromCharCode(len); + } + } while (len && copy < have); + if (state.flags & 0x0200) { + state.check = crc32(state.check, input, copy, next); + } + have -= copy; + next += copy; + if (len) { break inf_leave; } + } + else if (state.head) { + state.head.comment = null; + } + state.mode = HCRC; + /* falls through */ + case HCRC: + if (state.flags & 0x0200) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (hold !== (state.check & 0xffff)) { + strm.msg = 'header crc mismatch'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } + if (state.head) { + state.head.hcrc = ((state.flags >> 9) & 1); + state.head.done = true; + } + strm.adler = state.check = 0; + state.mode = TYPE; + break; + case DICTID: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + strm.adler = state.check = zswap32(hold); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = DICT; + /* falls through */ + case DICT: + if (state.havedict === 0) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + return Z_NEED_DICT; + } + strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; + state.mode = TYPE; + /* falls through */ + case TYPE: + if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; } + /* falls through */ + case TYPEDO: + if (state.last) { + //--- BYTEBITS() ---// + hold >>>= bits & 7; + bits -= bits & 7; + //---// + state.mode = CHECK; + break; + } + //=== NEEDBITS(3); */ + while (bits < 3) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.last = (hold & 0x01)/*BITS(1)*/; + //--- DROPBITS(1) ---// + hold >>>= 1; + bits -= 1; + //---// + + switch ((hold & 0x03)/*BITS(2)*/) { + case 0: /* stored block */ + //Tracev((stderr, "inflate: stored block%s\n", + // state.last ? " (last)" : "")); + state.mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + //Tracev((stderr, "inflate: fixed codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = LEN_; /* decode codes */ + if (flush === Z_TREES) { + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break inf_leave; + } + break; + case 2: /* dynamic block */ + //Tracev((stderr, "inflate: dynamic codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = TABLE; + break; + case 3: + strm.msg = 'invalid block type'; + state.mode = BAD; + } + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break; + case STORED: + //--- BYTEBITS() ---// /* go to byte boundary */ + hold >>>= bits & 7; + bits -= bits & 7; + //---// + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) { + strm.msg = 'invalid stored block lengths'; + state.mode = BAD; + break; + } + state.length = hold & 0xffff; + //Tracev((stderr, "inflate: stored length %u\n", + // state.length)); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = COPY_; + if (flush === Z_TREES) { break inf_leave; } + /* falls through */ + case COPY_: + state.mode = COPY; + /* falls through */ + case COPY: + copy = state.length; + if (copy) { + if (copy > have) { copy = have; } + if (copy > left) { copy = left; } + if (copy === 0) { break inf_leave; } + //--- zmemcpy(put, next, copy); --- + utils.arraySet(output, input, next, copy, put); + //---// + have -= copy; + next += copy; + left -= copy; + put += copy; + state.length -= copy; + break; + } + //Tracev((stderr, "inflate: stored end\n")); + state.mode = TYPE; + break; + case TABLE: + //=== NEEDBITS(14); */ + while (bits < 14) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4; + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// +//#ifndef PKZIP_BUG_WORKAROUND + if (state.nlen > 286 || state.ndist > 30) { + strm.msg = 'too many length or distance symbols'; + state.mode = BAD; + break; + } +//#endif + //Tracev((stderr, "inflate: table sizes ok\n")); + state.have = 0; + state.mode = LENLENS; + /* falls through */ + case LENLENS: + while (state.have < state.ncode) { + //=== NEEDBITS(3); + while (bits < 3) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.lens[order[state.have++]] = (hold & 0x07);//BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } + while (state.have < 19) { + state.lens[order[state.have++]] = 0; + } + // We have separate tables & no pointers. 2 commented lines below not needed. + //state.next = state.codes; + //state.lencode = state.next; + // Switch to use dynamic table + state.lencode = state.lendyn; + state.lenbits = 7; + + opts = { bits: state.lenbits }; + ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); + state.lenbits = opts.bits; + + if (ret) { + strm.msg = 'invalid code lengths set'; + state.mode = BAD; + break; + } + //Tracev((stderr, "inflate: code lengths ok\n")); + state.have = 0; + state.mode = CODELENS; + /* falls through */ + case CODELENS: + while (state.have < state.nlen + state.ndist) { + for (;;) { + here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if (here_val < 16) { + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.lens[state.have++] = here_val; + } + else { + if (here_val === 16) { + //=== NEEDBITS(here.bits + 2); + n = here_bits + 2; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + if (state.have === 0) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + len = state.lens[state.have - 1]; + copy = 3 + (hold & 0x03);//BITS(2); + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + } + else if (here_val === 17) { + //=== NEEDBITS(here.bits + 3); + n = here_bits + 3; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 3 + (hold & 0x07);//BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } + else { + //=== NEEDBITS(here.bits + 7); + n = here_bits + 7; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 11 + (hold & 0x7f);//BITS(7); + //--- DROPBITS(7) ---// + hold >>>= 7; + bits -= 7; + //---// + } + if (state.have + copy > state.nlen + state.ndist) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + while (copy--) { + state.lens[state.have++] = len; + } + } + } + + /* handle error breaks in while */ + if (state.mode === BAD) { break; } + + /* check for end-of-block code (better have one) */ + if (state.lens[256] === 0) { + strm.msg = 'invalid code -- missing end-of-block'; + state.mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state.lenbits = 9; + + opts = { bits: state.lenbits }; + ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.lenbits = opts.bits; + // state.lencode = state.next; + + if (ret) { + strm.msg = 'invalid literal/lengths set'; + state.mode = BAD; + break; + } + + state.distbits = 6; + //state.distcode.copy(state.codes); + // Switch to use dynamic table + state.distcode = state.distdyn; + opts = { bits: state.distbits }; + ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.distbits = opts.bits; + // state.distcode = state.next; + + if (ret) { + strm.msg = 'invalid distances set'; + state.mode = BAD; + break; + } + //Tracev((stderr, 'inflate: codes ok\n')); + state.mode = LEN_; + if (flush === Z_TREES) { break inf_leave; } + /* falls through */ + case LEN_: + state.mode = LEN; + /* falls through */ + case LEN: + if (have >= 6 && left >= 258) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + inflate_fast(strm, _out); + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + if (state.mode === TYPE) { + state.back = -1; + } + break; + } + state.back = 0; + for (;;) { + here = state.lencode[hold & ((1 << state.lenbits) - 1)]; /*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if (here_bits <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if (here_op && (here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = state.lencode[last_val + + ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)]; + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((last_bits + here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + state.length = here_val; + if (here_op === 0) { + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + state.mode = LIT; + break; + } + if (here_op & 32) { + //Tracevv((stderr, "inflate: end of block\n")); + state.back = -1; + state.mode = TYPE; + break; + } + if (here_op & 64) { + strm.msg = 'invalid literal/length code'; + state.mode = BAD; + break; + } + state.extra = here_op & 15; + state.mode = LENEXT; + /* falls through */ + case LENEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } + //Tracevv((stderr, "inflate: length %u\n", state.length)); + state.was = state.length; + state.mode = DIST; + /* falls through */ + case DIST: + for (;;) { + here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if ((here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = state.distcode[last_val + + ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)]; + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((last_bits + here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + if (here_op & 64) { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break; + } + state.offset = here_val; + state.extra = (here_op) & 15; + state.mode = DISTEXT; + /* falls through */ + case DISTEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } +//#ifdef INFLATE_STRICT + if (state.offset > state.dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } +//#endif + //Tracevv((stderr, "inflate: distance %u\n", state.offset)); + state.mode = MATCH; + /* falls through */ + case MATCH: + if (left === 0) { break inf_leave; } + copy = _out - left; + if (state.offset > copy) { /* copy from window */ + copy = state.offset - copy; + if (copy > state.whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility +//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR +// Trace((stderr, "inflate.c too far\n")); +// copy -= state.whave; +// if (copy > state.length) { copy = state.length; } +// if (copy > left) { copy = left; } +// left -= copy; +// state.length -= copy; +// do { +// output[put++] = 0; +// } while (--copy); +// if (state.length === 0) { state.mode = LEN; } +// break; +//#endif + } + if (copy > state.wnext) { + copy -= state.wnext; + from = state.wsize - copy; + } + else { + from = state.wnext - copy; + } + if (copy > state.length) { copy = state.length; } + from_source = state.window; + } + else { /* copy from output */ + from_source = output; + from = put - state.offset; + copy = state.length; + } + if (copy > left) { copy = left; } + left -= copy; + state.length -= copy; + do { + output[put++] = from_source[from++]; + } while (--copy); + if (state.length === 0) { state.mode = LEN; } + break; + case LIT: + if (left === 0) { break inf_leave; } + output[put++] = state.length; + left--; + state.mode = LEN; + break; + case CHECK: + if (state.wrap) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + // Use '|' insdead of '+' to make sure that result is signed + hold |= input[next++] << bits; + bits += 8; + } + //===// + _out -= left; + strm.total_out += _out; + state.total += _out; + if (_out) { + strm.adler = state.check = + /*UPDATE(state.check, put - _out, _out);*/ + (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out)); + + } + _out = left; + // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too + if ((state.flags ? hold : zswap32(hold)) !== state.check) { + strm.msg = 'incorrect data check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: check matches trailer\n")); + } + state.mode = LENGTH; + /* falls through */ + case LENGTH: + if (state.wrap && state.flags) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (hold !== (state.total & 0xffffffff)) { + strm.msg = 'incorrect length check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: length matches trailer\n")); + } + state.mode = DONE; + /* falls through */ + case DONE: + ret = Z_STREAM_END; + break inf_leave; + case BAD: + ret = Z_DATA_ERROR; + break inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + /* falls through */ + default: + return Z_STREAM_ERROR; + } + } + + // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + + if (state.wsize || (_out !== strm.avail_out && state.mode < BAD && + (state.mode < CHECK || flush !== Z_FINISH))) { + if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) { + state.mode = MEM; + return Z_MEM_ERROR; + } + } + _in -= strm.avail_in; + _out -= strm.avail_out; + strm.total_in += _in; + strm.total_out += _out; + state.total += _out; + if (state.wrap && _out) { + strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/ + (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out)); + } + strm.data_type = state.bits + (state.last ? 64 : 0) + + (state.mode === TYPE ? 128 : 0) + + (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); + if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) { + ret = Z_BUF_ERROR; + } + return ret; +} + +function inflateEnd(strm) { + + if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) { + return Z_STREAM_ERROR; + } + + var state = strm.state; + if (state.window) { + state.window = null; + } + strm.state = null; + return Z_OK; +} + +function inflateGetHeader(strm, head) { + var state; + + /* check state */ + if (!strm || !strm.state) { return Z_STREAM_ERROR; } + state = strm.state; + if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; } + + /* save header structure */ + state.head = head; + head.done = false; + return Z_OK; +} + +function inflateSetDictionary(strm, dictionary) { + var dictLength = dictionary.length; + + var state; + var dictid; + var ret; + + /* check state */ + if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR; } + state = strm.state; + + if (state.wrap !== 0 && state.mode !== DICT) { + return Z_STREAM_ERROR; + } + + /* check for correct dictionary identifier */ + if (state.mode === DICT) { + dictid = 1; /* adler32(0, null, 0)*/ + /* dictid = adler32(dictid, dictionary, dictLength); */ + dictid = adler32(dictid, dictionary, dictLength, 0); + if (dictid !== state.check) { + return Z_DATA_ERROR; + } + } + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary, dictLength, dictLength); + if (ret) { + state.mode = MEM; + return Z_MEM_ERROR; + } + state.havedict = 1; + // Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +export { inflateReset, inflateReset2, inflateResetKeep, inflateInit, inflateInit2, inflate, inflateEnd, inflateGetHeader, inflateSetDictionary }; +export var inflateInfo = 'pako inflate (from Nodeca project)'; + +/* Not implemented +exports.inflateCopy = inflateCopy; +exports.inflateGetDictionary = inflateGetDictionary; +exports.inflateMark = inflateMark; +exports.inflatePrime = inflatePrime; +exports.inflateSync = inflateSync; +exports.inflateSyncPoint = inflateSyncPoint; +exports.inflateUndermine = inflateUndermine; +*/ diff --git a/vendor/pako/lib/zlib/inftrees.js b/vendor/pako/lib/zlib/inftrees.js new file mode 100644 index 0000000..78b7c9e --- /dev/null +++ b/vendor/pako/lib/zlib/inftrees.js @@ -0,0 +1,322 @@ +import * as utils from "../utils/common.js"; + +var MAXBITS = 15; +var ENOUGH_LENS = 852; +var ENOUGH_DISTS = 592; +//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + +var CODES = 0; +var LENS = 1; +var DISTS = 2; + +var lbase = [ /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 +]; + +var lext = [ /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78 +]; + +var dbase = [ /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0 +]; + +var dext = [ /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64 +]; + +export default function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) +{ + var bits = opts.bits; + //here = opts.here; /* table entry for duplication */ + + var len = 0; /* a code's length in bits */ + var sym = 0; /* index of code symbols */ + var min = 0, max = 0; /* minimum and maximum code lengths */ + var root = 0; /* number of index bits for root table */ + var curr = 0; /* number of index bits for current table */ + var drop = 0; /* code bits to drop for sub-table */ + var left = 0; /* number of prefix codes available */ + var used = 0; /* code entries in table used */ + var huff = 0; /* Huffman code */ + var incr; /* for incrementing code, index */ + var fill; /* index for replicating entries */ + var low; /* low bits for current root entry */ + var mask; /* mask for low root bits */ + var next; /* next available space in table */ + var base = null; /* base value table to use */ + var base_index = 0; +// var shoextra; /* extra bits table to use */ + var end; /* use base and extra for symbol > end */ + var count = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */ + var offs = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */ + var extra = null; + var extra_index = 0; + + var here_bits, here_op, here_val; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) { + count[len] = 0; + } + for (sym = 0; sym < codes; sym++) { + count[lens[lens_index + sym]]++; + } + + /* bound code lengths, force root to be within code lengths */ + root = bits; + for (max = MAXBITS; max >= 1; max--) { + if (count[max] !== 0) { break; } + } + if (root > max) { + root = max; + } + if (max === 0) { /* no symbols to code at all */ + //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ + //table.bits[opts.table_index] = 1; //here.bits = (var char)1; + //table.val[opts.table_index++] = 0; //here.val = (var short)0; + table[table_index++] = (1 << 24) | (64 << 16) | 0; + + + //table.op[opts.table_index] = 64; + //table.bits[opts.table_index] = 1; + //table.val[opts.table_index++] = 0; + table[table_index++] = (1 << 24) | (64 << 16) | 0; + + opts.bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) { + if (count[min] !== 0) { break; } + } + if (root < min) { + root = min; + } + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) { + return -1; + } /* over-subscribed */ + } + if (left > 0 && (type === CODES || max !== 1)) { + return -1; /* incomplete set */ + } + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) { + offs[len + 1] = offs[len] + count[len]; + } + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) { + if (lens[lens_index + sym] !== 0) { + work[offs[lens[lens_index + sym]]++] = sym; + } + } + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + // poor man optimization - use if-else instead of switch, + // to avoid deopts in old v8 + if (type === CODES) { + base = extra = work; /* dummy value--not used */ + end = 19; + + } else if (type === LENS) { + base = lbase; + base_index -= 257; + extra = lext; + extra_index -= 257; + end = 256; + + } else { /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize opts for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = table_index; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = -1; /* trigger new sub-table when len > root */ + used = 1 << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type === LENS && used > ENOUGH_LENS) || + (type === DISTS && used > ENOUGH_DISTS)) { + return 1; + } + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here_bits = len - drop; + if (work[sym] < end) { + here_op = 0; + here_val = work[sym]; + } + else if (work[sym] > end) { + here_op = extra[extra_index + work[sym]]; + here_val = base[base_index + work[sym]]; + } + else { + here_op = 32 + 64; /* end of block */ + here_val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1 << (len - drop); + fill = 1 << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0; + } while (fill !== 0); + + /* backwards increment the len-bit code huff */ + incr = 1 << (len - 1); + while (huff & incr) { + incr >>= 1; + } + if (incr !== 0) { + huff &= incr - 1; + huff += incr; + } else { + huff = 0; + } + + /* go to next symbol, update count, len */ + sym++; + if (--count[len] === 0) { + if (len === max) { break; } + len = lens[lens_index + work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) !== low) { + /* if first time, transition to sub-tables */ + if (drop === 0) { + drop = root; + } + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = 1 << curr; + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) { break; } + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1 << curr; + if ((type === LENS && used > ENOUGH_LENS) || + (type === DISTS && used > ENOUGH_DISTS)) { + return 1; + } + + /* point entry in root table to sub-table */ + low = huff & mask; + /*table.op[low] = curr; + table.bits[low] = root; + table.val[low] = next - opts.table_index;*/ + table[low] = (root << 24) | (curr << 16) | (next - table_index) |0; + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff !== 0) { + //table.op[next + huff] = 64; /* invalid code marker */ + //table.bits[next + huff] = len - drop; + //table.val[next + huff] = 0; + table[next + huff] = ((len - drop) << 24) | (64 << 16) |0; + } + + /* set return parameters */ + //opts.table_index += used; + opts.bits = root; + return 0; +}; diff --git a/vendor/pako/lib/zlib/messages.js b/vendor/pako/lib/zlib/messages.js new file mode 100644 index 0000000..f95cb70 --- /dev/null +++ b/vendor/pako/lib/zlib/messages.js @@ -0,0 +1,11 @@ +export default { + 2: 'need dictionary', /* Z_NEED_DICT 2 */ + 1: 'stream end', /* Z_STREAM_END 1 */ + 0: '', /* Z_OK 0 */ + '-1': 'file error', /* Z_ERRNO (-1) */ + '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ + '-3': 'data error', /* Z_DATA_ERROR (-3) */ + '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ + '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ + '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ +}; diff --git a/vendor/pako/lib/zlib/trees.js b/vendor/pako/lib/zlib/trees.js new file mode 100644 index 0000000..a69b8a5 --- /dev/null +++ b/vendor/pako/lib/zlib/trees.js @@ -0,0 +1,1195 @@ +import * as utils from "../utils/common.js"; + +/* Public constants ==========================================================*/ +/* ===========================================================================*/ + + +//var Z_FILTERED = 1; +//var Z_HUFFMAN_ONLY = 2; +//var Z_RLE = 3; +var Z_FIXED = 4; +//var Z_DEFAULT_STRATEGY = 0; + +/* Possible values of the data_type field (though see inflate()) */ +var Z_BINARY = 0; +var Z_TEXT = 1; +//var Z_ASCII = 1; // = Z_TEXT +var Z_UNKNOWN = 2; + +/*============================================================================*/ + + +function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } + +// From zutil.h + +var STORED_BLOCK = 0; +var STATIC_TREES = 1; +var DYN_TREES = 2; +/* The three kinds of block type */ + +var MIN_MATCH = 3; +var MAX_MATCH = 258; +/* The minimum and maximum match lengths */ + +// From deflate.h +/* =========================================================================== + * Internal compression state. + */ + +var LENGTH_CODES = 29; +/* number of length codes, not counting the special END_BLOCK code */ + +var LITERALS = 256; +/* number of literal bytes 0..255 */ + +var L_CODES = LITERALS + 1 + LENGTH_CODES; +/* number of Literal or Length codes, including the END_BLOCK code */ + +var D_CODES = 30; +/* number of distance codes */ + +var BL_CODES = 19; +/* number of codes used to transfer the bit lengths */ + +var HEAP_SIZE = 2 * L_CODES + 1; +/* maximum heap size */ + +var MAX_BITS = 15; +/* All codes must not exceed MAX_BITS bits */ + +var Buf_size = 16; +/* size of bit buffer in bi_buf */ + + +/* =========================================================================== + * Constants + */ + +var MAX_BL_BITS = 7; +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +var END_BLOCK = 256; +/* end of block literal code */ + +var REP_3_6 = 16; +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +var REPZ_3_10 = 17; +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +var REPZ_11_138 = 18; +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +/* eslint-disable comma-spacing,array-bracket-spacing */ +var extra_lbits = /* extra bits for each length code */ + [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]; + +var extra_dbits = /* extra bits for each distance code */ + [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]; + +var extra_blbits = /* extra bits for each bit length code */ + [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]; + +var bl_order = + [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]; +/* eslint-enable comma-spacing,array-bracket-spacing */ + +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +// We pre-fill arrays with 0 to avoid uninitialized gaps + +var DIST_CODE_LEN = 512; /* see definition of array dist_code below */ + +// !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1 +var static_ltree = new Array((L_CODES + 2) * 2); +zero(static_ltree); +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +var static_dtree = new Array(D_CODES * 2); +zero(static_dtree); +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +var _dist_code = new Array(DIST_CODE_LEN); +zero(_dist_code); +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +var _length_code = new Array(MAX_MATCH - MIN_MATCH + 1); +zero(_length_code); +/* length code for each normalized match length (0 == MIN_MATCH) */ + +var base_length = new Array(LENGTH_CODES); +zero(base_length); +/* First normalized length for each code (0 = MIN_MATCH) */ + +var base_dist = new Array(D_CODES); +zero(base_dist); +/* First normalized distance for each code (0 = distance of 1) */ + + +function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) { + + this.static_tree = static_tree; /* static tree or NULL */ + this.extra_bits = extra_bits; /* extra bits for each code or NULL */ + this.extra_base = extra_base; /* base index for extra_bits */ + this.elems = elems; /* max number of elements in the tree */ + this.max_length = max_length; /* max bit length for the codes */ + + // show if `static_tree` has data or dummy - needed for monomorphic objects + this.has_stree = static_tree && static_tree.length; +} + + +var static_l_desc; +var static_d_desc; +var static_bl_desc; + + +function TreeDesc(dyn_tree, stat_desc) { + this.dyn_tree = dyn_tree; /* the dynamic tree */ + this.max_code = 0; /* largest code with non zero frequency */ + this.stat_desc = stat_desc; /* the corresponding static tree */ +} + + + +function d_code(dist) { + return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; +} + + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +function put_short(s, w) { +// put_byte(s, (uch)((w) & 0xff)); +// put_byte(s, (uch)((ush)(w) >> 8)); + s.pending_buf[s.pending++] = (w) & 0xff; + s.pending_buf[s.pending++] = (w >>> 8) & 0xff; +} + + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +function send_bits(s, value, length) { + if (s.bi_valid > (Buf_size - length)) { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + put_short(s, s.bi_buf); + s.bi_buf = value >> (Buf_size - s.bi_valid); + s.bi_valid += length - Buf_size; + } else { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + s.bi_valid += length; + } +} + + +function send_code(s, c, tree) { + send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/); +} + + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +function bi_reverse(code, len) { + var res = 0; + do { + res |= code & 1; + code >>>= 1; + res <<= 1; + } while (--len > 0); + return res >>> 1; +} + + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +function bi_flush(s) { + if (s.bi_valid === 16) { + put_short(s, s.bi_buf); + s.bi_buf = 0; + s.bi_valid = 0; + + } else if (s.bi_valid >= 8) { + s.pending_buf[s.pending++] = s.bi_buf & 0xff; + s.bi_buf >>= 8; + s.bi_valid -= 8; + } +} + + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +function gen_bitlen(s, desc) +// deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ +{ + var tree = desc.dyn_tree; + var max_code = desc.max_code; + var stree = desc.stat_desc.static_tree; + var has_stree = desc.stat_desc.has_stree; + var extra = desc.stat_desc.extra_bits; + var base = desc.stat_desc.extra_base; + var max_length = desc.stat_desc.max_length; + var h; /* heap index */ + var n, m; /* iterate over the tree elements */ + var bits; /* bit length */ + var xbits; /* extra bits */ + var f; /* frequency */ + var overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) { + s.bl_count[bits] = 0; + } + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */ + + for (h = s.heap_max + 1; h < HEAP_SIZE; h++) { + n = s.heap[h]; + bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1; + if (bits > max_length) { + bits = max_length; + overflow++; + } + tree[n * 2 + 1]/*.Len*/ = bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) { continue; } /* not a leaf node */ + + s.bl_count[bits]++; + xbits = 0; + if (n >= base) { + xbits = extra[n - base]; + } + f = tree[n * 2]/*.Freq*/; + s.opt_len += f * (bits + xbits); + if (has_stree) { + s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits); + } + } + if (overflow === 0) { return; } + + // Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length - 1; + while (s.bl_count[bits] === 0) { bits--; } + s.bl_count[bits]--; /* move one leaf down the tree */ + s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ + s.bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits !== 0; bits--) { + n = s.bl_count[bits]; + while (n !== 0) { + m = s.heap[--h]; + if (m > max_code) { continue; } + if (tree[m * 2 + 1]/*.Len*/ !== bits) { + // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/; + tree[m * 2 + 1]/*.Len*/ = bits; + } + n--; + } + } +} + + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +function gen_codes(tree, max_code, bl_count) +// ct_data *tree; /* the tree to decorate */ +// int max_code; /* largest code with non zero frequency */ +// ushf *bl_count; /* number of codes at each bit length */ +{ + var next_code = new Array(MAX_BITS + 1); /* next code value for each bit length */ + var code = 0; /* running code value */ + var bits; /* bit index */ + var n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits - 1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + //Assert (code + bl_count[MAX_BITS]-1 == (1< length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES - 1; code++) { + base_length[code] = length; + for (n = 0; n < (1 << extra_lbits[code]); n++) { + _length_code[length++] = code; + } + } + //Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + _length_code[length - 1] = code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1 << extra_dbits[code]); n++) { + _dist_code[dist++] = code; + } + } + //Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for (; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { + _dist_code[256 + dist++] = code; + } + } + //Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) { + bl_count[bits] = 0; + } + + n = 0; + while (n <= 143) { + static_ltree[n * 2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + while (n <= 255) { + static_ltree[n * 2 + 1]/*.Len*/ = 9; + n++; + bl_count[9]++; + } + while (n <= 279) { + static_ltree[n * 2 + 1]/*.Len*/ = 7; + n++; + bl_count[7]++; + } + while (n <= 287) { + static_ltree[n * 2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes(static_ltree, L_CODES + 1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n * 2 + 1]/*.Len*/ = 5; + static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5); + } + + // Now data ready and we can init static trees + static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS); + static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS); + static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS); + + //static_init_done = true; +} + + +/* =========================================================================== + * Initialize a new block. + */ +function init_block(s) { + var n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; } + for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; } + for (n = 0; n < BL_CODES; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; } + + s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1; + s.opt_len = s.static_len = 0; + s.last_lit = s.matches = 0; +} + + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +function bi_windup(s) +{ + if (s.bi_valid > 8) { + put_short(s, s.bi_buf); + } else if (s.bi_valid > 0) { + //put_byte(s, (Byte)s->bi_buf); + s.pending_buf[s.pending++] = s.bi_buf; + } + s.bi_buf = 0; + s.bi_valid = 0; +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +function copy_block(s, buf, len, header) +//DeflateState *s; +//charf *buf; /* the input data */ +//unsigned len; /* its length */ +//int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + + if (header) { + put_short(s, len); + put_short(s, ~len); + } +// while (len--) { +// put_byte(s, *buf++); +// } + utils.arraySet(s.pending_buf, s.window, buf, len, s.pending); + s.pending += len; +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +function smaller(tree, n, m, depth) { + var _n2 = n * 2; + var _m2 = m * 2; + return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ || + (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m])); +} + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +function pqdownheap(s, tree, k) +// deflate_state *s; +// ct_data *tree; /* the tree to restore */ +// int k; /* node to move down */ +{ + var v = s.heap[k]; + var j = k << 1; /* left son of k */ + while (j <= s.heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s.heap_len && + smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s.heap[j], s.depth)) { break; } + + /* Exchange v with the smallest son */ + s.heap[k] = s.heap[j]; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s.heap[k] = v; +} + + +// inlined manually +// var SMALLEST = 1; + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +function compress_block(s, ltree, dtree) +// deflate_state *s; +// const ct_data *ltree; /* literal tree */ +// const ct_data *dtree; /* distance tree */ +{ + var dist; /* distance of matched string */ + var lc; /* match length or unmatched char (if dist == 0) */ + var lx = 0; /* running index in l_buf */ + var code; /* the code to send */ + var extra; /* number of extra bits to send */ + + if (s.last_lit !== 0) { + do { + dist = (s.pending_buf[s.d_buf + lx * 2] << 8) | (s.pending_buf[s.d_buf + lx * 2 + 1]); + lc = s.pending_buf[s.l_buf + lx]; + lx++; + + if (dist === 0) { + send_code(s, lc, ltree); /* send a literal byte */ + //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code + LITERALS + 1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra !== 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + //Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra !== 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + // "pendingBuf overflow"); + + } while (lx < s.last_lit); + } + + send_code(s, END_BLOCK, ltree); +} + + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +function build_tree(s, desc) +// deflate_state *s; +// tree_desc *desc; /* the tree descriptor */ +{ + var tree = desc.dyn_tree; + var stree = desc.stat_desc.static_tree; + var has_stree = desc.stat_desc.has_stree; + var elems = desc.stat_desc.elems; + var n, m; /* iterate over heap elements */ + var max_code = -1; /* largest code with non zero frequency */ + var node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s.heap_len = 0; + s.heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n * 2]/*.Freq*/ !== 0) { + s.heap[++s.heap_len] = max_code = n; + s.depth[n] = 0; + + } else { + tree[n * 2 + 1]/*.Len*/ = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s.heap_len < 2) { + node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); + tree[node * 2]/*.Freq*/ = 1; + s.depth[node] = 0; + s.opt_len--; + + if (has_stree) { + s.static_len -= stree[node * 2 + 1]/*.Len*/; + } + /* node is 0 or 1 so it does not have extra bits */ + } + desc.max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); } + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + //pqremove(s, tree, n); /* n = node of least frequency */ + /*** pqremove ***/ + n = s.heap[1/*SMALLEST*/]; + s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--]; + pqdownheap(s, tree, 1/*SMALLEST*/); + /***/ + + m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */ + + s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ + s.heap[--s.heap_max] = m; + + /* Create a new node father of n and m */ + tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/; + s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; + tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node; + + /* and insert the new node in the heap */ + s.heap[1/*SMALLEST*/] = node++; + pqdownheap(s, tree, 1/*SMALLEST*/); + + } while (s.heap_len >= 2); + + s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes(tree, max_code, s.bl_count); +} + + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +function scan_tree(s, tree, max_code) +// deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ +{ + var n; /* iterates over all tree elements */ + var prevlen = -1; /* last emitted length */ + var curlen; /* length of current code */ + + var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ + + var count = 0; /* repeat count of the current code */ + var max_count = 7; /* max repeat count */ + var min_count = 4; /* min repeat count */ + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + s.bl_tree[curlen * 2]/*.Freq*/ += count; + + } else if (curlen !== 0) { + + if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; } + s.bl_tree[REP_3_6 * 2]/*.Freq*/++; + + } else if (count <= 10) { + s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++; + + } else { + s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++; + } + + count = 0; + prevlen = curlen; + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; + } + } +} + + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +function send_tree(s, tree, max_code) +// deflate_state *s; +// ct_data *tree; /* the tree to be scanned */ +// int max_code; /* and its largest code of non zero frequency */ +{ + var n; /* iterates over all tree elements */ + var prevlen = -1; /* last emitted length */ + var curlen; /* length of current code */ + + var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ + + var count = 0; /* repeat count of the current code */ + var max_count = 7; /* max repeat count */ + var min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); + + } else if (curlen !== 0) { + if (curlen !== prevlen) { + send_code(s, curlen, s.bl_tree); + count--; + } + //Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s.bl_tree); + send_bits(s, count - 3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s.bl_tree); + send_bits(s, count - 3, 3); + + } else { + send_code(s, REPZ_11_138, s.bl_tree); + send_bits(s, count - 11, 7); + } + + count = 0; + prevlen = curlen; + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; + } + } +} + + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +function build_bl_tree(s) { + var max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, s.dyn_ltree, s.l_desc.max_code); + scan_tree(s, s.dyn_dtree, s.d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, s.bl_desc); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) { + if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) { + break; + } + } + /* Update opt_len to include the bit length tree and counts */ + s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; + //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + // s->opt_len, s->static_len)); + + return max_blindex; +} + + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +function send_all_trees(s, lcodes, dcodes, blcodes) +// deflate_state *s; +// int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + var rank; /* index in bl_order */ + + //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + // "too many codes"); + //Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3); + } + //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */ + //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */ + //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +function detect_data_type(s) { + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + var black_mask = 0xf3ffc07f; + var n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>>= 1) { + if ((black_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) { + return Z_BINARY; + } + } + + /* Check for textual ("white-listed") bytes. */ + if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 || + s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) { + return Z_TEXT; + } + for (n = 32; n < LITERALS; n++) { + if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) { + return Z_TEXT; + } + } + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + + +var static_init_done = false; + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +function _tr_init(s) +{ + + if (!static_init_done) { + tr_static_init(); + static_init_done = true; + } + + s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); + s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); + s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); + + s.bi_buf = 0; + s.bi_valid = 0; + + /* Initialize the first block of the first file: */ + init_block(s); +} + + +/* =========================================================================== + * Send a stored block + */ +function _tr_stored_block(s, buf, stored_len, last) +//DeflateState *s; +//charf *buf; /* input block */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); /* send block type */ + copy_block(s, buf, stored_len, true); /* with header */ +} + + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +function _tr_align(s) { + send_bits(s, STATIC_TREES << 1, 3); + send_code(s, END_BLOCK, static_ltree); + bi_flush(s); +} + + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +function _tr_flush_block(s, buf, stored_len, last) +//DeflateState *s; +//charf *buf; /* input block, or NULL if too old */ +//ulg stored_len; /* length of input block */ +//int last; /* one if this is the last block for a file */ +{ + var opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + var max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s.level > 0) { + + /* Check if the file is binary or text */ + if (s.strm.data_type === Z_UNKNOWN) { + s.strm.data_type = detect_data_type(s); + } + + /* Construct the literal and distance trees */ + build_tree(s, s.l_desc); + // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + + build_tree(s, s.d_desc); + // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s.opt_len + 3 + 7) >>> 3; + static_lenb = (s.static_len + 3 + 7) >>> 3; + + // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + // s->last_lit)); + + if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } + + } else { + // Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + + if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) { + /* 4: two words for the lengths */ + + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + + } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) { + + send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3); + compress_block(s, static_ltree, static_dtree); + + } else { + send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3); + send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1); + compress_block(s, s.dyn_ltree, s.dyn_dtree); + } + // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); + } + // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + // s->compressed_len-7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +function _tr_tally(s, dist, lc) +// deflate_state *s; +// unsigned dist; /* distance of matched string */ +// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + //var out_length, in_length, dcode; + + s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff; + s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff; + + s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; + s.last_lit++; + + if (dist === 0) { + /* lc is the unmatched char */ + s.dyn_ltree[lc * 2]/*.Freq*/++; + } else { + s.matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + //Assert((ush)dist < (ush)MAX_DIST(s) && + // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]/*.Freq*/++; + s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++; + } + +// (!) This block is disabled in zlib defailts, +// don't enable it for binary compatibility + +//#ifdef TRUNCATE_BLOCK +// /* Try to guess if it is profitable to stop the current block here */ +// if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { +// /* Compute an upper bound for the compressed length */ +// out_length = s.last_lit*8; +// in_length = s.strstart - s.block_start; +// +// for (dcode = 0; dcode < D_CODES; dcode++) { +// out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); +// } +// out_length >>>= 3; +// //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", +// // s->last_lit, in_length, out_length, +// // 100L - out_length*100L/in_length)); +// if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { +// return true; +// } +// } +//#endif + + return (s.last_lit === s.lit_bufsize - 1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +export { _tr_init, _tr_stored_block, _tr_flush_block, _tr_tally, _tr_align }; diff --git a/vendor/pako/lib/zlib/zstream.js b/vendor/pako/lib/zlib/zstream.js new file mode 100644 index 0000000..e7e674e --- /dev/null +++ b/vendor/pako/lib/zlib/zstream.js @@ -0,0 +1,24 @@ +export default function ZStream() { + /* next input byte */ + this.input = null; // JS specific, because we have no pointers + this.next_in = 0; + /* number of bytes available at input */ + this.avail_in = 0; + /* total number of input bytes read so far */ + this.total_in = 0; + /* next output byte should be put there */ + this.output = null; // JS specific, because we have no pointers + this.next_out = 0; + /* remaining free space at output */ + this.avail_out = 0; + /* total number of bytes output so far */ + this.total_out = 0; + /* last error message, NULL if no error */ + this.msg = ''/*Z_NULL*/; + /* not visible by applications */ + this.state = null; + /* best guess about the data type: binary or text */ + this.data_type = 2/*Z_UNKNOWN*/; + /* adler32 value of the uncompressed data */ + this.adler = 0; +} diff --git a/vendor/promise.js b/vendor/promise.js new file mode 100644 index 0000000..ce84841 --- /dev/null +++ b/vendor/promise.js @@ -0,0 +1,255 @@ +/* Copyright (c) 2014 Taylor Hakes + * Copyright (c) 2014 Forbes Lindesay + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +(function (root) { + + // Store setTimeout reference so promise-polyfill will be unaffected by + // other code modifying setTimeout (like sinon.useFakeTimers()) + var setTimeoutFunc = setTimeout; + + function noop() {} + + // Polyfill for Function.prototype.bind + function bind(fn, thisArg) { + return function () { + fn.apply(thisArg, arguments); + }; + } + + function Promise(fn) { + if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new'); + if (typeof fn !== 'function') throw new TypeError('not a function'); + this._state = 0; + this._handled = false; + this._value = undefined; + this._deferreds = []; + + doResolve(fn, this); + } + + function handle(self, deferred) { + while (self._state === 3) { + self = self._value; + } + if (self._state === 0) { + self._deferreds.push(deferred); + return; + } + self._handled = true; + Promise._immediateFn(function () { + var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; + if (cb === null) { + (self._state === 1 ? resolve : reject)(deferred.promise, self._value); + return; + } + var ret; + try { + ret = cb(self._value); + } catch (e) { + reject(deferred.promise, e); + return; + } + resolve(deferred.promise, ret); + }); + } + + function resolve(self, newValue) { + try { + // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure + if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.'); + if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { + var then = newValue.then; + if (newValue instanceof Promise) { + self._state = 3; + self._value = newValue; + finale(self); + return; + } else if (typeof then === 'function') { + doResolve(bind(then, newValue), self); + return; + } + } + self._state = 1; + self._value = newValue; + finale(self); + } catch (e) { + reject(self, e); + } + } + + function reject(self, newValue) { + self._state = 2; + self._value = newValue; + finale(self); + } + + function finale(self) { + if (self._state === 2 && self._deferreds.length === 0) { + Promise._immediateFn(function() { + if (!self._handled) { + Promise._unhandledRejectionFn(self._value); + } + }); + } + + for (var i = 0, len = self._deferreds.length; i < len; i++) { + handle(self, self._deferreds[i]); + } + self._deferreds = null; + } + + function Handler(onFulfilled, onRejected, promise) { + this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; + this.onRejected = typeof onRejected === 'function' ? onRejected : null; + this.promise = promise; + } + + /** + * Take a potentially misbehaving resolver function and make sure + * onFulfilled and onRejected are only called once. + * + * Makes no guarantees about asynchrony. + */ + function doResolve(fn, self) { + var done = false; + try { + fn(function (value) { + if (done) return; + done = true; + resolve(self, value); + }, function (reason) { + if (done) return; + done = true; + reject(self, reason); + }); + } catch (ex) { + if (done) return; + done = true; + reject(self, ex); + } + } + + Promise.prototype['catch'] = function (onRejected) { + return this.then(null, onRejected); + }; + + Promise.prototype.then = function (onFulfilled, onRejected) { + var prom = new (this.constructor)(noop); + + handle(this, new Handler(onFulfilled, onRejected, prom)); + return prom; + }; + + Promise.all = function (arr) { + var args = Array.prototype.slice.call(arr); + + return new Promise(function (resolve, reject) { + if (args.length === 0) return resolve([]); + var remaining = args.length; + + function res(i, val) { + try { + if (val && (typeof val === 'object' || typeof val === 'function')) { + var then = val.then; + if (typeof then === 'function') { + then.call(val, function (val) { + res(i, val); + }, reject); + return; + } + } + args[i] = val; + if (--remaining === 0) { + resolve(args); + } + } catch (ex) { + reject(ex); + } + } + + for (var i = 0; i < args.length; i++) { + res(i, args[i]); + } + }); + }; + + Promise.resolve = function (value) { + if (value && typeof value === 'object' && value.constructor === Promise) { + return value; + } + + return new Promise(function (resolve) { + resolve(value); + }); + }; + + Promise.reject = function (value) { + return new Promise(function (resolve, reject) { + reject(value); + }); + }; + + Promise.race = function (values) { + return new Promise(function (resolve, reject) { + for (var i = 0, len = values.length; i < len; i++) { + values[i].then(resolve, reject); + } + }); + }; + + // Use polyfill for setImmediate for performance gains + Promise._immediateFn = (typeof setImmediate === 'function' && function (fn) { setImmediate(fn); }) || + function (fn) { + setTimeoutFunc(fn, 0); + }; + + Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) { + if (typeof console !== 'undefined' && console) { + console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console + } + }; + + /** + * Set the immediate function to execute callbacks + * @param fn {function} Function to execute + * @deprecated + */ + Promise._setImmediateFn = function _setImmediateFn(fn) { + Promise._immediateFn = fn; + }; + + /** + * Change the function to execute on unhandled rejection + * @param {function} fn Function to execute on unhandled rejection + * @deprecated + */ + Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) { + Promise._unhandledRejectionFn = fn; + }; + + if (typeof module !== 'undefined' && module.exports) { + module.exports = Promise; + } else if (!root.Promise) { + root.Promise = Promise; + } + + })(this); \ No newline at end of file diff --git a/vnc.html b/vnc.html new file mode 100644 index 0000000..d334d98 --- /dev/null +++ b/vnc.html @@ -0,0 +1,607 @@ + + + + + + KasmVNC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
KasmVNC encountered an error:
+
+
+
+
+ +
+ Loading statistics... +
+ + +
+
+
+
+
+ +
+ +

+ + + +

+ + +
+ + Drag Viewport +
+ + + +
+ +
+
+ + + + + + + +
+
+ Keys +
+ + +
+ + +
+
+
+ Power +
+ + + +
+
+ Power +
+ + +
+ + Clipboard +
+
+
+ Clipboard +
+ +
+ +
+
+
+ + +
+ + Fullscreen +
+ + +
+ + Game Cursor Mode +
+ + +
+ +
+
+
    +
  • + Settings +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • + + +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + + +
  • +

  • +
  • + +
  • +
  • + + +
  • +

  • +
  • +
    Keyboard Shortcuts
    +
    +
      +
    • + +
    • +
    • Ctrl+Shift+
    • +
    • 1 - Toggle Control Panel
    • +
    • 2 - Toggle Game Pointer Mode
    • +
    • 3 - Toggle Pointer Lock
    • +
    +
    +
  • +

  • +
  • +
    Stream Quality
    +
    +
      +
    • + + +
    • +
    • + + +
    • +
    • + + +
    • + +
    • + + + 3 +
    • +
    • + + + 9 +
    • +
    • + + + 7 +
    • +
    • + + +
    • +
    • + + + 5 +
    • +
    • + + + 5 +
    • +
    • + + + 65 +
    • +
    • + + + 5 +
    • +
    • + + + 3 +
    • +
    • + + +
    • +
    • + + +
    • +
    • + + +
    • +
    +
    +
  • +

  • +
  • +
    Advanced
    +
    +
      +
    • + + +
    • +

    • +
    • + + +
    • +
    • +
      WebSocket
      +
      +
        +
      • + +
      • +
      • + + +
      • +
      • + + +
      • +
      • + + +
      • +
      +
      +
    • +

    • +
    • + +
    • +
    • + + +
    • +

    • +
    • + +
    • +

    • + +
    • + +
    • +
    +
    +
  • +

  • +
  • + Version: + + + + Documentation + + +
  • +
+
+
+ Settings +
+ + +
+ + Disconnect +
+ + +
+ + Connect +
+ +
+
+ +
+ +
+ + +
+ + +
+
+ +
+
+ + +
+
+
    +
  • + + +
  • +
  • + + +
  • +
  • + +
  • +
+
+
+ + +
+
+
+ +
+
+
+ + +
+ + +
+ + + +
+
+
+
+
+
+
+
+
+ +
+
+ + diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..95be6ad --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,138 @@ +const path = require('path'); +const { CleanWebpackPlugin } = require('clean-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +const HtmlWebpackInlineSVGPlugin = require('html-webpack-inline-svg-plugin'); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +// const SvgSpriteHtmlWebpackPlugin = require('svg-sprite-html-webpack'); +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); + +module.exports = { + mode: "production", + entry: { + main: './app/ui.js', + error_handler: './app/error-handler.js', + promise: './vendor/promise.js', + style: './app/styles/base.css' + }, + output: { + path: path.resolve(__dirname, 'dist'), + filename: '[name].bundle.js' + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /(node_modules)/, + use: { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-env'] + } + } + }, + { + test: /\.(sa|sc|c)ss$/, + use: [ + { + loader: MiniCssExtractPlugin.loader + }, + { + loader: "css-loader", + }, + // { + // loader: "postcss-loader" + // }, + { + loader: "sass-loader", + options: { + implementation: require("sass") + } + } + ] + }, + { + // Now we apply rule for images + test: /\.(png|jpe?g|gif|svg)$/, + use: [ + { + // Using file-loader for these files + loader: "file-loader", + + // In options we can set different things like format + // and directory to save + options: { + outputPath: 'images' + } + } + ] + }, + { + // Apply rule for fonts files + test: /\.(woff|woff2|ttf|otf|eot)$/, + use: [ + { + // Using file-loader too + loader: "file-loader", + options: { + outputPath: 'fonts' + } + } + ] + }, + // { + // test: /\.svg$/, + // exclude: /node_modules/, + // use: SvgSpriteHtmlWebpackPlugin.getLoader(), + // } + ] + }, + optimization: { + minimize: true, + minimizer: [ + new CssMinimizerPlugin(), + ], + runtimeChunk: 'single', + splitChunks: { + chunks: 'all', + }, + }, + plugins: [ + new CleanWebpackPlugin(), + new HtmlWebpackPlugin({ + filename: '../index.html', + template: 'vnc.html', + minify: { + html5: true, + collapseWhitespace: true, + minifyCSS: true, + minifyJS: true, + minifyURLs: false, + removeAttributeQuotes: true, + removeComments: true, // false for Vue SSR to find app placeholder + removeEmptyAttributes: true, + removeOptionalTags: true, + removeRedundantAttributes: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributese: true, + useShortDoctype: true + } + }), + // new SvgSpriteHtmlWebpackPlugin({ + // append: true, + // includeFiles: [ + // 'app/images/*.svg', + // ], + // generateSymbolId: function(svgFilePath, svgHash, svgContent) { + // return svgHash.toString(); + // }, + // }), + new HtmlWebpackInlineSVGPlugin({ + inlineAll: true, + runPreEmit: true, + }), + new MiniCssExtractPlugin({ + filename: "[name].bundle.css" + }), + ], +};