Compare commits

...

58 Commits

Author SHA1 Message Date
add75b8c93 fix: reset canvas transformation to not accumulate error on non-zero dPR 2021-07-14 11:01:34 +02:00
0749d2c1f3 fix: color picker shortcuts not working when elements selected (#3817) 2021-07-10 21:05:00 +00:00
8787f3dc60 docs: release @excalidraw/excalidraw@0.9.0 🎉 (#3807)
* docs: release @excalidraw/excalidraw@0.9.0  🎉

* remove

* update changelog
2021-07-10 18:52:19 +05:30
5fabc57277 fix: view mode cursor adjustments (#3809) 2021-07-10 00:00:13 +02:00
e7cbb859f0 chore: Bump nginx version to newest (#3811)
Bump nginx version to newest.
2021-07-09 17:07:34 +02:00
aa860251c7 chore: Update translations from Crowdin (#3718)
Co-authored-by: dwelle <luzar.david@gmail.com>
2021-07-08 13:09:13 +02:00
380aaa30e6 fix: pass next release to updatePackageVersion & replace ## unreleased with new version (#3806)
* fix: pass next version to updatePackageVersion

* replace unreleased with next version in changelog

* fix

* fix
2021-07-06 00:13:56 +05:30
2e61fec7a6 build: Add release script to update relevant files and commit for next release (#3805)
* build: Add script to update package.json and commit for next release

* fix
2021-07-05 22:29:35 +05:30
3c295559c7 docs: specify to use yarn v1 not v2 (#3799)
Co-authored-by: David Luzar <luzar.david@gmail.com>
2021-07-05 18:01:52 +02:00
55d3287abf fix: include deleted elements when passing to restore (#3802) 2021-07-05 13:43:53 +02:00
e3e967421e fix: import React before using jsx (#3804) 2021-07-05 15:59:09 +05:30
77aae63006 docs: tweak changelog and readme (#3796)
* docs: tweak changelog and readme

* moving to discussions :)

* Apply suggestions from code review

Co-authored-by: David Luzar <luzar.david@gmail.com>

* Add about  attributes passed to updateScene

Co-authored-by: David Luzar <luzar.david@gmail.com>
2021-07-05 14:21:01 +05:30
ee64a7e264 fix: ensure s and g shortcuts work on no selection (#3800)
Co-authored-by: dwelle <luzar.david@gmail.com>
2021-07-04 22:27:33 +02:00
097362662d feat: pass localElements to restore and restoreElement API's and bump versions of duplicate elements on import (#3797) 2021-07-04 22:23:35 +02:00
038e9c13dd build: Add script to update changelog before a stable release (#3784)
* build: Add script to update changelog before a stable release

* fix

* fix

* fix

* Add note for lib updates

* Update scripts/updateChangelog.js

Co-authored-by: David Luzar <luzar.david@gmail.com>
2021-07-04 18:40:25 +05:30
bc8ba08ad0 build: Add script to update readme before stable release (#3781)
* build: Add script to update readme before stable release

* fix

* fix
2021-07-03 18:50:22 +05:30
f861a9fdd0 feat: support appState.exportEmbedScene to embed scene data in exportToSvg util (#3777)
* feat: add embedScene attribute to exportToSvg util

* fix

* return promise

* add docs and remove

* fix

* fix tests

* use

* fix

* fix

* remove metadata and use exportEmbedScene

* fix

* fix

* fix

* fix

* IIFE
2021-07-03 02:07:01 +05:30
62303b8a22 chore: bump browser-fs-access (#3780) 2021-07-02 14:55:16 +00:00
9cc741ab3a chore(deps): bump ssri from 6.0.1 to 6.0.2 (#3711)
Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/npm/ssri/releases)
- [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md)
- [Commits](https://github.com/npm/ssri/compare/v6.0.1...v6.0.2)

---
updated-dependencies:
- dependency-name: ssri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-30 01:29:46 +05:30
2d279cbb02 chore(deps-dev): bump mini-css-extract-plugin (#3767)
Bumps [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/webpack-contrib/mini-css-extract-plugin/releases)
- [Changelog](https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/mini-css-extract-plugin/compare/v1.6.0...v1.6.1)

---
updated-dependencies:
- dependency-name: mini-css-extract-plugin
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-29 02:13:49 +05:30
57ea4fdf9a chore(deps-dev): bump terser-webpack-plugin in /src/packages/excalidraw (#3768)
Bumps [terser-webpack-plugin](https://github.com/webpack-contrib/terser-webpack-plugin) from 5.1.3 to 5.1.4.
- [Release notes](https://github.com/webpack-contrib/terser-webpack-plugin/releases)
- [Changelog](https://github.com/webpack-contrib/terser-webpack-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v5.1.3...v5.1.4)

---
updated-dependencies:
- dependency-name: terser-webpack-plugin
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-29 02:13:27 +05:30
44402f42bf feat: switch to selection tool on library item insert (#3773)
* switch to selection tool on library item insert

* add test

Co-authored-by: dwelle <luzar.david@gmail.com>
2021-06-28 12:00:33 +02:00
bdead4d164 feat: expose getFreeDrawSvg, loadFromBlob and loadLibraryFromBlob from excalidraw package (#3764)
* feat: expose getFreeDrawSvg, loadFromBlob and loadLibraryFromBlob from excalidraw package

* Add docs

* fix
2021-06-26 02:12:58 +05:30
bfc0656475 chore(deps): bump color-string from 1.5.4 to 1.5.5 (#3761)
Bumps [color-string](https://github.com/Qix-/color-string) from 1.5.4 to 1.5.5.
- [Release notes](https://github.com/Qix-/color-string/releases)
- [Changelog](https://github.com/Qix-/color-string/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Qix-/color-string/compare/1.5.4...1.5.5)

---
updated-dependencies:
- dependency-name: color-string
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-26 01:37:59 +05:30
a33a3334f7 chore: upgrade deps in packages (#3760)
* chore: upgrade deps

* upgrade deps in utils
2021-06-24 01:26:44 +05:30
969d3c694a fix: keep binding for attached arrows after changing text (#3754)
Co-authored-by: David Luzar <luzar.david@gmail.com>
2021-06-21 14:31:49 +02:00
5cd921549a fix: deselect elements on viewMode toggle (#3741) 2021-06-16 19:01:16 +02:00
437afcbea4 fix: allow pointer events for disable zen mode button (#3743) 2021-06-16 22:25:22 +05:30
6dee02e320 feat: expose fontfamily and refactor FONT_FAMILY (#3710)
* feat: expose fontfamily and refactor FONT_FAMILY for better readability

* fix

* fix

* fix

* docs

* fix
2021-06-13 21:26:55 +05:30
74a2f16501 feat: Show active file name when saving to current file (#3733)
* feat: Show active file name when saving to current file

* Make requested changes

* More changes
2021-06-13 21:11:07 +05:30
fd4460be37 feat: add hint around text editing (#3708) 2021-06-12 22:58:34 +02:00
e82d0493cf chore(deps-dev): bump ts-loader in /src/packages/excalidraw (#3716)
Bumps [ts-loader](https://github.com/TypeStrong/ts-loader) from 8.1.0 to 9.2.3.
- [Release notes](https://github.com/TypeStrong/ts-loader/releases)
- [Changelog](https://github.com/TypeStrong/ts-loader/blob/main/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/ts-loader/compare/v8.1.0...v9.2.3)

---
updated-dependencies:
- dependency-name: ts-loader
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-12 20:03:02 +00:00
083cb4c656 chore(deps-dev): bump ts-loader in /src/packages/utils (#3712)
Bumps [ts-loader](https://github.com/TypeStrong/ts-loader) from 8.1.0 to 9.2.3.
- [Release notes](https://github.com/TypeStrong/ts-loader/releases)
- [Changelog](https://github.com/TypeStrong/ts-loader/blob/main/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/ts-loader/compare/v8.1.0...v9.2.3)

---
updated-dependencies:
- dependency-name: ts-loader
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-13 01:27:54 +05:30
d067365c1d chore(deps-dev): bump typescript in /src/packages/excalidraw (#3671)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.2.4 to 4.3.2.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v4.2.4...v4.3.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-13 01:26:27 +05:30
273cac6b60 chore(deps-dev): bump @babel/plugin-transform-typescript (#3713)
Bumps [@babel/plugin-transform-typescript](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-typescript) from 7.14.3 to 7.14.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.14.5/packages/babel-plugin-transform-typescript)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-typescript"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-12 21:48:03 +05:30
b9337b8a36 chore(deps-dev): bump @babel/preset-env in /src/packages/utils (#3714)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.14.4 to 7.14.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.14.5/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-12 15:41:26 +00:00
0e0025921b chore(deps-dev): bump @babel/plugin-transform-async-to-generator (#3715)
Bumps [@babel/plugin-transform-async-to-generator](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-async-to-generator) from 7.13.0 to 7.14.5.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.14.5/packages/babel-plugin-transform-async-to-generator)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-async-to-generator"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-12 15:36:46 +00:00
efc01ddab1 chore(deps): bump ws from 7.4.3 to 7.4.6 in /src/packages/excalidraw (#3665)
Bumps [ws](https://github.com/websockets/ws) from 7.4.3 to 7.4.6.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.4.3...7.4.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-12 15:34:00 +00:00
7bce22b114 chore(deps-dev): bump webpack in /src/packages/excalidraw (#3670)
Bumps [webpack](https://github.com/webpack/webpack) from 5.37.1 to 5.38.1.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.37.1...v5.38.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-12 15:31:49 +00:00
aab4965bbb chore(deps): bump ws from 7.4.3 to 7.4.6 in /src/packages/utils (#3664)
Bumps [ws](https://github.com/websockets/ws) from 7.4.3 to 7.4.6.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.4.3...7.4.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-12 15:30:49 +00:00
486a9a3da8 chore(deps-dev): bump autoprefixer in /src/packages/excalidraw (#3672)
Bumps [autoprefixer](https://github.com/postcss/autoprefixer) from 10.2.5 to 10.2.6.
- [Release notes](https://github.com/postcss/autoprefixer/releases)
- [Changelog](https://github.com/postcss/autoprefixer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/autoprefixer/compare/10.2.5...10.2.6)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-12 20:56:01 +05:30
2425c06082 chore(deps-dev): bump webpack in /src/packages/utils (#3673)
Bumps [webpack](https://github.com/webpack/webpack) from 5.37.1 to 5.38.1.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.37.1...v5.38.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-12 20:55:40 +05:30
79ea844901 chore(deps-dev): bump @babel/preset-env in /src/packages/utils (#3675)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.14.1 to 7.14.4.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.14.4/packages/babel-preset-env)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-12 20:54:40 +05:30
6690215cd1 feat: change library icon to be more clear (#3583) 2021-06-11 23:13:05 +02:00
7f5e783fe8 chore: Update translations from Crowdin (#3659) 2021-06-11 19:15:44 +02:00
9325109836 fix: use excal id so every element has unique id (#3696)
* fix: use excal id so every element has unique id

* fix

* fix

* fix

* add docs

* fix
2021-06-10 02:46:56 +05:30
69b6fbb3f4 feat: pass current theme when installing libraries (#3701)
* pass current `theme` when installing libraries

* pass `theme` instead of `appState`
2021-06-08 23:14:02 +02:00
6b6002baae refactor: Delete React SyntheticEvent persist (#3700) 2021-06-07 10:32:30 +02:00
54dcb73701 docs: improve grammar and example (#3699)
* Improve grammar, render only once

* Update README_NEXT.md
2021-06-07 01:38:05 +05:30
b595d3fcba test: add unit tests for restore.ts file (#3679)
* Add unit tests for restore.ts file

* Improving describe blocks in restore tests

* Move restore.tests.ts folder and remove depedency of UI in the tests

* Adding snapshots to restore.ts tests

* Using snapshot in freedraw test

* Updating description of test for line and draw elements

* Updating description of test for arrow element

* Improving restoreAppState tests

* specs cleanup

* fix

* fix
Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
2021-06-06 21:53:12 +05:30
d0867d1c3b refatcor: make ProjectName a functional component (#3695) 2021-06-04 21:22:09 +05:30
0d19e9210c feat: update virgil font (#3692)
Co-authored-by: tjangy <youri.tjang@rabobank.nl>
2021-06-02 21:41:14 +02:00
4249de41d4 feat: Add prop autoFocus to set focus on the Excalidraw component (#3691)
* feat: Add prop autofocus to set focus on Excalidraw component

* Update PR number

* Make requested changes

* Add note

* Update src/packages/excalidraw/CHANGELOG.md

Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>

* Update src/tests/excalidrawPackage.test.tsx

Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>

* Remove duplicate sentence

* Indent note

* autofocus -> autoFocus

Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
2021-06-02 19:54:21 +05:30
15f02ba191 refactor: code clean up (#3681)
* refactor: code clean up
Move types from App.tsx to types.ts
Move excalidrawPackage.test.tsx inside src/tests/package

* import type
2021-06-01 23:52:13 +05:30
a2e1199907 feat: support exporting json to excalidraw plus (#3678)
* feat: support exporting json to excalidraw plus

* add Firebase Storage rules to codebase

* factor the onClick handler out

* move excal icon to icons.tsx

* handle export error
2021-06-01 14:05:09 +02:00
c08e9c4172 fix: use rgba instead of shorthand alpha (#3688) 2021-05-31 14:29:40 +05:30
abfc58eb24 feat: save exportScale in AppState (#3580)
Co-authored-by: David Luzar <luzar.david@gmail.com>
Co-authored-by: dwelle <luzar.david@gmail.com>
2021-05-30 16:31:12 +02:00
035c7affff fix: color pickers not opening on mobile (#3676) 2021-05-30 12:05:07 +02:00
133 changed files with 5250 additions and 2470 deletions

2
.gitignore vendored
View File

@ -5,9 +5,11 @@
.env.test.local
.envrc
.eslintcache
.history
.idea
.vercel
.vscode
.yarn
*.log
*.tgz
build

View File

@ -10,7 +10,7 @@ ARG NODE_ENV=production
COPY . .
RUN yarn build:app:docker
FROM nginx:1.17-alpine
FROM nginx:1.21-alpine
COPY --from=build /opt/node_app/build /usr/share/nginx/html

View File

@ -93,7 +93,7 @@ These instructions will get you a copy of the project up and running on your loc
#### Requirements
- [Node.js](https://nodejs.org/en/)
- [Yarn](https://yarnpkg.com/getting-started/install)
- [Yarn](https://yarnpkg.com/getting-started/install) (v1 or v2.4.2+)
- [Git](https://git-scm.com/downloads)
#### Clone the repo

View File

@ -2,5 +2,8 @@
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"storage": {
"rules": "storage.rules"
}
}

View File

@ -0,0 +1,12 @@
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{migrations} {
match /{scenes}/{scene} {
allow get, write: if true;
// redundant, but let's be explicit'
allow list: if false;
}
}
}
}

View File

@ -27,7 +27,7 @@
"@types/react": "17.0.3",
"@types/react-dom": "17.0.3",
"@types/socket.io-client": "1.4.36",
"browser-fs-access": "0.16.4",
"browser-fs-access": "0.18.0",
"clsx": "1.1.1",
"firebase": "8.3.3",
"i18next-browser-languagedetector": "6.1.0",

Binary file not shown.

View File

@ -38,7 +38,8 @@ const crowdinMap = {
"zh-CN": "en-zhcn",
"zh-TW": "en-zhtw",
"lv-LV": "en-lv",
"cs-CZ": "cs-cz",
"cs-CZ": "en-cs",
"kk-KZ": "en-kk",
};
const flags = {
@ -78,6 +79,7 @@ const flags = {
"zh-TW": "🇹🇼",
"lv-LV": "🇱🇻",
"cs-CZ": "🇨🇿",
"kk-KZ": "🇰🇿",
};
const languages = {
@ -117,6 +119,7 @@ const languages = {
"zh-TW": "繁體中文",
"lv-LV": "Latviešu",
"cs-CZ": "Česky",
"kk-KZ": "Қазақ тілі",
};
const percentages = fs.readFileSync(

39
scripts/release.js Normal file
View File

@ -0,0 +1,39 @@
const fs = require("fs");
const util = require("util");
const exec = util.promisify(require("child_process").exec);
const updateReadme = require("./updateReadme");
const updateChangelog = require("./updateChangelog");
const excalidrawDir = `${__dirname}/../src/packages/excalidraw`;
const excalidrawPackage = `${excalidrawDir}/package.json`;
const updatePackageVersion = (nextVersion) => {
const pkg = require(excalidrawPackage);
pkg.version = nextVersion;
const content = `${JSON.stringify(pkg, null, 2)}\n`;
fs.writeFileSync(excalidrawPackage, content, "utf-8");
};
const release = async (nextVersion) => {
try {
updateReadme();
await updateChangelog(nextVersion);
updatePackageVersion(nextVersion);
await exec(`git add -u`);
await exec(
`git commit -m "docs: release excalidraw@excalidraw@${nextVersion} 🎉"`,
);
/* eslint-disable no-console */
console.log("Done!");
} catch (e) {
console.error(e);
process.exit(1);
}
};
const nextVersion = process.argv.slice(2)[0];
if (!nextVersion) {
console.error("Pass the next version to release!");
process.exit(1);
}
release(nextVersion);

View File

@ -0,0 +1,97 @@
const fs = require("fs");
const util = require("util");
const exec = util.promisify(require("child_process").exec);
const excalidrawDir = `${__dirname}/../src/packages/excalidraw`;
const excalidrawPackage = `${excalidrawDir}/package.json`;
const pkg = require(excalidrawPackage);
const lastVersion = pkg.version;
const existingChangeLog = fs.readFileSync(
`${excalidrawDir}/CHANGELOG.md`,
"utf8",
);
const supportedTypes = ["feat", "fix", "style", "refactor", "perf", "build"];
const headerForType = {
feat: "Features",
fix: "Fixes",
style: "Styles",
refactor: " Refactor",
perf: "Performance",
build: "Build",
};
const getCommitHashForLastVersion = async () => {
try {
const commitMessage = `"release @excalidraw/excalidraw@${lastVersion}"`;
const { stdout } = await exec(
`git log --format=format:"%H" --grep=${commitMessage}`,
);
return stdout;
} catch (e) {
console.error(e);
}
};
const getLibraryCommitsSinceLastRelease = async () => {
const commitHash = await getCommitHashForLastVersion();
const { stdout } = await exec(
`git log --pretty=format:%s ${commitHash}...master`,
);
const commitsSinceLastRelease = stdout.split("\n");
const commitList = {};
supportedTypes.forEach((type) => {
commitList[type] = [];
});
commitsSinceLastRelease.forEach((commit) => {
const indexOfColon = commit.indexOf(":");
const type = commit.slice(0, indexOfColon);
if (!supportedTypes.includes(type)) {
return;
}
const messageWithoutType = commit.slice(indexOfColon + 1).trim();
const messageWithCapitalizeFirst =
messageWithoutType.charAt(0).toUpperCase() + messageWithoutType.slice(1);
const prNumber = commit.match(/\(#([0-9]*)\)/)[1];
// return if the changelog already contains the pr number which would happen for package updates
if (existingChangeLog.includes(prNumber)) {
return;
}
const prMarkdown = `[#${prNumber}](https://github.com/excalidraw/excalidraw/pull/${prNumber})`;
const messageWithPRLink = messageWithCapitalizeFirst.replace(
/\(#[0-9]*\)/,
prMarkdown,
);
commitList[type].push(messageWithPRLink);
});
return commitList;
};
const updateChangelog = async (nextVersion) => {
const commitList = await getLibraryCommitsSinceLastRelease();
let changelogForLibrary =
"## Excalidraw Library\n\n**_This section lists the updates made to the excalidraw library and will not affect the integration._**\n\n";
supportedTypes.forEach((type) => {
if (commitList[type].length) {
changelogForLibrary += `### ${headerForType[type]}\n\n`;
const commits = commitList[type];
commits.forEach((commit) => {
changelogForLibrary += `- ${commit}\n\n`;
});
}
});
changelogForLibrary += "---\n";
const lastVersionIndex = existingChangeLog.indexOf(`## ${lastVersion}`);
let updatedContent =
existingChangeLog.slice(0, lastVersionIndex) +
changelogForLibrary +
existingChangeLog.slice(lastVersionIndex);
const currentDate = new Date().toISOString().slice(0, 10);
const newVersion = `## ${nextVersion} (${currentDate})`;
updatedContent = updatedContent.replace(`## Unreleased`, newVersion);
fs.writeFileSync(`${excalidrawDir}/CHANGELOG.md`, updatedContent, "utf8");
};
module.exports = updateChangelog;

27
scripts/updateReadme.js Normal file
View File

@ -0,0 +1,27 @@
const fs = require("fs");
const updateReadme = () => {
const excalidrawDir = `${__dirname}/../src/packages/excalidraw`;
let data = fs.readFileSync(`${excalidrawDir}/README_NEXT.md`, "utf8");
// remove note for unstable release
data = data.replace(
/<!-- unstable-readme-start-->[\s\S]*?<!-- unstable-readme-end-->/,
"",
);
// replace "excalidraw-next" with "excalidraw"
data = data.replace(/excalidraw-next/g, "excalidraw");
data = data.trim();
const demoIndex = data.indexOf("### Demo");
const excalidrawNextNote =
"#### Note\n\n**If you don't want to wait for the next stable release and try out the unreleased changes you can use [@excalidraw/excalidraw-next](https://www.npmjs.com/package/@excalidraw/excalidraw-next).**\n\n";
// Add excalidraw next note to try out for unreleased changes
data = data.slice(0, demoIndex) + excalidrawNextNote + data.slice(demoIndex);
// update readme
fs.writeFileSync(`${excalidrawDir}/README.md`, data, "utf8");
};
module.exports = updateReadme;

View File

@ -34,9 +34,9 @@ export const actionChangeViewBackgroundColor = register({
type="canvasBackground"
color={appState.viewBackgroundColor}
onChange={(color) => updateData({ viewBackgroundColor: color })}
isActive={appState.openMenu === "canvasColorPicker"}
isActive={appState.openPopup === "canvasColorPicker"}
setActive={(active) =>
updateData({ openMenu: active ? "canvasColorPicker" : null })
updateData({ openPopup: active ? "canvasColorPicker" : null })
}
data-testid="canvas-background-picker"
/>

View File

@ -1,6 +1,6 @@
import React from "react";
import { trackEvent } from "../analytics";
import { load, questionCircle, save, saveAs } from "../components/icons";
import { load, questionCircle, saveAs } from "../components/icons";
import { ProjectName } from "../components/ProjectName";
import { ToolButton } from "../components/ToolButton";
import "../components/ToolIcon.scss";
@ -13,6 +13,11 @@ import { KEYS } from "../keys";
import { register } from "./register";
import { supported as fsSupported } from "browser-fs-access";
import { CheckboxItem } from "../components/CheckboxItem";
import { getExportSize } from "../scene/export";
import { DEFAULT_EXPORT_PADDING, EXPORT_SCALES } from "../constants";
import { getSelectedElements, isSomeElementSelected } from "../scene";
import { getNonDeletedElements } from "../element";
import { ActiveFile } from "../components/ActiveFile";
export const actionChangeProjectName = register({
name: "changeProjectName",
@ -32,6 +37,54 @@ export const actionChangeProjectName = register({
),
});
export const actionChangeExportScale = register({
name: "changeExportScale",
perform: (_elements, appState, value) => {
return {
appState: { ...appState, exportScale: value },
commitToHistory: false,
};
},
PanelComponent: ({ elements: allElements, appState, updateData }) => {
const elements = getNonDeletedElements(allElements);
const exportSelected = isSomeElementSelected(elements, appState);
const exportedElements = exportSelected
? getSelectedElements(elements, appState)
: elements;
return (
<>
{EXPORT_SCALES.map((s) => {
const [width, height] = getExportSize(
exportedElements,
DEFAULT_EXPORT_PADDING,
s,
);
const scaleButtonTitle = `${t(
"buttons.scale",
)} ${s}x (${width}x${height})`;
return (
<ToolButton
key={s}
size="s"
type="radio"
icon={`${s}x`}
name="export-canvas-scale"
title={scaleButtonTitle}
aria-label={scaleButtonTitle}
id="export-canvas-scale"
checked={s === appState.exportScale}
onChange={() => updateData(s)}
/>
);
})}
</>
);
},
});
export const actionChangeExportBackground = register({
name: "changeExportBackground",
perform: (_elements, appState, value) => {
@ -101,14 +154,10 @@ export const actionSaveToActiveFile = register({
},
keyTest: (event) =>
event.key === KEYS.S && event[KEYS.CTRL_OR_CMD] && !event.shiftKey,
PanelComponent: ({ updateData }) => (
<ToolButton
type="icon"
icon={save}
title={t("buttons.save")}
aria-label={t("buttons.save")}
onClick={() => updateData(null)}
data-testid="save-button"
PanelComponent: ({ updateData, appState }) => (
<ActiveFile
onSave={() => updateData(null)}
fileName={appState.fileHandle?.name}
/>
),
});
@ -152,7 +201,7 @@ export const actionLoadScene = register({
const {
elements: loadedElements,
appState: loadedAppState,
} = await loadFromJSON(appState);
} = await loadFromJSON(appState, elements);
return {
elements: loadedElements,
appState: loadedAppState,

View File

@ -13,6 +13,13 @@ import {
FillCrossHatchIcon,
FillHachureIcon,
FillSolidIcon,
FontFamilyCodeIcon,
FontFamilyHandDrawnIcon,
FontFamilyNormalIcon,
FontSizeExtraLargeIcon,
FontSizeLargeIcon,
FontSizeMediumIcon,
FontSizeSmallIcon,
SloppinessArchitectIcon,
SloppinessArtistIcon,
SloppinessCartoonistIcon,
@ -20,18 +27,15 @@ import {
StrokeStyleDottedIcon,
StrokeStyleSolidIcon,
StrokeWidthIcon,
FontSizeSmallIcon,
FontSizeMediumIcon,
FontSizeLargeIcon,
FontSizeExtraLargeIcon,
FontFamilyHandDrawnIcon,
FontFamilyNormalIcon,
FontFamilyCodeIcon,
TextAlignLeftIcon,
TextAlignCenterIcon,
TextAlignLeftIcon,
TextAlignRightIcon,
} from "../components/icons";
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from "../constants";
import {
DEFAULT_FONT_FAMILY,
DEFAULT_FONT_SIZE,
FONT_FAMILY,
} from "../constants";
import {
getNonDeletedElements,
isTextElement,
@ -44,7 +48,7 @@ import {
ExcalidrawElement,
ExcalidrawLinearElement,
ExcalidrawTextElement,
FontFamily,
FontFamilyValues,
TextAlign,
} from "../element/types";
import { getLanguage, t } from "../i18n";
@ -126,9 +130,9 @@ export const actionChangeStrokeColor = register({
appState.currentItemStrokeColor,
)}
onChange={(color) => updateData({ currentItemStrokeColor: color })}
isActive={appState.openMenu === "strokeColorPicker"}
isActive={appState.openPopup === "strokeColorPicker"}
setActive={(active) =>
updateData({ openMenu: active ? "strokeColorPicker" : null })
updateData({ openPopup: active ? "strokeColorPicker" : null })
}
/>
</>
@ -166,9 +170,9 @@ export const actionChangeBackgroundColor = register({
appState.currentItemBackgroundColor,
)}
onChange={(color) => updateData({ currentItemBackgroundColor: color })}
isActive={appState.openMenu === "backgroundColorPicker"}
isActive={appState.openPopup === "backgroundColorPicker"}
setActive={(active) =>
updateData({ openMenu: active ? "backgroundColorPicker" : null })
updateData({ openPopup: active ? "backgroundColorPicker" : null })
}
/>
</>
@ -499,19 +503,23 @@ export const actionChangeFontFamily = register({
};
},
PanelComponent: ({ elements, appState, updateData }) => {
const options: { value: FontFamily; text: string; icon: JSX.Element }[] = [
const options: {
value: FontFamilyValues;
text: string;
icon: JSX.Element;
}[] = [
{
value: 1,
value: FONT_FAMILY.Virgil,
text: t("labels.handDrawn"),
icon: <FontFamilyHandDrawnIcon theme={appState.theme} />,
},
{
value: 2,
value: FONT_FAMILY.Helvetica,
text: t("labels.normal"),
icon: <FontFamilyNormalIcon theme={appState.theme} />,
},
{
value: 3,
value: FONT_FAMILY.Cascadia,
text: t("labels.code"),
icon: <FontFamilyCodeIcon theme={appState.theme} />,
},
@ -520,7 +528,7 @@ export const actionChangeFontFamily = register({
return (
<fieldset>
<legend>{t("labels.fontFamily")}</legend>
<ButtonIconSelect<FontFamily | false>
<ButtonIconSelect<FontFamilyValues | false>
group="font-family"
options={options}
value={getFormValue(

View File

@ -10,7 +10,6 @@ export const actionToggleViewMode = register({
appState: {
...appState,
viewModeEnabled: !this.checked!(appState),
selectedElementIds: {},
},
commitToHistory: false,
};

View File

@ -66,6 +66,7 @@ export type ActionName =
| "changeProjectName"
| "changeExportBackground"
| "changeExportEmbedScene"
| "changeExportScale"
| "saveToActiveFile"
| "saveFileToDisk"
| "loadScene"

View File

@ -3,11 +3,16 @@ import {
DEFAULT_FONT_FAMILY,
DEFAULT_FONT_SIZE,
DEFAULT_TEXT_ALIGN,
EXPORT_SCALES,
} from "./constants";
import { t } from "./i18n";
import { AppState, NormalizedZoomValue } from "./types";
import { getDateTime } from "./utils";
const defaultExportScale = EXPORT_SCALES.includes(devicePixelRatio)
? devicePixelRatio
: 1;
export const getDefaultAppState = (): Omit<
AppState,
"offsetTop" | "offsetLeft" | "width" | "height"
@ -39,6 +44,7 @@ export const getDefaultAppState = (): Omit<
elementType: "selection",
errorMessage: null,
exportBackground: true,
exportScale: defaultExportScale,
exportEmbedScene: false,
exportWithDarkMode: false,
fileHandle: null,
@ -52,6 +58,7 @@ export const getDefaultAppState = (): Omit<
multiElement: null,
name: `${t("labels.untitled")}-${getDateTime()}`,
openMenu: null,
openPopup: null,
pasteDialog: { shown: false, data: null },
previousSelectedElementIds: {},
resizingElement: null,
@ -116,6 +123,7 @@ const APP_STATE_STORAGE_CONF = (<
errorMessage: { browser: false, export: false },
exportBackground: { browser: true, export: false },
exportEmbedScene: { browser: true, export: false },
exportScale: { browser: true, export: false },
exportWithDarkMode: { browser: true, export: false },
fileHandle: { browser: false, export: false },
gridSize: { browser: true, export: true },
@ -131,6 +139,7 @@ const APP_STATE_STORAGE_CONF = (<
offsetLeft: { browser: false, export: false },
offsetTop: { browser: false, export: false },
openMenu: { browser: true, export: false },
openPopup: { browser: false, export: false },
pasteDialog: { browser: false, export: false },
previousSelectedElementIds: { browser: true, export: false },
resizingElement: { browser: false, export: false },

View File

@ -151,23 +151,14 @@ export const SelectedShapeActions = ({
);
};
const LIBRARY_ICON = (
// fa-th-large
<svg viewBox="0 0 512 512">
<path d="M296 32h192c13.255 0 24 10.745 24 24v160c0 13.255-10.745 24-24 24H296c-13.255 0-24-10.745-24-24V56c0-13.255 10.745-24 24-24zm-80 0H24C10.745 32 0 42.745 0 56v160c0 13.255 10.745 24 24 24h192c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24zM0 296v160c0 13.255 10.745 24 24 24h192c13.255 0 24-10.745 24-24V296c0-13.255-10.745-24-24-24H24c-13.255 0-24 10.745-24 24zm296 184h192c13.255 0 24-10.745 24-24V296c0-13.255-10.745-24-24-24H296c-13.255 0-24 10.745-24 24v160c0 13.255 10.745 24 24 24z" />
</svg>
);
export const ShapesSwitcher = ({
canvas,
elementType,
setAppState,
isLibraryOpen,
}: {
canvas: HTMLCanvasElement | null;
elementType: ExcalidrawElement["type"];
setAppState: React.Component<any, AppState>["setState"];
isLibraryOpen: boolean;
}) => (
<>
{SHAPES.map(({ value, icon, key }, index) => {
@ -201,19 +192,6 @@ export const ShapesSwitcher = ({
/>
);
})}
<ToolButton
className="Shape ToolIcon_type_button__library"
type="button"
icon={LIBRARY_ICON}
name="editor-library"
keyBindingLabel="9"
aria-keyshortcuts="9"
title={`${capitalizeString(t("toolBar.library"))} — 9`}
aria-label={capitalizeString(t("toolBar.library"))}
onClick={() => {
setAppState({ isLibraryOpen: !isLibraryOpen });
}}
/>
</>
);

View File

@ -0,0 +1,21 @@
.excalidraw {
.ActiveFile {
.ActiveFile__fileName {
display: flex;
align-items: center;
span {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 9.3em;
}
svg {
width: 1.15em;
margin-inline-end: 0.3em;
transform: scaleY(0.9);
}
}
}
}

View File

@ -0,0 +1,29 @@
import React from "react";
import Stack from "../components/Stack";
import { ToolButton } from "../components/ToolButton";
import { save, file } from "../components/icons";
import { t } from "../i18n";
import "./ActiveFile.scss";
type ActiveFileProps = {
fileName?: string;
onSave: () => void;
};
export const ActiveFile = ({ fileName, onSave }: ActiveFileProps) => (
<Stack.Row className="ActiveFile" gap={1} align="center">
<span className="ActiveFile__fileName">
{file}
<span>{fileName}</span>
</span>
<ToolButton
type="icon"
icon={save}
title={t("buttons.save")}
aria-label={t("buttons.save")}
onClick={onSave}
data-testid="save-button"
/>
</Stack.Row>
);

View File

@ -111,7 +111,6 @@ import {
import { LinearElementEditor } from "../element/linearElementEditor";
import { mutateElement } from "../element/mutateElement";
import { deepCopyElement, newFreeDrawElement } from "../element/newElement";
import { MaybeTransformHandleType } from "../element/transformHandles";
import {
isBindingElement,
isBindingElementType,
@ -157,6 +156,7 @@ import {
getElementsWithinSelection,
getNormalizedZoom,
getSelectedElements,
hasBackground,
isOverScrollBars,
isSomeElementSelected,
} from "../scene";
@ -167,9 +167,11 @@ import { findShapeByKey } from "../shapes";
import {
AppProps,
AppState,
ExcalidrawImperativeAPI,
Gesture,
GestureEvent,
LibraryItems,
PointerDownState,
SceneData,
} from "../types";
import {
@ -180,7 +182,6 @@ import {
isToolIcon,
isWritableElement,
resetCursor,
ResolvablePromise,
resolvablePromise,
sceneCoordsToViewportCoords,
setCursor,
@ -197,9 +198,10 @@ import { actionToggleViewMode } from "../actions/actionToggleViewMode";
const IsMobileContext = React.createContext(false);
export const useIsMobile = () => useContext(IsMobileContext);
const ExcalidrawContainerContext = React.createContext<HTMLDivElement | null>(
null,
);
const ExcalidrawContainerContext = React.createContext<{
container: HTMLDivElement | null;
id: string | null;
}>({ container: null, id: null });
export const useExcalidrawContainer = () =>
useContext(ExcalidrawContainerContext);
@ -222,83 +224,6 @@ const gesture: Gesture = {
initialScale: null,
};
export type PointerDownState = Readonly<{
// The first position at which pointerDown happened
origin: Readonly<{ x: number; y: number }>;
// Same as "origin" but snapped to the grid, if grid is on
originInGrid: Readonly<{ x: number; y: number }>;
// Scrollbar checks
scrollbars: ReturnType<typeof isOverScrollBars>;
// The previous pointer position
lastCoords: { x: number; y: number };
// map of original elements data
originalElements: Map<string, NonDeleted<ExcalidrawElement>>;
resize: {
// Handle when resizing, might change during the pointer interaction
handleType: MaybeTransformHandleType;
// This is determined on the initial pointer down event
isResizing: boolean;
// This is determined on the initial pointer down event
offset: { x: number; y: number };
// This is determined on the initial pointer down event
arrowDirection: "origin" | "end";
// This is a center point of selected elements determined on the initial pointer down event (for rotation only)
center: { x: number; y: number };
};
hit: {
// The element the pointer is "hitting", is determined on the initial
// pointer down event
element: NonDeleted<ExcalidrawElement> | null;
// The elements the pointer is "hitting", is determined on the initial
// pointer down event
allHitElements: NonDeleted<ExcalidrawElement>[];
// This is determined on the initial pointer down event
wasAddedToSelection: boolean;
// Whether selected element(s) were duplicated, might change during the
// pointer interaction
hasBeenDuplicated: boolean;
hasHitCommonBoundingBoxOfSelectedElements: boolean;
};
withCmdOrCtrl: boolean;
drag: {
// Might change during the pointer interation
hasOccurred: boolean;
// Might change during the pointer interation
offset: { x: number; y: number } | null;
};
// We need to have these in the state so that we can unsubscribe them
eventListeners: {
// It's defined on the initial pointer down event
onMove: null | ((event: PointerEvent) => void);
// It's defined on the initial pointer down event
onUp: null | ((event: PointerEvent) => void);
// It's defined on the initial pointer down event
onKeyDown: null | ((event: KeyboardEvent) => void);
// It's defined on the initial pointer down event
onKeyUp: null | ((event: KeyboardEvent) => void);
};
}>;
export type ExcalidrawImperativeAPI = {
updateScene: InstanceType<typeof App>["updateScene"];
resetScene: InstanceType<typeof App>["resetScene"];
getSceneElementsIncludingDeleted: InstanceType<
typeof App
>["getSceneElementsIncludingDeleted"];
history: {
clear: InstanceType<typeof App>["resetHistory"];
};
scrollToContent: InstanceType<typeof App>["scrollToContent"];
getSceneElements: InstanceType<typeof App>["getSceneElements"];
getAppState: () => InstanceType<typeof App>["state"];
refresh: InstanceType<typeof App>["refresh"];
importLibrary: InstanceType<typeof App>["importLibraryFromUrl"];
setToastMessage: InstanceType<typeof App>["setToastMessage"];
readyPromise: ResolvablePromise<ExcalidrawImperativeAPI>;
ready: true;
id: string;
};
class App extends React.Component<AppProps, AppState> {
canvas: HTMLCanvasElement | null = null;
rc: RoughCanvas | null = null;
@ -321,6 +246,10 @@ class App extends React.Component<AppProps, AppState> {
public libraryItemsFromStorage: LibraryItems | undefined;
private id: string;
private history: History;
private excalidrawContainerValue: {
container: HTMLDivElement | null;
id: string;
};
constructor(props: AppProps) {
super(props);
@ -377,6 +306,12 @@ class App extends React.Component<AppProps, AppState> {
}
readyPromise.resolve(api);
}
this.excalidrawContainerValue = {
container: this.excalidrawContainerRef.current,
id: this.id,
};
this.scene = new Scene();
this.library = new Library(this);
this.history = new History();
@ -404,11 +339,11 @@ class App extends React.Component<AppProps, AppState> {
if (viewModeEnabled) {
return (
<canvas
id="canvas"
className="excalidraw__canvas"
style={{
width: canvasDOMWidth,
height: canvasDOMHeight,
cursor: "grabbing",
cursor: CURSOR_TYPE.GRAB,
}}
width={canvasWidth}
height={canvasHeight}
@ -426,7 +361,7 @@ class App extends React.Component<AppProps, AppState> {
}
return (
<canvas
id="canvas"
className="excalidraw__canvas"
style={{
width: canvasDOMWidth,
height: canvasDOMHeight,
@ -471,7 +406,7 @@ class App extends React.Component<AppProps, AppState> {
}
>
<ExcalidrawContainerContext.Provider
value={this.excalidrawContainerRef.current}
value={this.excalidrawContainerValue}
>
<IsMobileContext.Provider value={this.isMobile}>
<LayerUI
@ -534,7 +469,9 @@ class App extends React.Component<AppProps, AppState> {
}
public focusContainer = () => {
this.excalidrawContainerRef.current?.focus();
if (this.props.autoFocus) {
this.excalidrawContainerRef.current?.focus();
}
};
public getSceneElementsIncludingDeleted = () => {
@ -718,7 +655,11 @@ class App extends React.Component<AppProps, AppState> {
const fileHandle = launchParams.files[0];
const blob: Blob = await fileHandle.getFile();
blob.handle = fileHandle;
loadFromBlob(blob, this.state)
loadFromBlob(
blob,
this.state,
this.scene.getElementsIncludingDeleted(),
)
.then(({ elements, appState }) =>
this.syncActionResult({
elements,
@ -756,7 +697,7 @@ class App extends React.Component<AppProps, AppState> {
};
}
const scene = restore(initialData, null);
const scene = restore(initialData, null, null);
scene.appState = {
...scene.appState,
isLoading: false,
@ -800,6 +741,8 @@ class App extends React.Component<AppProps, AppState> {
};
public async componentDidMount() {
this.excalidrawContainerValue.container = this.excalidrawContainerRef.current;
if (
process.env.NODE_ENV === ENV.TEST ||
process.env.NODE_ENV === ENV.DEVELOPMENT
@ -984,14 +927,12 @@ class App extends React.Component<AppProps, AppState> {
}
if (prevProps.viewModeEnabled !== this.props.viewModeEnabled) {
this.setState(
{ viewModeEnabled: !!this.props.viewModeEnabled },
this.addEventListeners,
);
this.setState({ viewModeEnabled: !!this.props.viewModeEnabled });
}
if (prevState.viewModeEnabled !== this.state.viewModeEnabled) {
this.addEventListeners();
this.deselectElements();
}
if (prevProps.zenModeEnabled !== this.props.zenModeEnabled) {
@ -1265,7 +1206,7 @@ class App extends React.Component<AppProps, AppState> {
});
} else if (data.elements) {
this.addElementsFromPasteOrLibrary({
elements: restoreElements(data.elements),
elements: data.elements,
position: "cursor",
});
} else if (data.text) {
@ -1280,7 +1221,7 @@ class App extends React.Component<AppProps, AppState> {
elements: readonly ExcalidrawElement[];
position: { clientX: number; clientY: number } | "cursor" | "center";
}) => {
const elements = restoreElements(opts.elements);
const elements = restoreElements(opts.elements, null);
const [minX, minY, maxX, maxY] = getCommonBounds(elements);
const elementsCenterX = distance(minX, maxX) / 2;
@ -1346,6 +1287,7 @@ class App extends React.Component<AppProps, AppState> {
this.scene.getElements(),
),
);
this.selectShapeTool("selection");
};
private addTextFromPaste(text: any) {
@ -1649,13 +1591,22 @@ class App extends React.Component<AppProps, AppState> {
this.scene.getElements(),
this.state,
);
if (selectedElements.length) {
if (event.key === KEYS.G) {
this.setState({ openMenu: "backgroundColorPicker" });
}
if (event.key === KEYS.S) {
this.setState({ openMenu: "strokeColorPicker" });
}
if (
this.state.elementType === "selection" &&
!selectedElements.length
) {
return;
}
if (
event.key === KEYS.G &&
(hasBackground(this.state.elementType) ||
selectedElements.some((element) => hasBackground(element.type)))
) {
this.setState({ openPopup: "backgroundColorPicker" });
}
if (event.key === KEYS.S) {
this.setState({ openPopup: "strokeColorPicker" });
}
}
},
@ -1663,7 +1614,9 @@ class App extends React.Component<AppProps, AppState> {
private onKeyUp = withBatchedUpdates((event: KeyboardEvent) => {
if (event.key === KEYS.SPACE) {
if (this.state.elementType === "selection") {
if (this.state.viewModeEnabled) {
setCursor(this.canvas, CURSOR_TYPE.GRAB);
} else if (this.state.elementType === "selection") {
resetCursor(this.canvas);
} else {
setCursorForShape(this.canvas, this.state.elementType);
@ -1811,7 +1764,8 @@ class App extends React.Component<AppProps, AppState> {
[element.id]: true,
},
}));
} else {
}
if (isDeleted) {
fixBindingsAfterDeletion(this.scene.getElements(), [element]);
}
if (!isDeleted || isExistingElement) {
@ -1832,15 +1786,19 @@ class App extends React.Component<AppProps, AppState> {
excalidrawContainer: this.excalidrawContainerRef.current,
});
// deselect all other elements when inserting text
this.deselectElements();
// do an initial update to re-initialize element position since we were
// modifying element's x/y for sake of editor (case: syncing to remote)
updateElement(element.text);
}
private deselectElements() {
this.setState({
selectedElementIds: {},
selectedGroupIds: {},
editingGroupId: null,
});
// do an initial update to re-initialize element position since we were
// modifying element's x/y for sake of editor (case: syncing to remote)
updateElement(element.text);
}
private getTextElementAtPosition(
@ -2283,6 +2241,8 @@ class App extends React.Component<AppProps, AppState> {
this.canvas,
isTextElement(hitElement) ? CURSOR_TYPE.TEXT : CURSOR_TYPE.CROSSHAIR,
);
} else if (this.state.viewModeEnabled) {
setCursor(this.canvas, CURSOR_TYPE.GRAB);
} else if (isOverScrollBar) {
setCursor(this.canvas, CURSOR_TYPE.AUTO);
} else if (
@ -2308,8 +2268,6 @@ class App extends React.Component<AppProps, AppState> {
private handleCanvasPointerDown = (
event: React.PointerEvent<HTMLCanvasElement>,
) => {
event.persist();
// remove any active selection when we start to interact with canvas
// (mainly, we care about removing selection outside the component which
// would prevent our copy handling otherwise)
@ -2522,7 +2480,11 @@ class App extends React.Component<AppProps, AppState> {
lastPointerUp = null;
isPanning = false;
if (!isHoldingSpace) {
setCursorForShape(this.canvas, this.state.elementType);
if (this.state.viewModeEnabled) {
setCursor(this.canvas, CURSOR_TYPE.GRAB);
} else {
setCursorForShape(this.canvas, this.state.elementType);
}
}
this.setState({
cursorButton: "up",
@ -3865,7 +3827,11 @@ class App extends React.Component<AppProps, AppState> {
try {
const file = event.dataTransfer.files[0];
if (file?.type === "image/png" || file?.type === "image/svg+xml") {
const { elements, appState } = await loadFromBlob(file, this.state);
const { elements, appState } = await loadFromBlob(
file,
this.state,
this.scene.getElementsIncludingDeleted(),
);
this.syncActionResult({
elements,
appState: {
@ -3925,7 +3891,7 @@ class App extends React.Component<AppProps, AppState> {
};
loadFileToCanvas = (file: Blob) => {
loadFromBlob(file, this.state)
loadFromBlob(file, this.state, this.scene.getElementsIncludingDeleted())
.then(({ elements, appState }) =>
this.syncActionResult({
elements,

View File

@ -16,10 +16,5 @@ export const BackgroundPickerAndDarkModeToggle = ({
<div style={{ display: "flex" }}>
{actionManager.renderAction("changeViewBackgroundColor")}
{showThemeBtn && actionManager.renderAction("toggleTheme")}
{appState.fileHandle && (
<div style={{ marginInlineStart: "0.25rem" }}>
{actionManager.renderAction("saveToActiveFile")}
</div>
)}
</div>
);

View File

@ -1,3 +1,4 @@
import React from "react";
import clsx from "clsx";
import { checkIcon } from "./icons";

View File

@ -2,7 +2,7 @@ import clsx from "clsx";
import React, { useEffect, useState } from "react";
import { useCallbackRefState } from "../hooks/useCallbackRefState";
import { t } from "../i18n";
import { useIsMobile } from "../components/App";
import { useExcalidrawContainer, useIsMobile } from "../components/App";
import { KEYS } from "../keys";
import "./Dialog.scss";
import { back, close } from "./icons";
@ -21,6 +21,7 @@ export const Dialog = (props: {
}) => {
const [islandNode, setIslandNode] = useCallbackRefState<HTMLDivElement>();
const [lastActiveElement] = useState(document.activeElement);
const { id } = useExcalidrawContainer();
useEffect(() => {
if (!islandNode) {
@ -82,7 +83,7 @@ export const Dialog = (props: {
theme={props.theme}
>
<Island ref={setIslandNode}>
<h2 id="dialog-title" className="Dialog__title">
<h2 id={`${id}-dialog-title`} className="Dialog__title">
<span className="Dialog__titleContent">{props.title}</span>
<button
className="Modal__close"

View File

@ -12,7 +12,7 @@ export const ErrorDialog = ({
onClose?: () => void;
}) => {
const [modalIsShown, setModalIsShown] = useState(!!message);
const excalidrawContainer = useExcalidrawContainer();
const { container: excalidrawContainer } = useExcalidrawContainer();
const handleClose = React.useCallback(() => {
setModalIsShown(false);

View File

@ -97,7 +97,8 @@
border-radius: 1rem;
background-color: var(--button-color);
box-shadow: 0 3px 5px -1px rgb(0 0 0 / 28%), 0 6px 10px 0 rgb(0 0 0 / 14%);
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.28),
0 6px 10px 0 rgba(0, 0, 0, 0.14);
font-family: Cascadia;
font-size: 1.8em;

View File

@ -157,6 +157,13 @@ export const HelpDialog = ({ onClose }: { onClose?: () => void }) => {
shortcuts={["Shift+P", "7"]}
/>
<Shortcut label={t("toolBar.text")} shortcuts={["T", "8"]} />
<Shortcut
label={t("helpDialog.editSelectedShape")}
shortcuts={[
getShortcutKey("Enter"),
t("helpDialog.doubleClick"),
]}
/>
<Shortcut
label={t("helpDialog.textNewLine")}
shortcuts={[

View File

@ -5,7 +5,7 @@ import { getSelectedElements } from "../scene";
import "./HintViewer.scss";
import { AppState } from "../types";
import { isLinearElement } from "../element/typeChecks";
import { isLinearElement, isTextElement } from "../element/typeChecks";
import { getShortcutKey } from "../utils";
interface Hint {
@ -57,6 +57,14 @@ const getHints = ({ appState, elements }: Hint) => {
return t("hints.lineEditor_info");
}
if (selectedElements.length === 1 && isTextElement(selectedElements[0])) {
return t("hints.text_selected");
}
if (appState.editingElement && isTextElement(appState.editingElement)) {
return t("hints.text_editing");
}
return null;
};

View File

@ -8,20 +8,17 @@ import { CanvasError } from "../errors";
import { t } from "../i18n";
import { useIsMobile } from "./App";
import { getSelectedElements, isSomeElementSelected } from "../scene";
import { exportToCanvas, getExportSize } from "../scene/export";
import { exportToCanvas } from "../scene/export";
import { AppState } from "../types";
import { Dialog } from "./Dialog";
import { clipboard, exportImage } from "./icons";
import Stack from "./Stack";
import { ToolButton } from "./ToolButton";
import "./ExportDialog.scss";
import { supported as fsSupported } from "browser-fs-access";
import OpenColor from "open-color";
import { CheckboxItem } from "./CheckboxItem";
const scales = [1, 2, 3];
const defaultScale = scales.includes(devicePixelRatio) ? devicePixelRatio : 1;
import { DEFAULT_EXPORT_PADDING } from "../constants";
const supportsContextFilters =
"filter" in document.createElement("canvas").getContext("2d")!;
@ -82,7 +79,7 @@ const ExportButton: React.FC<{
const ImageExportModal = ({
elements,
appState,
exportPadding = 10,
exportPadding = DEFAULT_EXPORT_PADDING,
actionManager,
onExportToPng,
onExportToSvg,
@ -98,7 +95,6 @@ const ImageExportModal = ({
onCloseRequest: () => void;
}) => {
const someElementIsSelected = isSomeElementSelected(elements, appState);
const [scale, setScale] = useState(defaultScale);
const [exportSelected, setExportSelected] = useState(someElementIsSelected);
const previewRef = useRef<HTMLDivElement>(null);
const { exportBackground, viewBackgroundColor } = appState;
@ -121,7 +117,6 @@ const ImageExportModal = ({
exportBackground,
viewBackgroundColor,
exportPadding,
scale,
});
// if converting to blob fails, there's some problem that will
@ -144,7 +139,6 @@ const ImageExportModal = ({
exportBackground,
exportPadding,
viewBackgroundColor,
scale,
]);
return (
@ -175,33 +169,8 @@ const ImageExportModal = ({
</div>
</div>
<div style={{ display: "flex", alignItems: "center", marginTop: ".6em" }}>
<Stack.Row gap={2} justifyContent={"center"}>
{scales.map((_scale) => {
const [width, height] = getExportSize(
exportedElements,
exportPadding,
_scale,
);
const scaleButtonTitle = `${t(
"buttons.scale",
)} ${_scale}x (${width}x${height})`;
return (
<ToolButton
key={_scale}
size="s"
type="radio"
icon={`${_scale}x`}
name="export-canvas-scale"
title={scaleButtonTitle}
aria-label={scaleButtonTitle}
id="export-canvas-scale"
checked={_scale === scale}
onChange={() => setScale(_scale)}
/>
);
})}
<Stack.Row gap={2}>
{actionManager.renderAction("changeExportScale")}
</Stack.Row>
<p style={{ marginLeft: "1em", userSelect: "none" }}>Scale</p>
</div>
@ -220,7 +189,7 @@ const ImageExportModal = ({
color="indigo"
title={t("buttons.exportToPng")}
aria-label={t("buttons.exportToPng")}
onClick={() => onExportToPng(exportedElements, scale)}
onClick={() => onExportToPng(exportedElements)}
>
PNG
</ExportButton>
@ -228,14 +197,14 @@ const ImageExportModal = ({
color="red"
title={t("buttons.exportToSvg")}
aria-label={t("buttons.exportToSvg")}
onClick={() => onExportToSvg(exportedElements, scale)}
onClick={() => onExportToSvg(exportedElements)}
>
SVG
</ExportButton>
{probablySupportsClipboardBlob && (
<ExportButton
title={t("buttons.copyPngToClipboard")}
onClick={() => onExportToClipboard(exportedElements, scale)}
onClick={() => onExportToClipboard(exportedElements)}
color="gray"
shade={7}
>
@ -250,7 +219,7 @@ const ImageExportModal = ({
export const ImageExportDialog = ({
elements,
appState,
exportPadding = 10,
exportPadding = DEFAULT_EXPORT_PADDING,
actionManager,
onExportToPng,
onExportToSvg,

View File

@ -116,7 +116,8 @@
}
}
.layer-ui__wrapper__footer-left,
.layer-ui__wrapper__footer-right {
.layer-ui__wrapper__footer-right,
.disable-zen-mode--visible {
pointer-events: all;
}
}

View File

@ -36,7 +36,7 @@ import { Island } from "./Island";
import "./LayerUI.scss";
import { LibraryUnit } from "./LibraryUnit";
import { LoadingMessage } from "./LoadingMessage";
import { LockIcon } from "./LockIcon";
import { LockButton } from "./LockButton";
import { MobileMenu } from "./MobileMenu";
import { PasteChartDialog } from "./PasteChartDialog";
import { Section } from "./Section";
@ -47,6 +47,7 @@ import { Tooltip } from "./Tooltip";
import { UserList } from "./UserList";
import Library from "../data/library";
import { JSONExportDialog } from "./JSONExportDialog";
import { LibraryButton } from "./LibraryButton";
interface LayerUIProps {
actionManager: ActionManager;
@ -107,6 +108,7 @@ const LibraryMenuItems = ({
onAddToLibrary,
onInsertShape,
pendingElements,
theme,
setAppState,
setLibraryItems,
libraryReturnUrl,
@ -119,6 +121,7 @@ const LibraryMenuItems = ({
onRemoveFromLibrary: (index: number) => void;
onInsertShape: (elements: LibraryItem) => void;
onAddToLibrary: (elements: LibraryItem) => void;
theme: AppState["theme"];
setAppState: React.Component<any, AppState>["setState"];
setLibraryItems: (library: LibraryItems) => void;
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
@ -192,7 +195,7 @@ const LibraryMenuItems = ({
<a
href={`https://libraries.excalidraw.com?target=${
window.name || "_blank"
}&referrer=${referrer}&useHash=true&token=${id}`}
}&referrer=${referrer}&useHash=true&token=${id}&theme=${theme}`}
target="_excalidraw_libraries"
>
{t("labels.libraries")}
@ -246,6 +249,7 @@ const LibraryMenu = ({
onInsertShape,
pendingElements,
onAddToLibrary,
theme,
setAppState,
libraryReturnUrl,
focusContainer,
@ -256,6 +260,7 @@ const LibraryMenu = ({
onClickOutside: (event: MouseEvent) => void;
onInsertShape: (elements: LibraryItem) => void;
onAddToLibrary: () => void;
theme: AppState["theme"];
setAppState: React.Component<any, AppState>["setState"];
libraryReturnUrl: ExcalidrawProps["libraryReturnUrl"];
focusContainer: () => void;
@ -345,6 +350,7 @@ const LibraryMenu = ({
libraryReturnUrl={libraryReturnUrl}
focusContainer={focusContainer}
library={library}
theme={theme}
id={id}
/>
)}
@ -400,13 +406,11 @@ const LayerUI = ({
const createExporter = (type: ExportType): ExportCB => async (
exportedElements,
scale,
) => {
await exportCanvas(type, exportedElements, appState, {
exportBackground: appState.exportBackground,
name: appState.name,
viewBackgroundColor: appState.viewBackgroundColor,
scale,
})
.catch(muteFSAbortError)
.catch((error) => {
@ -484,6 +488,9 @@ const LayerUI = ({
setAppState={setAppState}
showThemeBtn={showThemeBtn}
/>
{appState.fileHandle && (
<>{actionManager.renderAction("saveToActiveFile")}</>
)}
</Stack.Col>
</Island>
</Section>
@ -502,7 +509,8 @@ const LayerUI = ({
style={{
// we want to make sure this doesn't overflow so substracting 200
// which is approximately height of zoom footer and top left menu items with some buffer
maxHeight: `${appState.height - 200}px`,
// if active file name is displayed, subtracting 248 to account for its height
maxHeight: `${appState.height - (appState.fileHandle ? 248 : 200)}px`,
}}
>
<SelectedShapeActions
@ -539,6 +547,7 @@ const LayerUI = ({
libraryReturnUrl={libraryReturnUrl}
focusContainer={focusContainer}
library={library}
theme={appState.theme}
id={id}
/>
) : null;
@ -566,6 +575,12 @@ const LayerUI = ({
{(heading) => (
<Stack.Col gap={4} align="start">
<Stack.Row gap={1}>
<LockButton
zenModeEnabled={zenModeEnabled}
checked={appState.elementLocked}
onChange={onLockToggle}
title={t("toolBar.lock")}
/>
<Island
padding={1}
className={clsx({ "zen-mode": zenModeEnabled })}
@ -577,15 +592,12 @@ const LayerUI = ({
canvas={canvas}
elementType={appState.elementType}
setAppState={setAppState}
isLibraryOpen={appState.isLibraryOpen}
/>
</Stack.Row>
</Island>
<LockIcon
zenModeEnabled={zenModeEnabled}
checked={appState.elementLocked}
onChange={onLockToggle}
title={t("toolBar.lock")}
<LibraryButton
appState={appState}
setAppState={setAppState}
/>
</Stack.Row>
{libraryMenu}

View File

@ -0,0 +1,46 @@
import React from "react";
import clsx from "clsx";
import { t } from "../i18n";
import { AppState } from "../types";
import { capitalizeString } from "../utils";
const LIBRARY_ICON = (
<svg viewBox="0 0 576 512">
<path
fill="currentColor"
d="M542.22 32.05c-54.8 3.11-163.72 14.43-230.96 55.59-4.64 2.84-7.27 7.89-7.27 13.17v363.87c0 11.55 12.63 18.85 23.28 13.49 69.18-34.82 169.23-44.32 218.7-46.92 16.89-.89 30.02-14.43 30.02-30.66V62.75c.01-17.71-15.35-31.74-33.77-30.7zM264.73 87.64C197.5 46.48 88.58 35.17 33.78 32.05 15.36 31.01 0 45.04 0 62.75V400.6c0 16.24 13.13 29.78 30.02 30.66 49.49 2.6 149.59 12.11 218.77 46.95 10.62 5.35 23.21-1.94 23.21-13.46V100.63c0-5.29-2.62-10.14-7.27-12.99z"
></path>
</svg>
);
export const LibraryButton: React.FC<{
appState: AppState;
setAppState: React.Component<any, AppState>["setState"];
}> = ({ appState, setAppState }) => {
return (
<label
className={clsx(
"ToolIcon ToolIcon_type_floating ToolIcon__library zen-mode-visibility",
`ToolIcon_size_m`,
{
"zen-mode-visibility--hidden": appState.zenModeEnabled,
},
)}
title={`${capitalizeString(t("toolBar.library"))} — 9`}
style={{ marginInlineStart: "var(--space-factor)" }}
>
<input
className="ToolIcon_type_checkbox"
type="checkbox"
name="editor-library"
onChange={(event) => {
setAppState({ isLibraryOpen: event.target.checked });
}}
checked={appState.isLibraryOpen}
aria-label={capitalizeString(t("toolBar.library"))}
aria-keyshortcuts="9"
/>
<div className="ToolIcon__icon">{LIBRARY_ICON}</div>
</label>
);
};

View File

@ -36,21 +36,27 @@ export const LibraryUnit = ({
if (!elementsToRender) {
return;
}
const svg = exportToSvg(elementsToRender, {
exportBackground: false,
viewBackgroundColor: oc.white,
});
for (const child of ref.current!.children) {
if (child.tagName !== "svg") {
continue;
}
ref.current!.removeChild(child);
}
ref.current!.appendChild(svg);
let svg: SVGSVGElement;
const current = ref.current!;
(async () => {
svg = await exportToSvg(elementsToRender, {
exportBackground: false,
viewBackgroundColor: oc.white,
});
for (const child of ref.current!.children) {
if (child.tagName !== "svg") {
continue;
}
current!.removeChild(child);
}
current!.appendChild(svg);
})();
return () => {
current.removeChild(svg);
if (svg) {
current.removeChild(svg);
}
};
}, [elements, pendingElements]);

View File

@ -8,10 +8,8 @@ type LockIconSize = "s" | "m";
type LockIconProps = {
title?: string;
name?: string;
id?: string;
checked: boolean;
onChange?(): void;
size?: LockIconSize;
zenModeEnabled?: boolean;
};
@ -41,12 +39,12 @@ const ICONS = {
),
};
export const LockIcon = (props: LockIconProps) => {
export const LockButton = (props: LockIconProps) => {
return (
<label
className={clsx(
"ToolIcon ToolIcon__lock ToolIcon_type_floating zen-mode-visibility",
`ToolIcon_size_${props.size || DEFAULT_SIZE}`,
`ToolIcon_size_${DEFAULT_SIZE}`,
{
"zen-mode-visibility--hidden": props.zenModeEnabled,
},
@ -57,7 +55,6 @@ export const LockIcon = (props: LockIconProps) => {
className="ToolIcon_type_checkbox"
type="checkbox"
name={props.name}
id={props.id}
onChange={props.onChange}
checked={props.checked}
aria-label={props.title}

View File

@ -13,9 +13,10 @@ import { SelectedShapeActions, ShapesSwitcher } from "./Actions";
import { Section } from "./Section";
import CollabButton from "./CollabButton";
import { SCROLLBAR_WIDTH, SCROLLBAR_MARGIN } from "../scene/scrollbars";
import { LockIcon } from "./LockIcon";
import { LockButton } from "./LockButton";
import { UserList } from "./UserList";
import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle";
import { LibraryButton } from "./LibraryButton";
type MobileMenuProps = {
appState: AppState;
@ -64,15 +65,15 @@ export const MobileMenu = ({
canvas={canvas}
elementType={appState.elementType}
setAppState={setAppState}
isLibraryOpen={appState.isLibraryOpen}
/>
</Stack.Row>
</Island>
<LockIcon
<LockButton
checked={appState.elementLocked}
onChange={onLockToggle}
title={t("toolBar.lock")}
/>
<LibraryButton appState={appState} setAppState={setAppState} />
</Stack.Row>
{libraryMenu}
</Stack.Col>

View File

@ -58,7 +58,7 @@ const useBodyRoot = (theme: AppState["theme"]) => {
const isMobileRef = useRef(isMobile);
isMobileRef.current = isMobile;
const excalidrawContainer = useExcalidrawContainer();
const { container: excalidrawContainer } = useExcalidrawContainer();
useLayoutEffect(() => {
if (div) {

View File

@ -34,19 +34,21 @@ const ChartPreviewBtn = (props: {
0,
);
setChartElements(elements);
const svg = exportToSvg(elements, {
exportBackground: false,
viewBackgroundColor: oc.white,
});
let svg: SVGSVGElement;
const previewNode = previewRef.current!;
previewNode.appendChild(svg);
(async () => {
svg = await exportToSvg(elements, {
exportBackground: false,
viewBackgroundColor: oc.white,
});
if (props.selected) {
(previewNode.parentNode as HTMLDivElement).focus();
}
previewNode.appendChild(svg);
if (props.selected) {
(previewNode.parentNode as HTMLDivElement).focus();
}
})();
return () => {
previewNode.removeChild(svg);

View File

@ -1,9 +1,10 @@
import "./TextInput.scss";
import React, { Component } from "react";
import React, { useState } from "react";
import { focusNearestParent } from "../utils";
import "./ProjectName.scss";
import { useExcalidrawContainer } from "./App";
type Props = {
value: string;
@ -12,22 +13,19 @@ type Props = {
isNameEditable: boolean;
};
type State = {
fileName: string;
};
export class ProjectName extends Component<Props, State> {
state = {
fileName: this.props.value,
};
private handleBlur = (event: any) => {
export const ProjectName = (props: Props) => {
const { id } = useExcalidrawContainer();
const [fileName, setFileName] = useState<string>(props.value);
const handleBlur = (event: any) => {
focusNearestParent(event.target);
const value = event.target.value;
if (value !== this.props.value) {
this.props.onChange(value);
if (value !== props.value) {
props.onChange(value);
}
};
private handleKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
const handleKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
if (event.key === "Enter") {
event.preventDefault();
if (event.nativeEvent.isComposing || event.keyCode === 229) {
@ -37,29 +35,25 @@ export class ProjectName extends Component<Props, State> {
}
};
public render() {
return (
<div className="ProjectName">
<label className="ProjectName-label" htmlFor="filename">
{`${this.props.label}${this.props.isNameEditable ? "" : ":"}`}
</label>
{this.props.isNameEditable ? (
<input
className="TextInput"
onBlur={this.handleBlur}
onKeyDown={this.handleKeyDown}
id="filename"
value={this.state.fileName}
onChange={(event) =>
this.setState({ fileName: event.target.value })
}
/>
) : (
<span className="TextInput TextInput--readonly" id="filename">
{this.props.value}
</span>
)}
</div>
);
}
}
return (
<div className="ProjectName">
<label className="ProjectName-label" htmlFor="filename">
{`${props.label}${props.isNameEditable ? "" : ":"}`}
</label>
{props.isNameEditable ? (
<input
className="TextInput"
onBlur={handleBlur}
onKeyDown={handleKeyDown}
id={`${id}-filename`}
value={fileName}
onChange={(event) => setFileName(event.target.value)}
/>
) : (
<span className="TextInput TextInput--readonly" id={`${id}-filename`}>
{props.value}
</span>
)}
</div>
);
};

View File

@ -1,5 +1,6 @@
import React from "react";
import { t } from "../i18n";
import { useExcalidrawContainer } from "./App";
interface SectionProps extends React.HTMLProps<HTMLElement> {
heading: string;
@ -7,13 +8,14 @@ interface SectionProps extends React.HTMLProps<HTMLElement> {
}
export const Section = ({ heading, children, ...props }: SectionProps) => {
const { id } = useExcalidrawContainer();
const header = (
<h2 className="visually-hidden" id={`${heading}-title`}>
<h2 className="visually-hidden" id={`${id}-${heading}-title`}>
{t(`headings.${heading}`)}
</h2>
);
return (
<section {...props} aria-labelledby={`${heading}-title`}>
<section {...props} aria-labelledby={`${id}-${heading}-title`}>
{typeof children === "function" ? (
children(header)
) : (

View File

@ -2,6 +2,7 @@ import "./ToolIcon.scss";
import React from "react";
import clsx from "clsx";
import { useExcalidrawContainer } from "./App";
type ToolIconSize = "s" | "m";
@ -43,6 +44,7 @@ type ToolButtonProps =
const DEFAULT_SIZE: ToolIconSize = "m";
export const ToolButton = React.forwardRef((props: ToolButtonProps, ref) => {
const { id: excalId } = useExcalidrawContainer();
const innerRef = React.useRef(null);
React.useImperativeHandle(ref, () => innerRef.current);
const sizeCn = `ToolIcon_size_${props.size || DEFAULT_SIZE}`;
@ -98,7 +100,7 @@ export const ToolButton = React.forwardRef((props: ToolButtonProps, ref) => {
aria-label={props["aria-label"]}
aria-keyshortcuts={props["aria-keyshortcuts"]}
data-testid={props["data-testid"]}
id={props.id}
id={`${excalId}-${props.id}`}
onChange={props.onChange}
checked={props.checked}
ref={innerRef}

View File

@ -8,10 +8,18 @@
position: relative;
font-family: Cascadia;
cursor: pointer;
background-color: var(--button-gray-1);
-webkit-tap-highlight-color: transparent;
border-radius: var(--space-factor);
user-select: none;
background-color: var(--button-gray-1);
&:hover {
background-color: var(--button-gray-2);
}
&:active {
background-color: var(--button-gray-3);
}
}
.ToolIcon--plain {
@ -66,14 +74,6 @@
margin: 0;
font-size: inherit;
&:hover {
background-color: var(--button-gray-1);
}
&:active {
background-color: var(--button-gray-2);
}
&:focus {
box-shadow: 0 0 0 2px var(--focus-highlight-color);
}
@ -86,6 +86,14 @@
}
}
&:hover {
background-color: var(--button-gray-2);
}
&:active {
background-color: var(--button-gray-3);
}
&--show {
visibility: visible;
}
@ -103,6 +111,9 @@
&:not(.ToolIcon_toggle_opaque):checked + .ToolIcon__icon {
background-color: var(--button-gray-2);
&:active {
background-color: var(--button-gray-3);
}
}
&:focus + .ToolIcon__icon {
@ -130,12 +141,21 @@
}
.ToolIcon__icon {
background-color: var(--button-gray-1);
&:hover {
background-color: var(--button-gray-2);
}
&:active {
background-color: var(--button-gray-3);
}
width: 2rem;
height: 2em;
}
}
.ToolIcon.ToolIcon__lock {
margin-inline-end: var(--space-factor);
&.ToolIcon_type_floating {
margin-left: 0.1rem;
}
@ -166,10 +186,9 @@
// move the lock button out of the way on small viewports
// it begins to collide with the GitHub icon before we switch to mobile mode
@media (max-width: 760px) {
.ToolIcon.ToolIcon__lock {
.ToolIcon.ToolIcon_type_floating {
display: inline-block;
position: absolute;
top: 60px;
right: -8px;
margin-left: 0;
@ -194,6 +213,14 @@
position: static;
}
}
.ToolIcon.ToolIcon__library {
top: 100px;
}
.ToolIcon.ToolIcon__lock {
margin-inline-end: 0;
top: 60px;
}
}
.unlocked-icon {

View File

@ -24,7 +24,10 @@ type Opts = {
mirror?: true;
} & React.SVGProps<SVGSVGElement>;
const createIcon = (d: string | React.ReactNode, opts: number | Opts = 512) => {
export const createIcon = (
d: string | React.ReactNode,
opts: number | Opts = 512,
) => {
const { width = 512, height = width, mirror, style } =
typeof opts === "number" ? ({ width: opts } as Opts) : opts;
return (
@ -474,6 +477,11 @@ export const shield = createIcon(
{ width: 24 },
);
export const file = createIcon(
"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48zm32-48h224V288l-23.5-23.5c-4.7-4.7-12.3-4.7-17 0L176 352l-39.5-39.5c-4.7-4.7-12.3-4.7-17 0L80 352v64zm48-240c-26.5 0-48 21.5-48 48s21.5 48 48 48 48-21.5 48-48-21.5-48-48-48z",
{ width: 384, height: 512 },
);
export const GroupIcon = React.memo(({ theme }: { theme: "light" | "dark" }) =>
createIcon(
<>

View File

@ -1,6 +1,6 @@
import { FontFamily } from "./element/types";
import cssVariables from "./css/variables.module.scss";
import { AppProps } from "./types";
import { FontFamilyValues } from "./element/types";
export const APP_NAME = "Excalidraw";
@ -14,6 +14,7 @@ export const CURSOR_TYPE = {
TEXT: "text",
CROSSHAIR: "crosshair",
GRABBING: "grabbing",
GRAB: "grab",
POINTER: "pointer",
MOVE: "move",
AUTO: "",
@ -63,15 +64,15 @@ export const CLASSES = {
// 1-based in case we ever do `if(element.fontFamily)`
export const FONT_FAMILY = {
1: "Virgil",
2: "Helvetica",
3: "Cascadia",
} as const;
Virgil: 1,
Helvetica: 2,
Cascadia: 3,
};
export const WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji";
export const DEFAULT_FONT_SIZE = 20;
export const DEFAULT_FONT_FAMILY: FontFamily = 1;
export const DEFAULT_FONT_FAMILY: FontFamilyValues = FONT_FAMILY.Virgil;
export const DEFAULT_TEXT_ALIGN = "left";
export const DEFAULT_VERTICAL_ALIGN = "top";
export const DEFAULT_VERSION = "{version}";
@ -144,3 +145,6 @@ export const MQ_MAX_WIDTH_LANDSCAPE = 1000;
export const MQ_MAX_HEIGHT_LANDSCAPE = 500;
export const MAX_DECIMALS_FOR_SVG_EXPORT = 2;
export const EXPORT_SCALES = [1, 2, 3];
export const DEFAULT_EXPORT_PADDING = 10; // px

View File

@ -51,11 +51,12 @@
image-rendering: -moz-crisp-edges; // FF
z-index: var(--zIndex-canvas);
}
#canvas {
// Remove the main canvas from document flow to avoid resizeObserver
// feedback loop (see https://github.com/excalidraw/excalidraw/pull/3379)
}
&__canvas {
position: absolute;
}

View File

@ -1,6 +1,7 @@
import { cleanAppStateForExport } from "../appState";
import { EXPORT_DATA_TYPES } from "../constants";
import { clearElementsForExport } from "../element";
import { ExcalidrawElement } from "../element/types";
import { CanvasError } from "../errors";
import { t } from "../i18n";
import { calculateScrollCenter } from "../scene";
@ -83,6 +84,7 @@ export const loadFromBlob = async (
blob: Blob,
/** @see restore.localAppState */
localAppState: AppState | null,
localElements: readonly ExcalidrawElement[] | null,
) => {
const contents = await parseFileContents(blob);
try {
@ -103,6 +105,7 @@ export const loadFromBlob = async (
},
},
localAppState,
localElements,
);
return result;

View File

@ -3,6 +3,7 @@ import {
copyBlobToClipboardAsPng,
copyTextToSystemClipboard,
} from "../clipboard";
import { DEFAULT_EXPORT_PADDING } from "../constants";
import { NonDeletedExcalidrawElement } from "../element/types";
import { t } from "../i18n";
import { exportToCanvas, exportToSvg } from "../scene/export";
@ -20,36 +21,27 @@ export const exportCanvas = async (
appState: AppState,
{
exportBackground,
exportPadding = 10,
exportPadding = DEFAULT_EXPORT_PADDING,
viewBackgroundColor,
name,
scale = 1,
}: {
exportBackground: boolean;
exportPadding?: number;
viewBackgroundColor: string;
name: string;
scale?: number;
},
) => {
if (elements.length === 0) {
throw new Error(t("alerts.cannotExportEmptyCanvas"));
}
if (type === "svg" || type === "clipboard-svg") {
const tempSvg = exportToSvg(elements, {
const tempSvg = await exportToSvg(elements, {
exportBackground,
exportWithDarkMode: appState.exportWithDarkMode,
viewBackgroundColor,
exportPadding,
scale,
metadata:
appState.exportEmbedScene && type === "svg"
? await (
await import(/* webpackChunkName: "image" */ "./image")
).encodeSvgMetadata({
text: serializeAsJSON(elements, appState),
})
: undefined,
exportScale: appState.exportScale,
exportEmbedScene: appState.exportEmbedScene && type === "svg",
});
if (type === "svg") {
await fileSave(new Blob([tempSvg.outerHTML], { type: "image/svg+xml" }), {
@ -58,7 +50,7 @@ export const exportCanvas = async (
});
return;
} else if (type === "clipboard-svg") {
copyTextToSystemClipboard(tempSvg.outerHTML);
await copyTextToSystemClipboard(tempSvg.outerHTML);
return;
}
}
@ -67,7 +59,6 @@ export const exportCanvas = async (
exportBackground,
viewBackgroundColor,
exportPadding,
scale,
});
tempCanvas.style.display = "none";
document.body.appendChild(tempCanvas);

View File

@ -15,7 +15,7 @@ import Library from "./library";
export const serializeAsJSON = (
elements: readonly ExcalidrawElement[],
appState: AppState,
appState: Partial<AppState>,
): string => {
const data: ExportedDataState = {
type: EXPORT_DATA_TYPES.excalidraw,
@ -49,7 +49,10 @@ export const saveAsJSON = async (
return { fileHandle };
};
export const loadFromJSON = async (localAppState: AppState) => {
export const loadFromJSON = async (
localAppState: AppState,
localElements: readonly ExcalidrawElement[] | null,
) => {
const blob = await fileOpen({
description: "Excalidraw files",
// ToDo: Be over-permissive until https://bugs.webkit.org/show_bug.cgi?id=34442
@ -64,7 +67,7 @@ export const loadFromJSON = async (localAppState: AppState) => {
],
*/
});
return loadFromBlob(blob, localAppState);
return loadFromBlob(blob, localAppState, localElements);
};
export const isValidExcalidrawData = (data?: {

View File

@ -2,7 +2,7 @@ import { loadLibraryFromBlob } from "./blob";
import { LibraryItems, LibraryItem } from "../types";
import { restoreElements } from "./restore";
import { getNonDeletedElements } from "../element";
import App from "../components/App";
import type App from "../components/App";
class Library {
private libraryCache: LibraryItems | null = null;
@ -18,7 +18,7 @@ class Library {
};
restoreLibraryItem = (libraryItem: LibraryItem): LibraryItem | null => {
const elements = getNonDeletedElements(restoreElements(libraryItem));
const elements = getNonDeletedElements(restoreElements(libraryItem, null));
return elements.length ? elements : null;
};

View File

@ -1,21 +1,26 @@
import {
ExcalidrawElement,
FontFamily,
ExcalidrawSelectionElement,
FontFamilyValues,
} from "../element/types";
import { AppState, NormalizedZoomValue } from "../types";
import { ImportedDataState } from "./types";
import { isInvisiblySmallElement, getNormalizedDimensions } from "../element";
import {
getElementMap,
getNormalizedDimensions,
isInvisiblySmallElement,
} from "../element";
import { isLinearElementType } from "../element/typeChecks";
import { randomId } from "../random";
import {
FONT_FAMILY,
DEFAULT_FONT_FAMILY,
DEFAULT_TEXT_ALIGN,
DEFAULT_VERTICAL_ALIGN,
FONT_FAMILY,
} from "../constants";
import { getDefaultAppState } from "../appState";
import { LinearElementEditor } from "../element/linearElementEditor";
import { bumpVersion } from "../element/mutateElement";
type RestoredAppState = Omit<
AppState,
@ -41,11 +46,11 @@ export type RestoredDataState = {
appState: RestoredAppState;
};
const getFontFamilyByName = (fontFamilyName: string): FontFamily => {
for (const [id, fontFamilyString] of Object.entries(FONT_FAMILY)) {
if (fontFamilyString.includes(fontFamilyName)) {
return parseInt(id) as FontFamily;
}
const getFontFamilyByName = (fontFamilyName: string): FontFamilyValues => {
if (Object.keys(FONT_FAMILY).includes(fontFamilyName)) {
return FONT_FAMILY[
fontFamilyName as keyof typeof FONT_FAMILY
] as FontFamilyValues;
}
return DEFAULT_FONT_FAMILY;
};
@ -181,13 +186,20 @@ const restoreElement = (
export const restoreElements = (
elements: ImportedDataState["elements"],
/** NOTE doesn't serve for reconciliation */
localElements: readonly ExcalidrawElement[] | null | undefined,
): ExcalidrawElement[] => {
const localElementsMap = localElements ? getElementMap(localElements) : null;
return (elements || []).reduce((elements, element) => {
// filtering out selection, which is legacy, no longer kept in elements,
// and causing issues if retained
if (element.type !== "selection" && !isInvisiblySmallElement(element)) {
const migratedElement = restoreElement(element);
let migratedElement: ExcalidrawElement = restoreElement(element);
if (migratedElement) {
const localElement = localElementsMap?.[element.id];
if (localElement && localElement.version > migratedElement.version) {
migratedElement = bumpVersion(migratedElement, localElement.version);
}
elements.push(migratedElement);
}
}
@ -197,25 +209,25 @@ export const restoreElements = (
export const restoreAppState = (
appState: ImportedDataState["appState"],
localAppState: Partial<AppState> | null,
localAppState: Partial<AppState> | null | undefined,
): RestoredAppState => {
appState = appState || {};
const defaultAppState = getDefaultAppState();
const nextAppState = {} as typeof defaultAppState;
for (const [key, val] of Object.entries(defaultAppState) as [
for (const [key, defaultValue] of Object.entries(defaultAppState) as [
keyof typeof defaultAppState,
any,
][]) {
const restoredValue = appState[key];
const suppliedValue = appState[key];
const localValue = localAppState ? localAppState[key] : undefined;
(nextAppState as any)[key] =
restoredValue !== undefined
? restoredValue
suppliedValue !== undefined
? suppliedValue
: localValue !== undefined
? localValue
: val;
: defaultValue;
}
return {
@ -243,9 +255,10 @@ export const restore = (
* Supply `null` if you can't get access to it.
*/
localAppState: Partial<AppState> | null | undefined,
localElements: readonly ExcalidrawElement[] | null | undefined,
): RestoredDataState => {
return {
elements: restoreElements(data?.elements),
elements: restoreElements(data?.elements, localElements),
appState: restoreAppState(data?.appState, localAppState || null),
};
};

View File

@ -5,7 +5,7 @@ import { mutateElement } from "./mutateElement";
import { getPerfectElementSize } from "./sizeHelpers";
import Scene from "../scene/Scene";
import { NonDeletedExcalidrawElement } from "./types";
import { PointerDownState } from "../components/App";
import { PointerDownState } from "../types";
export const dragSelectedElements = (
pointerDownState: PointerDownState,

View File

@ -120,8 +120,11 @@ export const newElementWith = <TElement extends ExcalidrawElement>(
*
* NOTE: does not trigger re-render.
*/
export const bumpVersion = (element: Mutable<ExcalidrawElement>) => {
element.version = element.version + 1;
export const bumpVersion = (
element: Mutable<ExcalidrawElement>,
version?: ExcalidrawElement["version"],
) => {
element.version = (version ?? element.version) + 1;
element.versionNonce = randomInteger();
return element;
};

View File

@ -1,6 +1,7 @@
import { duplicateElement } from "./newElement";
import { mutateElement } from "./mutateElement";
import { API } from "../tests/helpers/api";
import { FONT_FAMILY } from "../constants";
const isPrimitive = (val: any) => {
const type = typeof val;
@ -79,7 +80,7 @@ it("clones text element", () => {
opacity: 100,
text: "hello",
fontSize: 20,
fontFamily: 1,
fontFamily: FONT_FAMILY.Virgil,
textAlign: "left",
verticalAlign: "top",
});

View File

@ -5,11 +5,11 @@ import {
ExcalidrawGenericElement,
NonDeleted,
TextAlign,
FontFamily,
GroupId,
VerticalAlign,
Arrowhead,
ExcalidrawFreeDrawElement,
FontFamilyValues,
} from "../element/types";
import { measureText, getFontString } from "../utils";
import { randomInteger, randomId } from "../random";
@ -109,7 +109,7 @@ export const newTextElement = (
opts: {
text: string;
fontSize: number;
fontFamily: FontFamily;
fontFamily: FontFamilyValues;
textAlign: TextAlign;
verticalAlign: VerticalAlign;
} & ElementConstructorOpts,

View File

@ -32,8 +32,7 @@ import {
MaybeTransformHandleType,
TransformHandleDirection,
} from "./transformHandles";
import { PointerDownState } from "../components/App";
import { Point } from "../types";
import { Point, PointerDownState } from "../types";
export const normalizeAngle = (angle: number): number => {
if (angle >= 2 * Math.PI) {

View File

@ -3,7 +3,8 @@ import { FONT_FAMILY } from "../constants";
export type ChartType = "bar" | "line";
export type FillStyle = "hachure" | "cross-hatch" | "solid";
export type FontFamily = keyof typeof FONT_FAMILY;
export type FontFamilyKeys = keyof typeof FONT_FAMILY;
export type FontFamilyValues = typeof FONT_FAMILY[FontFamilyKeys];
export type FontString = string & { _brand: "fontString" };
export type GroupId = string;
export type PointerType = "mouse" | "pen" | "touch";
@ -91,7 +92,7 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase &
Readonly<{
type: "text";
fontSize: number;
fontFamily: FontFamily;
fontFamily: FontFamilyValues;
text: string;
baseline: number;
textAlign: TextAlign;

View File

@ -1,6 +1,6 @@
import throttle from "lodash.throttle";
import React, { PureComponent } from "react";
import { ExcalidrawImperativeAPI } from "../../components/App";
import { ExcalidrawImperativeAPI } from "../../types";
import { ErrorDialog } from "../../components/ErrorDialog";
import { APP_NAME, ENV, EVENT } from "../../constants";
import { ImportedDataState } from "../../data/types";

View File

@ -0,0 +1,92 @@
import React from "react";
import { Card } from "../../components/Card";
import { ToolButton } from "../../components/ToolButton";
import { serializeAsJSON } from "../../data/json";
import { getImportedKey, createIV, generateEncryptionKey } from "../data";
import { loadFirebaseStorage } from "../data/firebase";
import { NonDeletedExcalidrawElement } from "../../element/types";
import { AppState } from "../../types";
import { nanoid } from "nanoid";
import { t } from "../../i18n";
import { excalidrawPlusIcon } from "./icons";
const encryptData = async (
key: string,
json: string,
): Promise<{ blob: Blob; iv: Uint8Array }> => {
const importedKey = await getImportedKey(key, "encrypt");
const iv = createIV();
const encoded = new TextEncoder().encode(json);
const ciphertext = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv,
},
importedKey,
encoded,
);
return { blob: new Blob([new Uint8Array(ciphertext)]), iv };
};
const exportToExcalidrawPlus = async (
elements: readonly NonDeletedExcalidrawElement[],
appState: AppState,
) => {
const firebase = await loadFirebaseStorage();
const id = `${nanoid(12)}`;
const key = (await generateEncryptionKey())!;
const encryptedData = await encryptData(
key,
serializeAsJSON(elements, appState),
);
const blob = new Blob([encryptedData.iv, encryptedData.blob], {
type: "application/octet-stream",
});
await firebase
.storage()
.ref(`/migrations/scenes/${id}`)
.put(blob, {
customMetadata: {
data: JSON.stringify({ version: 1, name: appState.name }),
created: Date.now().toString(),
},
});
window.open(`https://plus.excalidraw.com/import?excalidraw=${id},${key}`);
};
export const ExportToExcalidrawPlus: React.FC<{
elements: readonly NonDeletedExcalidrawElement[];
appState: AppState;
onError: (error: Error) => void;
}> = ({ elements, appState, onError }) => {
return (
<Card color="indigo">
<div className="Card-icon">{excalidrawPlusIcon}</div>
<h2>Excalidraw+</h2>
<div className="Card-details">
{t("exportDialog.excalidrawplus_description")}
</div>
<ToolButton
className="Card-button"
type="button"
title={t("exportDialog.excalidrawplus_button")}
aria-label={t("exportDialog.excalidrawplus_button")}
showAriaLabel={true}
onClick={async () => {
try {
await exportToExcalidrawPlus(elements, appState);
} catch (error) {
console.error(error);
onError(new Error(t("exportDialog.excalidrawplus_exportError")));
}
}}
/>
</Card>
);
};

File diff suppressed because one or more lines are too long

View File

@ -5,15 +5,19 @@ import { getSceneVersion } from "../../element";
import Portal from "../collab/Portal";
import { restoreElements } from "../../data/restore";
// private
// -----------------------------------------------------------------------------
let firebasePromise: Promise<
typeof import("firebase/app").default
> | null = null;
let firestorePromise: Promise<any> | null = null;
let firebseStoragePromise: Promise<any> | null = null;
const loadFirebase = async () => {
const _loadFirebase = async () => {
const firebase = (
await import(/* webpackChunkName: "firebase" */ "firebase/app")
).default;
await import(/* webpackChunkName: "firestore" */ "firebase/firestore");
const firebaseConfig = JSON.parse(process.env.REACT_APP_FIREBASE_CONFIG);
firebase.initializeApp(firebaseConfig);
@ -21,13 +25,37 @@ const loadFirebase = async () => {
return firebase;
};
const getFirebase = async (): Promise<
const _getFirebase = async (): Promise<
typeof import("firebase/app").default
> => {
if (!firebasePromise) {
firebasePromise = loadFirebase();
firebasePromise = _loadFirebase();
}
return await firebasePromise!;
return firebasePromise;
};
// -----------------------------------------------------------------------------
const loadFirestore = async () => {
const firebase = await _getFirebase();
if (!firestorePromise) {
firestorePromise = import(
/* webpackChunkName: "firestore" */ "firebase/firestore"
);
await firestorePromise;
}
return firebase;
};
export const loadFirebaseStorage = async () => {
const firebase = await _getFirebase();
if (!firebseStoragePromise) {
firebseStoragePromise = import(
/* webpackChunkName: "storage" */ "firebase/storage"
);
await firebseStoragePromise;
}
return firebase;
};
interface FirebaseStoredScene {
@ -108,7 +136,7 @@ export const saveToFirebase = async (
return true;
}
const firebase = await getFirebase();
const firebase = await loadFirestore();
const sceneVersion = getSceneVersion(elements);
const { ciphertext, iv } = await encryptElements(roomKey, elements);
@ -150,7 +178,7 @@ export const loadFromFirebase = async (
roomKey: string,
socket: SocketIOClient.Socket | null,
): Promise<readonly ExcalidrawElement[] | null> => {
const firebase = await getFirebase();
const firebase = await loadFirestore();
const db = firebase.firestore();
const docRef = db.collection("scenes").doc(roomId);
@ -168,5 +196,5 @@ export const loadFromFirebase = async (
firebaseSceneVersionCache.set(socket, getSceneVersion(elements));
}
return restoreElements(elements);
return restoreElements(elements, null);
};

View File

@ -17,7 +17,7 @@ const generateRandomID = async () => {
return Array.from(arr, byteToHex).join("");
};
const generateEncryptionKey = async () => {
export const generateEncryptionKey = async () => {
const key = await window.crypto.subtle.generateKey(
{
name: "AES-GCM",
@ -176,7 +176,7 @@ export const getImportedKey = (key: string, usage: KeyUsage) =>
[usage],
);
const decryptImported = async (
export const decryptImported = async (
iv: ArrayBuffer,
encrypted: ArrayBuffer,
privateKey: string,
@ -257,9 +257,10 @@ export const loadScene = async (
data = restore(
await importFromBackend(id, privateKey),
localDataState?.appState,
localDataState?.elements,
);
} else {
data = restore(localDataState || null, null);
data = restore(localDataState || null, null, null);
}
return {

View File

@ -8,7 +8,6 @@ import React, {
} from "react";
import { trackEvent } from "../analytics";
import { getDefaultAppState } from "../appState";
import { ExcalidrawImperativeAPI } from "../components/App";
import { ErrorDialog } from "../components/ErrorDialog";
import { TopErrorBoundary } from "../components/TopErrorBoundary";
import {
@ -31,7 +30,7 @@ import Excalidraw, {
defaultLang,
languages,
} from "../packages/excalidraw/index";
import { AppState, LibraryItems } from "../types";
import { AppState, LibraryItems, ExcalidrawImperativeAPI } from "../types";
import {
debounce,
getVersion,
@ -56,6 +55,7 @@ import { Tooltip } from "../components/Tooltip";
import { shield } from "../components/icons";
import "./index.scss";
import { ExportToExcalidrawPlus } from "./components/ExportToExcalidrawPlus";
const languageDetector = new LanguageDetector();
languageDetector.init({
@ -141,7 +141,7 @@ const initializeScene = async (opts: {
const url = externalUrlMatch[1];
try {
const request = await fetch(window.decodeURIComponent(url));
const data = await loadFromBlob(await request.blob(), null);
const data = await loadFromBlob(await request.blob(), null, null);
if (
!scene.elements.length ||
window.confirm(t("alerts.loadSceneOverridePrompt"))
@ -428,6 +428,21 @@ const ExcalidrawWrapper = () => {
canvasActions: {
export: {
onExportToBackend,
renderCustomUI: (elements, appState) => {
return (
<ExportToExcalidrawPlus
elements={elements}
appState={appState}
onError={(error) => {
excalidrawAPI?.updateScene({
appState: {
errorMessage: error.message,
},
});
}}
/>
);
},
},
},
}}
@ -438,6 +453,7 @@ const ExcalidrawWrapper = () => {
detectScroll={false}
handleKeyboardGlobally={true}
onLibraryChange={onLibraryChange}
autoFocus={true}
/>
{excalidrawAPI && <CollabWrapper excalidrawAPI={excalidrawAPI} />}
{errorMessage && (

View File

@ -49,6 +49,7 @@ const allLanguages: Language[] = [
{ code: "zh-TW", label: "繁體中文" },
{ code: "lv-LV", label: "Latviešu" },
{ code: "cs-CZ", label: "Česky" },
{ code: "kk-KZ", label: "Қазақ тілі" },
].concat([defaultLang]);
export const languages: Language[] = allLanguages

View File

@ -69,7 +69,6 @@ const canvas = exportToCanvas(
{
exportBackground: true,
viewBackgroundColor: "#ffffff",
scale: 1,
},
createCanvas,
);

View File

@ -101,6 +101,8 @@
"viewMode": "نمط العرض",
"toggleExportColorScheme": "",
"share": "مشاركة",
"showStroke": "",
"showBackground": "",
"toggleTheme": "غير النمط"
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "انقر لبدء نقاط متعددة، اسحب لخط واحد",
"freeDraw": "انقر واسحب، افرج عند الانتهاء",
"text": "نصيحة: يمكنك أيضًا إضافة نص بالنقر المزدوج في أي مكان بأداة الاختيار",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "انقر فوق النقطة الأخيرة أو اضغط على Esc أو Enter للإنهاء",
"lockAngle": "يمكنك تقييد الزاوية بالضغط على SHIFT",
"resize": "يمكنك تقييد النسب بالضغط على SHIFT أثناء تغيير الحجم،\nاضغط على ALT لتغيير الحجم من المركز",
@ -223,7 +227,10 @@
"disk_button": "إحفظ لملف",
"link_title": "رابط قابل للمشاركة",
"link_details": "صدر الملف للمشاهدة فقط.",
"link_button": "التصدير كرابط"
"link_button": "التصدير كرابط",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "اقرأ مدونتنا",
@ -231,16 +238,18 @@
"curvedArrow": "سهم مائل",
"curvedLine": "خط مائل",
"documentation": "دليل الاستخدام",
"doubleClick": "",
"drag": "اسحب",
"editor": "المحرر",
"editSelectedShape": "",
"github": "عثرت على مشكلة؟ إرسال",
"howto": "اتبع التعليمات",
"or": "أو",
"preventBinding": "منع ارتبط السهم",
"shapes": "أشكال",
"shortcuts": "اختصارات لوحة المفاتيح",
"textFinish": "الانتهاء من التحرير (نص)",
"textNewLine": "اضف سطر جديد (نص)",
"textFinish": "",
"textNewLine": "",
"title": "المساعدة",
"view": "عرض",
"zoomToFit": "تكبير للملائمة",

View File

@ -101,6 +101,8 @@
"viewMode": "Изглед",
"toggleExportColorScheme": "",
"share": "",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Кликнете, за да стартирате няколко точки, плъзнете за една линия",
"freeDraw": "Натиснете и влачете, пуснете като сте готови",
"text": "Подсказка: Можете също да добавите текст като натиснете някъде два път с инструмента за селекция",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "Кликнете върху последната точка или натиснете Escape или Enter, за да завършите",
"lockAngle": "Можете да ограничите ъгъла, като задържите SHIFT",
"resize": "Може да ограничите при преоразмеряване като задържите SHIFT,\nзадръжте ALT за преоразмерите през центъра",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "Прочетете нашия блог",
@ -231,16 +238,18 @@
"curvedArrow": "Извита стрелка",
"curvedLine": "Извита линия",
"documentation": "Документация",
"doubleClick": "",
"drag": "плъзнете",
"editor": "Редактор",
"editSelectedShape": "",
"github": "Намерихте проблем? Изпратете",
"howto": "Следвайте нашите ръководства",
"or": "или",
"preventBinding": "Спри прилепяне на стрелките",
"shapes": "Фигури",
"shortcuts": "Клавиши за бърз достъп",
"textFinish": "Завършете редактирането (текст)",
"textNewLine": "Добавяне на нов ред (текст)",
"textFinish": "",
"textNewLine": "",
"title": "Помощ",
"view": "Преглед",
"zoomToFit": "Приближи докато се виждат всички елементи",

View File

@ -1,29 +1,29 @@
{
"labels": {
"paste": "Enganxar",
"pasteCharts": "Enganxar diagrames",
"selectAll": "Seleccionar tot",
"multiSelect": "Afegir element a la selecció",
"moveCanvas": "Moure el llenç",
"cut": "Tallar",
"copy": "Copiar",
"copyAsPng": "Copiar al porta-retalls com a PNG",
"copyAsSvg": "Copiar al porta-retalls com a SVG",
"bringForward": "Portar endavant",
"sendToBack": "Enviar endarrere",
"bringToFront": "Portar al capdavant",
"sendBackward": "Enviar al fons",
"delete": "Eliminar",
"copyStyles": "Copiar estils",
"pasteStyles": "Enganxar estils",
"paste": "Enganxa",
"pasteCharts": "Enganxa els diagrames",
"selectAll": "Selecciona-ho tot",
"multiSelect": "Afegeix un element a la selecció",
"moveCanvas": "Mou el llenç",
"cut": "Retalla",
"copy": "Copia",
"copyAsPng": "Copia al porta-retalls com a PNG",
"copyAsSvg": "Copia al porta-retalls com a SVG",
"bringForward": "Porta endavant",
"sendToBack": "Envia enrere",
"bringToFront": "Porta al davant",
"sendBackward": "Envia al fons",
"delete": "Elimina",
"copyStyles": "Copia els estils",
"pasteStyles": "Enganxa els estils",
"stroke": "Color del traç",
"background": "Color del fons",
"fill": "Estil del fons",
"strokeWidth": "Amplada del traç",
"strokeShape": "",
"strokeShape_gel": "",
"strokeShape_fountain": "",
"strokeShape_brush": "",
"strokeShape": "Estil del traç",
"strokeShape_gel": "Bolígraf de gel",
"strokeShape_fountain": "Bolígraf de font",
"strokeShape_brush": "Bolígraf de raspall",
"strokeStyle": "Estil del traç",
"strokeStyle_solid": "Sòlid",
"strokeStyle_dashed": "Guions",
@ -42,10 +42,10 @@
"fontSize": "Mida de lletra",
"fontFamily": "Tipus de lletra",
"onlySelected": "Només seleccionats",
"withBackground": "",
"exportEmbedScene": "",
"withBackground": "Fons",
"exportEmbedScene": "Insereix l'escena",
"exportEmbedScene_details": "Les dades de lescena es desaran al fitxer PNG/SVG de manera que es pugui restaurar lescena.\nAugmentarà la mida del fitxer exportat.",
"addWatermark": "Afegir \"Fet amb Excalidraw\"",
"addWatermark": "Afegeix-hi «Fet amb Excalidraw»",
"handDrawn": "Dibuixat a mà",
"normal": "Normal",
"code": "Codi",
@ -73,73 +73,75 @@
"actions": "Accions",
"language": "Llengua",
"liveCollaboration": "Col·laboració en directe",
"duplicateSelection": "Duplicar",
"duplicateSelection": "Duplica",
"untitled": "Sense títol",
"name": "Nom",
"yourName": "El teu nom",
"yourName": "El vostre nom",
"madeWithExcalidraw": "Fet amb Excalidraw",
"group": "Agrupar la selecció",
"ungroup": "Desagrupar la selecció",
"group": "Agrupa la selecció",
"ungroup": "Desagrupa la selecció",
"collaborators": "Col·laboradors",
"showGrid": "Mostra la graella",
"addToLibrary": "Afegir a la biblioteca",
"removeFromLibrary": "Eliminar de la biblioteca",
"libraryLoadingMessage": "Carregant la biblioteca…",
"libraries": "Explorar biblioteques",
"loadingScene": "Carregant escena…",
"align": "Alinear",
"alignTop": "Alinear a dalt",
"alignBottom": "Alinear a baix",
"alignLeft": "Alinear a lesquerra",
"alignRight": "Alinear a la dreta",
"centerVertically": "Centrar verticalment",
"centerHorizontally": "Centrar horitzontalment",
"distributeHorizontally": "Distribuir horitzontalment",
"distributeVertically": "Distribuir verticalment",
"libraryLoadingMessage": "S'està carregant la biblioteca…",
"libraries": "Explora les biblioteques",
"loadingScene": "S'està carregant l'escena…",
"align": "Alinea",
"alignTop": "Alinea a la part superior",
"alignBottom": "Alinea a la part inferior",
"alignLeft": "Alinea a lesquerra",
"alignRight": "Alinea a la dreta",
"centerVertically": "Centra verticalment",
"centerHorizontally": "Centra horitzontalment",
"distributeHorizontally": "Distribueix horitzontalment",
"distributeVertically": "Distribueix verticalment",
"flipHorizontal": "Capgira horitzontalment",
"flipVertical": "Capgira verticalment",
"viewMode": "Mode de visualització",
"toggleExportColorScheme": "Canvia l'esquema de colors de l'exportació",
"share": "Compartir",
"toggleTheme": ""
"share": "Comparteix",
"showStroke": "Mostra el selector de color del traç",
"showBackground": "Mostra el selector de color de fons",
"toggleTheme": "Activa o desactiva el tema"
},
"buttons": {
"clearReset": "Netejar el llenç",
"exportJSON": "",
"exportImage": "",
"export": "Exportar",
"exportToPng": "Exportar a PNG",
"exportToSvg": "Exportar a SNG",
"copyToClipboard": "Copiar al porta-retalls",
"copyPngToClipboard": "Copiar PNG al porta-retalls",
"clearReset": "Neteja el llenç",
"exportJSON": "Exporta a un fitxer",
"exportImage": "Desa com a imatge",
"export": "Exporta",
"exportToPng": "Exporta a PNG",
"exportToSvg": "Exporta a SNG",
"copyToClipboard": "Copia al porta-retalls",
"copyPngToClipboard": "Copia el PNG al porta-retalls",
"scale": "Escala",
"save": "",
"saveAs": "Desar com",
"load": "Carregar",
"getShareableLink": "Obtenir enllaç per compartir",
"close": "Tancar",
"selectLanguage": "Triar idioma",
"scrollBackToContent": "Tornar al contingut",
"zoomIn": "Ampliar",
"zoomOut": "Reduir",
"resetZoom": "Restablir zoom",
"save": "Desa al fitxer actual",
"saveAs": "Anomena i desa",
"load": "Carrega",
"getShareableLink": "Obté l'enllaç per a compartir",
"close": "Tanca",
"selectLanguage": "Trieu la llengua",
"scrollBackToContent": "Torna al contingut",
"zoomIn": "Apropa't",
"zoomOut": "Allunya't",
"resetZoom": "Restableix el zoom",
"menu": "Menú",
"done": "Fet",
"edit": "Editar",
"undo": "Desfer",
"redo": "Refer",
"resetLibrary": "Restablir biblioteca",
"createNewRoom": "Crear sala nova",
"edit": "Edita",
"undo": "Desfés",
"redo": "Refés",
"resetLibrary": "Restableix la biblioteca",
"createNewRoom": "Crea una sala nova",
"fullScreen": "Pantalla completa",
"darkMode": "Mode fosc",
"lightMode": "Mode clar",
"zenMode": "Mode Zen",
"exitZenMode": "Sortir de modo zen"
"zenMode": "Mode zen",
"exitZenMode": "Surt de mode zen"
},
"alerts": {
"clearReset": "Tot el llenç s'esborrarà. Estàs segur?",
"couldNotCreateShareableLink": "No s'ha pogut crear un enllaç per compartir.",
"couldNotCreateShareableLinkTooBig": "No sha pogut crear un enllaç per compartir: lescena és massa gran",
"clearReset": "S'esborrarà tot el llenç. N'esteu segur?",
"couldNotCreateShareableLink": "No s'ha pogut crear un enllaç per a compartir.",
"couldNotCreateShareableLinkTooBig": "No sha pogut crear un enllaç per a compartir: lescena és massa gran",
"couldNotLoadInvalidFile": "No s'ha pogut carregar un fitxer no vàlid",
"importBackendFailed": "Importació fallida.",
"cannotExportEmptyCanvas": "No es pot exportar un llenç buit.",
@ -149,13 +151,13 @@
"loadSceneOverridePrompt": "Si carregas aquest dibuix extern, substituirá el que tens. Vols continuar?",
"collabStopOverridePrompt": "Aturar la sessió provocarà la sobreescriptura del dibuix previ, que hi ha desat en l'emmagatzematge local. N'esteu segur?\n\n(Si voleu conservar el dibuix local, tanqueu la pentanya del navegador en comptes d'aturar la sessió).",
"errorLoadingLibrary": "S'ha produït un error en carregar la biblioteca de tercers.",
"errorAddingToLibrary": "",
"errorRemovingFromLibrary": "",
"errorAddingToLibrary": "No s'ha pogut afegir l'element a la biblioteca",
"errorRemovingFromLibrary": "No s'ha pogut eliminar l'element de la biblioteca",
"confirmAddLibrary": "Això afegirà {{numShapes}} forma(es) a la vostra biblioteca. Estàs segur?",
"imageDoesNotContainScene": "En aquest moment no sadmet la importació dimatges.\n\nVolies importar una escena? Sembla que aquesta imatge no conté cap dada descena. Ho has activat durant l'exportació?",
"cannotRestoreFromImage": "Lescena no sha pogut restaurar des daquest fitxer dimatge",
"invalidSceneUrl": "No s'ha pogut importar l'escena des de l'adreça URL proporcionada. Està malformada o no conté dades Excalidraw JSON vàlides.",
"resetLibrary": "Tot el llenç s'esborrarà. Estàs segur?"
"resetLibrary": "Això buidarà la biblioteca. N'esteu segur?"
},
"toolBar": {
"selection": "Selecció",
@ -175,55 +177,60 @@
"shapes": "Formes"
},
"hints": {
"linearElement": "Fer clic per dibuixar múltiples punts; arrossegar per una sola línea",
"freeDraw": "Fer clic i arrosegar, deixar anar al punt final",
"text": "Consell: també pots afegir text fent doble clic a qualsevol lloc amb l'eina de selecció",
"linearElementMulti": "Fer clic a l'ultim punt, o polsar Escape o Enter per acabar",
"linearElement": "Feu clic per a dibuixar múltiples punts; arrossegueu per a una sola línia",
"freeDraw": "Feu clic i arrossegueu, deixeu anar per a finalitzar",
"text": "Consell: també podeu afegir text fent doble clic en qualsevol lloc amb l'eina de selecció",
"text_selected": "Feu doble clic o premeu Retorn per a editar el text",
"text_editing": "Premeu Escapada o Ctrl+Retorn (o Ordre+Retorn) per a finalitzar l'edició",
"linearElementMulti": "Feu clic a l'ultim punt, o pitgeu Esc o Retorn per a finalitzar",
"lockAngle": "Per restringir els angles, mantenir premut el majúscul (SHIFT)",
"resize": "Per restringir les proporcions mentres es canvia la mida, mantenir premut el majúscul (SHIFT); per canviar la mida des del centre, mantenir premut ALT",
"rotate": "Per restringir els angles mentre gira, mantenir premut el majúscul (SHIFT)",
"lineEditor_info": "Fes doble clic o premi Enter per editar punts",
"lineEditor_pointSelected": "Premi Suprimir per eliminar el punt, CtrlOrCmd+D per duplicar-lo, o arrosega'l per moure'l",
"lineEditor_pointSelected": "Premeu Suprimir per a eliminar el punt, CtrlOrCmd+D per a duplicar-lo, o arrossegueu-lo per a moure'l",
"lineEditor_nothingSelected": "Selecciona un punt per moure o eliminar, o manté premut Alt i fes clic per afegir punts nous"
},
"canvasError": {
"cannotShowPreview": "No es pot mostrar la vista prèvia",
"cannotShowPreview": "No es pot mostrar la previsualització",
"canvasTooBig": "Pot ser que el llenç sigui massa gran.",
"canvasTooBigTip": "Consell: prova dacostar una mica els elements més allunyats."
"canvasTooBigTip": "Consell: proveu dacostar una mica els elements més allunyats."
},
"errorSplash": {
"headingMain_pre": "S'ha produït un error. Intentar ",
"headingMain_pre": "S'ha produït un error. Proveu ",
"headingMain_button": "recarregar la pàgina.",
"clearCanvasMessage": "Si la recarrega no funciona, intentar ",
"clearCanvasMessage": "Si la recàrrega no funciona, proveu ",
"clearCanvasMessage_button": "esborrar el llenç.",
"clearCanvasCaveat": " Això resultarà en pèrdua de feina ",
"clearCanvasCaveat": " Això resultarà en la pèrdua de feina ",
"trackedToSentry_pre": "L'error amb l'identificador ",
"trackedToSentry_post": " s'ha rastrejat en el nostre sistema.",
"openIssueMessage_pre": "Estàvem molt amb compte de no incloure la teva informació de l'escena en l'error. Si la teva escena no és privada, pots fer el seguiment al nostre ",
"openIssueMessage_pre": "Anàvem amb molta cura de no incloure la informació de la vostra escena en l'error. Si l'escena no és privada, podeu fer-ne el seguiment al nostre ",
"openIssueMessage_button": "rastrejador d'errors.",
"openIssueMessage_post": " Si us plau incloure la informació a continuació copiant i enganxant a GitHub Issues.",
"openIssueMessage_post": " Incloeu la informació a continuació copiant i enganxant a GitHub Issues.",
"sceneContent": "Contingut de l'escena:"
},
"roomDialog": {
"desc_intro": "Pots convidar persones a la teva escena actual a col·laborar amb tu.",
"desc_privacy": "No et preocupis, la sessió utilitza el xifratge de punta a punta, de manera que qualsevol cosa que dibuixis quedarà privada. Ni tan sols el nostre servidor podrà veure el que fas.",
"button_startSession": "Iniciar sessió",
"button_stopSession": "Aturar sessió",
"desc_intro": "Podeu convidar persones a la vostra escena actual a col·laborar amb vós.",
"desc_privacy": "No us preocupeu, la sessió utilitza el xifratge de punta a punta, de manera que qualsevol cosa que dibuixeu romandrà privada. Ni tan sols el nostre servidor podrà veure què feu.",
"button_startSession": "Inicia la sessió",
"button_stopSession": "Atura la sessió",
"desc_inProgressIntro": "La sessió de col·laboració en directe està en marxa.",
"desc_shareLink": "Comparteix aquest enllaç amb qualsevol persona amb qui vulguis col·laborar:",
"desc_exitSession": "Si aturas la sessió, et desconectarás de la sala, però podrás continuar treballant amb el dibuix localment. Tingues en compte que això no afectarà a altres persones, i encara podran col·laborar en la seva versió.",
"desc_shareLink": "Comparteix aquest enllaç amb qualsevol persona amb qui vulgueu col·laborar:",
"desc_exitSession": "Si atureu la sessió, us desconectareu de la sala, però podreu continuar treballant amb el dibuix localment. Tingues en compte que això no afectarà a altres persones, i encara podran col·laborar en la seva versió.",
"shareTitle": "Uniu-vos a una sessió de col·laboració en directe a Excalidraw"
},
"errorDialog": {
"title": "Error"
},
"exportDialog": {
"disk_title": "",
"disk_details": "",
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"disk_title": "Desa al disc",
"disk_details": "Exporta les dades de l'escena a un fitxer que després podreu importar.",
"disk_button": "Desa en un fitxer",
"link_title": "Enllaç per a compartir",
"link_details": "Exporta com a un enllaç de només lectura.",
"link_button": "Exporta a un enllaç",
"excalidrawplus_description": "Desa l'escena en el vostre espai de treball Excalidraw+.",
"excalidrawplus_button": "Exporta",
"excalidrawplus_exportError": "No és possible exportar a Excalidraw+ ara mateix..."
},
"helpDialog": {
"blog": "Llegiu el nostre blog",
@ -231,16 +238,18 @@
"curvedArrow": "Fletxa corba",
"curvedLine": "Línia corba",
"documentation": "Documentació",
"doubleClick": "doble clic",
"drag": "arrossega",
"editor": "Editor",
"editSelectedShape": "Edita la forma seleccionada (text, fletxa o línia)",
"github": "Hi heu trobat un problema? Informeu-ne",
"howto": "Seguiu les nostres guies",
"or": "o",
"preventBinding": "Prevenir vinculació de la fletxa",
"shapes": "Formes",
"shortcuts": "Dreceres de teclat",
"textFinish": "Acaba d'editar (text)",
"textNewLine": "Afegeix línea nova (text)",
"textFinish": "Finalitza l'edició (editor de text)",
"textNewLine": "Afegeix una línia nova (editor de text)",
"title": "Ajuda",
"view": "Visualització",
"zoomToFit": "Zoom per veure tots els elements",

View File

@ -101,6 +101,8 @@
"viewMode": "Náhled",
"toggleExportColorScheme": "",
"share": "Sdílet",
"showStroke": "",
"showBackground": "",
"toggleTheme": "Přepnout tmavý řežim"
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "",
"freeDraw": "",
"text": "",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "",
"lockAngle": "",
"resize": "",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "",
@ -231,8 +238,10 @@
"curvedArrow": "",
"curvedLine": "",
"documentation": "",
"doubleClick": "",
"drag": "tažení",
"editor": "",
"editSelectedShape": "",
"github": "",
"howto": "",
"or": "nebo",

View File

@ -101,6 +101,8 @@
"viewMode": "Ansichtsmodus",
"toggleExportColorScheme": "Exportfarbschema umschalten",
"share": "Teilen",
"showStroke": "Auswahl für Strichfarbe anzeigen",
"showBackground": "Auswahl für Hintergrundfarbe anzeigen",
"toggleTheme": "Design umschalten"
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Klicken für Linie mit mehreren Punkten, Ziehen für einzelne Linie",
"freeDraw": "Klicke und ziehe. Lass los, wenn du fertig bist",
"text": "Tipp: Du kannst auch Text hinzufügen, indem du mit dem Auswahlwerkzeug auf eine beliebige Stelle doppelklickst",
"text_selected": "Doppelklicken oder Eingabetaste drücken, um Text zu bearbeiten",
"text_editing": "Drücke Escape oder Strg/Cmd+Eingabetaste, um die Bearbeitung abzuschließen",
"linearElementMulti": "Zum Beenden auf den letzten Punkt klicken oder Escape oder Eingabe drücken",
"lockAngle": "Du kannst Winkel einschränken, indem du SHIFT gedrückt hältst",
"resize": "Du kannst die Proportionen einschränken, indem du SHIFT während der Größenänderung gedrückt hältst. Halte ALT gedrückt, um die Größe vom Zentrum aus zu ändern",
@ -223,7 +227,10 @@
"disk_button": "In Datei speichern",
"link_title": "Teilbarer Link",
"link_details": "Als schreibgeschützten Link exportieren.",
"link_button": "Als Link exportieren"
"link_button": "Als Link exportieren",
"excalidrawplus_description": "Speichere die Szene in deinem Excalidraw+ Arbeitsbereich.",
"excalidrawplus_button": "Exportieren",
"excalidrawplus_exportError": "Konnte nicht nach Excalidraw+ exportieren..."
},
"helpDialog": {
"blog": "Lies unseren Blog",
@ -231,16 +238,18 @@
"curvedArrow": "Gebogener Pfeil",
"curvedLine": "Gebogene Linie",
"documentation": "Dokumentation",
"doubleClick": "doppelklicken",
"drag": "ziehen",
"editor": "Editor",
"editSelectedShape": "Ausgewählte Form bearbeiten (Text/Pfeil/Linie)",
"github": "Ein Problem gefunden? Informiere uns",
"howto": "Folge unseren Anleitungen",
"or": "oder",
"preventBinding": "Pfeil-Bindung verhindern",
"shapes": "Formen",
"shortcuts": "Tastaturkürzel",
"textFinish": "Bearbeiten beenden (Text)",
"textNewLine": "Neue Zeile hinzufügen (Text)",
"textFinish": "Bearbeitung beenden (Texteditor)",
"textNewLine": "Neue Zeile hinzufügen (Texteditor)",
"title": "Hilfe",
"view": "Ansicht",
"zoomToFit": "Zoomen um alle Elemente einzupassen",

View File

@ -101,6 +101,8 @@
"viewMode": "Λειτουργία προβολής",
"toggleExportColorScheme": "Εναλλαγή εξαγωγής θέματος χρωμάτων",
"share": "Κοινοποίηση",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Κάνε κλικ για να ξεκινήσεις πολλαπλά σημεία, σύρε για μια γραμμή",
"freeDraw": "Κάντε κλικ και σύρτε, απελευθερώσατε όταν έχετε τελειώσει",
"text": "Tip: μπορείτε επίσης να προσθέστε κείμενο με διπλό-κλικ οπουδήποτε με το εργαλείο επιλογών",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "Κάνε κλικ στο τελευταίο σημείο ή πάτησε Escape ή Enter για να τελειώσεις",
"lockAngle": "Μπορείτε να περιορίσετε τη γωνία κρατώντας πατημένο το SHIFT",
"resize": "Μπορείς να περιορίσεις τις αναλογίες κρατώντας το SHIFT ενώ αλλάζεις μέγεθος,\nκράτησε πατημένο το ALT για αλλαγή μεγέθους από το κέντρο",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "Διαβάστε το Blog μας",
@ -231,16 +238,18 @@
"curvedArrow": "Κυρτό βέλος",
"curvedLine": "Κυρτή γραμμή",
"documentation": "Εγχειρίδιο",
"doubleClick": "",
"drag": "σύρε",
"editor": "Επεξεργαστής",
"editSelectedShape": "",
"github": "Βρήκατε πρόβλημα; Υποβάλετε το",
"howto": "Ακολουθήστε τους οδηγούς μας",
"or": "ή",
"preventBinding": "Αποτροπή δέσμευσης βέλων",
"shapes": "Σχήματα",
"shortcuts": "Συντομεύσεις πληκτρολογίου",
"textFinish": "Ολοκλήρωση επεξεργασίας (κείμενο)",
"textNewLine": "Προσθήκη νέας γραμμής (κείμενο)",
"textFinish": "",
"textNewLine": "",
"title": "Βοήθεια",
"view": "Προβολή",
"zoomToFit": "Zoom ώστε να χωρέσουν όλα τα στοιχεία",

View File

@ -180,6 +180,8 @@
"linearElement": "Click to start multiple points, drag for single line",
"freeDraw": "Click and drag, release when you're finished",
"text": "Tip: you can also add text by double-clicking anywhere with the selection tool",
"text_selected": "Double-click or press ENTER to edit text",
"text_editing": "Press Escape or CtrlOrCmd+ENTER to finish editing",
"linearElementMulti": "Click on last point or press Escape or Enter to finish",
"lockAngle": "You can constrain angle by holding SHIFT",
"resize": "You can constrain proportions by holding SHIFT while resizing,\nhold ALT to resize from the center",
@ -225,7 +227,10 @@
"disk_button": "Save to file",
"link_title": "Shareable link",
"link_details": "Export as a read-only link.",
"link_button": "Export to Link"
"link_button": "Export to Link",
"excalidrawplus_description": "Save the scene to your Excalidraw+ workspace.",
"excalidrawplus_button": "Export",
"excalidrawplus_exportError": "Couldn't export to Excalidraw+ at this moment..."
},
"helpDialog": {
"blog": "Read our blog",
@ -233,16 +238,18 @@
"curvedArrow": "Curved arrow",
"curvedLine": "Curved line",
"documentation": "Documentation",
"doubleClick": "double-click",
"drag": "drag",
"editor": "Editor",
"editSelectedShape": "Edit selected shape (text/arrow/line)",
"github": "Found an issue? Submit",
"howto": "Follow our guides",
"or": "or",
"preventBinding": "Prevent arrow binding",
"shapes": "Shapes",
"shortcuts": "Keyboard shortcuts",
"textFinish": "Finish editing (text)",
"textNewLine": "Add new line (text)",
"textFinish": "Finish editing (text editor)",
"textNewLine": "Add new line (text editor)",
"title": "Help",
"view": "View",
"zoomToFit": "Zoom to fit all elements",

View File

@ -42,8 +42,8 @@
"fontSize": "Tamaño de la fuente",
"fontFamily": "Tipo de fuente",
"onlySelected": "Sólo seleccionados",
"withBackground": "",
"exportEmbedScene": "",
"withBackground": "Fondo",
"exportEmbedScene": "Embeber escena",
"exportEmbedScene_details": "Los datos de escena se guardarán en el archivo PNG/SVG exportado, así la escena puede ser restaurada de la misma.\nEsto aumentará el tamaño del archivo exportado.",
"addWatermark": "Agregar \"Hecho con Excalidraw\"",
"handDrawn": "Dibujado a mano",
@ -101,19 +101,21 @@
"viewMode": "Modo presentación",
"toggleExportColorScheme": "Cambiar el esquema de colores de exportación",
"share": "Compartir",
"showStroke": "Mostrar el selector de color del trazo",
"showBackground": "Mostrar el selector de color de fondo",
"toggleTheme": "Alternar tema"
},
"buttons": {
"clearReset": "Limpiar lienzo y reiniciar el color de fondo",
"exportJSON": "",
"exportImage": "",
"exportJSON": "Exportar como archivo",
"exportImage": "Guardar como imagen",
"export": "Exportar",
"exportToPng": "Exportar a PNG",
"exportToSvg": "Exportar a SVG",
"copyToClipboard": "Copiar al portapapeles",
"copyPngToClipboard": "Copiar PNG al portapapeles",
"scale": "Escalar",
"save": "",
"save": "Guardal al archivo actual",
"saveAs": "Guardar como",
"load": "Cargar",
"getShareableLink": "Obtener enlace para compartir",
@ -122,7 +124,7 @@
"scrollBackToContent": "Volver al contenido",
"zoomIn": "Acercarse",
"zoomOut": "Alejarse",
"resetZoom": "Restablecer acercamiento",
"resetZoom": "Restablecer zoom",
"menu": "Menú",
"done": "Hecho",
"edit": "Editar",
@ -178,6 +180,8 @@
"linearElement": "Haz clic para dibujar múltiples puntos, arrastrar para solo una línea",
"freeDraw": "Haz clic y arrastra, suelta al terminar",
"text": "Consejo: también puedes añadir texto haciendo doble clic en cualquier lugar con la herramienta de selección",
"text_selected": "Doble clic o pulse ENTER para editar el texto",
"text_editing": "Pulse Escape o CtrlOrCmd+ENTER para terminar de editar",
"linearElementMulti": "Haz clic en el último punto o presiona Escape o Enter para finalizar",
"lockAngle": "Puedes restringir el ángulo manteniendo presionado el botón SHIFT",
"resize": "Para mantener las proporciones mantén SHIFT presionado mientras modificas el tamaño, \nmantén presionado ALT para modificar el tamaño desde el centro",
@ -218,12 +222,15 @@
"title": "Error"
},
"exportDialog": {
"disk_title": "",
"disk_details": "",
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"disk_title": "Guardar en el disco",
"disk_details": "Exportar los datos de la escena a un archivo desde el cual se puede importar más tarde.",
"disk_button": "Guardar en el archivo",
"link_title": "Enlace para compartir",
"link_details": "Exportar como enlace de sólo lectura.",
"link_button": "Exportar al link",
"excalidrawplus_description": "Guarda la escena en tu espacio de trabajo de Excalidraw+.",
"excalidrawplus_button": "Exportar",
"excalidrawplus_exportError": "No se pudo exportar a Excalidraw+ en este momento..."
},
"helpDialog": {
"blog": "Lee nuestro blog",
@ -231,16 +238,18 @@
"curvedArrow": "Flecha curvada",
"curvedLine": "Línea curva",
"documentation": "Documentación",
"doubleClick": "doble clic",
"drag": "arrastrar",
"editor": "Editor",
"editSelectedShape": "Editar la forma seleccionada (texto/flecha/línea)",
"github": "¿Has encontrado un problema? Envíalo",
"howto": "Siga nuestras guías",
"or": "o",
"preventBinding": "Evitar yuxtaposición de flechas",
"shapes": "Formas",
"shortcuts": "Atajos del teclado",
"textFinish": "Finalizar edición (texto)",
"textNewLine": "Añadir nueva línea (texto)",
"textFinish": "Finalizar edición (editor de texto)",
"textNewLine": "Añadir nueva linea (editor de texto)",
"title": "Ayuda",
"view": "Vista",
"zoomToFit": "Ajustar la vista para mostrar todos los elementos",
@ -248,7 +257,7 @@
},
"encrypted": {
"tooltip": "Tus dibujos están cifrados de punto a punto, por lo que los servidores de Excalidraw nunca los verán.",
"link": ""
"link": "Entrada en el blog sobre cifrado de extremo a extremo"
},
"stats": {
"angle": "Ángulo",

View File

@ -101,6 +101,8 @@
"viewMode": "",
"toggleExportColorScheme": "",
"share": "",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "برای چند نقطه کلیک و برای یک خط بکشید",
"freeDraw": "کلیک کنید و بکشید و وقتی کار تمام شد رها کنید",
"text": "نکته: با برنامه انتخاب شده شما میتوانید با دوبار کلیک کردن هرکجا میخواید متن اظاف کنید",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "روی آخرین نقطه کلیک کنید یا کلید ESC را بزنید یا کلید Enter را بزنید برای اتمام کار",
"lockAngle": "با نگه داشتن SHIFT هنگام چرخش می توانید زاویه ها را محدود کنید",
"resize": "می توانید با نگه داشتن SHIFT در هنگام تغییر اندازه، نسبت ها را محدود کنید،ALT را برای تغییر اندازه از مرکز نگه دارید",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "بلاگ ما را بخوانید",
@ -231,8 +238,10 @@
"curvedArrow": "فلش خمیده",
"curvedLine": "منحنی",
"documentation": "مستندات",
"doubleClick": "",
"drag": "",
"editor": "ویرایشگر",
"editSelectedShape": "",
"github": "اشکالی می بینید؟ گزارش دهید",
"howto": "راهنمای ما را دنبال کنید",
"or": "یا",
@ -240,7 +249,7 @@
"shapes": "شکل‌ها",
"shortcuts": "میانبرهای صفحه کلید",
"textFinish": "",
"textNewLine": "یک خط جدید اضافه کنید (متن)",
"textNewLine": "",
"title": "راهنما",
"view": "مشاهده",
"zoomToFit": "بزرگنمایی برای دیدن تمام آیتم ها",

View File

@ -42,8 +42,8 @@
"fontSize": "Kirjasinkoko",
"fontFamily": "Kirjasintyyppi",
"onlySelected": "Vain valitut",
"withBackground": "",
"exportEmbedScene": "",
"withBackground": "Taustalla",
"exportEmbedScene": "Upota työ",
"exportEmbedScene_details": "Teoksen tiedot tallennetaan PNG/SVG-tiedostoon, jolloin teoksen voi palauttaa siitä. Kasvattaa tallennetun tiedoston kokoa.",
"addWatermark": "Lisää \"Tehty Excalidrawilla\"",
"handDrawn": "Käsinkirjoitettu",
@ -101,19 +101,21 @@
"viewMode": "Katselutila",
"toggleExportColorScheme": "Vaihda viennin väriteema",
"share": "Jaa",
"showStroke": "Näytä viivan värin valitsin",
"showBackground": "Näytä taustavärin valitsin",
"toggleTheme": "Vaihda teema"
},
"buttons": {
"clearReset": "Tyhjennä piirtoalue",
"exportJSON": "",
"exportImage": "",
"exportJSON": "Vie tiedostoon",
"exportImage": "Tallenna kuvana",
"export": "Vie",
"exportToPng": "Vie PNG-tiedostona",
"exportToSvg": "Vie SVG-tiedostona",
"copyToClipboard": "Kopioi leikepöydälle",
"copyPngToClipboard": "Kopioi PNG-tiedosto leikepöydälle",
"scale": "Koko",
"save": "",
"save": "Tallenna nykyiseen tiedostoon",
"saveAs": "Tallenna nimellä",
"load": "Avaa",
"getShareableLink": "Hae jaettava linkki",
@ -178,6 +180,8 @@
"linearElement": "Klikkaa piirtääksesi useampi piste, raahaa piirtääksesi yksittäinen viiva",
"freeDraw": "Paina ja raahaa, päästä irti kun olet valmis",
"text": "Vinkki: voit myös lisätä tekstiä kaksoisnapsauttamalla mihin tahansa valintatyökalulla",
"text_selected": "Kaksoisnapsauta tai paina ENTER muokataksesi tekstiä",
"text_editing": "Paina Escape tai CtrlOrCmd+ENTER lopettaaksesi muokkaamisen",
"linearElementMulti": "Lopeta klikkaamalla viimeistä pistettä, painamalla Escape- tai Enter-näppäintä",
"lockAngle": "Voit rajoittaa kulmaa pitämällä SHIFT-näppäintä alaspainettuna",
"resize": "Voit rajoittaa mittasuhteet pitämällä SHIFT-näppäintä alaspainettuna kun muutat kokoa, pidä ALT-näppäintä alaspainettuna muuttaaksesi kokoa keskipisteen suhteen",
@ -218,12 +222,15 @@
"title": "Virhe"
},
"exportDialog": {
"disk_title": "",
"disk_details": "",
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"disk_title": "Tallenna levylle",
"disk_details": "Vie työn tiedot tiedostoon, josta sen voi tuoda myöhemmin.",
"disk_button": "Tallenna tiedostoon",
"link_title": "Jaettava linkki",
"link_details": "Vie vain luku -linkkinä.",
"link_button": "Vie linkkinä",
"excalidrawplus_description": "Tallenna teos Excalidraw+ tilaan.",
"excalidrawplus_button": "Vie",
"excalidrawplus_exportError": "Ei voitu viedä Excalidraw+-palveluun tällä hetkellä..."
},
"helpDialog": {
"blog": "Lue blogiamme",
@ -231,16 +238,18 @@
"curvedArrow": "Kaareva nuoli",
"curvedLine": "Kaareva viiva",
"documentation": "Käyttöohjeet",
"doubleClick": "kaksoisnapsautus",
"drag": "vedä",
"editor": "Muokkausohjelma",
"editSelectedShape": "Muokkaa valittua muotoa (teksti/nuoli/viiva)",
"github": "Löysitkö ongelman? Kerro meille",
"howto": "Seuraa oppaitamme",
"or": "tai",
"preventBinding": "Estä nuolten kiinnitys",
"shapes": "Muodot",
"shortcuts": "Pikanäppäimet",
"textFinish": "Lopeta muokkaus (teksti)",
"textNewLine": "Lisää uusi rivi (teksti)",
"textFinish": "Lopeta muokkaus (tekstieditori)",
"textNewLine": "Lisää uusi rivi (tekstieditori)",
"title": "Ohjeet",
"view": "Näkymä",
"zoomToFit": "Näytä kaikki elementit",

View File

@ -16,7 +16,7 @@
"delete": "Supprimer",
"copyStyles": "Copier les styles",
"pasteStyles": "Coller les styles",
"stroke": "Contour",
"stroke": "Trait",
"background": "Arrière-plan",
"fill": "Remplissage",
"strokeWidth": "Largeur du trait",
@ -43,7 +43,7 @@
"fontFamily": "Police",
"onlySelected": "Uniquement la sélection",
"withBackground": "Arrière-plan",
"exportEmbedScene": "Scène intégrée",
"exportEmbedScene": "Intégrer la scène",
"exportEmbedScene_details": "Les données de scène seront enregistrées dans le fichier PNG/SVG exporté, afin que la scène puisse être restaurée à partir de celui-ci.\nCela augmentera la taille du fichier exporté.",
"addWatermark": "Ajouter \"Fait avec Excalidraw\"",
"handDrawn": "À main levée",
@ -101,19 +101,21 @@
"viewMode": "Mode présentation",
"toggleExportColorScheme": "Activer/Désactiver l'export du thème de couleur",
"share": "Partager",
"showStroke": "Afficher le sélecteur de couleur de trait",
"showBackground": "Afficher le sélecteur de couleur d'arrière-plan",
"toggleTheme": "Changer le thème"
},
"buttons": {
"clearReset": "Réinitialiser le canevas",
"exportJSON": "Exporter dans un fichier",
"exportJSON": "Exporter comme fichier",
"exportImage": "Enregistrer comme image",
"export": "Exporter",
"exportToPng": "Exporter en PNG",
"exportToSvg": "Exporter en SVG",
"exportToPng": "Enregistrer en PNG",
"exportToSvg": "Enregistrer en SVG",
"copyToClipboard": "Copier dans le presse-papier",
"copyPngToClipboard": "Copier le PNG vers le presse-papier",
"copyPngToClipboard": "Copier le PNG dans le presse-papier",
"scale": "Échelle",
"save": "Sauvegarder dans le fichier actuel",
"save": "Enregistrer dans le fichier actuel",
"saveAs": "Enregistrer sous",
"load": "Ouvrir",
"getShareableLink": "Obtenir un lien de partage",
@ -178,6 +180,8 @@
"linearElement": "Cliquez pour démarrer plusieurs points, faites glisser pour une seule ligne",
"freeDraw": "Cliquez et faites glissez, relâchez quand vous avez terminé",
"text": "Astuce : vous pouvez aussi ajouter du texte en double-cliquant n'importe où avec l'outil de sélection",
"text_selected": "Double-cliquez ou appuyez sur ENTRÉE pour modifier le texte",
"text_editing": "Appuyez sur ÉCHAP ou Ctrl/Cmd+ENTRÉE pour terminer l'édition",
"linearElementMulti": "Cliquez sur le dernier point ou appuyez sur Échap ou Entrée pour terminer",
"lockAngle": "Vous pouvez restreindre l'angle en maintenant MAJ",
"resize": "Vous pouvez conserver les proportions en maintenant la touche MAJ pendant le redimensionnement,\nmaintenez la touche ALT pour redimensionner par rapport au centre",
@ -218,12 +222,15 @@
"title": "Erreur"
},
"exportDialog": {
"disk_title": "Sauvegarder sur le disque",
"disk_details": "Exportez les données de la scène dans un fichier que vous pourrez importer ultérieurement.",
"disk_button": "Sauvegarder dans un fichier",
"link_title": "Lien à partager",
"disk_title": "Enregistrer sur le disque",
"disk_details": "Exporter les données de la scène comme un fichier que vous pourrez importer ultérieurement.",
"disk_button": "Enregistrer comme fichier",
"link_title": "Lien partageable",
"link_details": "Exporter comme un lien en lecture seule.",
"link_button": "Exporter vers un lien"
"link_button": "Exporter comme lien",
"excalidrawplus_description": "Enregistrer la scène dans votre espace de travail Excalidraw+.",
"excalidrawplus_button": "Exporter",
"excalidrawplus_exportError": "Impossible d'exporter vers Excalidraw+ pour le moment..."
},
"helpDialog": {
"blog": "Lire notre blog",
@ -231,16 +238,18 @@
"curvedArrow": "Flèche courbée",
"curvedLine": "Ligne courbée",
"documentation": "Documentation",
"doubleClick": "double-clic",
"drag": "glisser",
"editor": "Éditeur",
"editSelectedShape": "Modifier la forme sélectionnée (texte/flèche/ligne)",
"github": "Problème trouvé ? Soumettre",
"howto": "Suivez nos guides",
"or": "ou",
"preventBinding": "Empêcher la liaison de flèche",
"shapes": "Formes",
"shortcuts": "Raccourcis clavier",
"textFinish": "Terminer l'édition (texte)",
"textNewLine": "Ajouter une nouvelle ligne (texte)",
"textFinish": "Terminer l'édition (éditeur de texte)",
"textNewLine": "Ajouter une nouvelle ligne (éditeur de texte)",
"title": "Aide",
"view": "Affichage",
"zoomToFit": "Zoomer pour voir tous les éléments",
@ -267,8 +276,8 @@
},
"toast": {
"copyStyles": "Styles copiés.",
"copyToClipboard": "Copié vers le presse-papiers.",
"copyToClipboardAsPng": "{{exportSelection}} copié dans le presse-papiers en PNG\n({{exportColorScheme}})",
"copyToClipboard": "Copié dans le presse-papier.",
"copyToClipboardAsPng": "{{exportSelection}} copié dans le presse-papier en PNG\n({{exportColorScheme}})",
"fileSaved": "Fichier enregistré.",
"fileSavedToFilename": "Enregistré sous {filename}",
"canvas": "canevas",

View File

@ -101,6 +101,8 @@
"viewMode": "מצב תצוגה",
"toggleExportColorScheme": "",
"share": "",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "הקלק בשביל לבחור נקודות מרובות, גרור בשביל קו בודד",
"freeDraw": "לחץ וגרור, שחרר כשסיימת",
"text": "טיפ: אפשר להוסיף טקסט על ידי לחיצה כפולה בכל מקום עם כלי הבחירה",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "הקלק על הנקודה האחרונה או הקש Escape או Enter לסיום",
"lockAngle": "אתה יכול להגביל זווית ע״י לחיצה על SHIFT",
"resize": "ניתן להגביל פרופורציות על ידי לחיצה על SHIFT תוך כדי שינוי גודל,\nהחזק ALT בשביל לשנות גודל ביחס למרכז",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "קרא את הבלוג שלנו",
@ -231,16 +238,18 @@
"curvedArrow": "",
"curvedLine": "",
"documentation": "תיעוד",
"doubleClick": "",
"drag": "לגרור",
"editor": "עורך",
"editSelectedShape": "",
"github": "מצאת בעיה? דווח",
"howto": "עקוב אחר המדריכים שלנו",
"or": "או",
"preventBinding": "",
"shapes": "צורות",
"shortcuts": "קיצורי מקלדת",
"textFinish": "סיים עריכה (טקסט)",
"textNewLine": "הוסף שורה חדשה (טקסט)",
"textFinish": "",
"textNewLine": "",
"title": "עזרה",
"view": "תצוגה",
"zoomToFit": "",

View File

@ -101,6 +101,8 @@
"viewMode": "",
"toggleExportColorScheme": "",
"share": "",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "कई बिंदुओं को शुरू करने के लिए क्लिक करें, सिंगल लाइन के लिए खींचें",
"freeDraw": "क्लिक करें और खींचें। समाप्त करने के लिए, छोड़ो",
"text": "आप चयन टूल से कहीं भी डबल-क्लिक करके टेक्स्ट जोड़ सकते हैं",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "अंतिम बिंदु पर क्लिक करें या समाप्त होने के लिए एस्केप या एंटर दबाएं",
"lockAngle": "आप घूर्णन करते समय SHIFT पकड़कर कोणों को मोड़ सकते हैं",
"resize": "आकार बदलते समय आप SHIFT को पकड़ कर अनुपात में कमी कर सकते हैं,\nकेंद्र से आकार बदलने के लिए ALT दबाए रखें",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "हमारा ब्लॉग पढे",
@ -231,16 +238,18 @@
"curvedArrow": "वक्र तीर",
"curvedLine": "वक्र रेखा",
"documentation": "",
"doubleClick": "",
"drag": "खींचें",
"editor": "संपादक",
"editSelectedShape": "",
"github": "मुद्दा मिला? प्रस्तुत करें",
"howto": "हमारे गाइड का पालन करें",
"or": "या",
"preventBinding": "तीर बंधन रोकें",
"shapes": "आकृतियाँ",
"shortcuts": "कीबोर्ड के शॉर्टकट्स",
"textFinish": "संपादन समाप्त करें (पाठ)",
"textNewLine": "नई पंक्ति जोड़ें (पाठ)",
"textFinish": "",
"textNewLine": "",
"title": "मदद",
"view": "दृश्य",
"zoomToFit": "सभी तत्वों को फिट करने के लिए ज़ूम करें",

View File

@ -101,6 +101,8 @@
"viewMode": "",
"toggleExportColorScheme": "",
"share": "",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Kattintással görbe, az eger húzásával pedig egyenes nyilat rajzolhatsz",
"freeDraw": "Kattints és húzd, majd engedd el, amikor végeztél",
"text": "Tipp: A kijelölés eszközzel a dupla kattintás új szöveget hoz létre",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "Kattints a következő ív pozíciójára, vagy fejezd be a nyilat az Escape vagy Enter megnyomásával",
"lockAngle": "A SHIFT billentyű lenyomva tartásával korlátozhatja forgatás szögét",
"resize": "A SHIFT billentyű lenyomva tartásával az átméretezés megtartja az arányokat,\naz ALT lenyomva tartásával pedig a középpont egy helyben marad",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "",
@ -231,8 +238,10 @@
"curvedArrow": "",
"curvedLine": "",
"documentation": "",
"doubleClick": "",
"drag": "",
"editor": "",
"editSelectedShape": "",
"github": "",
"howto": "",
"or": "",

View File

@ -101,6 +101,8 @@
"viewMode": "Mode tampilan",
"toggleExportColorScheme": "Ubah skema warna ekspor",
"share": "Bagikan",
"showStroke": "Tampilkan garis pengambil warna",
"showBackground": "Tampilkan latar pengambil warna",
"toggleTheme": "Ubah tema"
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Klik untuk memulai banyak poin, seret untuk satu baris",
"freeDraw": "Klik dan seret, lepaskan jika Anda selesai",
"text": "Tip: Anda juga dapat menambahkan teks dengan klik ganda di mana saja dengan alat pemilihan",
"text_selected": "Klik ganda atau tekan ENTER untuk edit teks",
"text_editing": "Tekan Escape atau CtrlAtauCmd+ENTER untuk selesai mengedit",
"linearElementMulti": "Klik pada titik akhir atau tekan Escape atau Enter untuk menyelesaikan",
"lockAngle": "Anda dapat menjaga sudut dengan menahan SHIFT",
"resize": "Anda dapat menjaga proposi dengan menekan SHIFT sambil mengubah ukuran,\ntekan AlT untuk mengubah ukuran dari tengah",
@ -223,7 +227,10 @@
"disk_button": "Simpan ke file",
"link_title": "Tautan",
"link_details": "Ekspor sebagai tautan yang hanya dibaca.",
"link_button": "Ekspor ke tautan"
"link_button": "Ekspor ke tautan",
"excalidrawplus_description": "Simpan pemandangan ke ruang kerja Excalidraw+ Anda.",
"excalidrawplus_button": "Ekspor",
"excalidrawplus_exportError": "Tidak dapat ekspor ke Excalidraw+ saat ini..."
},
"helpDialog": {
"blog": "Baca blog kami",
@ -231,16 +238,18 @@
"curvedArrow": "Panah lengkung",
"curvedLine": "Garis lengkung",
"documentation": "Dokumentasi",
"doubleClick": "klik-ganda",
"drag": "seret",
"editor": "Editor",
"editSelectedShape": "Edit bentuk yang dipilih (teks/panah/garis)",
"github": "Menemukan masalah? Kirimkan",
"howto": "Ikuti panduan kami",
"or": "atau",
"preventBinding": "Cegah pengikatan panah",
"shapes": "Bentuk",
"shortcuts": "Pintasan keyboard",
"textFinish": "Selesai mengedit (teks)",
"textNewLine": "Tambahkan baris baru (teks)",
"textFinish": "Selesai mengedit (editor teks)",
"textNewLine": "Tambahkan garis baru (editor teks)",
"title": "Bantuan",
"view": "Tampilan",
"zoomToFit": "Perbesar agar sesuai dengan semua elemen",

View File

@ -101,6 +101,8 @@
"viewMode": "Modalità visualizzazione",
"toggleExportColorScheme": "Cambia lo schema di colori in esportazione",
"share": "Condividi",
"showStroke": "Mostra selettore colore del tratto",
"showBackground": "Mostra selettore colore di sfondo",
"toggleTheme": "Cambia tema"
},
"buttons": {
@ -164,7 +166,7 @@
"ellipse": "Ellisse",
"arrow": "Freccia",
"line": "Linea",
"freedraw": "",
"freedraw": "Disegno",
"text": "Testo",
"library": "Libreria",
"lock": "Mantieni lo strumento selezionato attivo dopo aver disegnato"
@ -178,6 +180,8 @@
"linearElement": "Clicca per iniziare una linea in più punti, trascina per singola linea",
"freeDraw": "Clicca e trascina, rilascia quando avrai finito",
"text": "Suggerimento: puoi anche aggiungere del testo facendo doppio clic ovunque con lo strumento di selezione",
"text_selected": "Fai doppio click o premi INVIO per modificare il testo",
"text_editing": "Premi ESC o CtrlOCmd+INVIO per completare le modifiche",
"linearElementMulti": "Clicca sull'ultimo punto o premi Esc o Invio per finire",
"lockAngle": "Puoi limitare l'angolo tenendo premuto SHIFT",
"resize": "Per vincolare le proporzioni, tieni premuto MAIUSC durante il ridimensionamento;\nper ridimensionare dal centro, tieni premuto ALT",
@ -223,7 +227,10 @@
"disk_button": "Salva su file",
"link_title": "Link condivisibile",
"link_details": "Esporta come link di sola lettura.",
"link_button": "Esporta come Link"
"link_button": "Esporta come Link",
"excalidrawplus_description": "Salva la scena nel tuo spazio di lavoro Excalidraw+.",
"excalidrawplus_button": "Esporta",
"excalidrawplus_exportError": "Non è stato possibile esportare su Excalidraw+ al questo momento..."
},
"helpDialog": {
"blog": "Leggi il nostro blog",
@ -231,16 +238,18 @@
"curvedArrow": "Freccia curva",
"curvedLine": "Linea curva",
"documentation": "Documentazione",
"doubleClick": "doppio-click",
"drag": "trascina",
"editor": "Editor",
"editSelectedShape": "Modifica la forma selezionata (testo/freccia/linea)",
"github": "Trovato un problema? Segnalalo",
"howto": "Segui le nostre guide",
"or": "oppure",
"preventBinding": "Impedisci legame della freccia",
"shapes": "Forme",
"shortcuts": "Scorciatoie da tastiera",
"textFinish": "Termina la modifica (testo)",
"textNewLine": "Aggiungi nuova riga (testo)",
"textFinish": "Completa la modifica (editor di testo)",
"textNewLine": "Aggiungi nuova riga (editor di testo)",
"title": "Guida",
"view": "Vista",
"zoomToFit": "Adatta zoom per mostrare tutti gli elementi",

View File

@ -43,7 +43,7 @@
"fontFamily": "フォントの種類",
"onlySelected": "選択中のみ",
"withBackground": "背景",
"exportEmbedScene": "",
"exportEmbedScene": "埋め込みシーン",
"exportEmbedScene_details": "シーンデータはエクスポートされたPNG/SVGファイルに保存され、シーンを復元することができます。\nエクスポートされたファイルのサイズは増加します。",
"addWatermark": "\"Made with Excalidraw\"と表示",
"handDrawn": "手描き風",
@ -99,8 +99,10 @@
"flipHorizontal": "水平方向に反転",
"flipVertical": "垂直方向に反転",
"viewMode": "閲覧モード",
"toggleExportColorScheme": "",
"toggleExportColorScheme": "エクスポートカラースキームの切り替え",
"share": "共有",
"showStroke": "ストロークカラーピッカーを表示",
"showBackground": "背景色ピッカーを表示",
"toggleTheme": "テーマの切り替え"
},
"buttons": {
@ -175,9 +177,11 @@
"shapes": "図形"
},
"hints": {
"linearElement": "クリックして複数の点を開始し、1行にドラッグます。",
"linearElement": "クリックして複数の点を開始し、ドラッグで直線を引きます。",
"freeDraw": "クリックしてドラッグします。離すと終了します",
"text": "ヒント: 選択ツールを使用して任意の場所をダブルクリックしてテキストを追加することもできます",
"text_selected": "テキストを編集するには、ダブルクリックまたはEnterキーを押します",
"text_editing": "Esc キーまたは CtrlOrCmd+ENTER キーを押して編集を終了します",
"linearElementMulti": "最後のポイントをクリックするか、エスケープまたはEnterを押して終了します",
"lockAngle": "SHIFTを押したままにすると、角度を制限することができます",
"resize": "サイズを変更中にSHIFTを押しすと比率を制御できます。Altを押すと中央からサイズを変更できます。",
@ -223,7 +227,10 @@
"disk_button": "ファイルへ保存",
"link_title": "共有可能なリンク",
"link_details": "読み取り専用リンクとしてエクスポート",
"link_button": "リンクとしてエクスポート"
"link_button": "リンクとしてエクスポート",
"excalidrawplus_description": "Excalidraw+ ワークスペースにシーンを保存します。",
"excalidrawplus_button": "エクスポート",
"excalidrawplus_exportError": "Excalidraw+ にエクスポートできませんでした..."
},
"helpDialog": {
"blog": "公式ブログを読む",
@ -231,15 +238,17 @@
"curvedArrow": "カーブした矢印",
"curvedLine": "曲線",
"documentation": "ドキュメント",
"doubleClick": "ダブルクリック",
"drag": "ドラッグ",
"editor": "エディタ",
"editSelectedShape": "選択した図形の編集 (テキスト/矢印/線)",
"github": "不具合報告はこちら",
"howto": "ヘルプ・マニュアル",
"or": "または",
"preventBinding": "矢印を結合しない",
"shapes": "図形",
"shortcuts": "キーボードショートカット",
"textFinish": "編集を終了する (テキスト)",
"textFinish": "編集を終了 (テキストエディタ)",
"textNewLine": "新しい行を追加 (テキスト)",
"title": "ヘルプ",
"view": "表示",

View File

@ -20,7 +20,7 @@
"background": "Agilal",
"fill": "Taččart",
"strokeWidth": "Tehri n yizirig",
"strokeShape": "",
"strokeShape": "Talɣa n yizirig",
"strokeShape_gel": "",
"strokeShape_fountain": "",
"strokeShape_brush": "Amfezzu",
@ -101,6 +101,8 @@
"viewMode": "Askar n tmuɣli",
"toggleExportColorScheme": "Sermed/sens asifeḍ usentel n yini",
"share": "Bḍu",
"showStroke": "Beqqeḍ amelqaḍ n yini n yizirig",
"showBackground": "Beqqeḍ amelqaḍ n yini n ugilal",
"toggleTheme": "Snifel asentel"
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Ssit akken ad tebduḍ aṭas n tenqiḍin, zuɣer i yiwen n yizirig",
"freeDraw": "Ssit yerna zuɣer, serreḥ ticki tfukeḍ",
"text": "Tixidest: tzemreḍ daɣen ad ternuḍ aḍris s usiti snat n tikkal anida tebɣiḍ s ufecku n tefrayt",
"text_selected": "Ssit snat n tikkal neɣ ssed taqeffalt Kcem akken ad tẓergeḍ aḍris",
"text_editing": "Ssit Escape neɣ CtrlOrCmd+ENTER akken ad tfakkeḍ asiẓreg",
"linearElementMulti": "Ssit ɣef tenqiḍt taneggarut neɣ ssed taqeffalt Escape neɣ taqeffalt Kcem akken ad tfakkeḍ",
"lockAngle": "Tzemreḍ ad tḥettmeḍ tiɣmert s tuṭṭfa n tqeffalt SHIFT",
"resize": "Tzemreḍ ad tḥettemeḍ assaɣ s tuṭṭfa n tqeffalt SHIFT mi ara tettbeddileḍ tiddi,\nma teṭṭfeḍ ALT abeddel n tiddi ad yili si tlemmast",
@ -223,7 +227,10 @@
"disk_button": "Sekles deg ufaylu",
"link_title": "Aseɣwen n beṭṭu",
"link_details": "Sifeḍ am useɣwen n tɣuri kan.",
"link_button": "Sifeḍ deg useɣwen"
"link_button": "Sifeḍ deg useɣwen",
"excalidrawplus_description": "Sekles asayes-inek•inem di tallunt n umahil Excalidraw+.",
"excalidrawplus_button": "Sifeḍ",
"excalidrawplus_exportError": "Ulamek asifeḍ ɣer Excalidraw+ akka tura..."
},
"helpDialog": {
"blog": "Ɣeṛ ablug-nneɣ",
@ -231,16 +238,18 @@
"curvedArrow": "Taneccabt izelgen",
"curvedLine": "Izirig izelgen",
"documentation": "Tasemlit",
"doubleClick": "ssit snat n tikkal",
"drag": "zuɣer",
"editor": "Amaẓrag",
"editSelectedShape": "Ẓreg talɣa yettwafernen (aḍris/taneccabt/izirig)",
"github": "Tufiḍ-d ugur? Azen-aɣ-d",
"howto": "Ḍfer imniren-nneɣ",
"or": "neɣ",
"preventBinding": "Seḥbes tuqqna n tneccabin",
"shapes": "Talɣiwin",
"shortcuts": "Inegzumen n unasiw",
"textFinish": "Fak asiẓreg (aḍris)",
"textNewLine": "Rnu ajerriḍ amaynut (aḍris)",
"textFinish": "Fak asiẓreg (amaẓrag n uḍris)",
"textNewLine": "Rnu ajerriḍ amaynut (amaẓrag n uḍris)",
"title": "Tallelt",
"view": "Tamuɣli",
"zoomToFit": "Simɣur akken ad twliḍ akk iferdisen",

286
src/locales/kk-KZ.json Normal file
View File

@ -0,0 +1,286 @@
{
"labels": {
"paste": "Қою",
"pasteCharts": "Диаграммаларды қою",
"selectAll": "Бәрін таңдау",
"multiSelect": "",
"moveCanvas": "",
"cut": "Қию",
"copy": "Көшіру",
"copyAsPng": "",
"copyAsSvg": "",
"bringForward": "",
"sendToBack": "",
"bringToFront": "",
"sendBackward": "",
"delete": "Жою",
"copyStyles": "Стильдерді көшіру",
"pasteStyles": "Стильдерді қою",
"stroke": "",
"background": "",
"fill": "",
"strokeWidth": "",
"strokeShape": "",
"strokeShape_gel": "",
"strokeShape_fountain": "",
"strokeShape_brush": "",
"strokeStyle": "",
"strokeStyle_solid": "",
"strokeStyle_dashed": "",
"strokeStyle_dotted": "",
"sloppiness": "",
"opacity": "",
"textAlign": "",
"edges": "",
"sharp": "",
"round": "",
"arrowheads": "Нұсқар ұштары",
"arrowhead_none": "Жоқ",
"arrowhead_arrow": "Нұсқар",
"arrowhead_bar": "Тосқауыл",
"arrowhead_dot": "Нүкте",
"fontSize": "Қаріп өлшемі",
"fontFamily": "Қаріп тобы",
"onlySelected": "",
"withBackground": "",
"exportEmbedScene": "",
"exportEmbedScene_details": "",
"addWatermark": "",
"handDrawn": "",
"normal": "Қалыпты",
"code": "",
"small": "Кіші",
"medium": "Орта",
"large": "Үлкен",
"veryLarge": "Өте үлкен",
"solid": "",
"hachure": "",
"crossHatch": "",
"thin": "",
"bold": "",
"left": "Солға",
"center": "Ортаға",
"right": "Оңға",
"extraBold": "",
"architect": "",
"artist": "",
"cartoonist": "",
"fileTitle": "Файл атауы",
"colorPicker": "",
"canvasBackground": "",
"drawingCanvas": "",
"layers": "",
"actions": "",
"language": "Тіл",
"liveCollaboration": "",
"duplicateSelection": "Көшірме",
"untitled": "Атауысыз",
"name": "",
"yourName": "",
"madeWithExcalidraw": "",
"group": "",
"ungroup": "",
"collaborators": "",
"showGrid": "",
"addToLibrary": "",
"removeFromLibrary": "",
"libraryLoadingMessage": "",
"libraries": "",
"loadingScene": "",
"align": "",
"alignTop": "",
"alignBottom": "",
"alignLeft": "",
"alignRight": "",
"centerVertically": "",
"centerHorizontally": "",
"distributeHorizontally": "",
"distributeVertically": "",
"flipHorizontal": "",
"flipVertical": "",
"viewMode": "",
"toggleExportColorScheme": "",
"share": "",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
"clearReset": "",
"exportJSON": "",
"exportImage": "",
"export": "Экспорт",
"exportToPng": "",
"exportToSvg": "",
"copyToClipboard": "",
"copyPngToClipboard": "",
"scale": "",
"save": "",
"saveAs": "",
"load": "",
"getShareableLink": "",
"close": "Жабу",
"selectLanguage": "Тілді таңдау",
"scrollBackToContent": "",
"zoomIn": "",
"zoomOut": "",
"resetZoom": "",
"menu": "Mәзір",
"done": "Дайын",
"edit": "",
"undo": "",
"redo": "",
"resetLibrary": "",
"createNewRoom": "",
"fullScreen": "",
"darkMode": "",
"lightMode": "",
"zenMode": "",
"exitZenMode": ""
},
"alerts": {
"clearReset": "",
"couldNotCreateShareableLink": "",
"couldNotCreateShareableLinkTooBig": "",
"couldNotLoadInvalidFile": "",
"importBackendFailed": "",
"cannotExportEmptyCanvas": "",
"couldNotCopyToClipboard": "",
"decryptFailed": "",
"uploadedSecurly": "",
"loadSceneOverridePrompt": "",
"collabStopOverridePrompt": "",
"errorLoadingLibrary": "",
"errorAddingToLibrary": "",
"errorRemovingFromLibrary": "",
"confirmAddLibrary": "",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": "",
"invalidSceneUrl": "",
"resetLibrary": ""
},
"toolBar": {
"selection": "",
"rectangle": "",
"diamond": "",
"ellipse": "",
"arrow": "Нұсқар",
"line": "",
"freedraw": "",
"text": "Мәтін",
"library": "",
"lock": ""
},
"headings": {
"canvasActions": "",
"selectedShapeActions": "",
"shapes": ""
},
"hints": {
"linearElement": "",
"freeDraw": "",
"text": "",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "",
"lockAngle": "",
"resize": "",
"rotate": "",
"lineEditor_info": "",
"lineEditor_pointSelected": "",
"lineEditor_nothingSelected": ""
},
"canvasError": {
"cannotShowPreview": "",
"canvasTooBig": "",
"canvasTooBigTip": ""
},
"errorSplash": {
"headingMain_pre": "",
"headingMain_button": "",
"clearCanvasMessage": "",
"clearCanvasMessage_button": "",
"clearCanvasCaveat": "",
"trackedToSentry_pre": "",
"trackedToSentry_post": "",
"openIssueMessage_pre": "",
"openIssueMessage_button": "",
"openIssueMessage_post": "",
"sceneContent": ""
},
"roomDialog": {
"desc_intro": "",
"desc_privacy": "",
"button_startSession": "",
"button_stopSession": "",
"desc_inProgressIntro": "",
"desc_shareLink": "",
"desc_exitSession": "",
"shareTitle": ""
},
"errorDialog": {
"title": "Қате"
},
"exportDialog": {
"disk_title": "",
"disk_details": "Сахна деректерін кейін қайта импорттауға болатын файлға экспорттаңыз.",
"disk_button": "Файлға сақтау",
"link_title": "Ортақ сілтеме",
"link_details": "Тек оқуға арналған сілтеме ретінде экспорттау.",
"link_button": "Сілтемеге экспорттау",
"excalidrawplus_description": "Сахнаны өзіңіздің Excalidraw+ жұмыс кеңістігінде сақтаңыз.",
"excalidrawplus_button": "Экспорт",
"excalidrawplus_exportError": "Қазіргі уақытта Excalidraw+ үшін экспорттау мүмкін емес..."
},
"helpDialog": {
"blog": "Біздің блогты оқу",
"click": "шерту",
"curvedArrow": "Майысқан нұсқар",
"curvedLine": "Майысқан сызық",
"documentation": "Құжаттама",
"doubleClick": "қос шерту",
"drag": "апару",
"editor": "Өңдеу",
"editSelectedShape": "Таңдалған пішінді өңдеу (мәтін/нұсқар/сызық)",
"github": "Қате таптыңыз ба? Жолдаңыз",
"howto": "Біздің нұсқаулықтарды орындаңыз",
"or": "немесе",
"preventBinding": "Нұсқарды байланыстыруға жол бермеу",
"shapes": "Пішіндер",
"shortcuts": "Пернетақта пәрмендері",
"textFinish": "Өңдеуді аяқтау (мәтіндік редактор)",
"textNewLine": "Жаңа жолға көшу (мәтіндік редактор)",
"title": "Көмек",
"view": "Көру",
"zoomToFit": "Барлық элементтердің көлеміне сәйкес үлкейту",
"zoomToSelection": "Таңдалғанды үлкейту"
},
"encrypted": {
"tooltip": "Сіздің сызбаларыңыз өтпелі шифрлеу арқылы шифрланған, сондықтан Excalidraw серверлері оларды ешқашан көрмейді.",
"link": "Excalidraw қолданатын өтпелі шифрлеу туралы блог жазбасы"
},
"stats": {
"angle": "Бұрыш",
"element": "Элемент",
"elements": "Элементтер",
"height": "Биіктігі",
"scene": "Сахна",
"selected": "Таңдалды",
"storage": "Сақтау көлемі",
"title": "",
"total": "Барлығы",
"version": "Нұсқа",
"versionCopy": "Көшіру үшін басыңыз",
"versionNotAvailable": "Бұл нұсқа қолжетімсіз",
"width": "Ені"
},
"toast": {
"copyStyles": "Стильдер көшірілді.",
"copyToClipboard": "",
"copyToClipboardAsPng": "",
"fileSaved": "Файл сақталды.",
"fileSavedToFilename": "{filename} сақталды",
"canvas": "",
"selection": "таңдау"
}
}

View File

@ -101,6 +101,8 @@
"viewMode": "보기 모드",
"toggleExportColorScheme": "",
"share": "",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "여러 점을 연결하려면 클릭하고, 직선을 그리려면 바로 드래그하세요.",
"freeDraw": "클릭 후 드래그하세요. 완료되면 놓으세요.",
"text": "팁: 선택 툴로 아무 곳이나 더블 클릭해 텍스트를 추가할 수도 있습니다.",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "마지막 지점을 클릭하거나 Esc 또는 Enter 키를 눌러 완료하세요.",
"lockAngle": "SHIFT 키를 누르면서 회전하면 각도를 제한할 수 있습니다.",
"resize": "SHIFT 키를 누르면서 조정하면 크기의 비율이 제한됩니다.\nALT를 누르면서 조정하면 중앙을 기준으로 크기를 조정합니다.",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "블로그 읽어보기",
@ -231,16 +238,18 @@
"curvedArrow": "곡선 화살표",
"curvedLine": "곡선",
"documentation": "설명서",
"doubleClick": "",
"drag": "드래그",
"editor": "에디터",
"editSelectedShape": "",
"github": "문제 제보하기",
"howto": "가이드 참고하기",
"or": "또는",
"preventBinding": "화살표가 붙지 않게 하기",
"shapes": "도형",
"shortcuts": "키보드 단축키",
"textFinish": "편집 완료 (텍스트)",
"textNewLine": "줄바꿈 (텍스트)",
"textFinish": "",
"textNewLine": "",
"title": "도움말",
"view": "보기",
"zoomToFit": "모든 요소가 보이도록 확대/축소",

View File

@ -101,6 +101,8 @@
"viewMode": "",
"toggleExportColorScheme": "",
"share": "",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "",
"freeDraw": "",
"text": "",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "",
"lockAngle": "",
"resize": "",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "",
@ -231,8 +238,10 @@
"curvedArrow": "",
"curvedLine": "",
"documentation": "",
"doubleClick": "",
"drag": "",
"editor": "",
"editSelectedShape": "",
"github": "",
"howto": "",
"or": "",

View File

@ -101,6 +101,8 @@
"viewMode": "",
"toggleExportColorScheme": "",
"share": "",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "အမှတ်များချမှတ်ရေးဆွဲရန်ကလစ်နှိပ်ပါ၊ မျဉ်းတစ်ကြောင်းတည်းအတွက် တရွတ်ဆွဲပါ။",
"freeDraw": "ကလစ်နှိပ်၍ တရွတ်ဆွဲပါ၊ ပြီးလျှင်လွှတ်ပါ။",
"text": "မှတ်ချက်။ ။မည်သည့်ကိရိယာရွေးထားသည်ဖြစ်စေ ကလစ်နှစ်ချက်နှိပ်၍စာသားထည့်နိုင်သည်",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "နောက်ဆုံးအမှတ်ပေါ်တွင်ကလစ်နှိပ်ခြင်း၊ Escape (သို့) Enter နှိပ်ခြင်းတို့ဖြင့်အဆုံးသတ်နိုင်",
"lockAngle": "",
"resize": "အချိုးအစားကန့်သတ်ရန် Shift နှင့် ဗဟိုမှချိန်ညှိရန် Alt တို့ကိုနှိပ်ထားနိုင်သည်",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "",
@ -231,8 +238,10 @@
"curvedArrow": "",
"curvedLine": "",
"documentation": "",
"doubleClick": "",
"drag": "",
"editor": "",
"editSelectedShape": "",
"github": "",
"howto": "",
"or": "",

View File

@ -101,6 +101,8 @@
"viewMode": "Visningsmodus",
"toggleExportColorScheme": "Veksle eksport av fargepalett",
"share": "Del",
"showStroke": "Vis fargevelger for kantfarge",
"showBackground": "Vis fargevelger for bakgrunnsfarge",
"toggleTheme": "Veksle tema"
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Klikk for å starte linje med flere punkter, eller dra for en enkel linje",
"freeDraw": "Klikk og dra, slipp når du er ferdig",
"text": "Tips: du kan også legge til tekst ved å dobbeltklikke hvor som helst med utvalgsverktøyet",
"text_selected": "Dobbeltklikk eller trykk ENTER for å redigere tekst",
"text_editing": "Trykk Escape eller Ctrl/Cmd+Enter for å fullføre redigering",
"linearElementMulti": "Klikk på siste punkt eller trykk Escape eller Enter for å fullføre",
"lockAngle": "Du kan låse vinkelen ved å holde nede SHIFT",
"resize": "Du kan beholde forholdet ved å trykke SHIFT mens du endrer størrelse,\ntrykk ALT for å endre størrelsen fra midten",
@ -223,7 +227,10 @@
"disk_button": "Lagre til fil",
"link_title": "Delbar lenke",
"link_details": "Eksporter som en skrivebeskyttet lenke.",
"link_button": "Eksporter til lenke"
"link_button": "Eksporter til lenke",
"excalidrawplus_description": "Lagre scenen til ditt Excalidraw+ arbeidsområde.",
"excalidrawplus_button": "Eksporter",
"excalidrawplus_exportError": "Kunne ikke eksportere til Excalidraw+ for øyeblikket..."
},
"helpDialog": {
"blog": "Les bloggen vår",
@ -231,16 +238,18 @@
"curvedArrow": "Buet pil",
"curvedLine": "Buet linje",
"documentation": "Dokumentasjon",
"doubleClick": "dobbeltklikk",
"drag": "dra",
"editor": "Redigeringsvisning",
"editSelectedShape": "Rediger valgt figur (tekst/pil/linje)",
"github": "Funnet et problem? Send inn",
"howto": "Følg våre veiledninger",
"or": "eller",
"preventBinding": "Forhindre pilbinding",
"shapes": "Former",
"shortcuts": "Tastatursnarveier",
"textFinish": "Fullfør redigering (tekst)",
"textNewLine": "Legg til ny linje (tekst)",
"textFinish": "Fullfør redigering (teksteditor)",
"textNewLine": "Legg til ny linje (teksteditor)",
"title": "Hjelp",
"view": "Vis",
"zoomToFit": "Zoom for å se alle elementer",

View File

@ -101,6 +101,8 @@
"viewMode": "Weergavemodus",
"toggleExportColorScheme": "Kleurenschema exporteren aan/uit",
"share": "Deel",
"showStroke": "Toon lijn kleur kiezer",
"showBackground": "Toon achtergrondkleur kiezer",
"toggleTheme": "Thema aan/uit"
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Klik om meerdere punten te starten, sleep voor één lijn",
"freeDraw": "Klik en sleep, laat los als je klaar bent",
"text": "Tip: je kunt tekst toevoegen door ergens dubbel te klikken met de selectietool",
"text_selected": "Dubbelklik of druk op ENTER om tekst te bewerken",
"text_editing": "Druk op Escape of CtrlOrCmd+ENTER om het bewerken te voltooien",
"linearElementMulti": "Klik op het laatste punt of druk op Escape of Enter om te stoppen",
"lockAngle": "Je kunt de hoek beperken door SHIFT ingedrukt te houden",
"resize": "Houd tijdens het vergroten SHIFT ingedrukt om verhoudingen te behouden,\ngebruik ALT om vanuit het midden te vergroten/verkleinen",
@ -223,7 +227,10 @@
"disk_button": "Opslaan naar bestand",
"link_title": "Deelbare link",
"link_details": "Exporteren als een alleen-lezen link.",
"link_button": "Exporteer naar link"
"link_button": "Exporteer naar link",
"excalidrawplus_description": "Sla de scène op in je Excalidraw+ werkruimte.",
"excalidrawplus_button": "Exporteren",
"excalidrawplus_exportError": "Kan op dit moment niet exporteren naar Excalidraw+..."
},
"helpDialog": {
"blog": "Lees onze blog",
@ -231,16 +238,18 @@
"curvedArrow": "Gebogen pijl",
"curvedLine": "Kromme lijn",
"documentation": "Documentatie",
"doubleClick": "dubbelklikken",
"drag": "slepen",
"editor": "Editor",
"editSelectedShape": "Bewerk geselecteerde vorm (tekst/pijl/lijn)",
"github": "Probleem gevonden? Verzenden",
"howto": "Volg onze handleidingen",
"or": "of",
"preventBinding": "Pijlbinding voorkomen",
"shapes": "Vormen",
"shortcuts": "Sneltoetsen",
"textFinish": "Voltooi bewerken (tekst)",
"textNewLine": "Nieuwe regel toevoegen (tekst)",
"textFinish": "Voltooi het bewerken (teksteditor)",
"textNewLine": "Nieuwe regel toevoegen (teksteditor)",
"title": "Help",
"view": "Weergave",
"zoomToFit": "Zoom in op alle elementen",

View File

@ -101,6 +101,8 @@
"viewMode": "Visningsmodus",
"toggleExportColorScheme": "Veksle eksport av fargepalett",
"share": "Del",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Klikk for å starte linje med fleire punkt, eller drag for ei enkel linje",
"freeDraw": "Klikk og drag, slepp når du er ferdig",
"text": "Tips: du kan òg leggje til tekst ved å dobbeltklikke kor som helst med utvalgsverktyet",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "Klikk på siste punkt eller trykk Escape eller Enter for å fullføre",
"lockAngle": "Du kan begrense vinkelen ved å holde nede SKIFT",
"resize": "Du kan halde fram med forholdet ved å trykke SHIFT medan du endrar storleik,\ntrykk ALT for å endre storleiken frå midten",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "Les bloggen vår",
@ -231,16 +238,18 @@
"curvedArrow": "Boga pil",
"curvedLine": "Boga linje",
"documentation": "Dokumentasjon",
"doubleClick": "",
"drag": "drag",
"editor": "Redigering",
"editSelectedShape": "",
"github": "Funne eit problem? Send inn",
"howto": "Følg vegleiinga vår",
"or": "eller",
"preventBinding": "Hindre pilkopling",
"shapes": "Formar",
"shortcuts": "Tastatursnarvegar",
"textFinish": "Fullfør redigering (tekst)",
"textNewLine": "Legg til ny linje (tekst)",
"textFinish": "",
"textNewLine": "",
"title": "Hjelp",
"view": "Vising",
"zoomToFit": "Zoom for å sjå alle elementa",

View File

@ -42,8 +42,8 @@
"fontSize": "Talha poliça",
"fontFamily": "Familha de poliça",
"onlySelected": "Seleccion sonque",
"withBackground": "",
"exportEmbedScene": "",
"withBackground": "Rèireplan",
"exportEmbedScene": "Scèna embarcada",
"exportEmbedScene_details": "Las donadas de scèna seràn enregistradas dins lo fichièr PNG/SVG exportat, per que la scèna pòsca èsser restaurada a partir daqueste fichièr.\nAumentarà la talha del fichièr exportat.",
"addWatermark": "Apondre «Fabricat amb Excalidraw»",
"handDrawn": "A la man levada",
@ -101,19 +101,21 @@
"viewMode": "Mòde de vista",
"toggleExportColorScheme": "Alternar lesquèma de color dexpòrt",
"share": "Partejar",
"showStroke": "Mostrar lo selector de color de contorn",
"showBackground": "Mostrar lo selector de color de fons",
"toggleTheme": "Alternar tèma"
},
"buttons": {
"clearReset": "Reïnicializar lo canabàs",
"exportJSON": "",
"exportImage": "",
"exportJSON": "Exportar en fichièr",
"exportImage": "Salvar coma imatge",
"export": "Exportar",
"exportToPng": "Exportar en PNG",
"exportToSvg": "Exportar en SVG",
"copyToClipboard": "Copiar al quichapapièrs",
"copyPngToClipboard": "Copiar PNG al quichapapièrs",
"scale": "Escala",
"save": "",
"save": "Salvar al fichièr actual",
"saveAs": "Enregistrar jos",
"load": "Cargar",
"getShareableLink": "Obténer lo ligam de partatge",
@ -178,6 +180,8 @@
"linearElement": "Clicatz per començar mantun punt, lisatz per una sola linha",
"freeDraw": "Clicatz e lisatz, relargatz un còp acabat",
"text": "Astúcia: podètz tanben apondre de tèxt en doble clicant ont que siá amb laisina de seleccion",
"text_selected": "Clicatz dos còps o quichatz ENTRADA per modificar lo tèxt",
"text_editing": "Quichatz ESCAPAR o CtrlOrCmd+ENTRADA per acabar la modificacion",
"linearElementMulti": "Clicatz sul darrièr punt o quichatz Ecap o Entrada per acabar",
"lockAngle": "Podètz restrénger langle en mantenent MAJ",
"resize": "Podètz servar las proporcions en mantenent la tòca MAJ pendent lo redimensionament,\nmantenètz la tòca ALT per redimensionar a partir del centre",
@ -218,12 +222,15 @@
"title": "Error"
},
"exportDialog": {
"disk_title": "",
"disk_details": "",
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"disk_title": "Salvar al disc",
"disk_details": "Exportar las donadas de la scèna cap a un fichièr que podètz importar mai tard.",
"disk_button": "Salvar al fichièr",
"link_title": "Ligam de partejar",
"link_details": "Exportar coma un ligam de lectura sola.",
"link_button": "Exportar en ligam",
"excalidrawplus_description": "Enregistrar la scèna dins vòstre espaci de trabalh Excalidraw+.",
"excalidrawplus_button": "Exportar",
"excalidrawplus_exportError": "Export impossibla cap a Excalidraw+ pel moment..."
},
"helpDialog": {
"blog": "Legir nòstre blog",
@ -231,16 +238,18 @@
"curvedArrow": "Sageta corba",
"curvedLine": "Linha corba",
"documentation": "Documentacion",
"doubleClick": "doble clic",
"drag": "lisar",
"editor": "Editor",
"editSelectedShape": "Modificar la fòrma seleccionada (tèxt/sageta/linha)",
"github": "Problèma trobat? Senhalatz-lo",
"howto": "Seguissètz nòstras guidas",
"or": "o",
"preventBinding": "Empachar la fixacion de sagetas",
"shapes": "Formas",
"shortcuts": "Acorchis clavièr",
"textFinish": "Terminar ledicion (tèxt)",
"textNewLine": "Apondre linha novèl (tèxt)",
"textFinish": "Terminar ledicion (editor de tèxt)",
"textNewLine": "Apondre linha novèl (editor de tèxt)",
"title": "Ajuda",
"view": "Vista",
"zoomToFit": "Zoomar per veire totes los elements",

View File

@ -20,7 +20,7 @@
"background": "ਬੈਕਗਰਾਉਂਡ",
"fill": "ਭਰਨਾ",
"strokeWidth": "ਰੇਖਾ ਦੀ ਚੌੜਾਈ",
"strokeShape": "",
"strokeShape": "ਰੇਖਾ ਦਾ ਆਕ੍ਰਿਤੀ",
"strokeShape_gel": "ਜੈੱਲ ਪੈੱਨ",
"strokeShape_fountain": "ਫਾਉਨਟੇਨ ਪੈੱਨ",
"strokeShape_brush": "ਬੁਰਸ਼ ਪੈੱਨ",
@ -42,8 +42,8 @@
"fontSize": "ਫੌਂਟ ਅਕਾਰ",
"fontFamily": "ਫੌਂਟ ਪਰਿਵਾਰ",
"onlySelected": "ਸਿਰਫ ਚੁਣੇ ਹੋਏ ਹੀ",
"withBackground": "",
"exportEmbedScene": "",
"withBackground": "ਬੈਕਗਰਾਉਂਡ",
"exportEmbedScene": "ਦ੍ਰਿਸ਼ ਮੜ੍ਹੋ",
"exportEmbedScene_details": "ਦ੍ਰਿਸ਼ ਦਾ ਡਾਟਾ ਨਿਰਯਾਤ ਕੀਤੀ PNG/SVG ਫਾਈਲ ਵਿੱਚ ਸਾਂਭ ਦਿੱਤਾ ਜਾਵੇਗਾ ਤਾਂ ਜੋ ਇਸ ਵਿੱਚੋਂ ਦ੍ਰਿਸ਼ ਨੂੰ ਬਹਾਲ ਕੀਤਾ ਜਾ ਸਕੇ। ਇਹ ਨਿਰਯਾਤ ਕੀਤੀ ਜਾਣ ਵਾਲੀ ਫਾਈਲ ਦਾ ਅਕਾਰ ਵਧਾ ਦੇਵੇਗਾ।",
"addWatermark": "\"Excalidraw ਨਾਲ ਬਣਾਇਆ\" ਜੋੜੋ",
"handDrawn": "ਹੱਥਲਿਖਤ",
@ -96,24 +96,26 @@
"centerHorizontally": "ਖੜ੍ਹਵੇਂ ਵਿਚਕਾਰ ਕਰੋ",
"distributeHorizontally": "ਖੜ੍ਹਵੇਂ ਇਕਸਾਰ ਵੰਡੋ",
"distributeVertically": "ਲੇਟਵੇਂ ਇਕਸਾਰ ਵੰਡੋ",
"flipHorizontal": "",
"flipVertical": "",
"flipHorizontal": "ਖਿਤਿਜ ਪਲਟੋ",
"flipVertical": "ਲੰਬਕਾਰੀ ਪਲਟੋ",
"viewMode": "ਦੇਖੋ ਮੋਡ",
"toggleExportColorScheme": "",
"toggleExportColorScheme": "ਨਿਰਯਾਤ ਰੰਗ ਦੀ ਸਕੀਮ ਟਾਗਲ ਕਰੋ",
"share": "ਸਾਂਝਾ ਕਰੋ",
"showStroke": "ਰੇਖਾ ਦਾ ਰੰਗ ਚੋਣਕਾਰ ਦਿਖਾਓ ",
"showBackground": "ਬੈਕਗਰਾਉਂਡ ਦਾ ਰੰਗ ਚੋਣਕਾਰ ਦਿਖਾਓ",
"toggleTheme": "ਥੀਮ ਬਦਲੋ"
},
"buttons": {
"clearReset": "ਕੈਨਵਸ ਰੀਸੈੱਟ ਕਰੋ",
"exportJSON": "",
"exportImage": "",
"exportJSON": "ਫਾਈਲ ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ",
"exportImage": "ਤਸਵੀਰ ਵਜੋਂ ਸਾਂਭੋ",
"export": "ਨਿਰਯਾਤ",
"exportToPng": "PNG ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ",
"exportToSvg": "SVG ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ",
"copyToClipboard": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕਰੋ",
"copyPngToClipboard": "PNG ਨੂੰ ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕਰੋ",
"scale": "ਪੈਮਾਇਸ਼",
"save": "",
"save": "ਮੌਜੂਦਾ ਫਾਈਲ ਵਿੱਚ ਸਾਂਭੋ",
"saveAs": "ਇਸ ਵਜੋਂ ਸਾਂਭੋ",
"load": "ਲੋਡ ਕਰੋ",
"getShareableLink": "ਸਾਂਝੀ ਕਰਨ ਵਾਲੀ ਲਿੰਕ ਲਵੋ",
@ -164,7 +166,7 @@
"ellipse": "ਅੰਡਾਕਾਰ",
"arrow": "ਤੀਰ",
"line": "ਲਕੀਰ",
"freedraw": "",
"freedraw": "ਵਾਹੋ",
"text": "ਪਾਠ",
"library": "ਲਾਇਬ੍ਰੇਰੀ",
"lock": "ਡਰਾਇੰਗ ਤੋਂ ਬਾਅਦ ਵੀ ਚੁਣੇ ਹੋਏ ਸੰਦ ਨੂੰ ਸਰਗਰਮ ਰੱਖੋ "
@ -178,6 +180,8 @@
"linearElement": "ਇੱਕ ਤੋਂ ਜ਼ਿਆਦਾ ਬਿੰਦੂਆਂ ਲਈ ਕਲਿੱਕ ਕਰਕੇ ਸ਼ੁਰੂਆਤ ਕਰੋ, ਇਕਹਿਰੀ ਲਕੀਰ ਲਈ ਘਸੀਟੋ",
"freeDraw": "ਕਲਿੱਕ ਕਰਕੇ ਘਸੀਟੋ, ਪੂਰਾ ਹੋਣ 'ਤੇ ਛੱਡ ਦਿਉ",
"text": "ਨੁਸਖਾ: ਤੁਸੀਂ ਚੋਣਕਾਰ ਸੰਦ ਰਾਹੀਂ ਕਿਤੇ ਵੀ ਡਬਲ-ਕਲਿੱਕ ਕਰਕੇ ਵੀ ਪਾਠ ਜੋੜ ਸਕਦੇ ਹੋ",
"text_selected": "ਲਿਖਤ ਨੂੰ ਸੋਧਣ ਲਈ ਡਬਲ-ਕਲਿੱਕ ਕਰੋ ਜਾਂ ਐਂਟਰ ਦਬਾਓ",
"text_editing": "",
"linearElementMulti": "ਮੁਕੰਮਲ ਕਰਨ ਲਈ ਆਖਰੀ ਬਿੰਦੂ 'ਤੇ ਕਲਿੱਕ ਕਰੋ ਜਾਂ ਇਸਕੇਪ ਜਾਂ ਐਂਟਰ ਦਬਾਓ",
"lockAngle": "ਤੁਸੀਂ SHIFT ਦਬਾਈ ਰੱਖ ਕੇ ਕੋਣਾਂ ਨੂੰ ਕਾਬੂ ਕਰ ਸਕਦੇ ਹੋ",
"resize": "ਤੁਸੀਂ ਅਕਾਰ ਬਦਲਦੇ ਸਮੇਂ SHIFT ਦਬਾਈ ਰੱਖ ਕੇ ਅਨੁਪਾਤ ਨੂੰ ਕਾਬੂ ਕਰ ਸਕਦੇ ਹੋ, ਵਿਚਕਾਰ ਤੋਂ ਅਕਾਰ ਬਦਲਣ ਲਈ ALT ਦਬਾਓ",
@ -218,12 +222,15 @@
"title": "ਗਲਤੀ"
},
"exportDialog": {
"disk_title": "",
"disk_title": "ਡਿਸਕ ਵਿੱਚ ਸਾਂਭੋ",
"disk_details": "",
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"disk_button": "ਫਾਈਲ ਵਿੱਚ ਸਾਂਭੋ",
"link_title": "ਸਾਂਝੀ ਕਰਨ ਵਾਲੀ ਲਿੰਕ",
"link_details": "ਸਿਰਫ ਪੜ੍ਹੇ-ਜਾਣ ਵਾਲੀ ਲਿੰਕ ਨਿਰਯਾਤ ਕਰੋ।",
"link_button": "ਲਿੰਕ ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ",
"excalidrawplus_description": "",
"excalidrawplus_button": "ਨਿਰਯਾਤ ਕਰੋ",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "ਸਾਡਾ ਬਲੌਗ ਪੜ੍ਹੋ",
@ -231,16 +238,18 @@
"curvedArrow": "ਵਿੰਗਾ ਤੀਰ",
"curvedLine": "ਵਿੰਗੀ ਲਕੀਰ",
"documentation": "ਕਾਗਜ਼ਾਤ",
"doubleClick": "ਡਬਲ-ਕਲਿੱਕ",
"drag": "ਘਸੀਟੋ",
"editor": "ਸੋਧਕ",
"editSelectedShape": "ਚੁਣੀ ਆਕ੍ਰਿਤੀ ਸੋਧੋ (ਲਿਖਤ/ਤੀਰ/ਲਾਈਨ)",
"github": "ਕੋਈ ਸਮੱਸਿਆ ਲੱਭੀ? ਜਮ੍ਹਾਂ ਕਰਵਾਓ",
"howto": "ਸਾਡੀਆਂ ਗਾਈਡਾਂ ਦੀ ਪਾਲਣਾ ਕਰੋ",
"or": "ਜਾਂ",
"preventBinding": "ਤੀਰ ਬੱਝਣਾ ਰੋਕੋ",
"shapes": "ਆਕ੍ਰਿਤੀਆਂ",
"shortcuts": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ",
"textFinish": "ਸੋਧ ਮੁਕੰਮਲ ਕਰੋ (ਪਾਠ)",
"textNewLine": "ਨਵੀਂ ਪੰਕਤੀ ਜੋੜੋ (ਪਾਠ)",
"textFinish": "ਸੋਧਣਾ ਮੁਕੰਮਲ ਕਰੋ (ਲਿਖਤ ਸੋਧਕ)",
"textNewLine": "",
"title": "ਮਦਦ",
"view": "ਦਿੱਖ",
"zoomToFit": "ਸਾਰੇ ਐਲੀਮੈਂਟਾਂ ਨੂੰ ਫਿੱਟ ਕਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ",

View File

@ -1,39 +1,40 @@
{
"ar-SA": 94,
"bg-BG": 85,
"ca-ES": 92,
"cs-CZ": 36,
"ar-SA": 90,
"bg-BG": 81,
"ca-ES": 100,
"cs-CZ": 35,
"de-DE": 100,
"el-GR": 90,
"el-GR": 86,
"en": 100,
"es-ES": 93,
"fa-IR": 81,
"fi-FI": 94,
"es-ES": 98,
"fa-IR": 77,
"fi-FI": 99,
"fr-FR": 100,
"he-IL": 82,
"hi-IN": 84,
"hu-HU": 74,
"he-IL": 78,
"hi-IN": 80,
"hu-HU": 71,
"id-ID": 100,
"it-IT": 99,
"ja-JP": 99,
"kab-KAB": 97,
"ko-KR": 85,
"lv-LV": 17,
"my-MM": 69,
"it-IT": 100,
"ja-JP": 100,
"kab-KAB": 98,
"kk-KZ": 31,
"ko-KR": 81,
"lv-LV": 16,
"my-MM": 67,
"nb-NO": 100,
"nl-NL": 100,
"nn-NO": 92,
"oc-FR": 95,
"pa-IN": 91,
"pl-PL": 87,
"pt-BR": 92,
"pt-PT": 94,
"nn-NO": 88,
"oc-FR": 100,
"pa-IN": 96,
"pl-PL": 83,
"pt-BR": 88,
"pt-PT": 100,
"ro-RO": 100,
"ru-RU": 95,
"sk-SK": 95,
"ru-RU": 100,
"sk-SK": 100,
"sv-SE": 100,
"tr-TR": 93,
"uk-UA": 100,
"zh-CN": 94,
"tr-TR": 89,
"uk-UA": 95,
"zh-CN": 98,
"zh-TW": 99
}

View File

@ -101,6 +101,8 @@
"viewMode": "Tryb widoku",
"toggleExportColorScheme": "",
"share": "",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Naciśnij, aby zrobić punkt, przeciągnij, aby narysować linię",
"freeDraw": "Naciśnij i przeciągnij by rysować, puść kiedy skończysz",
"text": "Wskazówka: możesz również dodać tekst klikając dwukrotnie gdziekolwiek za pomocą narzędzia zaznaczania",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "Aby zakończyć krzywą, ponownie kliknij w ostatni punkt, bądź naciśnij Esc albo Enter",
"lockAngle": "Możesz ograniczyć kąt trzymając SHIFT",
"resize": "Możesz zachować proporcję trzymająć wcisnięty SHIFT, przytrzymaj ALT by zmienić rozmiar względem środka",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "Przeczytaj na naszym blogu",
@ -231,16 +238,18 @@
"curvedArrow": "Zakrzywiona strzałka",
"curvedLine": "Zakrzywiona linia",
"documentation": "Dokumentacja",
"doubleClick": "",
"drag": "przeciągnij",
"editor": "Edytor",
"editSelectedShape": "",
"github": "Znalazłeś problem? Prześlij",
"howto": "Skorzystaj z instrukcji",
"or": "lub",
"preventBinding": "Zapobiegaj wiązaniu strzałek",
"shapes": "Kształty",
"shortcuts": "Skróty klawiszowe",
"textFinish": "Zakończ edycję (tekst)",
"textNewLine": "Dodaj nową linię (tekst)",
"textFinish": "",
"textNewLine": "",
"title": "Pomoc",
"view": "Widok",
"zoomToFit": "Powiększ, aby wyświetlić wszystkie elementy",

View File

@ -101,6 +101,8 @@
"viewMode": "Modo de visualização",
"toggleExportColorScheme": "Alternar esquema de cores de exportação",
"share": "Compartilhar",
"showStroke": "",
"showBackground": "",
"toggleTheme": ""
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Clique para iniciar vários pontos, arraste para uma única linha",
"freeDraw": "Toque e arraste, solte quando terminar",
"text": "Dica: você também pode adicionar texto clicando duas vezes em qualquer lugar com a ferramenta de seleção",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "Clique no último ponto ou pressione Escape ou Enter para terminar",
"lockAngle": "Você pode restringir o ângulo segurando o SHIFT",
"resize": "Você pode restringir proporções segurando SHIFT enquanto redimensiona,\nsegure ALT para redimensionar do centro",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "Leia o nosso blog",
@ -231,16 +238,18 @@
"curvedArrow": "Seta curva",
"curvedLine": "Linha curva",
"documentation": "Documentação",
"doubleClick": "",
"drag": "arrastar",
"editor": "Editor",
"editSelectedShape": "",
"github": "Encontrou algum problema? Nos informe",
"howto": "Siga nossos guias",
"or": "ou",
"preventBinding": "Evitar fixação de seta",
"shapes": "Formas",
"shortcuts": "Atalhos de teclado",
"textFinish": "Finalizar edição (texto)",
"textNewLine": "Adicionar nova linha (texto)",
"textFinish": "",
"textNewLine": "",
"title": "Ajudar",
"view": "Visualizar",
"zoomToFit": "Ampliar para encaixar todos os elementos",

View File

@ -42,9 +42,9 @@
"fontSize": "Tamanho da fonte",
"fontFamily": "Família da fontes",
"onlySelected": "Somente a seleção",
"withBackground": "",
"exportEmbedScene": "",
"exportEmbedScene_details": "Os dados da cena serão salvos no arquivo PNG/SVG exportado para que a cena possa ser restaurada.\nIrá aumentar o tamanho do arquivo exportado.",
"withBackground": "Fundo",
"exportEmbedScene": "Cena embutida",
"exportEmbedScene_details": "Os dados da cena serão guardados no ficheiro PNG/SVG exportado para que a cena possa ser restaurada.\nIrá aumentar o tamanho do ficheiro exportado.",
"addWatermark": "Adicionar \"Feito com Excalidraw\"",
"handDrawn": "Manuscrito",
"normal": "Normal",
@ -55,7 +55,7 @@
"veryLarge": "Muito grande",
"solid": "Sólido",
"hachure": "Eclosão",
"crossHatch": "Hachurado",
"crossHatch": "Sombreado",
"thin": "Fino",
"bold": "Espesso",
"left": "Esquerda",
@ -67,8 +67,8 @@
"cartoonist": "Caricaturista",
"fileTitle": "Nome do ficheiro",
"colorPicker": "Seletor de cores",
"canvasBackground": "Fundo da tela",
"drawingCanvas": "Tela de desenho",
"canvasBackground": "Fundo da área de desenho",
"drawingCanvas": "Área de desenho",
"layers": "Camadas",
"actions": "Ações",
"language": "Idioma",
@ -76,7 +76,7 @@
"duplicateSelection": "Duplicar",
"untitled": "Sem título",
"name": "Nome",
"yourName": "Seu nome",
"yourName": "O seu nome",
"madeWithExcalidraw": "Feito com Excalidraw",
"group": "Agrupar seleção",
"ungroup": "Desagrupar seleção",
@ -84,16 +84,16 @@
"showGrid": "Mostrar grelha",
"addToLibrary": "Adicionar à biblioteca",
"removeFromLibrary": "Remover da biblioteca",
"libraryLoadingMessage": "Carregando biblioteca…",
"libraryLoadingMessage": "A carregar a biblioteca…",
"libraries": "Procurar bibliotecas",
"loadingScene": "Carregando cena…",
"loadingScene": "A carregar a cena…",
"align": "Alinhamento",
"alignTop": "Alinhar ao topo",
"alignBottom": "Alinhar ao fundo",
"alignLeft": "Alinhar à esquerda",
"alignRight": "Alinhar à direita",
"centerVertically": "Centralizar verticalmente",
"centerHorizontally": "Centralizar horizontalmente",
"centerVertically": "Centrar verticalmente",
"centerHorizontally": "Centrar horizontalmente",
"distributeHorizontally": "Distribuir horizontalmente",
"distributeVertically": "Distribuir verticalmente",
"flipHorizontal": "Inverter horizontalmente",
@ -101,20 +101,22 @@
"viewMode": "Modo de visualização",
"toggleExportColorScheme": "Alternar esquema de cores de exportação",
"share": "Partilhar",
"showStroke": "Mostrar seletor de cores do traço",
"showBackground": "Mostrar seletor de cores do fundo",
"toggleTheme": "Alternar tema"
},
"buttons": {
"clearReset": "Limpar o canvas e redefinir a cor de fundo",
"exportJSON": "",
"exportImage": "",
"clearReset": "Limpar a área de desenho e redefinir a cor de fundo",
"exportJSON": "Exportar para ficheiro",
"exportImage": "Guardar como imagem",
"export": "Exportar",
"exportToPng": "Exportar em PNG",
"exportToSvg": "Exportar em SVG",
"copyToClipboard": "Copiar para o clipboard",
"copyPngToClipboard": "Copiar PNG para área de transferência",
"scale": "Escala",
"save": "",
"saveAs": "Salvar como",
"save": "Guardar no ficheiro atual",
"saveAs": "Guardar como",
"load": "Carregar",
"getShareableLink": "Obter um link de partilha",
"close": "Fechar",
@ -130,31 +132,31 @@
"redo": "Refazer",
"resetLibrary": "Repor a biblioteca",
"createNewRoom": "Criar nova sala",
"fullScreen": "Tela cheia",
"fullScreen": "Ecrã inteiro",
"darkMode": "Modo escuro",
"lightMode": "Modo claro",
"zenMode": "Modo Zen",
"zenMode": "Modo zen",
"exitZenMode": "Sair do modo zen"
},
"alerts": {
"clearReset": "Isto irá limpar toda a tela. Você tem certeza?",
"couldNotCreateShareableLink": "Não foi possível criar um link de compartilhamento.",
"couldNotCreateShareableLinkTooBig": "Não foi possível criar um link compartilhável: a cena é muito grande",
"couldNotLoadInvalidFile": "Não foi possível carregar o arquivo inválido",
"clearReset": "Isto irá limpar toda a área de desenho. Tem a certeza?",
"couldNotCreateShareableLink": "Não foi possível criar um link partilhável.",
"couldNotCreateShareableLinkTooBig": "Não foi possível criar um link partilhável: a cena é muito grande",
"couldNotLoadInvalidFile": "Não foi possível carregar o ficheiro inválido",
"importBackendFailed": "A importação do servidor falhou.",
"cannotExportEmptyCanvas": "Não é possível exportar um canvas vazío.",
"couldNotCopyToClipboard": "Não foi possível copiar no clipboard. Experimente no navegador Chrome.",
"decryptFailed": "Não foi possível descriptografar os dados.",
"cannotExportEmptyCanvas": "Não é possível exportar uma área de desenho vazia.",
"couldNotCopyToClipboard": "Não foi possível copiar para a área de transferência. Experimente no navegador Chrome.",
"decryptFailed": "Não foi possível desencriptar os dados.",
"uploadedSecurly": "O upload foi protegido com criptografia de ponta a ponta, o que significa que o servidor do Excalidraw e terceiros não podem ler o conteúdo.",
"loadSceneOverridePrompt": "Carregar um desenho externo substituirá o seu conteúdo existente. Deseja continuar?",
"loadSceneOverridePrompt": "Se carregar um desenho externo substituirá o conteúdo existente. Quer continuar?",
"collabStopOverridePrompt": "Ao interromper a sessão irá substituir o último desenho guardado. Tem a certeza?\n\n(Caso queira manter o último desenho, simplesmente feche a janela do navegador.)",
"errorLoadingLibrary": "Houve um erro ao carregar a biblioteca de terceiros.",
"errorAddingToLibrary": "",
"errorRemovingFromLibrary": "",
"confirmAddLibrary": "Isso adicionará {{numShapes}} forma(s) à sua biblioteca. Tem certeza?",
"imageDoesNotContainScene": "A importação de imagens não é suportada no momento.\n\nVocê deseja importar uma cena? Esta imagem parece não conter dados de cena. Você ativou isto durante a exportação?",
"cannotRestoreFromImage": "Não foi possível restaurar a cena deste arquivo de imagem",
"invalidSceneUrl": "Não foi possível importar a cena a partir da URL fornecida. Ela está malformada ou não contém dados JSON de Excalidraw válidos.",
"errorAddingToLibrary": "Não foi possível adicionar o item à biblioteca",
"errorRemovingFromLibrary": "Não foi possível remover o item da biblioteca",
"confirmAddLibrary": "Isso adicionará {{numShapes}} forma(s) à sua biblioteca. Tem a certeza?",
"imageDoesNotContainScene": "A importação de imagens não é suportada neste momento.\n\nQuer importar uma cena? Esta imagem parece não conter dados de cena. Ativou isto durante a exportação?",
"cannotRestoreFromImage": "Não foi possível restaurar a cena deste ficheiro de imagem",
"invalidSceneUrl": "Não foi possível importar a cena a partir do URL fornecido. Ou está mal formado ou não contém dados JSON do Excalidraw válidos.",
"resetLibrary": "Isto irá limpar a sua biblioteca. Tem a certeza?"
},
"toolBar": {
@ -170,85 +172,92 @@
"lock": "Manter a ferramenta selecionada ativa após desenhar"
},
"headings": {
"canvasActions": "Ações da tela",
"canvasActions": "Ações da área de desenho",
"selectedShapeActions": "Ações das formas selecionadas",
"shapes": "Formas"
},
"hints": {
"linearElement": "Clique para iniciar vários pontos, arraste para uma única linha",
"freeDraw": "Toque e arraste, solte quando terminar",
"text": "Dica: você também pode adicionar texto clicando duas vezes em qualquer lugar com a ferramenta de seleção",
"freeDraw": "Clique e arraste, large quando terminar",
"text": "Dica: também pode adicionar texto clicando duas vezes em qualquer lugar com a ferramenta de seleção",
"text_selected": "Clique duas vezes ou pressione a tecla Enter para editar o texto",
"text_editing": "Pressione a tecla Escape ou CtrlOrCmd+ENTER para terminar a edição",
"linearElementMulti": "Clique no último ponto ou pressione Escape ou Enter para terminar",
"lockAngle": "Você pode restringir o ângulo segurando SHIFT",
"resize": "Você pode restringir proporções segurando SHIFT enquanto redimensiona,\nsegure ALT para redimensionar do centro",
"rotate": "Você pode restringir os ângulos segurando SHIFT enquanto gira",
"lineEditor_info": "Clique duas vezes ou pressione Enter para editar os pontos",
"lineEditor_pointSelected": "Pressione Deletar para remover ponto, CtrlOuCmd+D para duplicar ou arraste para mover",
"lineEditor_nothingSelected": "Selecione um ponto para mover ou remover, ou segure Alt e clique para adicionar novos pontos"
"lockAngle": "Pode restringir o ângulo mantendo premida a tecla SHIFT",
"resize": "Pode restringir as proporções mantendo a tecla SHIFT premida enquanto redimensiona,\nmantenha a tecla ALT premida para redimensionar a partir do centro",
"rotate": "Pode restringir os ângulos mantendo a tecla SHIFT premida enquanto roda",
"lineEditor_info": "Clique duas vezes ou pressione a tecla Enter para editar os pontos",
"lineEditor_pointSelected": "Pressione a tecla Delete para remover o ponto, CtrlOuCmd+D para duplicar ou arraste para mover",
"lineEditor_nothingSelected": "Selecione um ponto para mover ou remover, ou mantenha premida a tecla Alt e clique para adicionar novos pontos"
},
"canvasError": {
"cannotShowPreview": "Não é possível mostrar pré-visualização",
"canvasTooBig": "A tela pode ser muito grande.",
"cannotShowPreview": "Não é possível mostrar uma pré-visualização",
"canvasTooBig": "A área de desenho pode ser muito grande.",
"canvasTooBigTip": "Dica: tente aproximar um pouco os elementos mais distantes."
},
"errorSplash": {
"headingMain_pre": "Foi encontrado um erro. Tente ",
"headingMain_button": "recarregar a página.",
"clearCanvasMessage": "Se a recarga não funcionar, tente ",
"clearCanvasMessage_button": "limpando a tela.",
"clearCanvasMessage_button": "a limpar a área de desenho.",
"clearCanvasCaveat": " Isso resultará em perda de trabalho ",
"trackedToSentry_pre": "O erro com o identificador ",
"trackedToSentry_post": " foi rastreado no nosso sistema.",
"openIssueMessage_pre": "Fomos muito cautelosos para não incluir suas informações de cena no erro. Se sua cena não for privada, por favor, considere seguir nosso ",
"openIssueMessage_button": "rastreador de bugs.",
"openIssueMessage_post": " Por favor, inclua informações abaixo, copiando e colando para a issue do GitHub.",
"openIssueMessage_post": " Por favor, inclua informações abaixo, copiando e colando no relatório de erros no GitHub.",
"sceneContent": "Conteúdo da cena:"
},
"roomDialog": {
"desc_intro": "Você pode convidar pessoas para sua cena atual para colaborar com você.",
"desc_privacy": "Não se preocupe, a sessão usa criptografia de ponta a ponta; portanto, o que você desenhar permanecerá privado. Nem mesmo nosso servidor poderá ver o que você cria.",
"desc_intro": "Pode convidar pessoas para colaborarem na sua cena atual.",
"desc_privacy": "Não se preocupe, a sessão usa criptografia de ponta-a-ponta, por isso o que desenhar permanecerá privado. Nem mesmo o nosso servidor poderá ver o que cria.",
"button_startSession": "Iniciar sessão",
"button_stopSession": "Parar sessão",
"desc_inProgressIntro": "A sessão de colaboração ao vivo está agora em andamento.",
"desc_shareLink": "Compartilhe este link com qualquer pessoa com quem você queira colaborar:",
"desc_exitSession": "Interrompendo a sessão você irá se desconectar da sala, mas você poderá continuar trabalhando com a cena localmente. Observe que isso não afetará outras pessoas, e elas ainda poderão colaborar em sua versão.",
"shareTitle": "Participe de uma sessão de colaboração ao vivo na Excalidraw"
"desc_shareLink": "Partilhe este link com qualquer pessoa com quem queira colaborar:",
"desc_exitSession": "Interrompendo a sessão irá desconectar-se da sala, mas poderá continuar a trabalhar com a cena localmente. Note que isso não afetará outras pessoas e elas ainda poderão colaborar nas versões deles.",
"shareTitle": "Participe numa sessão de colaboração ao vivo no Excalidraw"
},
"errorDialog": {
"title": "Erro"
},
"exportDialog": {
"disk_title": "",
"disk_details": "",
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"disk_title": "Guardar no disco",
"disk_details": "Exportar os dados da cena para um ficheiro do qual poderá importar mais tarde.",
"disk_button": "Guardar num ficheiro",
"link_title": "Link partilhável",
"link_details": "Exportar como um link de apenas leitura.",
"link_button": "Exportar para link",
"excalidrawplus_description": "Guardar a cena no seu espaço de trabalho Excalidraw+",
"excalidrawplus_button": "Exportar",
"excalidrawplus_exportError": "Não foi possível exportar para o Excalidraw+ neste momento..."
},
"helpDialog": {
"blog": "Leia o nosso blog",
"blog": "Leia o nosso blogue",
"click": "clicar",
"curvedArrow": "Seta curva",
"curvedLine": "Linha curva",
"documentation": "Documentação",
"doubleClick": "clique duplo",
"drag": "arrastar",
"editor": "Editor",
"github": "Encontrou algum problema? Nos informe",
"editSelectedShape": "Editar forma selecionada (texto/seta/linha)",
"github": "Encontrou algum problema? Informe-nos",
"howto": "Siga os nossos guias",
"or": "ou",
"preventBinding": "Prevenir fixação de seta",
"shapes": "Formas",
"shortcuts": "Atalhos de teclado",
"textFinish": "Finalizar edição (texto)",
"textNewLine": "Adicionar nova linha (texto)",
"textFinish": "Finalizar edição (editor texto)",
"textNewLine": "Adicionar nova linha (editor de texto)",
"title": "Ajuda",
"view": "Visualizar",
"zoomToFit": "Ajustar para caber todos os elementos",
"zoomToFit": "Ajustar para todos os elementos caberem",
"zoomToSelection": "Ampliar a seleção"
},
"encrypted": {
"tooltip": "Seus desenhos são criptografados de ponta a ponta, então os servidores do Excalidraw nunca os verão.",
"link": "Publicação de blog na encriptação de ponta a ponta na Excalidraw"
"tooltip": "Os seus desenhos são encriptados de ponta-a-ponta, por isso os servidores do Excalidraw nunca os verão.",
"link": "Publicação de blogue na encriptação ponta-a-ponta no Excalidraw"
},
"stats": {
"angle": "Ângulo",
@ -268,7 +277,7 @@
"toast": {
"copyStyles": "Estilos copiados.",
"copyToClipboard": "Copiado para a área de transferência.",
"copyToClipboardAsPng": "Copiado {{exportSelection}} para a área de transferência como PNG\n({{exportColorScheme}})",
"copyToClipboardAsPng": "{{exportSelection}} copiado para a área de transferência como PNG\n({{exportColorScheme}})",
"fileSaved": "Ficheiro guardado.",
"fileSavedToFilename": "Guardado como {filename}",
"canvas": "área de desenho",

View File

@ -101,6 +101,8 @@
"viewMode": "Mod de vizualizare",
"toggleExportColorScheme": "Comutare schemă de culori de export",
"share": "Distribuie",
"showStroke": "Afișare selector culoare contur",
"showBackground": "Afișare selector culoare fundal",
"toggleTheme": "Comutare temă"
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Dă clic pentru a crea mai multe puncte, glisează pentru a forma o singură linie",
"freeDraw": "Dă clic pe pânză și glisează cursorul, apoi eliberează-l când ai terminat",
"text": "Sfat: poți adăuga text și dând dublu clic oriunde cu instrumentul de selecție",
"text_selected": "Dă dublu clic sau apasă tasta Enter pentru a edita textul",
"text_editing": "Apasă tasta Escape sau Ctrl sau Cmd + Enter pentru a finaliza editarea",
"linearElementMulti": "Dă clic pe ultimul punct sau apasă tasta Escape sau tasta Enter pentru a termina",
"lockAngle": "Poți constrânge unghiul prin ținerea apăsată a tastei SHIFT",
"resize": "Poți constrânge proporțiile, ținând apăsată tasta SHIFT în timp ce redimensionezi,\nține apăsată tasta ALT pentru a redimensiona de la centru",
@ -223,7 +227,10 @@
"disk_button": "Salvare în fișier",
"link_title": "URL partajabil",
"link_details": "Exportă ca URL doar în citire.",
"link_button": "Exportare în URL"
"link_button": "Exportare în URL",
"excalidrawplus_description": "Salvează scena în spațiul de lucru Excalidraw+.",
"excalidrawplus_button": "Exportare",
"excalidrawplus_exportError": "Excalidraw+ nu a putut fi exportat în acest moment..."
},
"helpDialog": {
"blog": "Citește blogul nostru",
@ -231,16 +238,18 @@
"curvedArrow": "Săgeată curbată",
"curvedLine": "Linie curbată",
"documentation": "Documentație",
"doubleClick": "dublu clic",
"drag": "glisare",
"editor": "Editor",
"editSelectedShape": "Editează forma selectată (text/săgeată/linie)",
"github": "Ai întâmpinat o problemă? Trimite un raport",
"howto": "Urmărește ghidurile noastre",
"or": "sau",
"preventBinding": "Împiedică legarea săgeții",
"shapes": "Forme",
"shortcuts": "Comenzi rapide de la tastatură",
"textFinish": "Finalizează editarea (text)",
"textNewLine": "Adaugă o linie nouă (text)",
"textFinish": "Finalizează editarea (editor de text)",
"textNewLine": "Adaugă o linie nouă (editor de text)",
"title": "Ajutor",
"view": "Vizualizare",
"zoomToFit": "Transfocare pentru a cuprinde totul",

View File

@ -20,10 +20,10 @@
"background": "Фон",
"fill": "Заливка",
"strokeWidth": "Толщина штриха",
"strokeShape": "",
"strokeShape_gel": "",
"strokeShape_fountain": "",
"strokeShape_brush": "",
"strokeShape": "Стиль обводки",
"strokeShape_gel": "Гелевая ручка",
"strokeShape_fountain": "Фонтанная ручка",
"strokeShape_brush": "Кисть",
"strokeStyle": "Стиль обводки",
"strokeStyle_solid": "Сплошная",
"strokeStyle_dashed": "Пунктирная",
@ -96,12 +96,14 @@
"centerHorizontally": "Центрировать по горизонтали",
"distributeHorizontally": "Распределить по горизонтали",
"distributeVertically": "Распределить по вертикали",
"flipHorizontal": "",
"flipVertical": "",
"flipHorizontal": "Переворот по горизонтали",
"flipVertical": "Переворот по вертикали",
"viewMode": "Вид",
"toggleExportColorScheme": "Экспортировать цветовую схему",
"share": "Поделиться",
"toggleTheme": ""
"showStroke": "Показать выбор цвета обводки",
"showBackground": "Показать выбор цвета фона",
"toggleTheme": "Переключить тему"
},
"buttons": {
"clearReset": "Очистить холст и сбросить цвет фона",
@ -149,8 +151,8 @@
"loadSceneOverridePrompt": "Загрузка рисунка приведёт к замене имеющегося содержимого. Вы хотите продолжить?",
"collabStopOverridePrompt": "Остановка сессии перезапишет ваш предыдущий, локально сохранённый рисунок. Вы уверены? \n\n(Если вы хотите оставить ваш локальный рисунок, просто закройте вкладку браузера)",
"errorLoadingLibrary": "Произошла ошибка при загрузке сторонней библиотеки.",
"errorAddingToLibrary": "",
"errorRemovingFromLibrary": "",
"errorAddingToLibrary": "Не удалось добавить элемент в библиотеку",
"errorRemovingFromLibrary": "Не удалось удалить элемент из библиотеки",
"confirmAddLibrary": "Будет добавлено {{numShapes}} фигур в вашу библиотеку. Продолжить?",
"imageDoesNotContainScene": "Импорт изображений не поддерживается в данный момент.\n\nХотите импортировать сцену? Данное изображение не содержит данных о сцене. Было ли включено это во время экспорта?",
"cannotRestoreFromImage": "Сцена не может быть восстановлена из этого изображения",
@ -164,7 +166,7 @@
"ellipse": "Эллипс",
"arrow": "Cтрелка",
"line": "Линия",
"freedraw": "",
"freedraw": "Чертить",
"text": "Текст",
"library": "Библиотека",
"lock": "Сохранять выбранный инструмент активным после рисования"
@ -178,6 +180,8 @@
"linearElement": "Нажмите, чтобы начать несколько точек, перетащите для одной линии",
"freeDraw": "Нажмите и перетаскивайте, отпустите по завершении",
"text": "Совет: при выбранном инструменте выделения дважды щёлкните в любом месте, чтобы добавить текст",
"text_selected": "Дважды щелкните мышью или нажмите ENTER, чтобы редактировать текст",
"text_editing": "Нажмите Escape либо Ctrl или Cmd + ENTER для завершения редактирования",
"linearElementMulti": "Кликните на последней точке или нажмите Escape или Enter чтобы закончить",
"lockAngle": "Вы можете ограничить угол удерживая SHIFT",
"resize": "Вы можете ограничить пропорции, удерживая SHIFT во время изменения размеров,\nудерживайте ALT чтобы изменить размер из центра",
@ -223,7 +227,10 @@
"disk_button": "Сохранить в файл",
"link_title": "Поделитесь ссылкой",
"link_details": "Экспорт ссылки только для чтения.",
"link_button": "Экспорт в ссылку"
"link_button": "Экспорт в ссылку",
"excalidrawplus_description": "Сохраните сцену в ваше рабочее пространство Excalidraw+.",
"excalidrawplus_button": "Экспорт",
"excalidrawplus_exportError": "Не удалось экспортировать в Excalidraw+ на данный момент..."
},
"helpDialog": {
"blog": "Прочитайте наш блог",
@ -231,16 +238,18 @@
"curvedArrow": "Изогнутая стрелка",
"curvedLine": "Изогнутая линия",
"documentation": "Документация",
"doubleClick": "двойной клик",
"drag": "перетащить",
"editor": "Редактор",
"editSelectedShape": "Редактировать выбранную фигуру (текст/стрелка/линия)",
"github": "Нашли проблему? Отправьте",
"howto": "Следуйте нашим инструкциям",
"or": "или",
"preventBinding": "Предотвращать привязку стрелок",
"shapes": "Фигуры",
"shortcuts": "Горячие клавиши",
"textFinish": "Закончить редактирование (текст)",
"textNewLine": "Добавить новую строку (текст)",
"textFinish": "Закончить редактирование (текстовый редактор)",
"textNewLine": "Добавить новую строку (текстовый редактор)",
"title": "Помощь",
"view": "Просмотр",
"zoomToFit": "Отмастштабировать, чтобы поместились все элементы",
@ -248,7 +257,7 @@
},
"encrypted": {
"tooltip": "Ваши данные защищены сквозным (End-to-end) шифрованием. Серверы Excalidraw никогда не получат доступ к ним.",
"link": ""
"link": "Запись блога о сквозном шифровании в Excalidraw"
},
"stats": {
"angle": "Угол",

View File

@ -42,8 +42,8 @@
"fontSize": "Veľkosť písma",
"fontFamily": "Písmo",
"onlySelected": "Iba vybrané",
"withBackground": "",
"exportEmbedScene": "",
"withBackground": "Pozadie",
"exportEmbedScene": "Zahrnúť scénu",
"exportEmbedScene_details": "Údaje scény budú uložené do exportovaného PNG/SVG súboru, takže scéna z neho môže byť opäť obnovená.\nBude to mať za následok zvýšenie veľkosti súboru.",
"addWatermark": "Pridať \"Vytvorené s Excalidraw\"",
"handDrawn": "Ručne písané",
@ -101,19 +101,21 @@
"viewMode": "Režim zobrazenia",
"toggleExportColorScheme": "Prepnúť exportovanie farebnej schémy",
"share": "Zdieľať",
"showStroke": "Zobraziť výber farby pre obrys",
"showBackground": "Zobraziť výber farby pre pozadie",
"toggleTheme": "Prepnúť tému"
},
"buttons": {
"clearReset": "Obnoviť plátno",
"exportJSON": "",
"exportImage": "",
"exportJSON": "Exportovať do súboru",
"exportImage": "Uložiť ako obrázok",
"export": "Exportovať",
"exportToPng": "Exportovať do PNG",
"exportToSvg": "Exportovať do SVG",
"copyToClipboard": "Kopírovať do schránky",
"copyPngToClipboard": "Kopírovať PNG do schránky",
"scale": "Mierka",
"save": "",
"save": "Uložiť do aktuálneho súboru",
"saveAs": "Uložiť ako",
"load": "Nahrať",
"getShareableLink": "Získať odkaz na zdieľanie",
@ -178,6 +180,8 @@
"linearElement": "Kliknite na vloženie viacerých bodov, potiahnite na vytvorenie jednej priamky",
"freeDraw": "Kliknite a ťahajte, pustite na ukončenie",
"text": "Tip: text môžete pridať aj dvojklikom kdekoľvek, ak je zvolený nástroj výber",
"text_selected": "Použite dvojklik alebo stlačte Enter na editáciu textu",
"text_editing": "Stlačte Escape alebo CtrlOrCmd+ENTER na ukončenie editovania",
"linearElementMulti": "Kliknite na počiatočný bod alebo stlačte Escape alebo Enter na ukončenie",
"lockAngle": "Počas rotácie obmedzíte uhol podržaním SHIFT",
"resize": "Počas zmeny veľkosti zachováte proporcie podržaním SHIFT,\\npodržaním ALT meníte veľkosť so zachovaním stredu",
@ -218,12 +222,15 @@
"title": "Chyba"
},
"exportDialog": {
"disk_title": "",
"disk_details": "",
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"disk_title": "Uložiť na disk",
"disk_details": "Exportovať údaje scény do súboru, z ktorého môžu byť neskôr importované.",
"disk_button": "Uložiť do súboru",
"link_title": "Odkaz na zdieľanie",
"link_details": "Exportovať ako odkaz iba na čítanie.",
"link_button": "Exportovať ako odkaz",
"excalidrawplus_description": "Uložiť scénu do vášho Excalidraw+ pracovného priestoru.",
"excalidrawplus_button": "Exportovať",
"excalidrawplus_exportError": "Nepodarilo sa vykonať export do Excalidraw+..."
},
"helpDialog": {
"blog": "Prečítajte si náš blog",
@ -231,16 +238,18 @@
"curvedArrow": "Zakrivená šípka",
"curvedLine": "Zakrivená čiara",
"documentation": "Dokumentácia",
"doubleClick": "dvojklik",
"drag": "potiahnutie",
"editor": "Editovanie",
"editSelectedShape": "Editovať zvolený tvar (text/šípka/čiara)",
"github": "Objavili ste problém? Nahláste ho",
"howto": "Postupujte podľa naších návodov",
"or": "alebo",
"preventBinding": "Zakázať pripájanie šípky",
"shapes": "Tvary",
"shortcuts": "Klávesové skratky",
"textFinish": "Ukončenie editovania (text)",
"textNewLine": "Vložiť nový riadok (text)",
"textFinish": "Ukončenie editovania (text editor)",
"textNewLine": "Vložiť nový riadok (text editor)",
"title": "Pomocník",
"view": "Zobrazenie",
"zoomToFit": "Priblížiť aby boli zahrnuté všetky prvky",

View File

@ -101,6 +101,8 @@
"viewMode": "Visningsläge",
"toggleExportColorScheme": "Växla färgschema för export",
"share": "Dela",
"showStroke": "Visa färgväljare för linjefärg",
"showBackground": "Visa färgväljare för bakgrundsfärg",
"toggleTheme": "Växla tema"
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Klicka för att starta flera punkter, dra för en linje",
"freeDraw": "Klicka och dra, släpp när du är klar",
"text": "Tips: du kan också lägga till text genom att dubbelklicka var som helst med markeringsverktyget",
"text_selected": "Dubbelklicka eller tryck ENTER för att redigera text",
"text_editing": "Tryck Escape eller CtrlOrCmd + ENTER för att slutföra redigeringen",
"linearElementMulti": "Klicka på sista punkten eller tryck Escape eller Enter för att avsluta",
"lockAngle": "Du kan begränsa vinkeln genom att hålla SKIFT",
"resize": "Du kan behålla proportioner genom att hålla SHIFT medan du ändrar storlek,\nhåller du ALT ändras storlek relativt mitten",
@ -223,7 +227,10 @@
"disk_button": "Spara till fil",
"link_title": "Delbar länk",
"link_details": "Exportera som en skrivskyddad länk.",
"link_button": "Exportera till länk"
"link_button": "Exportera till länk",
"excalidrawplus_description": "Spara skissen till din Excalidraw+ arbetsyta.",
"excalidrawplus_button": "Exportera",
"excalidrawplus_exportError": "Det gick inte att exportera till Excalidraw+ just nu..."
},
"helpDialog": {
"blog": "Läs vår blogg",
@ -231,8 +238,10 @@
"curvedArrow": "Böjd pil",
"curvedLine": "Böjd linje",
"documentation": "Dokumentation",
"doubleClick": "dubbelklicka",
"drag": "dra",
"editor": "Redigerare",
"editSelectedShape": "Redigera markerad form (text/pil/linje)",
"github": "Hittat ett problem? Rapportera",
"howto": "Följ våra guider",
"or": "eller",

View File

@ -101,6 +101,8 @@
"viewMode": "Görünüm modu",
"toggleExportColorScheme": "Renk şemasını dışa aktar/aktarma",
"share": "Paylaş",
"showStroke": "",
"showBackground": "",
"toggleTheme": "Temayı etkinleştir/devre dışı bırak"
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Birden fazla nokta için tıklayın, tek çizgi için sürükleyin",
"freeDraw": "Tıkla ve sürükle, bitirdiğinde serbest bırak",
"text": "İpucu: seçme aracıyla herhangi bir yere çift tıklayarak da yazı ekleyebilirsin",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "Tamamlamak için son noktayı seçin veya Escape ve Enter'dan birine basın",
"lockAngle": "SHIFT tuşuna basılı tutarak açıyı koruyabilirsiniz",
"resize": "Yeniden boyutlandırırken SHIFT'e basılı tutarak oranları kısıtlayabilirsiniz, merkezden yeniden boyutlandırmak için ALT'a basılı tutun",
@ -223,7 +227,10 @@
"disk_button": "",
"link_title": "",
"link_details": "",
"link_button": ""
"link_button": "",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "Blog'umuzu okuyun",
@ -231,16 +238,18 @@
"curvedArrow": "Eğri ok",
"curvedLine": "Eğri çizgi",
"documentation": "Dokümantasyon",
"doubleClick": "",
"drag": "sürükle",
"editor": "Düzenleyici",
"editSelectedShape": "",
"github": "Bir hata mı buldun? Bildir",
"howto": "Rehberlerimizi takip edin",
"or": "veya",
"preventBinding": "Ok bağlamayı önleyin",
"shapes": "Şekiller",
"shortcuts": "Klavye kısayolları",
"textFinish": "(Metin) düzenlemeyi bitir",
"textNewLine": "Yeni satır ekle (metin)",
"textFinish": "",
"textNewLine": "",
"title": "Yardım",
"view": "Görünüm",
"zoomToFit": "Tüm öğeleri sığdırmak için yakınlaştır",

View File

@ -101,6 +101,8 @@
"viewMode": "Режим перегляду",
"toggleExportColorScheme": "Переключити колірну схему експорту",
"share": "Поділитися",
"showStroke": "",
"showBackground": "",
"toggleTheme": "Перемкнути тему"
},
"buttons": {
@ -178,6 +180,8 @@
"linearElement": "Натисніть щоб додати кілька точок, перетягніть щоб намалювати одну лінію",
"freeDraw": "Натисніть і потягніть, відпустіть коли завершите",
"text": "Порада: можна також додати текст, двічі клацнувши по будь-якому місці інструментом вибору",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "Натисніть на останню точку, клацніть Esc або Enter щоб завершити",
"lockAngle": "Ви можете обмежити кут, утримуюючи SHIFT",
"resize": "Ви можете зберегти пропорції, утримуючи SHIFT під час зміни розміру,\nутримуйте ALT для змінення розміру від центру",
@ -223,7 +227,10 @@
"disk_button": "Зберегти до файлу",
"link_title": "Доступ за посиланням",
"link_details": "Експортувати як посилання тільки для читання.",
"link_button": "Експортувати у посилання"
"link_button": "Експортувати у посилання",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "Наш блог",
@ -231,16 +238,18 @@
"curvedArrow": "Крива стрілка",
"curvedLine": "Крива лінія",
"documentation": "Документація",
"doubleClick": "",
"drag": "перетягнути",
"editor": "Редактор",
"editSelectedShape": "",
"github": "Знайшли помилку? Повідомте",
"howto": "Дотримуйтесь наших інструкцій",
"or": "або",
"preventBinding": "Запобігти зв'язування зі стрілками",
"shapes": "Фігури",
"shortcuts": "Гарячі клавіші",
"textFinish": "Завершити редагування (текст)",
"textNewLine": "Додати новий рядок (текст)",
"textFinish": "",
"textNewLine": "",
"title": "Допомога",
"view": "Вигляд",
"zoomToFit": "Збільшити щоб умістити всі елементи",

Some files were not shown because too many files have changed in this diff Show More