Merge remote-tracking branch 'origin/master' into aakansha-custom-elements

This commit is contained in:
ad1992 2022-04-21 19:50:46 +05:30
commit 4953828d86
126 changed files with 4379 additions and 1606 deletions

View File

@ -4,9 +4,10 @@ REACT_APP_BACKEND_V2_POST_URL=https://json-dev.excalidraw.com/api/v2/post/
REACT_APP_LIBRARY_URL=https://libraries.excalidraw.com REACT_APP_LIBRARY_URL=https://libraries.excalidraw.com
REACT_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries REACT_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries
REACT_APP_PORTAL_URL=http://localhost:3002 # collaboration WebSocket server (https://github.com/excalidraw/excalidraw-room)
# Fill to set socket server URL used for collaboration. REACT_APP_WS_SERVER_URL=http://localhost:3002
# Meant for forks only: excalidraw.com uses custom REACT_APP_PORTAL_URL flow
REACT_APP_WS_SERVER_URL= # set this only if using the collaboration workflow we use on excalidraw.com
REACT_APP_PORTAL_URL=
REACT_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8","authDomain":"excalidraw-oss-dev.firebaseapp.com","projectId":"excalidraw-oss-dev","storageBucket":"excalidraw-oss-dev.appspot.com","messagingSenderId":"664559512677","appId":"1:664559512677:web:a385181f2928d328a7aa8c"}' REACT_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8","authDomain":"excalidraw-oss-dev.firebaseapp.com","projectId":"excalidraw-oss-dev","storageBucket":"excalidraw-oss-dev.appspot.com","messagingSenderId":"664559512677","appId":"1:664559512677:web:a385181f2928d328a7aa8c"}'

View File

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

View File

@ -36,6 +36,7 @@
"i18next-browser-languagedetector": "6.1.2", "i18next-browser-languagedetector": "6.1.2",
"idb-keyval": "6.0.3", "idb-keyval": "6.0.3",
"image-blob-reduce": "3.0.1", "image-blob-reduce": "3.0.1",
"jotai": "1.6.4",
"lodash.throttle": "4.1.1", "lodash.throttle": "4.1.1",
"nanoid": "3.1.32", "nanoid": "3.1.32",
"open-color": "1.9.1", "open-color": "1.9.1",

View File

@ -124,26 +124,6 @@
user-select: none; user-select: none;
} }
.LoadingMessage {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
}
.LoadingMessage span {
background-color: var(--button-gray-1);
border-radius: 5px;
padding: 0.8em 1.2em;
color: var(--popup-text-color);
font-size: 1.3em;
}
#root { #root {
height: 100%; height: 100%;
-webkit-touch-callout: none; -webkit-touch-callout: none;
@ -152,8 +132,10 @@
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
}
@media screen and (min-width: 1200px) { @media screen and (min-width: 1200px) {
#root {
-webkit-touch-callout: default; -webkit-touch-callout: default;
-webkit-user-select: auto; -webkit-user-select: auto;
-khtml-user-select: auto; -khtml-user-select: auto;
@ -170,10 +152,6 @@
<header> <header>
<h1 class="visually-hidden">Excalidraw</h1> <h1 class="visually-hidden">Excalidraw</h1>
</header> </header>
<div id="root"> <div id="root"></div>
<div class="LoadingMessage">
<span>Loading scene...</span>
</div>
</div>
</body> </body>
</html> </html>

View File

@ -316,6 +316,7 @@ export const actionErase = register({
activeTool.lastActiveToolBeforeEraser = appState.activeTool.type; activeTool.lastActiveToolBeforeEraser = appState.activeTool.type;
} }
} }
debugger;
if (isEraserActive(appState)) { if (isEraserActive(appState)) {
if (appState.activeTool.lastActiveToolBeforeEraser) { if (appState.activeTool.lastActiveToolBeforeEraser) {
if ( if (
@ -326,7 +327,7 @@ export const actionErase = register({
activeTool.customType = activeTool.customType =
appState.activeTool.lastActiveToolBeforeEraser.customType; appState.activeTool.lastActiveToolBeforeEraser.customType;
} else { } else {
activeTool.type = appState.activeTool.type; activeTool.type = appState.activeTool.lastActiveToolBeforeEraser;
} }
} else { } else {
activeTool.type = "selection"; activeTool.type = "selection";
@ -344,12 +345,7 @@ export const actionErase = register({
commitToHistory: true, commitToHistory: true,
}; };
}, },
keyTest: (event, appState) => { keyTest: (event) => event.key === KEYS.E,
return (
event.key === KEYS.E ||
(event.key === KEYS.ESCAPE && isEraserActive(appState))
);
},
PanelComponent: ({ elements, appState, updateData, data }) => ( PanelComponent: ({ elements, appState, updateData, data }) => (
<ToolButton <ToolButton
type="button" type="button"

View File

@ -1,10 +1,14 @@
import { CODES, KEYS } from "../keys"; import { CODES, KEYS } from "../keys";
import { register } from "./register"; import { register } from "./register";
import { copyToClipboard } from "../clipboard"; import {
copyTextToSystemClipboard,
copyToClipboard,
probablySupportsClipboardWriteText,
} from "../clipboard";
import { actionDeleteSelected } from "./actionDeleteSelected"; import { actionDeleteSelected } from "./actionDeleteSelected";
import { getSelectedElements } from "../scene/selection"; import { getSelectedElements } from "../scene/selection";
import { exportCanvas } from "../data/index"; import { exportCanvas } from "../data/index";
import { getNonDeletedElements } from "../element"; import { getNonDeletedElements, isTextElement } from "../element";
import { t } from "../i18n"; import { t } from "../i18n";
export const actionCopy = register({ export const actionCopy = register({
@ -126,3 +130,35 @@ export const actionCopyAsPng = register({
contextItemLabel: "labels.copyAsPng", contextItemLabel: "labels.copyAsPng",
keyTest: (event) => event.code === CODES.C && event.altKey && event.shiftKey, keyTest: (event) => event.code === CODES.C && event.altKey && event.shiftKey,
}); });
export const copyText = register({
name: "copyText",
trackEvent: { category: "element" },
perform: (elements, appState) => {
const selectedElements = getSelectedElements(
getNonDeletedElements(elements),
appState,
true,
);
const text = selectedElements
.reduce((acc: string[], element) => {
if (isTextElement(element)) {
acc.push(element.text);
}
return acc;
}, [])
.join("\n\n");
copyTextToSystemClipboard(text);
return {
commitToHistory: false,
};
},
contextItemPredicate: (elements, appState) => {
return (
probablySupportsClipboardWriteText &&
getSelectedElements(elements, appState, true).some(isTextElement)
);
},
contextItemLabel: "labels.copyText",
});

View File

@ -14,7 +14,6 @@ import {
bindOrUnbindLinearElement, bindOrUnbindLinearElement,
} from "../element/binding"; } from "../element/binding";
import { isBindingElement } from "../element/typeChecks"; import { isBindingElement } from "../element/typeChecks";
import { isEraserActive } from "../appState";
export const actionFinalize = register({ export const actionFinalize = register({
name: "finalize", name: "finalize",
@ -40,6 +39,7 @@ export const actionFinalize = register({
: undefined, : undefined,
appState: { appState: {
...appState, ...appState,
cursorButton: "up",
editingLinearElement: null, editingLinearElement: null,
}, },
commitToHistory: true, commitToHistory: true,
@ -136,17 +136,36 @@ export const actionFinalize = register({
) { ) {
resetCursor(canvas); resetCursor(canvas);
} }
const activeTool: any = { ...appState.activeTool };
if (appState.activeTool.lastActiveToolBeforeEraser) {
if (
typeof appState.activeTool.lastActiveToolBeforeEraser === "object" &&
appState.activeTool.lastActiveToolBeforeEraser.type === "custom"
) {
activeTool.type = appState.activeTool.lastActiveToolBeforeEraser.type;
activeTool.customType =
appState.activeTool.lastActiveToolBeforeEraser.customType;
} else {
activeTool.type = appState.activeTool.lastActiveToolBeforeEraser;
}
} else {
activeTool.type = "selection";
}
return { return {
elements: newElements, elements: newElements,
appState: { appState: {
...appState, ...appState,
cursorButton: "up",
activeTool: activeTool:
(appState.activeTool.locked || (appState.activeTool.locked ||
appState.activeTool.type === "freedraw") && appState.activeTool.type === "freedraw") &&
multiPointElement multiPointElement
? appState.activeTool ? appState.activeTool
: { ...appState.activeTool, type: "selection" }, : {
...appState.activeTool,
activeTool,
},
draggingElement: null, draggingElement: null,
multiElement: null, multiElement: null,
editingElement: null, editingElement: null,
@ -167,12 +186,11 @@ export const actionFinalize = register({
}; };
}, },
keyTest: (event, appState) => keyTest: (event, appState) =>
!isEraserActive(appState) && (event.key === KEYS.ESCAPE &&
((event.key === KEYS.ESCAPE &&
(appState.editingLinearElement !== null || (appState.editingLinearElement !== null ||
(!appState.draggingElement && appState.multiElement === null))) || (!appState.draggingElement && appState.multiElement === null))) ||
((event.key === KEYS.ESCAPE || event.key === KEYS.ENTER) && ((event.key === KEYS.ESCAPE || event.key === KEYS.ENTER) &&
appState.multiElement !== null)), appState.multiElement !== null),
PanelComponent: ({ appState, updateData, data }) => ( PanelComponent: ({ appState, updateData, data }) => (
<ToolButton <ToolButton
type="button" type="button"

View File

@ -18,7 +18,8 @@ export const actionSelectAll = register({
selectedElementIds: elements.reduce((map, element) => { selectedElementIds: elements.reduce((map, element) => {
if ( if (
!element.isDeleted && !element.isDeleted &&
!(isTextElement(element) && element.containerId) !(isTextElement(element) && element.containerId) &&
element.locked === false
) { ) {
map[element.id] = true; map[element.id] = true;
} }

View File

@ -0,0 +1,63 @@
import { newElementWith } from "../element/mutateElement";
import { ExcalidrawElement } from "../element/types";
import { KEYS } from "../keys";
import { getSelectedElements } from "../scene";
import { arrayToMap } from "../utils";
import { register } from "./register";
export const actionToggleLock = register({
name: "toggleLock",
trackEvent: { category: "element" },
perform: (elements, appState) => {
const selectedElements = getSelectedElements(elements, appState, true);
if (!selectedElements.length) {
return false;
}
const operation = getOperation(selectedElements);
const selectedElementsMap = arrayToMap(selectedElements);
return {
elements: elements.map((element) => {
if (!selectedElementsMap.has(element.id)) {
return element;
}
return newElementWith(element, { locked: operation === "lock" });
}),
appState,
commitToHistory: true,
};
},
contextItemLabel: (elements, appState) => {
const selected = getSelectedElements(elements, appState, false);
if (selected.length === 1) {
return selected[0].locked
? "labels.elementLock.unlock"
: "labels.elementLock.lock";
}
if (selected.length > 1) {
return getOperation(selected) === "lock"
? "labels.elementLock.lockAll"
: "labels.elementLock.unlockAll";
}
throw new Error(
"Unexpected zero elements to lock/unlock. This should never happen.",
);
},
keyTest: (event, appState, elements) => {
return (
event.key.toLocaleLowerCase() === KEYS.L &&
event[KEYS.CTRL_OR_CMD] &&
event.shiftKey &&
getSelectedElements(elements, appState, false).length > 0
);
},
});
const getOperation = (
elements: readonly ExcalidrawElement[],
): "lock" | "unlock" => (elements.some((el) => !el.locked) ? "lock" : "unlock");

View File

@ -75,6 +75,7 @@ export {
actionCut, actionCut,
actionCopyAsPng, actionCopyAsPng,
actionCopyAsSvg, actionCopyAsSvg,
copyText,
} from "./actionClipboard"; } from "./actionClipboard";
export { actionToggleGridMode } from "./actionToggleGridMode"; export { actionToggleGridMode } from "./actionToggleGridMode";
@ -83,3 +84,4 @@ export { actionToggleZenMode } from "./actionToggleZenMode";
export { actionToggleStats } from "./actionToggleStats"; export { actionToggleStats } from "./actionToggleStats";
export { actionUnbindText, actionBindText } from "./actionBoundText"; export { actionUnbindText, actionBindText } from "./actionBoundText";
export { actionLink } from "../element/Hyperlink"; export { actionLink } from "../element/Hyperlink";
export { actionToggleLock } from "./actionToggleLock";

View File

@ -29,6 +29,7 @@ export type ShortcutName = SubtypeOf<
| "flipHorizontal" | "flipHorizontal"
| "flipVertical" | "flipVertical"
| "hyperlink" | "hyperlink"
| "toggleLock"
>; >;
const shortcutMap: Record<ShortcutName, string[]> = { const shortcutMap: Record<ShortcutName, string[]> = {
@ -67,6 +68,7 @@ const shortcutMap: Record<ShortcutName, string[]> = {
flipVertical: [getShortcutKey("Shift+V")], flipVertical: [getShortcutKey("Shift+V")],
viewMode: [getShortcutKey("Alt+R")], viewMode: [getShortcutKey("Alt+R")],
hyperlink: [getShortcutKey("CtrlOrCmd+K")], hyperlink: [getShortcutKey("CtrlOrCmd+K")],
toggleLock: [getShortcutKey("CtrlOrCmd+Shift+L")],
}; };
export const getShortcutFromShortcutName = (name: ShortcutName) => { export const getShortcutFromShortcutName = (name: ShortcutName) => {

View File

@ -41,6 +41,7 @@ export type ActionName =
| "paste" | "paste"
| "copyAsPng" | "copyAsPng"
| "copyAsSvg" | "copyAsSvg"
| "copyText"
| "sendBackward" | "sendBackward"
| "bringForward" | "bringForward"
| "sendToBack" | "sendToBack"
@ -110,7 +111,8 @@ export type ActionName =
| "unbindText" | "unbindText"
| "hyperlink" | "hyperlink"
| "eraser" | "eraser"
| "bindText"; | "bindText"
| "toggleLock";
export type PanelComponentProps = { export type PanelComponentProps = {
elements: readonly ExcalidrawElement[]; elements: readonly ExcalidrawElement[];

View File

@ -167,6 +167,7 @@ const commonProps = {
strokeStyle: "solid", strokeStyle: "solid",
strokeWidth: 1, strokeWidth: 1,
verticalAlign: VERTICAL_ALIGN.MIDDLE, verticalAlign: VERTICAL_ALIGN.MIDDLE,
locked: false,
} as const; } as const;
const getChartDimentions = (spreadsheet: Spreadsheet) => { const getChartDimentions = (spreadsheet: Spreadsheet) => {

View File

@ -8,6 +8,7 @@ import { SVG_EXPORT_TAG } from "./scene/export";
import { tryParseSpreadsheet, Spreadsheet, VALID_SPREADSHEET } from "./charts"; import { tryParseSpreadsheet, Spreadsheet, VALID_SPREADSHEET } from "./charts";
import { EXPORT_DATA_TYPES, MIME_TYPES } from "./constants"; import { EXPORT_DATA_TYPES, MIME_TYPES } from "./constants";
import { isInitializedImageElement } from "./element/typeChecks"; import { isInitializedImageElement } from "./element/typeChecks";
import { isPromiseLike } from "./utils";
type ElementsClipboard = { type ElementsClipboard = {
type: typeof EXPORT_DATA_TYPES.excalidrawClipboard; type: typeof EXPORT_DATA_TYPES.excalidrawClipboard;
@ -166,10 +167,35 @@ export const parseClipboard = async (
} }
}; };
export const copyBlobToClipboardAsPng = async (blob: Blob) => { export const copyBlobToClipboardAsPng = async (blob: Blob | Promise<Blob>) => {
await navigator.clipboard.write([ let promise;
new window.ClipboardItem({ [MIME_TYPES.png]: blob }), try {
]); // in Safari so far we need to construct the ClipboardItem synchronously
// (i.e. in the same tick) otherwise browser will complain for lack of
// user intent. Using a Promise ClipboardItem constructor solves this.
// https://bugs.webkit.org/show_bug.cgi?id=222262
//
// not await so that we can detect whether the thrown error likely relates
// to a lack of support for the Promise ClipboardItem constructor
promise = navigator.clipboard.write([
new window.ClipboardItem({
[MIME_TYPES.png]: blob,
}),
]);
} catch (error: any) {
// if we're using a Promise ClipboardItem, let's try constructing
// with resolution value instead
if (isPromiseLike(blob)) {
await navigator.clipboard.write([
new window.ClipboardItem({
[MIME_TYPES.png]: await blob,
}),
]);
} else {
throw error;
}
}
await promise;
}; };
export const copyTextToSystemClipboard = async (text: string | null) => { export const copyTextToSystemClipboard = async (text: string | null) => {

View File

@ -15,12 +15,7 @@ import {
} from "../scene"; } from "../scene";
import { SHAPES } from "../shapes"; import { SHAPES } from "../shapes";
import { AppState, Zoom } from "../types"; import { AppState, Zoom } from "../types";
import { import { capitalizeString, isTransparent, setCursorForShape } from "../utils";
capitalizeString,
isTransparent,
setCursorForShape,
withBatchedUpdates,
} from "../utils";
import Stack from "./Stack"; import Stack from "./Stack";
import { ToolButton } from "./ToolButton"; import { ToolButton } from "./ToolButton";
import { hasStrokeColor } from "../scene/comparisons"; import { hasStrokeColor } from "../scene/comparisons";
@ -201,69 +196,58 @@ export const ShapesSwitcher = ({
setAppState: React.Component<any, AppState>["setState"]; setAppState: React.Component<any, AppState>["setState"];
onImageAction: (data: { pointerType: PointerType | null }) => void; onImageAction: (data: { pointerType: PointerType | null }) => void;
appState: AppState; appState: AppState;
}) => { }) => (
const onChange = withBatchedUpdates( <>
({ {SHAPES.map(({ value, icon, key }, index) => {
activeToolType, const label = t(`toolBar.${value}`);
pointerType, const letter = key && (typeof key === "string" ? key : key[0]);
}: { const shortcut = letter
activeToolType: typeof SHAPES[number]["value"]; ? `${capitalizeString(letter)} ${t("helpDialog.or")} ${index + 1}`
pointerType: PointerType | null; : `${index + 1}`;
}) => { return (
if (appState.activeTool.type !== activeToolType) { <ToolButton
trackEvent("toolbar", activeToolType, "ui"); className="Shape"
} key={value}
if (!appState.penDetected && pointerType === "pen") { type="radio"
setAppState({ icon={icon}
penDetected: true, checked={activeTool.type === value}
penMode: true, name="editor-current-shape"
}); title={`${capitalizeString(label)}${shortcut}`}
} keyBindingLabel={`${index + 1}`}
setAppState({ aria-label={capitalizeString(label)}
activeTool: { ...activeTool, type: activeToolType }, aria-keyshortcuts={shortcut}
multiElement: null, data-testid={value}
selectedElementIds: {}, onPointerDown={({ pointerType }) => {
}); if (!appState.penDetected && pointerType === "pen") {
setCursorForShape(canvas, { ...appState, activeTool }); setAppState({
if (activeTool.type === "image") { penDetected: true,
onImageAction({ pointerType }); penMode: true,
} });
}, }
); }}
onChange={({ pointerType }) => {
return ( if (appState.activeTool.type !== value) {
<> trackEvent("toolbar", value, "ui");
{SHAPES.map(({ value, icon, key }, index) => { }
const label = t(`toolBar.${value}`); const nextActiveTool = { ...activeTool, type: value };
const letter = key && (typeof key === "string" ? key : key[0]); setAppState({
const shortcut = letter activeTool: nextActiveTool,
? `${capitalizeString(letter)} ${t("helpDialog.or")} ${index + 1}` multiElement: null,
: `${index + 1}`; selectedElementIds: {},
return ( });
<ToolButton setCursorForShape(canvas, {
className="Shape" ...appState,
key={value} activeTool: nextActiveTool,
type="radio" });
icon={icon} if (value === "image") {
checked={activeTool.type === value} onImageAction({ pointerType });
name="editor-current-shape" }
title={`${capitalizeString(label)}${shortcut}`} }}
keyBindingLabel={`${index + 1}`} />
aria-label={capitalizeString(label)} );
aria-keyshortcuts={shortcut} })}
data-testid={value} </>
onPointerDown={({ pointerType }) => { );
onChange({ activeToolType: value, pointerType });
}}
onChange={({ pointerType }) => {
onChange({ activeToolType: value, pointerType });
}}
/>
);
})}
</>
);
};
export const ZoomActions = ({ export const ZoomActions = ({
renderAction, renderAction,

View File

@ -11,6 +11,7 @@ import {
actionCopy, actionCopy,
actionCopyAsPng, actionCopyAsPng,
actionCopyAsSvg, actionCopyAsSvg,
copyText,
actionCopyStyles, actionCopyStyles,
actionCut, actionCut,
actionDeleteSelected, actionDeleteSelected,
@ -30,6 +31,7 @@ import {
actionBindText, actionBindText,
actionUngroup, actionUngroup,
actionLink, actionLink,
actionToggleLock,
} from "../actions"; } from "../actions";
import { createRedoAction, createUndoAction } from "../actions/actionHistory"; import { createRedoAction, createUndoAction } from "../actions/actionHistory";
import { ActionManager } from "../actions/manager"; import { ActionManager } from "../actions/manager";
@ -74,7 +76,6 @@ import {
ZOOM_STEP, ZOOM_STEP,
} from "../constants"; } from "../constants";
import { loadFromBlob } from "../data"; import { loadFromBlob } from "../data";
import { isValidLibrary } from "../data/json";
import Library from "../data/library"; import Library from "../data/library";
import { restore, restoreElements, restoreLibraryItems } from "../data/restore"; import { restore, restoreElements, restoreLibraryItems } from "../data/restore";
import { import {
@ -234,6 +235,7 @@ import {
generateIdFromFile, generateIdFromFile,
getDataURL, getDataURL,
isSupportedImageFile, isSupportedImageFile,
loadLibraryFromBlob,
resizeImageFile, resizeImageFile,
SVGStringToFile, SVGStringToFile,
} from "../data/blob"; } from "../data/blob";
@ -451,6 +453,7 @@ class App extends React.Component<AppProps, AppState> {
strokeSharpness: this.state.currentItemLinearStrokeSharpness, strokeSharpness: this.state.currentItemLinearStrokeSharpness,
width, width,
height, height,
locked: false,
}); });
const unbind = this.scene.addCallback(() => { const unbind = this.scene.addCallback(() => {
@ -768,28 +771,21 @@ class App extends React.Component<AppProps, AppState> {
try { try {
const request = await fetch(decodeURIComponent(url)); const request = await fetch(decodeURIComponent(url));
const blob = await request.blob(); const blob = await request.blob();
const json = JSON.parse(await blob.text()); const defaultStatus = "published";
if (!isValidLibrary(json)) { const libraryItems = await loadLibraryFromBlob(blob, defaultStatus);
throw new Error();
}
if ( if (
token === this.id || token === this.id ||
window.confirm( window.confirm(
t("alerts.confirmAddLibrary", { t("alerts.confirmAddLibrary", {
numShapes: (json.libraryItems || json.library || []).length, numShapes: libraryItems.length,
}), }),
) )
) { ) {
await this.library.importLibrary(blob, "published"); await this.library.importLibrary(libraryItems, defaultStatus);
// hack to rerender the library items after import
if (this.state.isLibraryOpen) {
this.setState({ isLibraryOpen: false });
}
this.setState({ isLibraryOpen: true });
} }
} catch (error: any) { } catch (error: any) {
window.alert(t("alerts.errorLoadingLibrary"));
console.error(error); console.error(error);
this.setState({ errorMessage: t("errors.importLibraryError") });
} finally { } finally {
this.focusContainer(); this.focusContainer();
} }
@ -854,10 +850,7 @@ class App extends React.Component<AppProps, AppState> {
try { try {
initialData = (await this.props.initialData) || null; initialData = (await this.props.initialData) || null;
if (initialData?.libraryItems) { if (initialData?.libraryItems) {
this.libraryItemsFromStorage = restoreLibraryItems( this.library.importLibrary(initialData.libraryItems, "unpublished");
initialData.libraryItems,
"unpublished",
) as LibraryItems;
} }
} catch (error: any) { } catch (error: any) {
console.error(error); console.error(error);
@ -1134,7 +1127,10 @@ class App extends React.Component<AppProps, AppState> {
activeTool: { ...this.state.activeTool, type: "selection" }, activeTool: { ...this.state.activeTool, type: "selection" },
}); });
} }
if (prevState.theme !== this.state.theme) { if (
this.state.activeTool.type === "eraser" &&
prevState.theme !== this.state.theme
) {
setEraserCursor(this.canvas, this.state.theme); setEraserCursor(this.canvas, this.state.theme);
} }
// Hide hyperlink popup if shown when element type is not selection // Hide hyperlink popup if shown when element type is not selection
@ -1197,7 +1193,7 @@ class App extends React.Component<AppProps, AppState> {
prevState.activeTool !== this.state.activeTool && prevState.activeTool !== this.state.activeTool &&
multiElement != null && multiElement != null &&
isBindingEnabled(this.state) && isBindingEnabled(this.state) &&
isBindingElement(multiElement) isBindingElement(multiElement, false)
) { ) {
maybeBindLinearElement( maybeBindLinearElement(
multiElement, multiElement,
@ -1610,6 +1606,7 @@ class App extends React.Component<AppProps, AppState> {
fontFamily: this.state.currentItemFontFamily, fontFamily: this.state.currentItemFontFamily,
textAlign: this.state.currentItemTextAlign, textAlign: this.state.currentItemTextAlign,
verticalAlign: DEFAULT_VERTICAL_ALIGN, verticalAlign: DEFAULT_VERTICAL_ALIGN,
locked: false,
}); });
this.scene.replaceAllElements([ this.scene.replaceAllElements([
@ -1744,7 +1741,9 @@ class App extends React.Component<AppProps, AppState> {
appState?: Pick<AppState, K> | null; appState?: Pick<AppState, K> | null;
collaborators?: SceneData["collaborators"]; collaborators?: SceneData["collaborators"];
commitToHistory?: SceneData["commitToHistory"]; commitToHistory?: SceneData["commitToHistory"];
libraryItems?: SceneData["libraryItems"]; libraryItems?:
| Required<SceneData>["libraryItems"]
| Promise<Required<SceneData>["libraryItems"]>;
}) => { }) => {
if (sceneData.commitToHistory) { if (sceneData.commitToHistory) {
this.history.resumeRecording(); this.history.resumeRecording();
@ -1764,7 +1763,18 @@ class App extends React.Component<AppProps, AppState> {
if (sceneData.libraryItems) { if (sceneData.libraryItems) {
this.library.saveLibrary( this.library.saveLibrary(
restoreLibraryItems(sceneData.libraryItems, "unpublished"), new Promise<LibraryItems>(async (resolve, reject) => {
try {
resolve(
restoreLibraryItems(
await sceneData.libraryItems,
"unpublished",
),
);
} catch {
reject(new Error(t("errors.importLibraryError")));
}
}),
); );
} }
}, },
@ -2194,12 +2204,14 @@ class App extends React.Component<AppProps, AppState> {
of all hit elements */ of all hit elements */
preferSelected?: boolean; preferSelected?: boolean;
includeBoundTextElement?: boolean; includeBoundTextElement?: boolean;
includeLockedElements?: boolean;
}, },
): NonDeleted<ExcalidrawElement> | null { ): NonDeleted<ExcalidrawElement> | null {
const allHitElements = this.getElementsAtPosition( const allHitElements = this.getElementsAtPosition(
x, x,
y, y,
opts?.includeBoundTextElement, opts?.includeBoundTextElement,
opts?.includeLockedElements,
); );
if (allHitElements.length > 1) { if (allHitElements.length > 1) {
if (opts?.preferSelected) { if (opts?.preferSelected) {
@ -2232,14 +2244,19 @@ class App extends React.Component<AppProps, AppState> {
x: number, x: number,
y: number, y: number,
includeBoundTextElement: boolean = false, includeBoundTextElement: boolean = false,
includeLockedElements: boolean = false,
): NonDeleted<ExcalidrawElement>[] { ): NonDeleted<ExcalidrawElement>[] {
const elements = includeBoundTextElement const elements =
? this.scene.getElements() includeBoundTextElement && includeLockedElements
: this.scene ? this.scene.getElements()
.getElements() : this.scene
.filter( .getElements()
(element) => !(isTextElement(element) && element.containerId), .filter(
); (element) =>
(includeLockedElements || !element.locked) &&
(includeBoundTextElement ||
!(isTextElement(element) && element.containerId)),
);
return getElementsAtPosition(elements, (element) => return getElementsAtPosition(elements, (element) =>
hitTest(element, this.state, x, y), hitTest(element, this.state, x, y),
@ -2281,7 +2298,7 @@ class App extends React.Component<AppProps, AppState> {
if (selectedElements.length === 1) { if (selectedElements.length === 1) {
if (isTextElement(selectedElements[0])) { if (isTextElement(selectedElements[0])) {
existingTextElement = selectedElements[0]; existingTextElement = selectedElements[0];
} else if (isTextBindableContainer(selectedElements[0])) { } else if (isTextBindableContainer(selectedElements[0], false)) {
container = selectedElements[0]; container = selectedElements[0];
existingTextElement = getBoundTextElement(container); existingTextElement = getBoundTextElement(container);
} }
@ -2301,7 +2318,8 @@ class App extends React.Component<AppProps, AppState> {
this.scene this.scene
.getElements() .getElements()
.filter( .filter(
(ele) => isTextBindableContainer(ele) && !getBoundTextElement(ele), (ele) =>
isTextBindableContainer(ele, false) && !getBoundTextElement(ele),
), ),
sceneX, sceneX,
sceneY, sceneY,
@ -2359,6 +2377,7 @@ class App extends React.Component<AppProps, AppState> {
: DEFAULT_VERTICAL_ALIGN, : DEFAULT_VERTICAL_ALIGN,
containerId: container?.id ?? undefined, containerId: container?.id ?? undefined,
groupIds: container?.groupIds ?? [], groupIds: container?.groupIds ?? [],
locked: false,
}); });
this.setState({ editingElement: element }); this.setState({ editingElement: element });
@ -2665,7 +2684,7 @@ class App extends React.Component<AppProps, AppState> {
// Hovering with a selected tool or creating new linear element via click // Hovering with a selected tool or creating new linear element via click
// and point // and point
const { draggingElement } = this.state; const { draggingElement } = this.state;
if (isBindingElement(draggingElement)) { if (isBindingElement(draggingElement, false)) {
this.maybeSuggestBindingsForLinearElementAtCoords( this.maybeSuggestBindingsForLinearElementAtCoords(
draggingElement, draggingElement,
[scenePointer], [scenePointer],
@ -2848,7 +2867,8 @@ class App extends React.Component<AppProps, AppState> {
this.isHittingCommonBoundingBoxOfSelectedElements( this.isHittingCommonBoundingBoxOfSelectedElements(
scenePointer, scenePointer,
selectedElements, selectedElements,
)) )) &&
!hitElement?.locked
) { ) {
setCursor(this.canvas, CURSOR_TYPE.MOVE); setCursor(this.canvas, CURSOR_TYPE.MOVE);
} else { } else {
@ -2864,6 +2884,10 @@ class App extends React.Component<AppProps, AppState> {
) => { ) => {
const updateElementIds = (elements: ExcalidrawElement[]) => { const updateElementIds = (elements: ExcalidrawElement[]) => {
elements.forEach((element) => { elements.forEach((element) => {
if (element.locked) {
return;
}
idsToUpdate.push(element.id); idsToUpdate.push(element.id);
if (event.altKey) { if (event.altKey) {
if ( if (
@ -2989,6 +3013,8 @@ class App extends React.Component<AppProps, AppState> {
}); });
this.savePointer(event.clientX, event.clientY, "down"); this.savePointer(event.clientX, event.clientY, "down");
this.updateGestureOnPointerDown(event);
if (this.handleCanvasPanUsingWheelOrSpaceDrag(event)) { if (this.handleCanvasPanUsingWheelOrSpaceDrag(event)) {
return; return;
} }
@ -3001,8 +3027,6 @@ class App extends React.Component<AppProps, AppState> {
return; return;
} }
this.updateGestureOnPointerDown(event);
// don't select while panning // don't select while panning
if (gesture.pointers.size > 1) { if (gesture.pointers.size > 1) {
return; return;
@ -3201,7 +3225,7 @@ class App extends React.Component<AppProps, AppState> {
): boolean => { ): boolean => {
if ( if (
!( !(
gesture.pointers.size === 0 && gesture.pointers.size <= 1 &&
(event.button === POINTER_BUTTON.WHEEL || (event.button === POINTER_BUTTON.WHEEL ||
(event.button === POINTER_BUTTON.MAIN && isHoldingSpace) || (event.button === POINTER_BUTTON.MAIN && isHoldingSpace) ||
this.state.viewModeEnabled) this.state.viewModeEnabled)
@ -3715,6 +3739,7 @@ class App extends React.Component<AppProps, AppState> {
opacity: this.state.currentItemOpacity, opacity: this.state.currentItemOpacity,
strokeSharpness: this.state.currentItemLinearStrokeSharpness, strokeSharpness: this.state.currentItemLinearStrokeSharpness,
simulatePressure: event.pressure === 0.5, simulatePressure: event.pressure === 0.5,
locked: false,
}); });
this.setState((prevState) => ({ this.setState((prevState) => ({
@ -3770,6 +3795,7 @@ class App extends React.Component<AppProps, AppState> {
roughness: this.state.currentItemRoughness, roughness: this.state.currentItemRoughness,
opacity: this.state.currentItemOpacity, opacity: this.state.currentItemOpacity,
strokeSharpness: this.state.currentItemLinearStrokeSharpness, strokeSharpness: this.state.currentItemLinearStrokeSharpness,
locked: false,
}); });
return element; return element;
@ -3857,6 +3883,7 @@ class App extends React.Component<AppProps, AppState> {
strokeSharpness: this.state.currentItemLinearStrokeSharpness, strokeSharpness: this.state.currentItemLinearStrokeSharpness,
startArrowhead, startArrowhead,
endArrowhead, endArrowhead,
locked: false,
}); });
this.setState((prevState) => ({ this.setState((prevState) => ({
selectedElementIds: { selectedElementIds: {
@ -3905,6 +3932,7 @@ class App extends React.Component<AppProps, AppState> {
roughness: this.state.currentItemRoughness, roughness: this.state.currentItemRoughness,
opacity: this.state.currentItemOpacity, opacity: this.state.currentItemOpacity,
strokeSharpness: this.state.currentItemStrokeSharpness, strokeSharpness: this.state.currentItemStrokeSharpness,
locked: false,
}); });
if (element.type === "selection") { if (element.type === "selection") {
@ -4054,13 +4082,16 @@ class App extends React.Component<AppProps, AppState> {
pointerDownState.hit.element?.id || pointerDownState.hit.element?.id ||
pointerDownState.hit.hasHitElementInside) pointerDownState.hit.hasHitElementInside)
) { ) {
// Marking that click was used for dragging to check
// if elements should be deselected on pointerup
pointerDownState.drag.hasOccurred = true;
const selectedElements = getSelectedElements( const selectedElements = getSelectedElements(
this.scene.getElements(), this.scene.getElements(),
this.state, this.state,
); );
if (selectedElements.every((element) => element.locked)) {
return;
}
// Marking that click was used for dragging to check
// if elements should be deselected on pointerup
pointerDownState.drag.hasOccurred = true;
// prevent dragging even if we're no longer holding cmd/ctrl otherwise // prevent dragging even if we're no longer holding cmd/ctrl otherwise
// it would have weird results (stuff jumping all over the screen) // it would have weird results (stuff jumping all over the screen)
if (selectedElements.length > 0 && !pointerDownState.withCmdOrCtrl) { if (selectedElements.length > 0 && !pointerDownState.withCmdOrCtrl) {
@ -4204,7 +4235,7 @@ class App extends React.Component<AppProps, AppState> {
}); });
} }
if (isBindingElement(draggingElement)) { if (isBindingElement(draggingElement, false)) {
// When creating a linear element by dragging // When creating a linear element by dragging
this.maybeSuggestBindingsForLinearElementAtCoords( this.maybeSuggestBindingsForLinearElementAtCoords(
draggingElement, draggingElement,
@ -4484,7 +4515,7 @@ class App extends React.Component<AppProps, AppState> {
} else if (pointerDownState.drag.hasOccurred && !multiElement) { } else if (pointerDownState.drag.hasOccurred && !multiElement) {
if ( if (
isBindingEnabled(this.state) && isBindingEnabled(this.state) &&
isBindingElement(draggingElement) isBindingElement(draggingElement, false)
) { ) {
maybeBindLinearElement( maybeBindLinearElement(
draggingElement, draggingElement,
@ -5343,11 +5374,6 @@ class App extends React.Component<AppProps, AppState> {
) { ) {
this.library this.library
.importLibrary(file) .importLibrary(file)
.then(() => {
// Close and then open to get the libraries updated
this.setState({ isLibraryOpen: false });
this.setState({ isLibraryOpen: true });
})
.catch((error) => .catch((error) =>
this.setState({ isLoading: false, errorMessage: error.message }), this.setState({ isLoading: false, errorMessage: error.message }),
); );
@ -5402,7 +5428,10 @@ class App extends React.Component<AppProps, AppState> {
} }
const { x, y } = viewportCoordsToSceneCoords(event, this.state); const { x, y } = viewportCoordsToSceneCoords(event, this.state);
const element = this.getElementAtPosition(x, y, { preferSelected: true }); const element = this.getElementAtPosition(x, y, {
preferSelected: true,
includeLockedElements: true,
});
const type = element ? "element" : "canvas"; const type = element ? "element" : "canvas";
@ -5413,9 +5442,18 @@ class App extends React.Component<AppProps, AppState> {
const top = event.clientY - offsetTop; const top = event.clientY - offsetTop;
if (element && !this.state.selectedElementIds[element.id]) { if (element && !this.state.selectedElementIds[element.id]) {
this.setState({ selectedElementIds: { [element.id]: true } }, () => { this.setState(
this._openContextMenu({ top, left }, type); selectGroupsForSelectedElements(
}); {
...this.state,
selectedElementIds: { [element.id]: true },
},
this.scene.getElements(),
),
() => {
this._openContextMenu({ top, left }, type);
},
);
} else { } else {
this._openContextMenu({ top, left }, type); this._openContextMenu({ top, left }, type);
} }
@ -5575,6 +5613,11 @@ class App extends React.Component<AppProps, AppState> {
const elements = this.scene.getElements(); const elements = this.scene.getElements();
const selectedElements = getSelectedElements(
this.scene.getElements(),
this.state,
);
const options: ContextMenuOption[] = []; const options: ContextMenuOption[] = [];
if (probablySupportsClipboardBlob && elements.length > 0) { if (probablySupportsClipboardBlob && elements.length > 0) {
options.push(actionCopyAsPng); options.push(actionCopyAsPng);
@ -5583,6 +5626,14 @@ class App extends React.Component<AppProps, AppState> {
if (probablySupportsClipboardWriteText && elements.length > 0) { if (probablySupportsClipboardWriteText && elements.length > 0) {
options.push(actionCopyAsSvg); options.push(actionCopyAsSvg);
} }
if (
type === "element" &&
copyText.contextItemPredicate(elements, this.state) &&
probablySupportsClipboardWriteText
) {
options.push(copyText);
}
if (type === "canvas") { if (type === "canvas") {
const viewModeOptions = [ const viewModeOptions = [
...options, ...options,
@ -5626,6 +5677,9 @@ class App extends React.Component<AppProps, AppState> {
probablySupportsClipboardWriteText && probablySupportsClipboardWriteText &&
elements.length > 0 && elements.length > 0 &&
actionCopyAsSvg, actionCopyAsSvg,
probablySupportsClipboardWriteText &&
selectedElements.length > 0 &&
copyText,
((probablySupportsClipboardBlob && elements.length > 0) || ((probablySupportsClipboardBlob && elements.length > 0) ||
(probablySupportsClipboardWriteText && elements.length > 0)) && (probablySupportsClipboardWriteText && elements.length > 0)) &&
separator, separator,
@ -5698,6 +5752,8 @@ class App extends React.Component<AppProps, AppState> {
(maybeFlipHorizontal || maybeFlipVertical) && separator, (maybeFlipHorizontal || maybeFlipVertical) && separator,
actionLink.contextItemPredicate(elements, this.state) && actionLink, actionLink.contextItemPredicate(elements, this.state) && actionLink,
actionDuplicateSelection, actionDuplicateSelection,
actionToggleLock,
separator,
actionDeleteSelected, actionDeleteSelected,
], ],
top, top,

View File

@ -363,6 +363,10 @@ export const HelpDialog = ({ onClose }: { onClose?: () => void }) => {
getShortcutKey(`Alt+${t("helpDialog.drag")}`), getShortcutKey(`Alt+${t("helpDialog.drag")}`),
]} ]}
/> />
<Shortcut
label={t("helpDialog.toggleElementLock")}
shortcuts={[getShortcutKey("CtrlOrCmd+Shift+L")]}
/>
<Shortcut <Shortcut
label={t("buttons.undo")} label={t("buttons.undo")}
shortcuts={[getShortcutKey("CtrlOrCmd+Z")]} shortcuts={[getShortcutKey("CtrlOrCmd+Z")]}

View File

@ -23,6 +23,10 @@ const getHints = ({ appState, elements, isMobile }: HintViewerProps) => {
const { activeTool, isResizing, isRotating, lastPointerDownWith } = appState; const { activeTool, isResizing, isRotating, lastPointerDownWith } = appState;
const multiMode = appState.multiElement !== null; const multiMode = appState.multiElement !== null;
if (appState.isLibraryOpen) {
return null;
}
if (isEraserActive(appState)) { if (isEraserActive(appState)) {
return t("hints.eraserRevert"); return t("hints.eraserRevert");
} }

View File

@ -496,7 +496,7 @@ const LayerUI = ({
const dialogs = ( const dialogs = (
<> <>
{appState.isLoading && <LoadingMessage />} {appState.isLoading && <LoadingMessage delay={250} />}
{appState.errorMessage && ( {appState.errorMessage && (
<ErrorDialog <ErrorDialog
message={appState.errorMessage} message={appState.errorMessage}

View File

@ -28,8 +28,17 @@
} }
.layer-ui__library-message { .layer-ui__library-message {
padding: 10px 20px; padding: 2em 4em;
max-width: 200px; min-width: 200px;
display: flex;
flex-direction: column;
align-items: center;
.Spinner {
margin-bottom: 1em;
}
span {
font-size: 0.8em;
}
} }
.publish-library-success { .publish-library-success {

View File

@ -1,5 +1,12 @@
import { useRef, useState, useEffect, useCallback, RefObject } from "react"; import {
import Library from "../data/library"; useRef,
useState,
useEffect,
useCallback,
RefObject,
forwardRef,
} from "react";
import Library, { libraryItemsAtom } from "../data/library";
import { t } from "../i18n"; import { t } from "../i18n";
import { randomId } from "../random"; import { randomId } from "../random";
import { import {
@ -20,6 +27,9 @@ import { EVENT } from "../constants";
import { KEYS } from "../keys"; import { KEYS } from "../keys";
import { arrayToMap } from "../utils"; import { arrayToMap } from "../utils";
import { trackEvent } from "../analytics"; import { trackEvent } from "../analytics";
import { useAtom } from "jotai";
import { jotaiScope } from "../jotai";
import Spinner from "./Spinner";
const useOnClickOutside = ( const useOnClickOutside = (
ref: RefObject<HTMLElement>, ref: RefObject<HTMLElement>,
@ -54,6 +64,17 @@ const getSelectedItems = (
selectedItems: LibraryItem["id"][], selectedItems: LibraryItem["id"][],
) => libraryItems.filter((item) => selectedItems.includes(item.id)); ) => libraryItems.filter((item) => selectedItems.includes(item.id));
const LibraryMenuWrapper = forwardRef<
HTMLDivElement,
{ children: React.ReactNode }
>(({ children }, ref) => {
return (
<Island padding={1} ref={ref} className="layer-ui__library">
{children}
</Island>
);
});
export const LibraryMenu = ({ export const LibraryMenu = ({
onClose, onClose,
onInsertShape, onInsertShape,
@ -103,11 +124,6 @@ export const LibraryMenu = ({
}; };
}, [onClose]); }, [onClose]);
const [libraryItems, setLibraryItems] = useState<LibraryItems>([]);
const [loadingState, setIsLoading] = useState<
"preloading" | "loading" | "ready"
>("preloading");
const [selectedItems, setSelectedItems] = useState<LibraryItem["id"][]>([]); const [selectedItems, setSelectedItems] = useState<LibraryItem["id"][]>([]);
const [showPublishLibraryDialog, setShowPublishLibraryDialog] = const [showPublishLibraryDialog, setShowPublishLibraryDialog] =
useState(false); useState(false);
@ -115,56 +131,35 @@ export const LibraryMenu = ({
url: string; url: string;
authorName: string; authorName: string;
}>(null); }>(null);
const loadingTimerRef = useRef<number | null>(null);
useEffect(() => { const [libraryItemsData] = useAtom(libraryItemsAtom, jotaiScope);
Promise.race([
new Promise((resolve) => {
loadingTimerRef.current = window.setTimeout(() => {
resolve("loading");
}, 100);
}),
library.loadLibrary().then((items) => {
setLibraryItems(items);
setIsLoading("ready");
}),
]).then((data) => {
if (data === "loading") {
setIsLoading("loading");
}
});
return () => {
clearTimeout(loadingTimerRef.current!);
};
}, [library]);
const removeFromLibrary = useCallback(async () => { const removeFromLibrary = useCallback(
const items = await library.loadLibrary(); async (libraryItems: LibraryItems) => {
const nextItems = libraryItems.filter(
const nextItems = items.filter((item) => !selectedItems.includes(item.id)); (item) => !selectedItems.includes(item.id),
library.saveLibrary(nextItems).catch((error) => { );
setLibraryItems(items); library.saveLibrary(nextItems).catch(() => {
setAppState({ errorMessage: t("alerts.errorRemovingFromLibrary") }); setAppState({ errorMessage: t("alerts.errorRemovingFromLibrary") });
}); });
setSelectedItems([]); setSelectedItems([]);
setLibraryItems(nextItems); },
}, [library, setAppState, selectedItems, setSelectedItems]); [library, setAppState, selectedItems, setSelectedItems],
);
const resetLibrary = useCallback(() => { const resetLibrary = useCallback(() => {
library.resetLibrary(); library.resetLibrary();
setLibraryItems([]);
focusContainer(); focusContainer();
}, [library, focusContainer]); }, [library, focusContainer]);
const addToLibrary = useCallback( const addToLibrary = useCallback(
async (elements: LibraryItem["elements"]) => { async (elements: LibraryItem["elements"], libraryItems: LibraryItems) => {
trackEvent("element", "addToLibrary", "ui"); trackEvent("element", "addToLibrary", "ui");
if (elements.some((element) => element.type === "image")) { if (elements.some((element) => element.type === "image")) {
return setAppState({ return setAppState({
errorMessage: "Support for adding images to the library coming soon!", errorMessage: "Support for adding images to the library coming soon!",
}); });
} }
const items = await library.loadLibrary();
const nextItems: LibraryItems = [ const nextItems: LibraryItems = [
{ {
status: "unpublished", status: "unpublished",
@ -172,14 +167,12 @@ export const LibraryMenu = ({
id: randomId(), id: randomId(),
created: Date.now(), created: Date.now(),
}, },
...items, ...libraryItems,
]; ];
onAddToLibrary(); onAddToLibrary();
library.saveLibrary(nextItems).catch((error) => { library.saveLibrary(nextItems).catch(() => {
setLibraryItems(items);
setAppState({ errorMessage: t("alerts.errorAddingToLibrary") }); setAppState({ errorMessage: t("alerts.errorAddingToLibrary") });
}); });
setLibraryItems(nextItems);
}, },
[onAddToLibrary, library, setAppState], [onAddToLibrary, library, setAppState],
); );
@ -218,7 +211,7 @@ export const LibraryMenu = ({
}, [setPublishLibSuccess, publishLibSuccess]); }, [setPublishLibSuccess, publishLibSuccess]);
const onPublishLibSuccess = useCallback( const onPublishLibSuccess = useCallback(
(data) => { (data, libraryItems: LibraryItems) => {
setShowPublishLibraryDialog(false); setShowPublishLibraryDialog(false);
setPublishLibSuccess({ url: data.url, authorName: data.authorName }); setPublishLibSuccess({ url: data.url, authorName: data.authorName });
const nextLibItems = libraryItems.slice(); const nextLibItems = libraryItems.slice();
@ -228,101 +221,109 @@ export const LibraryMenu = ({
} }
}); });
library.saveLibrary(nextLibItems); library.saveLibrary(nextLibItems);
setLibraryItems(nextLibItems);
}, },
[ [setShowPublishLibraryDialog, setPublishLibSuccess, selectedItems, library],
setShowPublishLibraryDialog,
setPublishLibSuccess,
libraryItems,
selectedItems,
library,
],
); );
const [lastSelectedItem, setLastSelectedItem] = useState< const [lastSelectedItem, setLastSelectedItem] = useState<
LibraryItem["id"] | null LibraryItem["id"] | null
>(null); >(null);
return loadingState === "preloading" ? null : ( if (libraryItemsData.status === "loading") {
<Island padding={1} ref={ref} className="layer-ui__library"> return (
<LibraryMenuWrapper ref={ref}>
<div className="layer-ui__library-message">
<Spinner size="2em" />
<span>{t("labels.libraryLoadingMessage")}</span>
</div>
</LibraryMenuWrapper>
);
}
return (
<LibraryMenuWrapper ref={ref}>
{showPublishLibraryDialog && ( {showPublishLibraryDialog && (
<PublishLibrary <PublishLibrary
onClose={() => setShowPublishLibraryDialog(false)} onClose={() => setShowPublishLibraryDialog(false)}
libraryItems={getSelectedItems(libraryItems, selectedItems)} libraryItems={getSelectedItems(
libraryItemsData.libraryItems,
selectedItems,
)}
appState={appState} appState={appState}
onSuccess={onPublishLibSuccess} onSuccess={(data) =>
onPublishLibSuccess(data, libraryItemsData.libraryItems)
}
onError={(error) => window.alert(error)} onError={(error) => window.alert(error)}
updateItemsInStorage={() => library.saveLibrary(libraryItems)} updateItemsInStorage={() =>
library.saveLibrary(libraryItemsData.libraryItems)
}
onRemove={(id: string) => onRemove={(id: string) =>
setSelectedItems(selectedItems.filter((_id) => _id !== id)) setSelectedItems(selectedItems.filter((_id) => _id !== id))
} }
/> />
)} )}
{publishLibSuccess && renderPublishSuccess()} {publishLibSuccess && renderPublishSuccess()}
<LibraryMenuItems
libraryItems={libraryItemsData.libraryItems}
onRemoveFromLibrary={() =>
removeFromLibrary(libraryItemsData.libraryItems)
}
onAddToLibrary={(elements) =>
addToLibrary(elements, libraryItemsData.libraryItems)
}
onInsertShape={onInsertShape}
pendingElements={pendingElements}
setAppState={setAppState}
libraryReturnUrl={libraryReturnUrl}
library={library}
theme={theme}
files={files}
id={id}
selectedItems={selectedItems}
onToggle={(id, event) => {
const shouldSelect = !selectedItems.includes(id);
{loadingState === "loading" ? ( if (shouldSelect) {
<div className="layer-ui__library-message"> if (event.shiftKey && lastSelectedItem) {
{t("labels.libraryLoadingMessage")} const rangeStart = libraryItemsData.libraryItems.findIndex(
</div> (item) => item.id === lastSelectedItem,
) : ( );
<LibraryMenuItems const rangeEnd = libraryItemsData.libraryItems.findIndex(
libraryItems={libraryItems} (item) => item.id === id,
onRemoveFromLibrary={removeFromLibrary} );
onAddToLibrary={addToLibrary}
onInsertShape={onInsertShape}
pendingElements={pendingElements}
setAppState={setAppState}
libraryReturnUrl={libraryReturnUrl}
library={library}
theme={theme}
files={files}
id={id}
selectedItems={selectedItems}
onToggle={(id, event) => {
const shouldSelect = !selectedItems.includes(id);
if (shouldSelect) { if (rangeStart === -1 || rangeEnd === -1) {
if (event.shiftKey && lastSelectedItem) {
const rangeStart = libraryItems.findIndex(
(item) => item.id === lastSelectedItem,
);
const rangeEnd = libraryItems.findIndex(
(item) => item.id === id,
);
if (rangeStart === -1 || rangeEnd === -1) {
setSelectedItems([...selectedItems, id]);
return;
}
const selectedItemsMap = arrayToMap(selectedItems);
const nextSelectedIds = libraryItems.reduce(
(acc: LibraryItem["id"][], item, idx) => {
if (
(idx >= rangeStart && idx <= rangeEnd) ||
selectedItemsMap.has(item.id)
) {
acc.push(item.id);
}
return acc;
},
[],
);
setSelectedItems(nextSelectedIds);
} else {
setSelectedItems([...selectedItems, id]); setSelectedItems([...selectedItems, id]);
return;
} }
setLastSelectedItem(id);
const selectedItemsMap = arrayToMap(selectedItems);
const nextSelectedIds = libraryItemsData.libraryItems.reduce(
(acc: LibraryItem["id"][], item, idx) => {
if (
(idx >= rangeStart && idx <= rangeEnd) ||
selectedItemsMap.has(item.id)
) {
acc.push(item.id);
}
return acc;
},
[],
);
setSelectedItems(nextSelectedIds);
} else { } else {
setLastSelectedItem(null); setSelectedItems([...selectedItems, id]);
setSelectedItems(selectedItems.filter((_id) => _id !== id));
} }
}} setLastSelectedItem(id);
onPublish={() => setShowPublishLibraryDialog(true)} } else {
resetLibrary={resetLibrary} setLastSelectedItem(null);
/> setSelectedItems(selectedItems.filter((_id) => _id !== id));
)} }
</Island> }}
onPublish={() => setShowPublishLibraryDialog(true)}
resetLibrary={resetLibrary}
/>
</LibraryMenuWrapper>
); );
}; };

View File

@ -106,11 +106,6 @@ const LibraryMenuItems = ({
icon={load} icon={load}
onClick={() => { onClick={() => {
importLibraryFromJSON(library) importLibraryFromJSON(library)
.then(() => {
// Close and then open to get the libraries updated
setAppState({ isLibraryOpen: false });
setAppState({ isLibraryOpen: true });
})
.catch(muteFSAbortError) .catch(muteFSAbortError)
.catch((error) => { .catch((error) => {
setAppState({ errorMessage: error.message }); setAppState({ errorMessage: error.message });

View File

@ -1,10 +1,30 @@
import { t } from "../i18n"; import { t } from "../i18n";
import { useState, useEffect } from "react";
import Spinner from "./Spinner";
export const LoadingMessage: React.FC<{ delay?: number }> = ({ delay }) => {
const [isWaiting, setIsWaiting] = useState(!!delay);
useEffect(() => {
if (!delay) {
return;
}
const timer = setTimeout(() => {
setIsWaiting(false);
}, delay);
return () => clearTimeout(timer);
}, [delay]);
if (isWaiting) {
return null;
}
export const LoadingMessage = () => {
// !! KEEP THIS IN SYNC WITH index.html !!
return ( return (
<div className="LoadingMessage"> <div className="LoadingMessage">
<span>{t("labels.loadingScene")}</span> <div>
<Spinner />
</div>
<div className="LoadingMessage-text">{t("labels.loadingScene")}</div>
</div> </div>
); );
}; };

View File

@ -16,15 +16,17 @@
left: 0; left: 0;
z-index: 999; z-index: 999;
display: flex; display: flex;
flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
pointer-events: none; pointer-events: none;
}
.LoadingMessage span { .Spinner {
background-color: var(--button-gray-1); font-size: 2.8em;
border-radius: 5px; }
padding: 0.8em 1.2em;
color: var(--popup-text-color); .LoadingMessage-text {
font-size: 1.3em; margin-top: 1em;
font-size: 0.8em;
}
} }

View File

@ -1,20 +1,16 @@
import { nanoid } from "nanoid"; import { nanoid } from "nanoid";
import { cleanAppStateForExport } from "../appState"; import { cleanAppStateForExport } from "../appState";
import { import { ALLOWED_IMAGE_MIME_TYPES, MIME_TYPES } from "../constants";
ALLOWED_IMAGE_MIME_TYPES,
EXPORT_DATA_TYPES,
MIME_TYPES,
} from "../constants";
import { clearElementsForExport } from "../element"; import { clearElementsForExport } from "../element";
import { ExcalidrawElement, FileId } from "../element/types"; import { ExcalidrawElement, FileId } from "../element/types";
import { CanvasError } from "../errors"; import { CanvasError } from "../errors";
import { t } from "../i18n"; import { t } from "../i18n";
import { calculateScrollCenter } from "../scene"; import { calculateScrollCenter } from "../scene";
import { AppState, DataURL } from "../types"; import { AppState, DataURL, LibraryItem } from "../types";
import { bytesToHexString } from "../utils"; import { bytesToHexString } from "../utils";
import { FileSystemHandle } from "./filesystem"; import { FileSystemHandle } from "./filesystem";
import { isValidExcalidrawData } from "./json"; import { isValidExcalidrawData, isValidLibrary } from "./json";
import { restore } from "./restore"; import { restore, restoreLibraryItems } from "./restore";
import { ImportedLibraryData } from "./types"; import { ImportedLibraryData } from "./types";
const parseFileContents = async (blob: Blob | File) => { const parseFileContents = async (blob: Blob | File) => {
@ -163,13 +159,17 @@ export const loadFromBlob = async (
} }
}; };
export const loadLibraryFromBlob = async (blob: Blob) => { export const loadLibraryFromBlob = async (
blob: Blob,
defaultStatus: LibraryItem["status"] = "unpublished",
) => {
const contents = await parseFileContents(blob); const contents = await parseFileContents(blob);
const data: ImportedLibraryData = JSON.parse(contents); const data: ImportedLibraryData | undefined = JSON.parse(contents);
if (data.type !== EXPORT_DATA_TYPES.excalidrawLibrary) { if (!isValidLibrary(data)) {
throw new Error(t("alerts.couldNotLoadInvalidFile")); throw new Error("Invalid library");
} }
return data; const libraryItems = data.libraryItems || data.library;
return restoreLibraryItems(libraryItems, defaultStatus);
}; };
export const canvasToBlob = async ( export const canvasToBlob = async (

View File

@ -105,7 +105,9 @@ export const encodeSvgMetadata = async ({ text }: { text: string }) => {
export const decodeSvgMetadata = async ({ svg }: { svg: string }) => { export const decodeSvgMetadata = async ({ svg }: { svg: string }) => {
if (svg.includes(`payload-type:${MIME_TYPES.excalidraw}`)) { if (svg.includes(`payload-type:${MIME_TYPES.excalidraw}`)) {
const match = svg.match(/<!-- payload-start -->(.+?)<!-- payload-end -->/); const match = svg.match(
/<!-- payload-start -->\s*(.+?)\s*<!-- payload-end -->/,
);
if (!match) { if (!match) {
throw new Error("INVALID"); throw new Error("INVALID");
} }

View File

@ -16,7 +16,7 @@ export { loadFromBlob } from "./blob";
export { loadFromJSON, saveAsJSON } from "./json"; export { loadFromJSON, saveAsJSON } from "./json";
export const exportCanvas = async ( export const exportCanvas = async (
type: ExportType, type: Omit<ExportType, "backend">,
elements: readonly NonDeletedExcalidrawElement[], elements: readonly NonDeletedExcalidrawElement[],
appState: AppState, appState: AppState,
files: BinaryFiles, files: BinaryFiles,
@ -73,10 +73,10 @@ export const exportCanvas = async (
}); });
tempCanvas.style.display = "none"; tempCanvas.style.display = "none";
document.body.appendChild(tempCanvas); document.body.appendChild(tempCanvas);
let blob = await canvasToBlob(tempCanvas);
tempCanvas.remove();
if (type === "png") { if (type === "png") {
let blob = await canvasToBlob(tempCanvas);
tempCanvas.remove();
if (appState.exportEmbedScene) { if (appState.exportEmbedScene) {
blob = await ( blob = await (
await import(/* webpackChunkName: "image" */ "./image") await import(/* webpackChunkName: "image" */ "./image")
@ -94,12 +94,19 @@ export const exportCanvas = async (
}); });
} else if (type === "clipboard") { } else if (type === "clipboard") {
try { try {
const blob = canvasToBlob(tempCanvas);
await copyBlobToClipboardAsPng(blob); await copyBlobToClipboardAsPng(blob);
} catch (error: any) { } catch (error: any) {
if (error.name === "CANVAS_POSSIBLY_TOO_BIG") { if (error.name === "CANVAS_POSSIBLY_TOO_BIG") {
throw error; throw error;
} }
throw new Error(t("alerts.couldNotCopyToClipboard")); throw new Error(t("alerts.couldNotCopyToClipboard"));
} finally {
tempCanvas.remove();
} }
} else {
tempCanvas.remove();
// shouldn't happen
throw new Error("Unsupported export type");
} }
}; };

View File

@ -15,6 +15,7 @@ import {
ExportedDataState, ExportedDataState,
ImportedDataState, ImportedDataState,
ExportedLibraryData, ExportedLibraryData,
ImportedLibraryData,
} from "./types"; } from "./types";
import Library from "./library"; import Library from "./library";
@ -114,7 +115,7 @@ export const isValidExcalidrawData = (data?: {
); );
}; };
export const isValidLibrary = (json: any) => { export const isValidLibrary = (json: any): json is ImportedLibraryData => {
return ( return (
typeof json === "object" && typeof json === "object" &&
json && json &&
@ -123,14 +124,18 @@ export const isValidLibrary = (json: any) => {
); );
}; };
export const saveLibraryAsJSON = async (libraryItems: LibraryItems) => { export const serializeLibraryAsJSON = (libraryItems: LibraryItems) => {
const data: ExportedLibraryData = { const data: ExportedLibraryData = {
type: EXPORT_DATA_TYPES.excalidrawLibrary, type: EXPORT_DATA_TYPES.excalidrawLibrary,
version: VERSIONS.excalidrawLibrary, version: VERSIONS.excalidrawLibrary,
source: EXPORT_SOURCE, source: EXPORT_SOURCE,
libraryItems, libraryItems,
}; };
const serialized = JSON.stringify(data, null, 2); return JSON.stringify(data, null, 2);
};
export const saveLibraryAsJSON = async (libraryItems: LibraryItems) => {
const serialized = serializeLibraryAsJSON(libraryItems);
await fileSave( await fileSave(
new Blob([serialized], { new Blob([serialized], {
type: MIME_TYPES.excalidrawlib, type: MIME_TYPES.excalidrawlib,

View File

@ -1,11 +1,52 @@
import { loadLibraryFromBlob } from "./blob"; import { loadLibraryFromBlob } from "./blob";
import { LibraryItems, LibraryItem } from "../types"; import { LibraryItems, LibraryItem } from "../types";
import { restoreElements, restoreLibraryItems } from "./restore"; import { restoreLibraryItems } from "./restore";
import { getNonDeletedElements } from "../element";
import type App from "../components/App"; import type App from "../components/App";
import { ImportedDataState } from "./types";
import { atom } from "jotai";
import { jotaiStore } from "../jotai";
import { isPromiseLike } from "../utils";
import { t } from "../i18n";
export const libraryItemsAtom = atom<
| { status: "loading"; libraryItems: null; promise: Promise<LibraryItems> }
| { status: "loaded"; libraryItems: LibraryItems }
>({ status: "loaded", libraryItems: [] });
const cloneLibraryItems = (libraryItems: LibraryItems): LibraryItems =>
JSON.parse(JSON.stringify(libraryItems));
/**
* checks if library item does not exist already in current library
*/
const isUniqueItem = (
existingLibraryItems: LibraryItems,
targetLibraryItem: LibraryItem,
) => {
return !existingLibraryItems.find((libraryItem) => {
if (libraryItem.elements.length !== targetLibraryItem.elements.length) {
return false;
}
// detect z-index difference by checking the excalidraw elements
// are in order
return libraryItem.elements.every((libItemExcalidrawItem, idx) => {
return (
libItemExcalidrawItem.id === targetLibraryItem.elements[idx].id &&
libItemExcalidrawItem.versionNonce ===
targetLibraryItem.elements[idx].versionNonce
);
});
});
};
class Library { class Library {
private libraryCache: LibraryItems | null = null; /** cache for currently active promise when initializing/updating libaries
asynchronously */
private libraryItemsPromise: Promise<LibraryItems> | null = null;
/** last resolved libraryItems */
private lastLibraryItems: LibraryItems = [];
private app: App; private app: App;
constructor(app: App) { constructor(app: App) {
@ -13,107 +54,92 @@ class Library {
} }
resetLibrary = async () => { resetLibrary = async () => {
await this.app.props.onLibraryChange?.([]); this.saveLibrary([]);
this.libraryCache = [];
};
restoreLibraryItem = (libraryItem: LibraryItem): LibraryItem | null => {
const elements = getNonDeletedElements(
restoreElements(libraryItem.elements, null),
);
return elements.length ? { ...libraryItem, elements } : null;
}; };
/** imports library (currently merges, removing duplicates) */ /** imports library (currently merges, removing duplicates) */
async importLibrary(blob: Blob, defaultStatus = "unpublished") { async importLibrary(
const libraryFile = await loadLibraryFromBlob(blob); library:
if (!libraryFile || !(libraryFile.libraryItems || libraryFile.library)) { | Blob
return; | Required<ImportedDataState>["libraryItems"]
} | Promise<Required<ImportedDataState>["libraryItems"]>,
defaultStatus: LibraryItem["status"] = "unpublished",
) {
return this.saveLibrary(
new Promise<LibraryItems>(async (resolve, reject) => {
try {
let libraryItems: LibraryItems;
if (library instanceof Blob) {
libraryItems = await loadLibraryFromBlob(library, defaultStatus);
} else {
libraryItems = restoreLibraryItems(await library, defaultStatus);
}
/** const existingLibraryItems = this.lastLibraryItems;
* checks if library item does not exist already in current library
*/ const filteredItems = [];
const isUniqueitem = ( for (const item of libraryItems) {
existingLibraryItems: LibraryItems, if (isUniqueItem(existingLibraryItems, item)) {
targetLibraryItem: LibraryItem, filteredItems.push(item);
) => { }
return !existingLibraryItems.find((libraryItem) => { }
if (libraryItem.elements.length !== targetLibraryItem.elements.length) {
return false; resolve([...filteredItems, ...existingLibraryItems]);
} catch (error) {
reject(new Error(t("errors.importLibraryError")));
} }
}),
// detect z-index difference by checking the excalidraw elements
// are in order
return libraryItem.elements.every((libItemExcalidrawItem, idx) => {
return (
libItemExcalidrawItem.id === targetLibraryItem.elements[idx].id &&
libItemExcalidrawItem.versionNonce ===
targetLibraryItem.elements[idx].versionNonce
);
});
});
};
const existingLibraryItems = await this.loadLibrary();
const library = libraryFile.libraryItems || libraryFile.library || [];
const restoredLibItems = restoreLibraryItems(
library,
defaultStatus as "published" | "unpublished",
); );
const filteredItems = [];
for (const item of restoredLibItems) {
const restoredItem = this.restoreLibraryItem(item as LibraryItem);
if (restoredItem && isUniqueitem(existingLibraryItems, restoredItem)) {
filteredItems.push(restoredItem);
}
}
await this.saveLibrary([...filteredItems, ...existingLibraryItems]);
} }
loadLibrary = (): Promise<LibraryItems> => { loadLibrary = (): Promise<LibraryItems> => {
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
if (this.libraryCache) {
return resolve(JSON.parse(JSON.stringify(this.libraryCache)));
}
try { try {
const libraryItems = this.app.libraryItemsFromStorage; resolve(
if (!libraryItems) { cloneLibraryItems(
return resolve([]); await (this.libraryItemsPromise || this.lastLibraryItems),
} ),
);
const items = libraryItems.reduce((acc, item) => { } catch (error) {
const restoredItem = this.restoreLibraryItem(item); return resolve(this.lastLibraryItems);
if (restoredItem) {
acc.push(item);
}
return acc;
}, [] as Mutable<LibraryItems>);
// clone to ensure we don't mutate the cached library elements in the app
this.libraryCache = JSON.parse(JSON.stringify(items));
resolve(items);
} catch (error: any) {
console.error(error);
resolve([]);
} }
}); });
}; };
saveLibrary = async (items: LibraryItems) => { saveLibrary = async (items: LibraryItems | Promise<LibraryItems>) => {
const prevLibraryItems = this.libraryCache; const prevLibraryItems = this.lastLibraryItems;
try { try {
const serializedItems = JSON.stringify(items); let nextLibraryItems;
// cache optimistically so that the app has access to the latest if (isPromiseLike(items)) {
// immediately const promise = items.then((items) => cloneLibraryItems(items));
this.libraryCache = JSON.parse(serializedItems); this.libraryItemsPromise = promise;
await this.app.props.onLibraryChange?.(items); jotaiStore.set(libraryItemsAtom, {
status: "loading",
promise,
libraryItems: null,
});
nextLibraryItems = await promise;
} else {
nextLibraryItems = cloneLibraryItems(items);
}
this.lastLibraryItems = nextLibraryItems;
this.libraryItemsPromise = null;
jotaiStore.set(libraryItemsAtom, {
status: "loaded",
libraryItems: nextLibraryItems,
});
await this.app.props.onLibraryChange?.(
cloneLibraryItems(nextLibraryItems),
);
} catch (error: any) { } catch (error: any) {
this.libraryCache = prevLibraryItems; this.lastLibraryItems = prevLibraryItems;
this.libraryItemsPromise = null;
jotaiStore.set(libraryItemsAtom, {
status: "loaded",
libraryItems: prevLibraryItems,
});
throw error; throw error;
} }
}; };

View File

@ -10,7 +10,11 @@ import {
NormalizedZoomValue, NormalizedZoomValue,
} from "../types"; } from "../types";
import { ImportedDataState } from "./types"; import { ImportedDataState } from "./types";
import { getNormalizedDimensions, isInvisiblySmallElement } from "../element"; import {
getNonDeletedElements,
getNormalizedDimensions,
isInvisiblySmallElement,
} from "../element";
import { isLinearElementType } from "../element/typeChecks"; import { isLinearElementType } from "../element/typeChecks";
import { randomId } from "../random"; import { randomId } from "../random";
import { import {
@ -108,6 +112,7 @@ const restoreElementWithProperties = <
: element.boundElements ?? [], : element.boundElements ?? [],
updated: element.updated ?? getUpdatedTimestamp(), updated: element.updated ?? getUpdatedTimestamp(),
link: element.link ?? null, link: element.link ?? null,
locked: element.locked ?? false,
}; };
return { return {
@ -255,11 +260,26 @@ export const restoreAppState = (
? localValue ? localValue
: defaultValue; : defaultValue;
} }
const activeTool: any = {
lastActiveToolBeforeEraser: null,
locked: nextAppState.activeTool.locked ?? false,
};
if (AllowedExcalidrawActiveTools[nextAppState.activeTool.type]) {
if (nextAppState.activeTool.type === "custom") {
activeTool.type = "custom";
activeTool.customType = nextAppState.activeTool.customType ?? "custom";
} else {
activeTool.type = nextAppState.activeTool.type;
}
}
return { return {
...nextAppState, ...nextAppState,
activeTool: AllowedExcalidrawActiveTools[nextAppState.activeTool.type] cursorButton: localAppState?.cursorButton || "up",
? nextAppState.activeTool // reset on fresh restore so as to hide the UI button if penMode not active
: { ...nextAppState.activeTool, type: "selection" }, penDetected:
localAppState?.penDetected ??
(appState.penMode ? appState.penDetected ?? false : false),
activeTool,
// Migrates from previous version where appState.zoom was a number // Migrates from previous version where appState.zoom was a number
zoom: zoom:
typeof appState.zoom === "number" typeof appState.zoom === "number"
@ -271,7 +291,7 @@ export const restoreAppState = (
}; };
export const restore = ( export const restore = (
data: ImportedDataState | null, data: Pick<ImportedDataState, "appState" | "elements" | "files"> | null,
/** /**
* Local AppState (`this.state` or initial state from localStorage) so that we * Local AppState (`this.state` or initial state from localStorage) so that we
* don't overwrite local state with default values (when values not * don't overwrite local state with default values (when values not
@ -288,28 +308,45 @@ export const restore = (
}; };
}; };
const restoreLibraryItem = (libraryItem: LibraryItem) => {
const elements = restoreElements(
getNonDeletedElements(libraryItem.elements),
null,
);
return elements.length ? { ...libraryItem, elements } : null;
};
export const restoreLibraryItems = ( export const restoreLibraryItems = (
libraryItems: NonOptional<ImportedDataState["libraryItems"]>, libraryItems: ImportedDataState["libraryItems"] = [],
defaultStatus: LibraryItem["status"], defaultStatus: LibraryItem["status"],
) => { ) => {
const restoredItems: LibraryItem[] = []; const restoredItems: LibraryItem[] = [];
for (const item of libraryItems) { for (const item of libraryItems) {
// migrate older libraries // migrate older libraries
if (Array.isArray(item)) { if (Array.isArray(item)) {
restoredItems.push({ const restoredItem = restoreLibraryItem({
status: defaultStatus, status: defaultStatus,
elements: item, elements: item,
id: randomId(), id: randomId(),
created: Date.now(), created: Date.now(),
}); });
if (restoredItem) {
restoredItems.push(restoredItem);
}
} else { } else {
const _item = item as MarkOptional<LibraryItem, "id" | "status">; const _item = item as MarkOptional<
restoredItems.push({ LibraryItem,
"id" | "status" | "created"
>;
const restoredItem = restoreLibraryItem({
..._item, ..._item,
id: _item.id || randomId(), id: _item.id || randomId(),
status: _item.status || defaultStatus, status: _item.status || defaultStatus,
created: _item.created || Date.now(), created: _item.created || Date.now(),
}); });
if (restoredItem) {
restoredItems.push(restoredItem);
}
} }
} }
return restoredItems; return restoredItems;

View File

@ -255,7 +255,8 @@ export const getHoveredElementForBinding = (
const hoveredElement = getElementAtPosition( const hoveredElement = getElementAtPosition(
scene.getElements(), scene.getElements(),
(element) => (element) =>
isBindableElement(element) && bindingBorderTest(element, pointerCoords), isBindableElement(element, false) &&
bindingBorderTest(element, pointerCoords),
); );
return hoveredElement as NonDeleted<ExcalidrawBindableElement> | null; return hoveredElement as NonDeleted<ExcalidrawBindableElement> | null;
}; };
@ -456,13 +457,13 @@ export const getEligibleElementsForBinding = (
): SuggestedBinding[] => { ): SuggestedBinding[] => {
const includedElementIds = new Set(elements.map(({ id }) => id)); const includedElementIds = new Set(elements.map(({ id }) => id));
return elements.flatMap((element) => return elements.flatMap((element) =>
isBindingElement(element) isBindingElement(element, false)
? (getElligibleElementsForBindingElement( ? (getElligibleElementsForBindingElement(
element as NonDeleted<ExcalidrawLinearElement>, element as NonDeleted<ExcalidrawLinearElement>,
).filter( ).filter(
(element) => !includedElementIds.has(element.id), (element) => !includedElementIds.has(element.id),
) as SuggestedBinding[]) ) as SuggestedBinding[])
: isBindableElement(element) : isBindableElement(element, false)
? getElligibleElementsForBindableElementAndWhere(element).filter( ? getElligibleElementsForBindableElementAndWhere(element).filter(
(binding) => !includedElementIds.has(binding[0].id), (binding) => !includedElementIds.has(binding[0].id),
) )
@ -508,7 +509,7 @@ const getElligibleElementsForBindableElementAndWhere = (
return Scene.getScene(bindableElement)! return Scene.getScene(bindableElement)!
.getElements() .getElements()
.map((element) => { .map((element) => {
if (!isBindingElement(element)) { if (!isBindingElement(element, false)) {
return null; return null;
} }
const canBindStart = isLinearElementEligibleForNewBindingByBindable( const canBindStart = isLinearElementEligibleForNewBindingByBindable(
@ -659,28 +660,47 @@ export const fixBindingsAfterDeletion = (
const deletedElementIds = new Set( const deletedElementIds = new Set(
deletedElements.map((element) => element.id), deletedElements.map((element) => element.id),
); );
// Non deleted and need an update // non-deleted which bindings need to be updated
const boundElementIds: Set<ExcalidrawElement["id"]> = new Set(); const affectedElements: Set<ExcalidrawElement["id"]> = new Set();
deletedElements.forEach((deletedElement) => { deletedElements.forEach((deletedElement) => {
if (isBindableElement(deletedElement)) { if (isBindableElement(deletedElement)) {
deletedElement.boundElements?.forEach((element) => { deletedElement.boundElements?.forEach((element) => {
if (!deletedElementIds.has(element.id)) { if (!deletedElementIds.has(element.id)) {
boundElementIds.add(element.id); affectedElements.add(element.id);
} }
}); });
} else if (isBindingElement(deletedElement)) {
if (deletedElement.startBinding) {
affectedElements.add(deletedElement.startBinding.elementId);
}
if (deletedElement.endBinding) {
affectedElements.add(deletedElement.endBinding.elementId);
}
} }
}); });
( sceneElements
sceneElements.filter(({ id }) => .filter(({ id }) => affectedElements.has(id))
boundElementIds.has(id), .forEach((element) => {
) as ExcalidrawLinearElement[] if (isBindableElement(element)) {
).forEach((element: ExcalidrawLinearElement) => { mutateElement(element, {
const { startBinding, endBinding } = element; boundElements: newBoundElementsAfterDeletion(
mutateElement(element, { element.boundElements,
startBinding: newBindingAfterDeletion(startBinding, deletedElementIds), deletedElementIds,
endBinding: newBindingAfterDeletion(endBinding, deletedElementIds), ),
});
} else if (isBindingElement(element)) {
mutateElement(element, {
startBinding: newBindingAfterDeletion(
element.startBinding,
deletedElementIds,
),
endBinding: newBindingAfterDeletion(
element.endBinding,
deletedElementIds,
),
});
}
}); });
});
}; };
const newBindingAfterDeletion = ( const newBindingAfterDeletion = (
@ -692,3 +712,13 @@ const newBindingAfterDeletion = (
} }
return binding; return binding;
}; };
const newBoundElementsAfterDeletion = (
boundElements: ExcalidrawElement["boundElements"],
deletedElementIds: Set<ExcalidrawElement["id"]>,
) => {
if (!boundElements) {
return null;
}
return boundElements.filter((ele) => !deletedElementIds.has(ele.id));
};

View File

@ -106,6 +106,20 @@ export const normalizeSVG = async (SVGString: string) => {
svg.setAttribute("xmlns", SVG_NS); svg.setAttribute("xmlns", SVG_NS);
} }
if (!svg.hasAttribute("width") || !svg.hasAttribute("height")) {
const viewBox = svg.getAttribute("viewBox");
let width = svg.getAttribute("width") || "50";
let height = svg.getAttribute("height") || "50";
if (viewBox) {
const match = viewBox.match(/\d+ +\d+ +(\d+) +(\d+)/);
if (match) {
[, width, height] = match;
}
}
svg.setAttribute("width", width);
svg.setAttribute("height", height);
}
return svg.outerHTML; return svg.outerHTML;
} }
}; };

View File

@ -205,7 +205,7 @@ export class LinearElementEditor {
); );
// suggest bindings for first and last point if selected // suggest bindings for first and last point if selected
if (isBindingElement(element)) { if (isBindingElement(element, false)) {
const coords: { x: number; y: number }[] = []; const coords: { x: number; y: number }[] = [];
const firstSelectedIndex = selectedPointsIndices[0]; const firstSelectedIndex = selectedPointsIndices[0];

View File

@ -57,6 +57,7 @@ const _newElementBase = <T extends ExcalidrawElement>(
strokeSharpness, strokeSharpness,
boundElements = null, boundElements = null,
link = null, link = null,
locked,
...rest ...rest
}: ElementConstructorOpts & Omit<Partial<ExcalidrawGenericElement>, "type">, }: ElementConstructorOpts & Omit<Partial<ExcalidrawGenericElement>, "type">,
) => { ) => {
@ -84,6 +85,7 @@ const _newElementBase = <T extends ExcalidrawElement>(
boundElements, boundElements,
updated: getUpdatedTimestamp(), updated: getUpdatedTimestamp(),
link, link,
locked,
}; };
return element; return element;
}; };

View File

@ -222,6 +222,13 @@ export const getTransformHandles = (
zoom: Zoom, zoom: Zoom,
pointerType: PointerType = "mouse", pointerType: PointerType = "mouse",
): TransformHandles => { ): TransformHandles => {
// so that when locked element is selected (especially when you toggle lock
// via keyboard) the locked element is visually distinct, indicating
// you can't move/resize
if (element.locked) {
return {};
}
let omitSides: { [T in TransformHandleType]?: boolean } = {}; let omitSides: { [T in TransformHandleType]?: boolean } = {};
if ( if (
element.type === "arrow" || element.type === "arrow" ||

View File

@ -71,8 +71,13 @@ export const isLinearElementType = (
export const isBindingElement = ( export const isBindingElement = (
element?: ExcalidrawElement | null, element?: ExcalidrawElement | null,
includeLocked = true,
): element is ExcalidrawLinearElement => { ): element is ExcalidrawLinearElement => {
return element != null && isBindingElementType(element.type); return (
element != null &&
(!element.locked || includeLocked === true) &&
isBindingElementType(element.type)
);
}; };
export const isBindingElementType = ( export const isBindingElementType = (
@ -83,9 +88,11 @@ export const isBindingElementType = (
export const isBindableElement = ( export const isBindableElement = (
element: ExcalidrawElement | null, element: ExcalidrawElement | null,
includeLocked = true,
): element is ExcalidrawBindableElement => { ): element is ExcalidrawBindableElement => {
return ( return (
element != null && element != null &&
(!element.locked || includeLocked === true) &&
(element.type === "rectangle" || (element.type === "rectangle" ||
element.type === "diamond" || element.type === "diamond" ||
element.type === "ellipse" || element.type === "ellipse" ||
@ -96,9 +103,11 @@ export const isBindableElement = (
export const isTextBindableContainer = ( export const isTextBindableContainer = (
element: ExcalidrawElement | null, element: ExcalidrawElement | null,
includeLocked = true,
): element is ExcalidrawTextContainer => { ): element is ExcalidrawTextContainer => {
return ( return (
element != null && element != null &&
(!element.locked || includeLocked === true) &&
(element.type === "rectangle" || (element.type === "rectangle" ||
element.type === "diamond" || element.type === "diamond" ||
element.type === "ellipse" || element.type === "ellipse" ||

View File

@ -55,6 +55,7 @@ type _ExcalidrawElementBase = Readonly<{
/** epoch (ms) timestamp of last element update */ /** epoch (ms) timestamp of last element update */
updated: number; updated: number;
link: string | null; link: string | null;
locked: boolean;
}>; }>;
export type ExcalidrawSelectionElement = _ExcalidrawElementBase & { export type ExcalidrawSelectionElement = _ExcalidrawElementBase & {

View File

@ -11,12 +11,12 @@ export const FILE_UPLOAD_MAX_BYTES = 3 * 1024 * 1024; // 3 MiB
// 1 year (https://stackoverflow.com/a/25201898/927631) // 1 year (https://stackoverflow.com/a/25201898/927631)
export const FILE_CACHE_MAX_AGE_SEC = 31536000; export const FILE_CACHE_MAX_AGE_SEC = 31536000;
export const BROADCAST = { export const WS_EVENTS = {
SERVER_VOLATILE: "server-volatile-broadcast", SERVER_VOLATILE: "server-volatile-broadcast",
SERVER: "server-broadcast", SERVER: "server-broadcast",
}; };
export enum SCENE { export enum WS_SCENE_EVENT_TYPES {
INIT = "SCENE_INIT", INIT = "SCENE_INIT",
UPDATE = "SCENE_UPDATE", UPDATE = "SCENE_UPDATE",
} }

View File

@ -22,7 +22,7 @@ import {
FIREBASE_STORAGE_PREFIXES, FIREBASE_STORAGE_PREFIXES,
INITIAL_SCENE_UPDATE_TIMEOUT, INITIAL_SCENE_UPDATE_TIMEOUT,
LOAD_IMAGES_TIMEOUT, LOAD_IMAGES_TIMEOUT,
SCENE, WS_SCENE_EVENT_TYPES,
STORAGE_KEYS, STORAGE_KEYS,
SYNC_FULL_SCENE_INTERVAL_MS, SYNC_FULL_SCENE_INTERVAL_MS,
} from "../app_constants"; } from "../app_constants";
@ -68,6 +68,7 @@ import {
} from "./reconciliation"; } from "./reconciliation";
import { decryptData } from "../../data/encryption"; import { decryptData } from "../../data/encryption";
import { resetBrowserStateVersions } from "../data/tabSync"; import { resetBrowserStateVersions } from "../data/tabSync";
import { LocalData } from "../data/LocalData";
interface CollabState { interface CollabState {
modalIsShown: boolean; modalIsShown: boolean;
@ -87,7 +88,7 @@ export interface CollabAPI {
onPointerUpdate: CollabInstance["onPointerUpdate"]; onPointerUpdate: CollabInstance["onPointerUpdate"];
initializeSocketClient: CollabInstance["initializeSocketClient"]; initializeSocketClient: CollabInstance["initializeSocketClient"];
onCollabButtonClick: CollabInstance["onCollabButtonClick"]; onCollabButtonClick: CollabInstance["onCollabButtonClick"];
broadcastElements: CollabInstance["broadcastElements"]; syncElements: CollabInstance["syncElements"];
fetchImageFilesFromFirebase: CollabInstance["fetchImageFilesFromFirebase"]; fetchImageFilesFromFirebase: CollabInstance["fetchImageFilesFromFirebase"];
setUsername: (username: string) => void; setUsername: (username: string) => void;
} }
@ -109,10 +110,11 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
portal: Portal; portal: Portal;
fileManager: FileManager; fileManager: FileManager;
excalidrawAPI: Props["excalidrawAPI"]; excalidrawAPI: Props["excalidrawAPI"];
isCollaborating: boolean = false;
activeIntervalId: number | null; activeIntervalId: number | null;
idleTimeoutId: number | null; idleTimeoutId: number | null;
// marked as private to ensure we don't change it outside this class
private _isCollaborating: boolean = false;
private socketInitializationTimer?: number; private socketInitializationTimer?: number;
private lastBroadcastedOrReceivedSceneVersion: number = -1; private lastBroadcastedOrReceivedSceneVersion: number = -1;
private collaborators = new Map<string, Collaborator>(); private collaborators = new Map<string, Collaborator>();
@ -193,6 +195,8 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
} }
} }
isCollaborating = () => this._isCollaborating;
private onUnload = () => { private onUnload = () => {
this.destroySocketClient({ isUnload: true }); this.destroySocketClient({ isUnload: true });
}; };
@ -203,7 +207,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
); );
if ( if (
this.isCollaborating && this._isCollaborating &&
(this.fileManager.shouldPreventUnload(syncableElements) || (this.fileManager.shouldPreventUnload(syncableElements) ||
!isSavedToFirebase(this.portal, syncableElements)) !isSavedToFirebase(this.portal, syncableElements))
) { ) {
@ -228,12 +232,20 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
}); });
saveCollabRoomToFirebase = async ( saveCollabRoomToFirebase = async (
syncableElements: readonly ExcalidrawElement[] = this.getSyncableElements( syncableElements: readonly ExcalidrawElement[],
this.excalidrawAPI.getSceneElementsIncludingDeleted(),
),
) => { ) => {
try { try {
await saveToFirebase(this.portal, syncableElements); const savedData = await saveToFirebase(
this.portal,
syncableElements,
this.excalidrawAPI.getAppState(),
);
if (this.isCollaborating() && savedData && savedData.reconciledElements) {
this.handleRemoteSceneUpdate(
this.reconcileElements(savedData.reconciledElements),
);
}
} catch (error: any) { } catch (error: any) {
console.error(error); console.error(error);
} }
@ -246,9 +258,14 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
closePortal = () => { closePortal = () => {
this.queueBroadcastAllElements.cancel(); this.queueBroadcastAllElements.cancel();
this.queueSaveToFirebase.cancel();
this.loadImageFiles.cancel(); this.loadImageFiles.cancel();
this.saveCollabRoomToFirebase(); this.saveCollabRoomToFirebase(
this.getSyncableElements(
this.excalidrawAPI.getSceneElementsIncludingDeleted(),
),
);
if (window.confirm(t("alerts.collabStopOverridePrompt"))) { if (window.confirm(t("alerts.collabStopOverridePrompt"))) {
// hack to ensure that we prefer we disregard any new browser state // hack to ensure that we prefer we disregard any new browser state
// that could have been saved in other tabs while we were collaborating // that could have been saved in other tabs while we were collaborating
@ -285,7 +302,8 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
this.setState({ this.setState({
activeRoomLink: "", activeRoomLink: "",
}); });
this.isCollaborating = false; this._isCollaborating = false;
LocalData.resumeSave("collaboration");
} }
this.lastBroadcastedOrReceivedSceneVersion = -1; this.lastBroadcastedOrReceivedSceneVersion = -1;
this.portal.close(); this.portal.close();
@ -353,7 +371,8 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
const scenePromise = resolvablePromise<ImportedDataState | null>(); const scenePromise = resolvablePromise<ImportedDataState | null>();
this.isCollaborating = true; this._isCollaborating = true;
LocalData.pauseSave("collaboration");
const { default: socketIOClient } = await import( const { default: socketIOClient } = await import(
/* webpackChunkName: "socketIoClient" */ "socket.io-client" /* webpackChunkName: "socketIoClient" */ "socket.io-client"
@ -394,10 +413,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
commitToHistory: true, commitToHistory: true,
}); });
this.broadcastElements(elements); this.saveCollabRoomToFirebase(this.getSyncableElements(elements));
const syncableElements = this.getSyncableElements(elements);
this.saveCollabRoomToFirebase(syncableElements);
} }
// fallback in case you're not alone in the room but still don't receive // fallback in case you're not alone in the room but still don't receive
@ -427,7 +443,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
switch (decryptedData.type) { switch (decryptedData.type) {
case "INVALID_RESPONSE": case "INVALID_RESPONSE":
return; return;
case SCENE.INIT: { case WS_SCENE_EVENT_TYPES.INIT: {
if (!this.portal.socketInitialized) { if (!this.portal.socketInitialized) {
this.initializeRoom({ fetchScene: false }); this.initializeRoom({ fetchScene: false });
const remoteElements = decryptedData.payload.elements; const remoteElements = decryptedData.payload.elements;
@ -443,7 +459,7 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
} }
break; break;
} }
case SCENE.UPDATE: case WS_SCENE_EVENT_TYPES.UPDATE:
this.handleRemoteSceneUpdate( this.handleRemoteSceneUpdate(
this.reconcileElements(decryptedData.payload.elements), this.reconcileElements(decryptedData.payload.elements),
); );
@ -705,15 +721,20 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
getSceneVersion(elements) > getSceneVersion(elements) >
this.getLastBroadcastedOrReceivedSceneVersion() this.getLastBroadcastedOrReceivedSceneVersion()
) { ) {
this.portal.broadcastScene(SCENE.UPDATE, elements, false); this.portal.broadcastScene(WS_SCENE_EVENT_TYPES.UPDATE, elements, false);
this.lastBroadcastedOrReceivedSceneVersion = getSceneVersion(elements); this.lastBroadcastedOrReceivedSceneVersion = getSceneVersion(elements);
this.queueBroadcastAllElements(); this.queueBroadcastAllElements();
} }
}; };
syncElements = (elements: readonly ExcalidrawElement[]) => {
this.broadcastElements(elements);
this.queueSaveToFirebase();
};
queueBroadcastAllElements = throttle(() => { queueBroadcastAllElements = throttle(() => {
this.portal.broadcastScene( this.portal.broadcastScene(
SCENE.UPDATE, WS_SCENE_EVENT_TYPES.UPDATE,
this.excalidrawAPI.getSceneElementsIncludingDeleted(), this.excalidrawAPI.getSceneElementsIncludingDeleted(),
true, true,
); );
@ -725,6 +746,16 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
this.setLastBroadcastedOrReceivedSceneVersion(newVersion); this.setLastBroadcastedOrReceivedSceneVersion(newVersion);
}, SYNC_FULL_SCENE_INTERVAL_MS); }, SYNC_FULL_SCENE_INTERVAL_MS);
queueSaveToFirebase = throttle(() => {
if (this.portal.socketInitialized) {
this.saveCollabRoomToFirebase(
this.getSyncableElements(
this.excalidrawAPI.getSceneElementsIncludingDeleted(),
),
);
}
}, SYNC_FULL_SCENE_INTERVAL_MS);
handleClose = () => { handleClose = () => {
this.setState({ modalIsShown: false }); this.setState({ modalIsShown: false });
}; };
@ -760,12 +791,12 @@ class CollabWrapper extends PureComponent<Props, CollabState> {
this.contextValue = {} as CollabAPI; this.contextValue = {} as CollabAPI;
} }
this.contextValue.isCollaborating = () => this.isCollaborating; this.contextValue.isCollaborating = this.isCollaborating;
this.contextValue.username = this.state.username; this.contextValue.username = this.state.username;
this.contextValue.onPointerUpdate = this.onPointerUpdate; this.contextValue.onPointerUpdate = this.onPointerUpdate;
this.contextValue.initializeSocketClient = this.initializeSocketClient; this.contextValue.initializeSocketClient = this.initializeSocketClient;
this.contextValue.onCollabButtonClick = this.onCollabButtonClick; this.contextValue.onCollabButtonClick = this.onCollabButtonClick;
this.contextValue.broadcastElements = this.broadcastElements; this.contextValue.syncElements = this.syncElements;
this.contextValue.fetchImageFilesFromFirebase = this.contextValue.fetchImageFilesFromFirebase =
this.fetchImageFilesFromFirebase; this.fetchImageFilesFromFirebase;
this.contextValue.setUsername = this.setUsername; this.contextValue.setUsername = this.setUsername;

View File

@ -3,7 +3,11 @@ import { SocketUpdateData, SocketUpdateDataSource } from "../data";
import CollabWrapper from "./CollabWrapper"; import CollabWrapper from "./CollabWrapper";
import { ExcalidrawElement } from "../../element/types"; import { ExcalidrawElement } from "../../element/types";
import { BROADCAST, FILE_UPLOAD_TIMEOUT, SCENE } from "../app_constants"; import {
WS_EVENTS,
FILE_UPLOAD_TIMEOUT,
WS_SCENE_EVENT_TYPES,
} from "../app_constants";
import { UserIdleState } from "../../types"; import { UserIdleState } from "../../types";
import { trackEvent } from "../../analytics"; import { trackEvent } from "../../analytics";
import { throttle } from "lodash"; import { throttle } from "lodash";
@ -37,7 +41,7 @@ class Portal {
}); });
this.socket.on("new-user", async (_socketId: string) => { this.socket.on("new-user", async (_socketId: string) => {
this.broadcastScene( this.broadcastScene(
SCENE.INIT, WS_SCENE_EVENT_TYPES.INIT,
this.collab.getSceneElementsIncludingDeleted(), this.collab.getSceneElementsIncludingDeleted(),
/* syncAll */ true, /* syncAll */ true,
); );
@ -81,7 +85,7 @@ class Portal {
const { encryptedBuffer, iv } = await encryptData(this.roomKey!, encoded); const { encryptedBuffer, iv } = await encryptData(this.roomKey!, encoded);
this.socket?.emit( this.socket?.emit(
volatile ? BROADCAST.SERVER_VOLATILE : BROADCAST.SERVER, volatile ? WS_EVENTS.SERVER_VOLATILE : WS_EVENTS.SERVER,
this.roomId, this.roomId,
encryptedBuffer, encryptedBuffer,
iv, iv,
@ -121,11 +125,11 @@ class Portal {
}, FILE_UPLOAD_TIMEOUT); }, FILE_UPLOAD_TIMEOUT);
broadcastScene = async ( broadcastScene = async (
sceneType: SCENE.INIT | SCENE.UPDATE, updateType: WS_SCENE_EVENT_TYPES.INIT | WS_SCENE_EVENT_TYPES.UPDATE,
allElements: readonly ExcalidrawElement[], allElements: readonly ExcalidrawElement[],
syncAll: boolean, syncAll: boolean,
) => { ) => {
if (sceneType === SCENE.INIT && !syncAll) { if (updateType === WS_SCENE_EVENT_TYPES.INIT && !syncAll) {
throw new Error("syncAll must be true when sending SCENE.INIT"); throw new Error("syncAll must be true when sending SCENE.INIT");
} }
@ -152,8 +156,8 @@ class Portal {
[] as BroadcastedExcalidrawElement[], [] as BroadcastedExcalidrawElement[],
); );
const data: SocketUpdateDataSource[typeof sceneType] = { const data: SocketUpdateDataSource[typeof updateType] = {
type: sceneType, type: updateType,
payload: { payload: {
elements: syncableElements, elements: syncableElements,
}, },
@ -166,20 +170,9 @@ class Portal {
); );
} }
const broadcastPromise = this._broadcastSocketData(
data as SocketUpdateData,
);
this.queueFileUpload(); this.queueFileUpload();
if (syncAll && this.collab.isCollaborating) { await this._broadcastSocketData(data as SocketUpdateData);
await Promise.all([
broadcastPromise,
this.collab.saveCollabRoomToFirebase(syncableElements),
]);
} else {
await broadcastPromise;
}
}; };
broadcastIdleChange = (userState: UserIdleState) => { broadcastIdleChange = (userState: UserIdleState) => {

View File

@ -78,8 +78,14 @@ export const reconcileElements = (
continue; continue;
} }
// Mark duplicate for removal as it'll be replaced with the remote element
if (local) { if (local) {
// mark for removal since it'll be replaced with the remote element // Unless the ramote and local elements are the same element in which case
// we need to keep it as we'd otherwise discard it from the resulting
// array.
if (local[0] === remoteElement) {
continue;
}
duplicates.set(local[0], true); duplicates.set(local[0], true);
} }

View File

@ -0,0 +1,154 @@
/**
* This file deals with saving data state (appState, elements, images, ...)
* locally to the browser.
*
* Notes:
*
* - DataState refers to full state of the app: appState, elements, images,
* though some state is saved separately (collab username, library) for one
* reason or another. We also save different data to different sotrage
* (localStorage, indexedDB).
*/
import { createStore, keys, del, getMany, set } from "idb-keyval";
import { clearAppStateForLocalStorage } from "../../appState";
import { clearElementsForLocalStorage } from "../../element";
import { ExcalidrawElement, FileId } from "../../element/types";
import { AppState, BinaryFileData, BinaryFiles } from "../../types";
import { debounce } from "../../utils";
import { SAVE_TO_LOCAL_STORAGE_TIMEOUT, STORAGE_KEYS } from "../app_constants";
import { FileManager } from "./FileManager";
import { Locker } from "./Locker";
import { updateBrowserStateVersion } from "./tabSync";
const filesStore = createStore("files-db", "files-store");
class LocalFileManager extends FileManager {
clearObsoleteFiles = async (opts: { currentFileIds: FileId[] }) => {
const allIds = await keys(filesStore);
for (const id of allIds) {
if (!opts.currentFileIds.includes(id as FileId)) {
del(id, filesStore);
}
}
};
}
const saveDataStateToLocalStorage = (
elements: readonly ExcalidrawElement[],
appState: AppState,
) => {
try {
localStorage.setItem(
STORAGE_KEYS.LOCAL_STORAGE_ELEMENTS,
JSON.stringify(clearElementsForLocalStorage(elements)),
);
localStorage.setItem(
STORAGE_KEYS.LOCAL_STORAGE_APP_STATE,
JSON.stringify(clearAppStateForLocalStorage(appState)),
);
updateBrowserStateVersion(STORAGE_KEYS.VERSION_DATA_STATE);
} catch (error: any) {
// Unable to access window.localStorage
console.error(error);
}
};
type SavingLockTypes = "collaboration";
export class LocalData {
private static _save = debounce(
async (
elements: readonly ExcalidrawElement[],
appState: AppState,
files: BinaryFiles,
onFilesSaved: () => void,
) => {
saveDataStateToLocalStorage(elements, appState);
await this.fileStorage.saveFiles({
elements,
files,
});
onFilesSaved();
},
SAVE_TO_LOCAL_STORAGE_TIMEOUT,
);
/** Saves DataState, including files. Bails if saving is paused */
static save = (
elements: readonly ExcalidrawElement[],
appState: AppState,
files: BinaryFiles,
onFilesSaved: () => void,
) => {
// we need to make the `isSavePaused` check synchronously (undebounced)
if (!this.isSavePaused()) {
this._save(elements, appState, files, onFilesSaved);
}
};
static flushSave = () => {
this._save.flush();
};
private static locker = new Locker<SavingLockTypes>();
static pauseSave = (lockType: SavingLockTypes) => {
this.locker.lock(lockType);
};
static resumeSave = (lockType: SavingLockTypes) => {
this.locker.unlock(lockType);
};
static isSavePaused = () => {
return document.hidden || this.locker.isLocked();
};
// ---------------------------------------------------------------------------
static fileStorage = new LocalFileManager({
getFiles(ids) {
return getMany(ids, filesStore).then(
(filesData: (BinaryFileData | undefined)[]) => {
const loadedFiles: BinaryFileData[] = [];
const erroredFiles = new Map<FileId, true>();
filesData.forEach((data, index) => {
const id = ids[index];
if (data) {
loadedFiles.push(data);
} else {
erroredFiles.set(id, true);
}
});
return { loadedFiles, erroredFiles };
},
);
},
async saveFiles({ addedFiles }) {
const savedFiles = new Map<FileId, true>();
const erroredFiles = new Map<FileId, true>();
// before we use `storage` event synchronization, let's update the flag
// optimistically. Hopefully nothing fails, and an IDB read executed
// before an IDB write finishes will read the latest value.
updateBrowserStateVersion(STORAGE_KEYS.VERSION_FILES);
await Promise.all(
[...addedFiles].map(async ([id, fileData]) => {
try {
await set(id, fileData, filesStore);
savedFiles.set(id, true);
} catch (error: any) {
console.error(error);
erroredFiles.set(id, true);
}
}),
);
return { savedFiles, erroredFiles };
},
});
}

View File

@ -0,0 +1,18 @@
export class Locker<T extends string> {
private locks = new Map<T, true>();
lock = (lockType: T) => {
this.locks.set(lockType, true);
};
/** @returns whether no locks remaining */
unlock = (lockType: T) => {
this.locks.delete(lockType);
return !this.isLocked();
};
/** @returns whether some (or specific) locks are present */
isLocked(lockType?: T) {
return lockType ? this.locks.has(lockType) : !!this.locks.size;
}
}

View File

@ -2,11 +2,17 @@ import { ExcalidrawElement, FileId } from "../../element/types";
import { getSceneVersion } from "../../element"; import { getSceneVersion } from "../../element";
import Portal from "../collab/Portal"; import Portal from "../collab/Portal";
import { restoreElements } from "../../data/restore"; import { restoreElements } from "../../data/restore";
import { BinaryFileData, BinaryFileMetadata, DataURL } from "../../types"; import {
AppState,
BinaryFileData,
BinaryFileMetadata,
DataURL,
} from "../../types";
import { FILE_CACHE_MAX_AGE_SEC } from "../app_constants"; import { FILE_CACHE_MAX_AGE_SEC } from "../app_constants";
import { decompressData } from "../../data/encode"; import { decompressData } from "../../data/encode";
import { encryptData, decryptData } from "../../data/encryption"; import { encryptData, decryptData } from "../../data/encryption";
import { MIME_TYPES } from "../../constants"; import { MIME_TYPES } from "../../constants";
import { reconcileElements } from "../collab/reconciliation";
// private // private
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -108,11 +114,13 @@ const encryptElements = async (
}; };
const decryptElements = async ( const decryptElements = async (
key: string, data: FirebaseStoredScene,
iv: Uint8Array, roomKey: string,
ciphertext: ArrayBuffer | Uint8Array,
): Promise<readonly ExcalidrawElement[]> => { ): Promise<readonly ExcalidrawElement[]> => {
const decrypted = await decryptData(iv, ciphertext, key); const ciphertext = data.ciphertext.toUint8Array();
const iv = data.iv.toUint8Array();
const decrypted = await decryptData(iv, ciphertext, roomKey);
const decodedData = new TextDecoder("utf-8").decode( const decodedData = new TextDecoder("utf-8").decode(
new Uint8Array(decrypted), new Uint8Array(decrypted),
); );
@ -171,57 +179,86 @@ export const saveFilesToFirebase = async ({
return { savedFiles, erroredFiles }; return { savedFiles, erroredFiles };
}; };
export const saveToFirebase = async ( const createFirebaseSceneDocument = async (
portal: Portal, firebase: ResolutionType<typeof loadFirestore>,
elements: readonly ExcalidrawElement[], elements: readonly ExcalidrawElement[],
roomKey: string,
) => { ) => {
const { roomId, roomKey, socket } = portal;
if (
// if no room exists, consider the room saved because there's nothing we can
// do at this point
!roomId ||
!roomKey ||
!socket ||
isSavedToFirebase(portal, elements)
) {
return true;
}
const firebase = await loadFirestore();
const sceneVersion = getSceneVersion(elements); const sceneVersion = getSceneVersion(elements);
const { ciphertext, iv } = await encryptElements(roomKey, elements); const { ciphertext, iv } = await encryptElements(roomKey, elements);
return {
const nextDocData = {
sceneVersion, sceneVersion,
ciphertext: firebase.firestore.Blob.fromUint8Array( ciphertext: firebase.firestore.Blob.fromUint8Array(
new Uint8Array(ciphertext), new Uint8Array(ciphertext),
), ),
iv: firebase.firestore.Blob.fromUint8Array(iv), iv: firebase.firestore.Blob.fromUint8Array(iv),
} as FirebaseStoredScene; } as FirebaseStoredScene;
};
const db = firebase.firestore(); export const saveToFirebase = async (
const docRef = db.collection("scenes").doc(roomId); portal: Portal,
const didUpdate = await db.runTransaction(async (transaction) => { elements: readonly ExcalidrawElement[],
const doc = await transaction.get(docRef); appState: AppState,
if (!doc.exists) { ) => {
transaction.set(docRef, nextDocData); const { roomId, roomKey, socket } = portal;
return true; if (
} // bail if no room exists as there's nothing we can do at this point
!roomId ||
const prevDocData = doc.data() as FirebaseStoredScene; !roomKey ||
if (prevDocData.sceneVersion >= nextDocData.sceneVersion) { !socket ||
return false; isSavedToFirebase(portal, elements)
} ) {
return false;
transaction.update(docRef, nextDocData);
return true;
});
if (didUpdate) {
firebaseSceneVersionCache.set(socket, sceneVersion);
} }
return didUpdate; const firebase = await loadFirestore();
const firestore = firebase.firestore();
const docRef = firestore.collection("scenes").doc(roomId);
const savedData = await firestore.runTransaction(async (transaction) => {
const snapshot = await transaction.get(docRef);
if (!snapshot.exists) {
const sceneDocument = await createFirebaseSceneDocument(
firebase,
elements,
roomKey,
);
transaction.set(docRef, sceneDocument);
return {
sceneVersion: sceneDocument.sceneVersion,
reconciledElements: null,
};
}
const prevDocData = snapshot.data() as FirebaseStoredScene;
const prevElements = await decryptElements(prevDocData, roomKey);
const reconciledElements = reconcileElements(
elements,
prevElements,
appState,
);
const sceneDocument = await createFirebaseSceneDocument(
firebase,
reconciledElements,
roomKey,
);
transaction.update(docRef, sceneDocument);
return {
reconciledElements,
sceneVersion: sceneDocument.sceneVersion,
};
});
firebaseSceneVersionCache.set(socket, savedData.sceneVersion);
return savedData;
}; };
export const loadFromFirebase = async ( export const loadFromFirebase = async (
@ -238,10 +275,7 @@ export const loadFromFirebase = async (
return null; return null;
} }
const storedScene = doc.data() as FirebaseStoredScene; const storedScene = doc.data() as FirebaseStoredScene;
const ciphertext = storedScene.ciphertext.toUint8Array(); const elements = await decryptElements(storedScene, roomKey);
const iv = storedScene.iv.toUint8Array();
const elements = await decryptElements(roomKey, iv, ciphertext);
if (socket) { if (socket) {
firebaseSceneVersionCache.set(socket, getSceneVersion(elements)); firebaseSceneVersionCache.set(socket, getSceneVersion(elements));

View File

@ -5,8 +5,8 @@ import {
getDefaultAppState, getDefaultAppState,
} from "../../appState"; } from "../../appState";
import { clearElementsForLocalStorage } from "../../element"; import { clearElementsForLocalStorage } from "../../element";
import { updateBrowserStateVersion } from "./tabSync";
import { STORAGE_KEYS } from "../app_constants"; import { STORAGE_KEYS } from "../app_constants";
import { ImportedDataState } from "../../data/types";
export const saveUsernameToLocalStorage = (username: string) => { export const saveUsernameToLocalStorage = (username: string) => {
try { try {
@ -34,26 +34,6 @@ export const importUsernameFromLocalStorage = (): string | null => {
return null; return null;
}; };
export const saveToLocalStorage = (
elements: readonly ExcalidrawElement[],
appState: AppState,
) => {
try {
localStorage.setItem(
STORAGE_KEYS.LOCAL_STORAGE_ELEMENTS,
JSON.stringify(clearElementsForLocalStorage(elements)),
);
localStorage.setItem(
STORAGE_KEYS.LOCAL_STORAGE_APP_STATE,
JSON.stringify(clearAppStateForLocalStorage(appState)),
);
updateBrowserStateVersion(STORAGE_KEYS.VERSION_DATA_STATE);
} catch (error: any) {
// Unable to access window.localStorage
console.error(error);
}
};
export const importFromLocalStorage = () => { export const importFromLocalStorage = () => {
let savedElements = null; let savedElements = null;
let savedState = null; let savedState = null;
@ -123,14 +103,13 @@ export const getTotalStorageSize = () => {
export const getLibraryItemsFromStorage = () => { export const getLibraryItemsFromStorage = () => {
try { try {
const libraryItems = const libraryItems: ImportedDataState["libraryItems"] = JSON.parse(
JSON.parse( localStorage.getItem(STORAGE_KEYS.LOCAL_STORAGE_LIBRARY) as string,
localStorage.getItem(STORAGE_KEYS.LOCAL_STORAGE_LIBRARY) as string, );
) || [];
return libraryItems; return libraryItems || [];
} catch (e) { } catch (error) {
console.error(e); console.error(error);
return []; return [];
} }
}; };

View File

@ -26,3 +26,9 @@
} }
} }
} }
.excalidraw-app.is-collaborating {
[data-testid="clear-canvas-button"] {
visibility: hidden;
pointer-events: none;
}
}

View File

@ -12,7 +12,6 @@ import {
VERSION_TIMEOUT, VERSION_TIMEOUT,
} from "../constants"; } from "../constants";
import { loadFromBlob } from "../data/blob"; import { loadFromBlob } from "../data/blob";
import { ImportedDataState } from "../data/types";
import { import {
ExcalidrawElement, ExcalidrawElement,
FileId, FileId,
@ -28,8 +27,8 @@ import {
AppState, AppState,
LibraryItems, LibraryItems,
ExcalidrawImperativeAPI, ExcalidrawImperativeAPI,
BinaryFileData,
BinaryFiles, BinaryFiles,
ExcalidrawInitialDataState,
} from "../types"; } from "../types";
import { import {
debounce, debounce,
@ -42,7 +41,6 @@ import {
} from "../utils"; } from "../utils";
import { import {
FIREBASE_STORAGE_PREFIXES, FIREBASE_STORAGE_PREFIXES,
SAVE_TO_LOCAL_STORAGE_TIMEOUT,
STORAGE_KEYS, STORAGE_KEYS,
SYNC_BROWSER_TABS_TIMEOUT, SYNC_BROWSER_TABS_TIMEOUT,
} from "./app_constants"; } from "./app_constants";
@ -57,7 +55,6 @@ import {
getLibraryItemsFromStorage, getLibraryItemsFromStorage,
importFromLocalStorage, importFromLocalStorage,
importUsernameFromLocalStorage, importUsernameFromLocalStorage,
saveToLocalStorage,
} from "./data/localStorage"; } from "./data/localStorage";
import CustomStats from "./CustomStats"; import CustomStats from "./CustomStats";
import { restoreAppState, RestoredDataState } from "../data/restore"; import { restoreAppState, RestoredDataState } from "../data/restore";
@ -67,72 +64,13 @@ import { shield } from "../components/icons";
import "./index.scss"; import "./index.scss";
import { ExportToExcalidrawPlus } from "./components/ExportToExcalidrawPlus"; import { ExportToExcalidrawPlus } from "./components/ExportToExcalidrawPlus";
import { getMany, set, del, keys, createStore } from "idb-keyval"; import { updateStaleImageStatuses } from "./data/FileManager";
import { FileManager, updateStaleImageStatuses } from "./data/FileManager";
import { newElementWith } from "../element/mutateElement"; import { newElementWith } from "../element/mutateElement";
import { isInitializedImageElement } from "../element/typeChecks"; import { isInitializedImageElement } from "../element/typeChecks";
import { loadFilesFromFirebase } from "./data/firebase"; import { loadFilesFromFirebase } from "./data/firebase";
import { import { LocalData } from "./data/LocalData";
isBrowserStorageStateNewer, import { isBrowserStorageStateNewer } from "./data/tabSync";
updateBrowserStateVersion, import clsx from "clsx";
} from "./data/tabSync";
const filesStore = createStore("files-db", "files-store");
const clearObsoleteFilesFromIndexedDB = async (opts: {
currentFileIds: FileId[];
}) => {
const allIds = await keys(filesStore);
for (const id of allIds) {
if (!opts.currentFileIds.includes(id as FileId)) {
del(id, filesStore);
}
}
};
const localFileStorage = new FileManager({
getFiles(ids) {
return getMany(ids, filesStore).then(
(filesData: (BinaryFileData | undefined)[]) => {
const loadedFiles: BinaryFileData[] = [];
const erroredFiles = new Map<FileId, true>();
filesData.forEach((data, index) => {
const id = ids[index];
if (data) {
loadedFiles.push(data);
} else {
erroredFiles.set(id, true);
}
});
return { loadedFiles, erroredFiles };
},
);
},
async saveFiles({ addedFiles }) {
const savedFiles = new Map<FileId, true>();
const erroredFiles = new Map<FileId, true>();
// before we use `storage` event synchronization, let's update the flag
// optimistically. Hopefully nothing fails, and an IDB read executed
// before an IDB write finishes will read the latest value.
updateBrowserStateVersion(STORAGE_KEYS.VERSION_FILES);
await Promise.all(
[...addedFiles].map(async ([id, fileData]) => {
try {
await set(id, fileData, filesStore);
savedFiles.set(id, true);
} catch (error: any) {
console.error(error);
erroredFiles.set(id, true);
}
}),
);
return { savedFiles, erroredFiles };
},
});
const languageDetector = new LanguageDetector(); const languageDetector = new LanguageDetector();
languageDetector.init({ languageDetector.init({
@ -143,32 +81,10 @@ languageDetector.init({
checkWhitelist: false, checkWhitelist: false,
}); });
const saveDebounced = debounce(
async (
elements: readonly ExcalidrawElement[],
appState: AppState,
files: BinaryFiles,
onFilesSaved: () => void,
) => {
saveToLocalStorage(elements, appState);
await localFileStorage.saveFiles({
elements,
files,
});
onFilesSaved();
},
SAVE_TO_LOCAL_STORAGE_TIMEOUT,
);
const onBlur = () => {
saveDebounced.flush();
};
const initializeScene = async (opts: { const initializeScene = async (opts: {
collabAPI: CollabAPI; collabAPI: CollabAPI;
}): Promise< }): Promise<
{ scene: ImportedDataState | null } & ( { scene: ExcalidrawInitialDataState | null } & (
| { isExternalScene: true; id: string; key: string } | { isExternalScene: true; id: string; key: string }
| { isExternalScene: false; id?: null; key?: null } | { isExternalScene: false; id?: null; key?: null }
) )
@ -295,11 +211,11 @@ const ExcalidrawWrapper = () => {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
const initialStatePromiseRef = useRef<{ const initialStatePromiseRef = useRef<{
promise: ResolvablePromise<ImportedDataState | null>; promise: ResolvablePromise<ExcalidrawInitialDataState | null>;
}>({ promise: null! }); }>({ promise: null! });
if (!initialStatePromiseRef.current.promise) { if (!initialStatePromiseRef.current.promise) {
initialStatePromiseRef.current.promise = initialStatePromiseRef.current.promise =
resolvablePromise<ImportedDataState | null>(); resolvablePromise<ExcalidrawInitialDataState | null>();
} }
useEffect(() => { useEffect(() => {
@ -366,7 +282,7 @@ const ExcalidrawWrapper = () => {
}); });
} else if (isInitialLoad) { } else if (isInitialLoad) {
if (fileIds.length) { if (fileIds.length) {
localFileStorage LocalData.fileStorage
.getFiles(fileIds) .getFiles(fileIds)
.then(({ loadedFiles, erroredFiles }) => { .then(({ loadedFiles, erroredFiles }) => {
if (loadedFiles.length) { if (loadedFiles.length) {
@ -381,7 +297,7 @@ const ExcalidrawWrapper = () => {
} }
// on fresh load, clear unused files from IDB (from previous // on fresh load, clear unused files from IDB (from previous
// session) // session)
clearObsoleteFilesFromIndexedDB({ currentFileIds: fileIds }); LocalData.fileStorage.clearObsoleteFiles({ currentFileIds: fileIds });
} }
} }
@ -458,7 +374,7 @@ const ExcalidrawWrapper = () => {
return acc; return acc;
}, [] as FileId[]) || []; }, [] as FileId[]) || [];
if (fileIds.length) { if (fileIds.length) {
localFileStorage LocalData.fileStorage
.getFiles(fileIds) .getFiles(fileIds)
.then(({ loadedFiles, erroredFiles }) => { .then(({ loadedFiles, erroredFiles }) => {
if (loadedFiles.length) { if (loadedFiles.length) {
@ -475,28 +391,50 @@ const ExcalidrawWrapper = () => {
} }
}, SYNC_BROWSER_TABS_TIMEOUT); }, SYNC_BROWSER_TABS_TIMEOUT);
const onUnload = () => {
LocalData.flushSave();
};
const visibilityChange = (event: FocusEvent | Event) => {
if (event.type === EVENT.BLUR || document.hidden) {
LocalData.flushSave();
}
if (
event.type === EVENT.VISIBILITY_CHANGE ||
event.type === EVENT.FOCUS
) {
syncData();
}
};
window.addEventListener(EVENT.HASHCHANGE, onHashChange, false); window.addEventListener(EVENT.HASHCHANGE, onHashChange, false);
window.addEventListener(EVENT.UNLOAD, onBlur, false); window.addEventListener(EVENT.UNLOAD, onUnload, false);
window.addEventListener(EVENT.BLUR, onBlur, false); window.addEventListener(EVENT.BLUR, visibilityChange, false);
document.addEventListener(EVENT.VISIBILITY_CHANGE, syncData, false); document.addEventListener(EVENT.VISIBILITY_CHANGE, visibilityChange, false);
window.addEventListener(EVENT.FOCUS, syncData, false); window.addEventListener(EVENT.FOCUS, visibilityChange, false);
return () => { return () => {
window.removeEventListener(EVENT.HASHCHANGE, onHashChange, false); window.removeEventListener(EVENT.HASHCHANGE, onHashChange, false);
window.removeEventListener(EVENT.UNLOAD, onBlur, false); window.removeEventListener(EVENT.UNLOAD, onUnload, false);
window.removeEventListener(EVENT.BLUR, onBlur, false); window.removeEventListener(EVENT.BLUR, visibilityChange, false);
window.removeEventListener(EVENT.FOCUS, syncData, false); window.removeEventListener(EVENT.FOCUS, visibilityChange, false);
document.removeEventListener(EVENT.VISIBILITY_CHANGE, syncData, false); document.removeEventListener(
EVENT.VISIBILITY_CHANGE,
visibilityChange,
false,
);
clearTimeout(titleTimeout); clearTimeout(titleTimeout);
}; };
}, [collabAPI, excalidrawAPI]); }, [collabAPI, excalidrawAPI]);
useEffect(() => { useEffect(() => {
const unloadHandler = (event: BeforeUnloadEvent) => { const unloadHandler = (event: BeforeUnloadEvent) => {
saveDebounced.flush(); LocalData.flushSave();
if ( if (
excalidrawAPI && excalidrawAPI &&
localFileStorage.shouldPreventUnload(excalidrawAPI.getSceneElements()) LocalData.fileStorage.shouldPreventUnload(
excalidrawAPI.getSceneElements(),
)
) { ) {
preventUnload(event); preventUnload(event);
} }
@ -517,9 +455,13 @@ const ExcalidrawWrapper = () => {
files: BinaryFiles, files: BinaryFiles,
) => { ) => {
if (collabAPI?.isCollaborating()) { if (collabAPI?.isCollaborating()) {
collabAPI.broadcastElements(elements); collabAPI.syncElements(elements);
} else { }
saveDebounced(elements, appState, files, () => {
// this check is redundant, but since this is a hot path, it's best
// not to evaludate the nested expression every time
if (!LocalData.isSavePaused()) {
LocalData.save(elements, appState, files, () => {
if (excalidrawAPI) { if (excalidrawAPI) {
let didChange = false; let didChange = false;
@ -527,7 +469,9 @@ const ExcalidrawWrapper = () => {
const elements = excalidrawAPI const elements = excalidrawAPI
.getSceneElementsIncludingDeleted() .getSceneElementsIncludingDeleted()
.map((element) => { .map((element) => {
if (localFileStorage.shouldUpdateImageElementStatus(element)) { if (
LocalData.fileStorage.shouldUpdateImageElementStatus(element)
) {
didChange = true; didChange = true;
const newEl = newElementWith(element, { status: "saved" }); const newEl = newElementWith(element, { status: "saved" });
if (pendingImageElement === element) { if (pendingImageElement === element) {
@ -687,11 +631,16 @@ const ExcalidrawWrapper = () => {
}; };
const onRoomClose = useCallback(() => { const onRoomClose = useCallback(() => {
localFileStorage.reset(); LocalData.fileStorage.reset();
}, []); }, []);
return ( return (
<> <div
style={{ height: "100%" }}
className={clsx("excalidraw-app", {
"is-collaborating": collabAPI?.isCollaborating(),
})}
>
<Excalidraw <Excalidraw
ref={excalidrawRefCallback} ref={excalidrawRefCallback}
onChange={onChange} onChange={onChange}
@ -743,7 +692,7 @@ const ExcalidrawWrapper = () => {
onClose={() => setErrorMessage("")} onClose={() => setErrorMessage("")}
/> />
)} )}
</> </div>
); );
}; };

2
src/global.d.ts vendored
View File

@ -34,6 +34,8 @@ type Mutable<T> = {
-readonly [P in keyof T]: T[P]; -readonly [P in keyof T]: T[P];
}; };
type Merge<M, N> = Omit<M, keyof N> & N;
/** utility type to assert that the second type is a subtype of the first type. /** utility type to assert that the second type is a subtype of the first type.
* Returns the subtype. */ * Returns the subtype. */
type SubtypeOf<Supertype, Subtype extends Supertype> = Subtype; type SubtypeOf<Supertype, Subtype extends Supertype> = Subtype;

4
src/jotai.ts Normal file
View File

@ -0,0 +1,4 @@
import { unstable_createStore } from "jotai";
export const jotaiScope = Symbol();
export const jotaiStore = unstable_createStore();

View File

@ -9,6 +9,7 @@
"copy": "نسخ", "copy": "نسخ",
"copyAsPng": "نسخ إلى الحافظة بصيغة PNG", "copyAsPng": "نسخ إلى الحافظة بصيغة PNG",
"copyAsSvg": "نسخ إلى الحافظة بصيغة SVG", "copyAsSvg": "نسخ إلى الحافظة بصيغة SVG",
"copyText": "نسخ إلى الحافظة كنص",
"bringForward": "جلب للأمام", "bringForward": "جلب للأمام",
"sendToBack": "أرسل للخلف", "sendToBack": "أرسل للخلف",
"bringToFront": "أحضر للأمام", "bringToFront": "أحضر للأمام",
@ -21,7 +22,7 @@
"fill": "التعبئة", "fill": "التعبئة",
"strokeWidth": "سُمك الخط", "strokeWidth": "سُمك الخط",
"strokeStyle": "نمط الخط", "strokeStyle": "نمط الخط",
"strokeStyle_solid": "كامل", "strokeStyle_solid": "متصل",
"strokeStyle_dashed": "متقطع", "strokeStyle_dashed": "متقطع",
"strokeStyle_dotted": "منقط", "strokeStyle_dotted": "منقط",
"sloppiness": "الإمالة", "sloppiness": "الإمالة",
@ -107,10 +108,17 @@
"decreaseFontSize": "تصغير حجم الخط", "decreaseFontSize": "تصغير حجم الخط",
"increaseFontSize": "تكبير حجم الخط", "increaseFontSize": "تكبير حجم الخط",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "تعديل الرابط", "edit": "تعديل الرابط",
"create": "إنشاء رابط", "create": "إنشاء رابط",
"label": "رابط" "label": "رابط"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "تعذر التحميل، الملف غير صالح", "couldNotLoadInvalidFile": "تعذر التحميل، الملف غير صالح",
"importBackendFailed": "فشل الاستيراد من الخادوم.", "importBackendFailed": "فشل الاستيراد من الخادوم.",
"cannotExportEmptyCanvas": "لا يمكن تصدير لوحة فارغة.", "cannotExportEmptyCanvas": "لا يمكن تصدير لوحة فارغة.",
"couldNotCopyToClipboard": "تعذر النسخ إلى الحافظة. حاول استخدام متصفح Chrome.", "couldNotCopyToClipboard": "",
"decryptFailed": "تعذر فك تشفير البيانات.", "decryptFailed": "تعذر فك تشفير البيانات.",
"uploadedSecurly": "تم تأمين التحميل بتشفير النهاية إلى النهاية، مما يعني أن خادوم Excalidraw والأطراف الثالثة لا يمكنها قراءة المحتوى.", "uploadedSecurly": "تم تأمين التحميل بتشفير النهاية إلى النهاية، مما يعني أن خادوم Excalidraw والأطراف الثالثة لا يمكنها قراءة المحتوى.",
"loadSceneOverridePrompt": "تحميل الرسم الخارجي سيحل محل المحتوى الموجود لديك. هل ترغب في المتابعة؟", "loadSceneOverridePrompt": "تحميل الرسم الخارجي سيحل محل المحتوى الموجود لديك. هل ترغب في المتابعة؟",
@ -172,7 +180,7 @@
"cannotRestoreFromImage": "تعذر استعادة المشهد من ملف الصورة", "cannotRestoreFromImage": "تعذر استعادة المشهد من ملف الصورة",
"invalidSceneUrl": "تعذر استيراد المشهد من عنوان URL المتوفر. إما أنها مشوهة، أو لا تحتوي على بيانات Excalidraw JSON صالحة.", "invalidSceneUrl": "تعذر استيراد المشهد من عنوان URL المتوفر. إما أنها مشوهة، أو لا تحتوي على بيانات Excalidraw JSON صالحة.",
"resetLibrary": "هذا سوف يمسح مكتبتك. هل أنت متأكد؟", "resetLibrary": "هذا سوف يمسح مكتبتك. هل أنت متأكد؟",
"removeItemsFromsLibrary": "", "removeItemsFromsLibrary": "حذف {{count}} عنصر (عناصر) من المكتبة؟",
"invalidEncryptionKey": "مفتاح التشفير يجب أن يكون من 22 حرفاً. التعاون المباشر معطل." "invalidEncryptionKey": "مفتاح التشفير يجب أن يكون من 22 حرفاً. التعاون المباشر معطل."
}, },
"errors": { "errors": {
@ -196,7 +204,8 @@
"library": "مكتبة", "library": "مكتبة",
"lock": "الحفاظ على أداة التحديد نشطة بعد الرسم", "lock": "الحفاظ على أداة التحديد نشطة بعد الرسم",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": "ممحاة"
}, },
"headings": { "headings": {
"canvasActions": "إجراءات اللوحة", "canvasActions": "إجراءات اللوحة",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "نشر مكتبتك", "publishLibrary": "نشر مكتبتك",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "تعذر عرض المعاينة", "cannotShowPreview": "تعذر عرض المعاينة",
@ -281,14 +291,15 @@
"howto": "اتبع التعليمات", "howto": "اتبع التعليمات",
"or": "أو", "or": "أو",
"preventBinding": "منع ارتبط السهم", "preventBinding": "منع ارتبط السهم",
"shapes": "أشكال", "tools": "الأدوات",
"shortcuts": "اختصارات لوحة المفاتيح", "shortcuts": "اختصارات لوحة المفاتيح",
"textFinish": "إنهاء التعديل (محرر النص)", "textFinish": "إنهاء التعديل (محرر النص)",
"textNewLine": "أضف سطر جديد (محرر نص)", "textNewLine": "أضف سطر جديد (محرر نص)",
"title": "المساعدة", "title": "المساعدة",
"view": "عرض", "view": "عرض",
"zoomToFit": "تكبير للملائمة", "zoomToFit": "تكبير للملائمة",
"zoomToSelection": "تكبير للعنصر المحدد" "zoomToSelection": "تكبير للعنصر المحدد",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "مسح اللوحة" "title": "مسح اللوحة"

View File

@ -9,6 +9,7 @@
"copy": "Копирай", "copy": "Копирай",
"copyAsPng": "Копиране в клипборда", "copyAsPng": "Копиране в клипборда",
"copyAsSvg": "Копирано в клипборда като SVG", "copyAsSvg": "Копирано в клипборда като SVG",
"copyText": "",
"bringForward": "Преместване напред", "bringForward": "Преместване напред",
"sendToBack": "Изнасяне назад", "sendToBack": "Изнасяне назад",
"bringToFront": "Изнасяне отпред", "bringToFront": "Изнасяне отпред",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Невалиден файл не може да се зареди", "couldNotLoadInvalidFile": "Невалиден файл не може да се зареди",
"importBackendFailed": "Импортирането от бекенд не беше успешно.", "importBackendFailed": "Импортирането от бекенд не беше успешно.",
"cannotExportEmptyCanvas": "Не може да се експортира празно платно.", "cannotExportEmptyCanvas": "Не може да се експортира празно платно.",
"couldNotCopyToClipboard": "Неуспешно копиране в клипборда. Опитайте да използвате браузъра Chrome.", "couldNotCopyToClipboard": "",
"decryptFailed": "Данните не можаха да се дешифрират.", "decryptFailed": "Данните не можаха да се дешифрират.",
"uploadedSecurly": "Качването е защитено с криптиране от край до край, което означава, че сървърът Excalidraw и трети страни не могат да четат съдържанието.", "uploadedSecurly": "Качването е защитено с криптиране от край до край, което означава, че сървърът Excalidraw и трети страни не могат да четат съдържанието.",
"loadSceneOverridePrompt": "Зареждането на външна рисунка ще презапише настоящото ви съдържание. Желаете ли да продължите?", "loadSceneOverridePrompt": "Зареждането на външна рисунка ще презапише настоящото ви съдържание. Желаете ли да продължите?",
@ -196,7 +204,8 @@
"library": "Библиотека", "library": "Библиотека",
"lock": "Поддържайте избрания инструмент активен след рисуване", "lock": "Поддържайте избрания инструмент активен след рисуване",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "Действия по платното", "canvasActions": "Действия по платното",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "Натиснете Enter, за да добавите", "bindTextToElement": "Натиснете Enter, за да добавите",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Невъзможност за показване на preview", "cannotShowPreview": "Невъзможност за показване на preview",
@ -281,14 +291,15 @@
"howto": "Следвайте нашите ръководства", "howto": "Следвайте нашите ръководства",
"or": "или", "or": "или",
"preventBinding": "Спри прилепяне на стрелките", "preventBinding": "Спри прилепяне на стрелките",
"shapes": "Фигури", "tools": "",
"shortcuts": "Клавиши за бърз достъп", "shortcuts": "Клавиши за бърз достъп",
"textFinish": "", "textFinish": "",
"textNewLine": "", "textNewLine": "",
"title": "Помощ", "title": "Помощ",
"view": "Преглед", "view": "Преглед",
"zoomToFit": "Приближи докато се виждат всички елементи", "zoomToFit": "Приближи докато се виждат всички елементи",
"zoomToSelection": "Приближи селекцията" "zoomToSelection": "Приближи селекцията",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "", "copy": "",
"copyAsPng": "", "copyAsPng": "",
"copyAsSvg": "", "copyAsSvg": "",
"copyText": "",
"bringForward": "", "bringForward": "",
"sendToBack": "", "sendToBack": "",
"bringToFront": "", "bringToFront": "",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -196,7 +204,8 @@
"library": "", "library": "",
"lock": "", "lock": "",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "", "canvasActions": "",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "", "cannotShowPreview": "",
@ -281,14 +291,15 @@
"howto": "", "howto": "",
"or": "", "or": "",
"preventBinding": "", "preventBinding": "",
"shapes": "", "tools": "",
"shortcuts": "", "shortcuts": "",
"textFinish": "", "textFinish": "",
"textNewLine": "", "textNewLine": "",
"title": "", "title": "",
"view": "", "view": "",
"zoomToFit": "", "zoomToFit": "",
"zoomToSelection": "" "zoomToSelection": "",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "Copia", "copy": "Copia",
"copyAsPng": "Copia al porta-retalls com a PNG", "copyAsPng": "Copia al porta-retalls com a PNG",
"copyAsSvg": "Copia al porta-retalls com a SVG", "copyAsSvg": "Copia al porta-retalls com a SVG",
"copyText": "",
"bringForward": "Porta endavant", "bringForward": "Porta endavant",
"sendToBack": "Envia enrere", "sendToBack": "Envia enrere",
"bringToFront": "Porta al davant", "bringToFront": "Porta al davant",
@ -107,10 +108,17 @@
"decreaseFontSize": "Redueix la mida de la lletra", "decreaseFontSize": "Redueix la mida de la lletra",
"increaseFontSize": "Augmenta la mida de la lletra", "increaseFontSize": "Augmenta la mida de la lletra",
"unbindText": "Desvincular el text", "unbindText": "Desvincular el text",
"bindText": "",
"link": { "link": {
"edit": "Edita l'enllaç", "edit": "Edita l'enllaç",
"create": "Crea un enllaç", "create": "Crea un enllaç",
"label": "Enllaç" "label": "Enllaç"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "No s'ha pogut carregar un fitxer no vàlid", "couldNotLoadInvalidFile": "No s'ha pogut carregar un fitxer no vàlid",
"importBackendFailed": "Importació fallida.", "importBackendFailed": "Importació fallida.",
"cannotExportEmptyCanvas": "No es pot exportar un llenç buit.", "cannotExportEmptyCanvas": "No es pot exportar un llenç buit.",
"couldNotCopyToClipboard": "No s'ha pogut copiar al porta-retalls. Intentar amb el navegador Google Chrome.", "couldNotCopyToClipboard": "",
"decryptFailed": "No s'ha pogut desencriptar.", "decryptFailed": "No s'ha pogut desencriptar.",
"uploadedSecurly": "La càrrega s'ha assegurat amb xifratge punta a punta, cosa que significa que el servidor Excalidraw i tercers no poden llegir el contingut.", "uploadedSecurly": "La càrrega s'ha assegurat amb xifratge punta a punta, cosa que significa que el servidor Excalidraw i tercers no poden llegir el contingut.",
"loadSceneOverridePrompt": "Si carregas aquest dibuix extern, substituirá el que tens. Vols continuar?", "loadSceneOverridePrompt": "Si carregas aquest dibuix extern, substituirá el que tens. Vols continuar?",
@ -196,7 +204,8 @@
"library": "Biblioteca", "library": "Biblioteca",
"lock": "Mantenir activa l'eina seleccionada desprès de dibuixar", "lock": "Mantenir activa l'eina seleccionada desprès de dibuixar",
"penMode": "Evita el zoom i accepta solament el dibuix lliure amb bolígraf", "penMode": "Evita el zoom i accepta solament el dibuix lliure amb bolígraf",
"link": "Afegeix / actualitza l'enllaç per a la forma seleccionada" "link": "Afegeix / actualitza l'enllaç per a la forma seleccionada",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "Accions del llenç", "canvasActions": "Accions del llenç",
@ -221,7 +230,8 @@
"placeImage": "Feu clic per a col·locar la imatge o clic i arrossegar per a establir-ne la mida manualment", "placeImage": "Feu clic per a col·locar la imatge o clic i arrossegar per a establir-ne la mida manualment",
"publishLibrary": "Publiqueu la vostra pròpia llibreria", "publishLibrary": "Publiqueu la vostra pròpia llibreria",
"bindTextToElement": "Premeu enter per a afegir-hi text", "bindTextToElement": "Premeu enter per a afegir-hi text",
"deepBoxSelect": "Manteniu CtrlOrCmd per a selecció profunda, i per a evitar l'arrossegament" "deepBoxSelect": "Manteniu CtrlOrCmd per a selecció profunda, i per a evitar l'arrossegament",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "No es pot mostrar la previsualització", "cannotShowPreview": "No es pot mostrar la previsualització",
@ -281,14 +291,15 @@
"howto": "Seguiu les nostres guies", "howto": "Seguiu les nostres guies",
"or": "o", "or": "o",
"preventBinding": "Prevenir vinculació de la fletxa", "preventBinding": "Prevenir vinculació de la fletxa",
"shapes": "Formes", "tools": "",
"shortcuts": "Dreceres de teclat", "shortcuts": "Dreceres de teclat",
"textFinish": "Finalitza l'edició (editor de text)", "textFinish": "Finalitza l'edició (editor de text)",
"textNewLine": "Afegeix una línia nova (editor de text)", "textNewLine": "Afegeix una línia nova (editor de text)",
"title": "Ajuda", "title": "Ajuda",
"view": "Visualització", "view": "Visualització",
"zoomToFit": "Zoom per veure tots els elements", "zoomToFit": "Zoom per veure tots els elements",
"zoomToSelection": "Zoom per veure la selecció" "zoomToSelection": "Zoom per veure la selecció",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Neteja el llenç" "title": "Neteja el llenç"

View File

@ -9,6 +9,7 @@
"copy": "Kopírovat", "copy": "Kopírovat",
"copyAsPng": "Zkopírovat do schránky jako PNG", "copyAsPng": "Zkopírovat do schránky jako PNG",
"copyAsSvg": "Zkopírovat do schránky jako SVG", "copyAsSvg": "Zkopírovat do schránky jako SVG",
"copyText": "",
"bringForward": "Přenést blíž", "bringForward": "Přenést blíž",
"sendToBack": "Přenést do pozadí", "sendToBack": "Přenést do pozadí",
"bringToFront": "Přenést do popředí", "bringToFront": "Přenést do popředí",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -196,7 +204,8 @@
"library": "", "library": "",
"lock": "", "lock": "",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "", "canvasActions": "",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "", "cannotShowPreview": "",
@ -281,14 +291,15 @@
"howto": "", "howto": "",
"or": "nebo", "or": "nebo",
"preventBinding": "", "preventBinding": "",
"shapes": "", "tools": "",
"shortcuts": "", "shortcuts": "",
"textFinish": "", "textFinish": "",
"textNewLine": "", "textNewLine": "",
"title": "", "title": "",
"view": "", "view": "",
"zoomToFit": "", "zoomToFit": "",
"zoomToSelection": "" "zoomToSelection": "",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "Kopier", "copy": "Kopier",
"copyAsPng": "Kopier til klippebord som PNG", "copyAsPng": "Kopier til klippebord som PNG",
"copyAsSvg": "Kopier til klippebord som SVG", "copyAsSvg": "Kopier til klippebord som SVG",
"copyText": "",
"bringForward": "", "bringForward": "",
"sendToBack": "", "sendToBack": "",
"bringToFront": "", "bringToFront": "",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "", "couldNotLoadInvalidFile": "",
"importBackendFailed": "", "importBackendFailed": "",
"cannotExportEmptyCanvas": "", "cannotExportEmptyCanvas": "",
"couldNotCopyToClipboard": "Kunne ikke kopiere til klippebord. Prøv at bruge Chrome browser.", "couldNotCopyToClipboard": "",
"decryptFailed": "", "decryptFailed": "",
"uploadedSecurly": "", "uploadedSecurly": "",
"loadSceneOverridePrompt": "", "loadSceneOverridePrompt": "",
@ -196,7 +204,8 @@
"library": "", "library": "",
"lock": "", "lock": "",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "", "canvasActions": "",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "", "cannotShowPreview": "",
@ -281,14 +291,15 @@
"howto": "", "howto": "",
"or": "", "or": "",
"preventBinding": "", "preventBinding": "",
"shapes": "", "tools": "",
"shortcuts": "", "shortcuts": "",
"textFinish": "", "textFinish": "",
"textNewLine": "", "textNewLine": "",
"title": "", "title": "",
"view": "", "view": "",
"zoomToFit": "", "zoomToFit": "",
"zoomToSelection": "" "zoomToSelection": "",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "Kopieren", "copy": "Kopieren",
"copyAsPng": "In Zwischenablage kopieren (PNG)", "copyAsPng": "In Zwischenablage kopieren (PNG)",
"copyAsSvg": "In Zwischenablage kopieren (SVG)", "copyAsSvg": "In Zwischenablage kopieren (SVG)",
"copyText": "In die Zwischenablage als Text kopieren",
"bringForward": "Nach vorne", "bringForward": "Nach vorne",
"sendToBack": "In den Hintergrund", "sendToBack": "In den Hintergrund",
"bringToFront": "In den Vordergrund", "bringToFront": "In den Vordergrund",
@ -107,10 +108,17 @@
"decreaseFontSize": "Schrift verkleinern", "decreaseFontSize": "Schrift verkleinern",
"increaseFontSize": "Schrift vergrößern", "increaseFontSize": "Schrift vergrößern",
"unbindText": "Text lösen", "unbindText": "Text lösen",
"bindText": "Text an Container binden",
"link": { "link": {
"edit": "Link bearbeiten", "edit": "Link bearbeiten",
"create": "Link erstellen", "create": "Link erstellen",
"label": "Link" "label": "Link"
},
"elementLock": {
"lock": "Sperren",
"unlock": "Entsperren",
"lockAll": "Alle sperren",
"unlockAll": "Alle entsperren"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Ungültige Datei konnte nicht geladen werden", "couldNotLoadInvalidFile": "Ungültige Datei konnte nicht geladen werden",
"importBackendFailed": "Import vom Server ist fehlgeschlagen.", "importBackendFailed": "Import vom Server ist fehlgeschlagen.",
"cannotExportEmptyCanvas": "Leere Zeichenfläche kann nicht exportiert werden.", "cannotExportEmptyCanvas": "Leere Zeichenfläche kann nicht exportiert werden.",
"couldNotCopyToClipboard": "Konnte nicht in die Zwischenablage kopieren. Versuch es mit dem Chrome Browser.", "couldNotCopyToClipboard": "Kopieren in die Zwischenablage fehlgeschlagen.",
"decryptFailed": "Daten konnten nicht entschlüsselt werden.", "decryptFailed": "Daten konnten nicht entschlüsselt werden.",
"uploadedSecurly": "Der Upload wurde mit Ende-zu-Ende-Verschlüsselung gespeichert. Weder Excalidraw noch Dritte können den Inhalt einsehen.", "uploadedSecurly": "Der Upload wurde mit Ende-zu-Ende-Verschlüsselung gespeichert. Weder Excalidraw noch Dritte können den Inhalt einsehen.",
"loadSceneOverridePrompt": "Das Laden einer externen Zeichnung ersetzt den vorhandenen Inhalt. Möchtest du fortfahren?", "loadSceneOverridePrompt": "Das Laden einer externen Zeichnung ersetzt den vorhandenen Inhalt. Möchtest du fortfahren?",
@ -195,8 +203,9 @@
"text": "Text", "text": "Text",
"library": "Bibliothek", "library": "Bibliothek",
"lock": "Ausgewähltes Werkzeug nach Zeichnen aktiv lassen", "lock": "Ausgewähltes Werkzeug nach Zeichnen aktiv lassen",
"penMode": "", "penMode": "Verhindere Pinch-Zoom und akzeptiere Eingabe nur vom Stift",
"link": "Link für ausgewählte Form hinzufügen / aktualisieren" "link": "Link für ausgewählte Form hinzufügen / aktualisieren",
"eraser": "Radierer"
}, },
"headings": { "headings": {
"canvasActions": "Aktionen für Zeichenfläche", "canvasActions": "Aktionen für Zeichenfläche",
@ -221,7 +230,8 @@
"placeImage": "Klicken, um das Bild zu platzieren oder klicken und ziehen um seine Größe manuell zu setzen", "placeImage": "Klicken, um das Bild zu platzieren oder klicken und ziehen um seine Größe manuell zu setzen",
"publishLibrary": "Veröffentliche deine eigene Bibliothek", "publishLibrary": "Veröffentliche deine eigene Bibliothek",
"bindTextToElement": "Zum Hinzufügen Eingabetaste drücken", "bindTextToElement": "Zum Hinzufügen Eingabetaste drücken",
"deepBoxSelect": "Halte CtrlOrCmd gedrückt, um innerhalb der Gruppe auszuwählen, und um Ziehen zu vermeiden" "deepBoxSelect": "Halte CtrlOrCmd gedrückt, um innerhalb der Gruppe auszuwählen, und um Ziehen zu vermeiden",
"eraserRevert": "Halte Alt gedrückt, um die zum Löschen markierten Elemente zurückzusetzen"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Vorschau kann nicht angezeigt werden", "cannotShowPreview": "Vorschau kann nicht angezeigt werden",
@ -281,14 +291,15 @@
"howto": "Folge unseren Anleitungen", "howto": "Folge unseren Anleitungen",
"or": "oder", "or": "oder",
"preventBinding": "Pfeil-Bindung verhindern", "preventBinding": "Pfeil-Bindung verhindern",
"shapes": "Formen", "tools": "Werkzeuge",
"shortcuts": "Tastaturkürzel", "shortcuts": "Tastaturkürzel",
"textFinish": "Bearbeitung beenden (Texteditor)", "textFinish": "Bearbeitung beenden (Texteditor)",
"textNewLine": "Neue Zeile hinzufügen (Texteditor)", "textNewLine": "Neue Zeile hinzufügen (Texteditor)",
"title": "Hilfe", "title": "Hilfe",
"view": "Ansicht", "view": "Ansicht",
"zoomToFit": "Zoomen um alle Elemente einzupassen", "zoomToFit": "Zoomen um alle Elemente einzupassen",
"zoomToSelection": "Auf Auswahl zoomen" "zoomToSelection": "Auf Auswahl zoomen",
"toggleElementLock": "Auswahl sperren/entsperren"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Zeichenfläche löschen" "title": "Zeichenfläche löschen"

View File

@ -9,6 +9,7 @@
"copy": "Αντιγραφή", "copy": "Αντιγραφή",
"copyAsPng": "Αντιγραφή στο πρόχειρο ως PNG", "copyAsPng": "Αντιγραφή στο πρόχειρο ως PNG",
"copyAsSvg": "Αντιγραφή στο πρόχειρο ως SVG", "copyAsSvg": "Αντιγραφή στο πρόχειρο ως SVG",
"copyText": "",
"bringForward": "Στο προσκήνιο", "bringForward": "Στο προσκήνιο",
"sendToBack": "Ένα επίπεδο πίσω", "sendToBack": "Ένα επίπεδο πίσω",
"bringToFront": "Ένα επίπεδο μπροστά", "bringToFront": "Ένα επίπεδο μπροστά",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Δεν μπόρεσε να ανοίξει εσφαλμένο αρχείο", "couldNotLoadInvalidFile": "Δεν μπόρεσε να ανοίξει εσφαλμένο αρχείο",
"importBackendFailed": "Η εισαγωγή από το backend απέτυχε.", "importBackendFailed": "Η εισαγωγή από το backend απέτυχε.",
"cannotExportEmptyCanvas": "Δεν είναι δυνατή η εξαγωγή κενού καμβά.", "cannotExportEmptyCanvas": "Δεν είναι δυνατή η εξαγωγή κενού καμβά.",
"couldNotCopyToClipboard": "Δεν ήταν δυνατή η αντιγραφή στο πρόχειρο. Δοκίμασε τη χρήση του προγράμματος περιήγησης Chrome.", "couldNotCopyToClipboard": "",
"decryptFailed": "Δεν ήταν δυνατή η αποκρυπτογράφηση δεδομένων.", "decryptFailed": "Δεν ήταν δυνατή η αποκρυπτογράφηση δεδομένων.",
"uploadedSecurly": "Η μεταφόρτωση έχει εξασφαλιστεί με κρυπτογράφηση από άκρο σε άκρο, πράγμα που σημαίνει ότι ο διακομιστής Excalidraw και τρίτα μέρη δεν μπορούν να διαβάσουν το περιεχόμενο.", "uploadedSecurly": "Η μεταφόρτωση έχει εξασφαλιστεί με κρυπτογράφηση από άκρο σε άκρο, πράγμα που σημαίνει ότι ο διακομιστής Excalidraw και τρίτα μέρη δεν μπορούν να διαβάσουν το περιεχόμενο.",
"loadSceneOverridePrompt": "Η φόρτωση εξωτερικού σχεδίου θα αντικαταστήσει το υπάρχον περιεχόμενο. Επιθυμείτε να συνεχίσετε;", "loadSceneOverridePrompt": "Η φόρτωση εξωτερικού σχεδίου θα αντικαταστήσει το υπάρχον περιεχόμενο. Επιθυμείτε να συνεχίσετε;",
@ -196,7 +204,8 @@
"library": "Βιβλιοθήκη", "library": "Βιβλιοθήκη",
"lock": "Κράτησε επιλεγμένο το εργαλείο μετά το σχέδιο", "lock": "Κράτησε επιλεγμένο το εργαλείο μετά το σχέδιο",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "Ενέργειες καμβά", "canvasActions": "Ενέργειες καμβά",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "Δημοσιεύστε τη δική σας βιβλιοθήκη", "publishLibrary": "Δημοσιεύστε τη δική σας βιβλιοθήκη",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Αδυναμία εμφάνισης προεπισκόπησης", "cannotShowPreview": "Αδυναμία εμφάνισης προεπισκόπησης",
@ -281,14 +291,15 @@
"howto": "Ακολουθήστε τους οδηγούς μας", "howto": "Ακολουθήστε τους οδηγούς μας",
"or": "ή", "or": "ή",
"preventBinding": "Αποτροπή δέσμευσης βέλων", "preventBinding": "Αποτροπή δέσμευσης βέλων",
"shapes": "Σχήματα", "tools": "",
"shortcuts": "Συντομεύσεις πληκτρολογίου", "shortcuts": "Συντομεύσεις πληκτρολογίου",
"textFinish": "Ολοκλήρωση επεξεργασίας (επεξεργαστής κειμένου)", "textFinish": "Ολοκλήρωση επεξεργασίας (επεξεργαστής κειμένου)",
"textNewLine": "Προσθήκη νέας γραμμής (επεξεργαστής κειμένου)", "textNewLine": "Προσθήκη νέας γραμμής (επεξεργαστής κειμένου)",
"title": "Βοήθεια", "title": "Βοήθεια",
"view": "Προβολή", "view": "Προβολή",
"zoomToFit": "Zoom ώστε να χωρέσουν όλα τα στοιχεία", "zoomToFit": "Zoom ώστε να χωρέσουν όλα τα στοιχεία",
"zoomToSelection": "Ζουμ στην επιλογή" "zoomToSelection": "Ζουμ στην επιλογή",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Καθαρισμός καμβά" "title": "Καθαρισμός καμβά"

View File

@ -9,6 +9,7 @@
"copy": "Copy", "copy": "Copy",
"copyAsPng": "Copy to clipboard as PNG", "copyAsPng": "Copy to clipboard as PNG",
"copyAsSvg": "Copy to clipboard as SVG", "copyAsSvg": "Copy to clipboard as SVG",
"copyText": "Copy to clipboard as text",
"bringForward": "Bring forward", "bringForward": "Bring forward",
"sendToBack": "Send to back", "sendToBack": "Send to back",
"bringToFront": "Bring to front", "bringToFront": "Bring to front",
@ -112,6 +113,12 @@
"edit": "Edit link", "edit": "Edit link",
"create": "Create link", "create": "Create link",
"label": "Link" "label": "Link"
},
"elementLock": {
"lock": "Lock",
"unlock": "Unlock",
"lockAll": "Lock all",
"unlockAll": "Unlock all"
} }
}, },
"buttons": { "buttons": {
@ -160,12 +167,11 @@
"couldNotLoadInvalidFile": "Couldn't load invalid file", "couldNotLoadInvalidFile": "Couldn't load invalid file",
"importBackendFailed": "Importing from backend failed.", "importBackendFailed": "Importing from backend failed.",
"cannotExportEmptyCanvas": "Cannot export empty canvas.", "cannotExportEmptyCanvas": "Cannot export empty canvas.",
"couldNotCopyToClipboard": "Couldn't copy to clipboard. Try using Chrome browser.", "couldNotCopyToClipboard": "Couldn't copy to clipboard.",
"decryptFailed": "Couldn't decrypt data.", "decryptFailed": "Couldn't decrypt data.",
"uploadedSecurly": "The upload has been secured with end-to-end encryption, which means that Excalidraw server and third parties can't read the content.", "uploadedSecurly": "The upload has been secured with end-to-end encryption, which means that Excalidraw server and third parties can't read the content.",
"loadSceneOverridePrompt": "Loading external drawing will replace your existing content. Do you wish to continue?", "loadSceneOverridePrompt": "Loading external drawing will replace your existing content. Do you wish to continue?",
"collabStopOverridePrompt": "Stopping the session will overwrite your previous, locally stored drawing. Are you sure?\n\n(If you want to keep your local drawing, simply close the browser tab instead.)", "collabStopOverridePrompt": "Stopping the session will overwrite your previous, locally stored drawing. Are you sure?\n\n(If you want to keep your local drawing, simply close the browser tab instead.)",
"errorLoadingLibrary": "There was an error loading the third party library.",
"errorAddingToLibrary": "Couldn't add item to the library", "errorAddingToLibrary": "Couldn't add item to the library",
"errorRemovingFromLibrary": "Couldn't remove item from the library", "errorRemovingFromLibrary": "Couldn't remove item from the library",
"confirmAddLibrary": "This will add {{numShapes}} shape(s) to your library. Are you sure?", "confirmAddLibrary": "This will add {{numShapes}} shape(s) to your library. Are you sure?",
@ -182,7 +188,8 @@
"fileTooBig": "File is too big. Maximum allowed size is {{maxSize}}.", "fileTooBig": "File is too big. Maximum allowed size is {{maxSize}}.",
"svgImageInsertError": "Couldn't insert SVG image. The SVG markup looks invalid.", "svgImageInsertError": "Couldn't insert SVG image. The SVG markup looks invalid.",
"invalidSVGString": "Invalid SVG.", "invalidSVGString": "Invalid SVG.",
"cannotResolveCollabServer": "Couldn't connect to the collab server. Please reload the page and try again." "cannotResolveCollabServer": "Couldn't connect to the collab server. Please reload the page and try again.",
"importLibraryError": "Couldn't load library"
}, },
"toolBar": { "toolBar": {
"selection": "Selection", "selection": "Selection",
@ -291,7 +298,8 @@
"title": "Help", "title": "Help",
"view": "View", "view": "View",
"zoomToFit": "Zoom to fit all elements", "zoomToFit": "Zoom to fit all elements",
"zoomToSelection": "Zoom to selection" "zoomToSelection": "Zoom to selection",
"toggleElementLock": "Lock/unlock selection"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Clear canvas" "title": "Clear canvas"
@ -335,7 +343,6 @@
"noteItems": "Each library item must have its own name so it's filterable. The following library items will be included:", "noteItems": "Each library item must have its own name so it's filterable. The following library items will be included:",
"atleastOneLibItem": "Please select at least one library item to get started" "atleastOneLibItem": "Please select at least one library item to get started"
}, },
"publishSuccessDialog": { "publishSuccessDialog": {
"title": "Library submitted", "title": "Library submitted",
"content": "Thank you {{authorName}}. Your library has been submitted for review. You can track the status", "content": "Thank you {{authorName}}. Your library has been submitted for review. You can track the status",

View File

@ -9,6 +9,7 @@
"copy": "Copiar", "copy": "Copiar",
"copyAsPng": "Copiar al portapapeles como PNG", "copyAsPng": "Copiar al portapapeles como PNG",
"copyAsSvg": "Copiar al portapapeles como SVG", "copyAsSvg": "Copiar al portapapeles como SVG",
"copyText": "",
"bringForward": "Traer hacia delante", "bringForward": "Traer hacia delante",
"sendToBack": "Enviar al fondo", "sendToBack": "Enviar al fondo",
"bringToFront": "Traer al frente", "bringToFront": "Traer al frente",
@ -107,10 +108,17 @@
"decreaseFontSize": "Disminuir tamaño de letra", "decreaseFontSize": "Disminuir tamaño de letra",
"increaseFontSize": "Aumentar el tamaño de letra", "increaseFontSize": "Aumentar el tamaño de letra",
"unbindText": "Desvincular texto", "unbindText": "Desvincular texto",
"bindText": "Vincular texto al contenedor",
"link": { "link": {
"edit": "Editar enlace", "edit": "Editar enlace",
"create": "Crear enlace", "create": "Crear enlace",
"label": "Enlace" "label": "Enlace"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "No se pudo cargar el archivo no válido", "couldNotLoadInvalidFile": "No se pudo cargar el archivo no válido",
"importBackendFailed": "La importación falló.", "importBackendFailed": "La importación falló.",
"cannotExportEmptyCanvas": "No se puede exportar un lienzo vació", "cannotExportEmptyCanvas": "No se puede exportar un lienzo vació",
"couldNotCopyToClipboard": "No se ha podido copiar al portapapeles, intente usar Chrome como navegador.", "couldNotCopyToClipboard": "No se pudo copiar al portapapeles.",
"decryptFailed": "No se pudieron descifrar los datos.", "decryptFailed": "No se pudieron descifrar los datos.",
"uploadedSecurly": "La carga ha sido asegurada con cifrado de principio a fin, lo que significa que el servidor de Excalidraw y terceros no pueden leer el contenido.", "uploadedSecurly": "La carga ha sido asegurada con cifrado de principio a fin, lo que significa que el servidor de Excalidraw y terceros no pueden leer el contenido.",
"loadSceneOverridePrompt": "Si carga este dibujo externo, reemplazará el que tiene. ¿Desea continuar?", "loadSceneOverridePrompt": "Si carga este dibujo externo, reemplazará el que tiene. ¿Desea continuar?",
@ -181,7 +189,7 @@
"fileTooBig": "Archivo demasiado grande. El tamaño máximo permitido es {{maxSize}}.", "fileTooBig": "Archivo demasiado grande. El tamaño máximo permitido es {{maxSize}}.",
"svgImageInsertError": "No se pudo insertar la imagen SVG. El código SVG parece inválido.", "svgImageInsertError": "No se pudo insertar la imagen SVG. El código SVG parece inválido.",
"invalidSVGString": "SVG no válido.", "invalidSVGString": "SVG no válido.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "No se pudo conectar al servidor colaborador. Por favor, vuelva a cargar la página y vuelva a intentarlo."
}, },
"toolBar": { "toolBar": {
"selection": "Selección", "selection": "Selección",
@ -196,7 +204,8 @@
"library": "Biblioteca", "library": "Biblioteca",
"lock": "Mantener la herramienta seleccionada activa después de dibujar", "lock": "Mantener la herramienta seleccionada activa después de dibujar",
"penMode": "Evitar el zoom de pellizco y aceptar la entrada libre sólo desde el lápiz", "penMode": "Evitar el zoom de pellizco y aceptar la entrada libre sólo desde el lápiz",
"link": "Añadir/Actualizar enlace para una forma seleccionada" "link": "Añadir/Actualizar enlace para una forma seleccionada",
"eraser": "Borrar"
}, },
"headings": { "headings": {
"canvasActions": "Acciones del lienzo", "canvasActions": "Acciones del lienzo",
@ -221,7 +230,8 @@
"placeImage": "Haga clic para colocar la imagen o haga clic y arrastre para establecer su tamaño manualmente", "placeImage": "Haga clic para colocar la imagen o haga clic y arrastre para establecer su tamaño manualmente",
"publishLibrary": "Publica tu propia biblioteca", "publishLibrary": "Publica tu propia biblioteca",
"bindTextToElement": "Presione Entrar para agregar", "bindTextToElement": "Presione Entrar para agregar",
"deepBoxSelect": "Mantén CtrlOrCmd para seleccionar en profundidad, y para evitar arrastrar" "deepBoxSelect": "Mantén CtrlOrCmd para seleccionar en profundidad, y para evitar arrastrar",
"eraserRevert": "Mantenga pulsado Alt para revertir los elementos marcados para su eliminación"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "No se puede mostrar la vista previa", "cannotShowPreview": "No se puede mostrar la vista previa",
@ -281,14 +291,15 @@
"howto": "Siga nuestras guías", "howto": "Siga nuestras guías",
"or": "o", "or": "o",
"preventBinding": "Evitar yuxtaposición de flechas", "preventBinding": "Evitar yuxtaposición de flechas",
"shapes": "Formas", "tools": "Herramientas",
"shortcuts": "Atajos del teclado", "shortcuts": "Atajos del teclado",
"textFinish": "Finalizar edición (editor de texto)", "textFinish": "Finalizar edición (editor de texto)",
"textNewLine": "Añadir nueva linea (editor de texto)", "textNewLine": "Añadir nueva linea (editor de texto)",
"title": "Ayuda", "title": "Ayuda",
"view": "Vista", "view": "Vista",
"zoomToFit": "Ajustar la vista para mostrar todos los elementos", "zoomToFit": "Ajustar la vista para mostrar todos los elementos",
"zoomToSelection": "Zoom a la selección" "zoomToSelection": "Zoom a la selección",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Borrar lienzo" "title": "Borrar lienzo"

View File

@ -9,6 +9,7 @@
"copy": "Kopiatu", "copy": "Kopiatu",
"copyAsPng": "Kopiatu arbelera PNG gisa", "copyAsPng": "Kopiatu arbelera PNG gisa",
"copyAsSvg": "Kopiatu arbelera SVG gisa", "copyAsSvg": "Kopiatu arbelera SVG gisa",
"copyText": "Kopiatu arbelera testu gisa",
"bringForward": "Ekarri aurrerago", "bringForward": "Ekarri aurrerago",
"sendToBack": "Eraman atzera", "sendToBack": "Eraman atzera",
"bringToFront": "Ekarri aurrera", "bringToFront": "Ekarri aurrera",
@ -64,7 +65,7 @@
"cartoonist": "Marrazkilaria", "cartoonist": "Marrazkilaria",
"fileTitle": "Fitxategi izena", "fileTitle": "Fitxategi izena",
"colorPicker": "Kolore-hautatzailea", "colorPicker": "Kolore-hautatzailea",
"canvasColors": "", "canvasColors": "Oihalean erabilita",
"canvasBackground": "Oihalaren atzeko planoa", "canvasBackground": "Oihalaren atzeko planoa",
"drawingCanvas": "Marrazteko oihala", "drawingCanvas": "Marrazteko oihala",
"layers": "Geruzak", "layers": "Geruzak",
@ -107,10 +108,17 @@
"decreaseFontSize": "Txikitu letra tamaina", "decreaseFontSize": "Txikitu letra tamaina",
"increaseFontSize": "Handitu letra tamaina", "increaseFontSize": "Handitu letra tamaina",
"unbindText": "Askatu testua", "unbindText": "Askatu testua",
"bindText": "Lotu testua edukiontziari",
"link": { "link": {
"edit": "Editatu esteka", "edit": "Editatu esteka",
"create": "Sortu esteka", "create": "Sortu esteka",
"label": "Esteka" "label": "Esteka"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -181,7 +189,7 @@
"fileTooBig": "Fitxategia handiegia da. Onartutako gehienezko tamaina {{maxSize}} da.", "fileTooBig": "Fitxategia handiegia da. Onartutako gehienezko tamaina {{maxSize}} da.",
"svgImageInsertError": "Ezin izan da SVG irudia txertatu. SVG markak baliogabea dirudi.", "svgImageInsertError": "Ezin izan da SVG irudia txertatu. SVG markak baliogabea dirudi.",
"invalidSVGString": "SVG baliogabea.", "invalidSVGString": "SVG baliogabea.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "Ezin izan da elkarlaneko zerbitzarira konektatu. Mesedez, berriro kargatu orria eta saiatu berriro."
}, },
"toolBar": { "toolBar": {
"selection": "Hautapena", "selection": "Hautapena",
@ -196,7 +204,8 @@
"library": "Liburutegia", "library": "Liburutegia",
"lock": "Mantendu aktibo hautatutako tresna marraztu ondoren", "lock": "Mantendu aktibo hautatutako tresna marraztu ondoren",
"penMode": "Saihestu txikiagotzea eta onartu marrazte libreko idazketa solik arkatza bidez", "penMode": "Saihestu txikiagotzea eta onartu marrazte libreko idazketa solik arkatza bidez",
"link": "Gehitu / Eguneratu esteka hautatutako forma baterako" "link": "Gehitu / Eguneratu esteka hautatutako forma baterako",
"eraser": "Borragoma"
}, },
"headings": { "headings": {
"canvasActions": "Canvas ekintzak", "canvasActions": "Canvas ekintzak",
@ -221,7 +230,8 @@
"placeImage": "Egin klik irudia kokatzeko, edo egin klik eta arrastatu bere tamaina eskuz ezartzeko", "placeImage": "Egin klik irudia kokatzeko, edo egin klik eta arrastatu bere tamaina eskuz ezartzeko",
"publishLibrary": "Argitaratu zure liburutegia", "publishLibrary": "Argitaratu zure liburutegia",
"bindTextToElement": "Sakatu Sartu testua gehitzeko", "bindTextToElement": "Sakatu Sartu testua gehitzeko",
"deepBoxSelect": "Eutsi Ctrl edo Cmd sakatuta aukeraketa sakona egiteko eta arrastatzea saihesteko" "deepBoxSelect": "Eutsi Ctrl edo Cmd sakatuta aukeraketa sakona egiteko eta arrastatzea saihesteko",
"eraserRevert": "Eduki Alt sakatuta ezabatzeko markatutako elementuak leheneratzeko"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Ezin da oihala aurreikusi", "cannotShowPreview": "Ezin da oihala aurreikusi",
@ -281,14 +291,15 @@
"howto": "Jarraitu gure gidak", "howto": "Jarraitu gure gidak",
"or": "edo", "or": "edo",
"preventBinding": "Saihestu gezien gainjartzea", "preventBinding": "Saihestu gezien gainjartzea",
"shapes": "Formak", "tools": "Tresnak",
"shortcuts": "Laster-teklak", "shortcuts": "Laster-teklak",
"textFinish": "Bukatu edizioa (testu editorea)", "textFinish": "Bukatu edizioa (testu editorea)",
"textNewLine": "Gehitu lerro berri bat (testu editorea)", "textNewLine": "Gehitu lerro berri bat (testu editorea)",
"title": "Laguntza", "title": "Laguntza",
"view": "Bistaratu", "view": "Bistaratu",
"zoomToFit": "Egin zoom elementu guztiak ikusteko", "zoomToFit": "Egin zoom elementu guztiak ikusteko",
"zoomToSelection": "Zooma hautapenera" "zoomToSelection": "Zooma hautapenera",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Garbitu oihala" "title": "Garbitu oihala"

View File

@ -9,6 +9,7 @@
"copy": "کپی", "copy": "کپی",
"copyAsPng": "کپی در حافطه موقت به صورت PNG", "copyAsPng": "کپی در حافطه موقت به صورت PNG",
"copyAsSvg": "کپی در حافطه موقت به صورت SVG", "copyAsSvg": "کپی در حافطه موقت به صورت SVG",
"copyText": "",
"bringForward": "جلو آوردن", "bringForward": "جلو آوردن",
"sendToBack": "پس فرستادن", "sendToBack": "پس فرستادن",
"bringToFront": "جلو آوردن", "bringToFront": "جلو آوردن",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "عدم توانایی در بازگذاری فایل نامعتبر", "couldNotLoadInvalidFile": "عدم توانایی در بازگذاری فایل نامعتبر",
"importBackendFailed": "بارگیری از پشت صحنه با شکست مواجه شد.", "importBackendFailed": "بارگیری از پشت صحنه با شکست مواجه شد.",
"cannotExportEmptyCanvas": "بوم خالی قابل تبدیل نیست.", "cannotExportEmptyCanvas": "بوم خالی قابل تبدیل نیست.",
"couldNotCopyToClipboard": "کپی نشد. از مرورگر Chrome استفاده کنید.", "couldNotCopyToClipboard": "",
"decryptFailed": "رمزگشایی داده ها امکان پذیر نیست.", "decryptFailed": "رمزگشایی داده ها امکان پذیر نیست.",
"uploadedSecurly": "آپلود با رمزگذاری دو طرفه انجام میشود، به این معنی که سرور Excalidraw و اشخاص ثالث نمی توانند مطالب شما را بخوانند.", "uploadedSecurly": "آپلود با رمزگذاری دو طرفه انجام میشود، به این معنی که سرور Excalidraw و اشخاص ثالث نمی توانند مطالب شما را بخوانند.",
"loadSceneOverridePrompt": "بارگزاری یک طرح خارجی محتوای فعلی رو از بین میبرد. آیا میخواهید ادامه دهید؟", "loadSceneOverridePrompt": "بارگزاری یک طرح خارجی محتوای فعلی رو از بین میبرد. آیا میخواهید ادامه دهید؟",
@ -196,7 +204,8 @@
"library": "کتابخانه", "library": "کتابخانه",
"lock": "ابزار انتخاب شده را بعد از کشیدن نگه دار", "lock": "ابزار انتخاب شده را بعد از کشیدن نگه دار",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "عملیات روی بوم", "canvasActions": "عملیات روی بوم",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "پیش نمایش نشان داده نمی شود", "cannotShowPreview": "پیش نمایش نشان داده نمی شود",
@ -281,14 +291,15 @@
"howto": "راهنمای ما را دنبال کنید", "howto": "راهنمای ما را دنبال کنید",
"or": "یا", "or": "یا",
"preventBinding": "مانع شدن از چسبیدن فلش ها", "preventBinding": "مانع شدن از چسبیدن فلش ها",
"shapes": "شکل‌ها", "tools": "",
"shortcuts": "میانبرهای صفحه کلید", "shortcuts": "میانبرهای صفحه کلید",
"textFinish": "پایان ویرایش (ویرایشگر متن)", "textFinish": "پایان ویرایش (ویرایشگر متن)",
"textNewLine": "افزودن خط جدید (ویرایشگر متن)", "textNewLine": "افزودن خط جدید (ویرایشگر متن)",
"title": "راهنما", "title": "راهنما",
"view": "مشاهده", "view": "مشاهده",
"zoomToFit": "بزرگنمایی برای دیدن تمام آیتم ها", "zoomToFit": "بزرگنمایی برای دیدن تمام آیتم ها",
"zoomToSelection": "بزرگنمایی قسمت انتخاب شده" "zoomToSelection": "بزرگنمایی قسمت انتخاب شده",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "Kopioi", "copy": "Kopioi",
"copyAsPng": "Kopioi leikepöydälle PNG-tiedostona", "copyAsPng": "Kopioi leikepöydälle PNG-tiedostona",
"copyAsSvg": "Kopioi leikepöydälle SVG-tiedostona", "copyAsSvg": "Kopioi leikepöydälle SVG-tiedostona",
"copyText": "Kopioi tekstinä",
"bringForward": "Tuo eteenpäin", "bringForward": "Tuo eteenpäin",
"sendToBack": "Vie taakse", "sendToBack": "Vie taakse",
"bringToFront": "Tuo eteen", "bringToFront": "Tuo eteen",
@ -64,7 +65,7 @@
"cartoonist": "Sarjakuva", "cartoonist": "Sarjakuva",
"fileTitle": "Tiedostonimi", "fileTitle": "Tiedostonimi",
"colorPicker": "Värin valinta", "colorPicker": "Värin valinta",
"canvasColors": "", "canvasColors": "Käytössä piirtoalueella",
"canvasBackground": "Piirtoalueen tausta", "canvasBackground": "Piirtoalueen tausta",
"drawingCanvas": "Piirtoalue", "drawingCanvas": "Piirtoalue",
"layers": "Tasot", "layers": "Tasot",
@ -106,11 +107,18 @@
"excalidrawLib": "Excalidraw kirjasto", "excalidrawLib": "Excalidraw kirjasto",
"decreaseFontSize": "Pienennä kirjasinkokoa", "decreaseFontSize": "Pienennä kirjasinkokoa",
"increaseFontSize": "Kasvata kirjasinkokoa", "increaseFontSize": "Kasvata kirjasinkokoa",
"unbindText": "", "unbindText": "Irroita teksti",
"bindText": "Kiinnitä teksti säiliöön",
"link": { "link": {
"edit": "Muokkaa linkkiä", "edit": "Muokkaa linkkiä",
"create": "Luo linkki", "create": "Luo linkki",
"label": "Linkki" "label": "Linkki"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Virheellistä tiedostoa ei voitu avata", "couldNotLoadInvalidFile": "Virheellistä tiedostoa ei voitu avata",
"importBackendFailed": "Palvelimelta tuonti epäonnistui.", "importBackendFailed": "Palvelimelta tuonti epäonnistui.",
"cannotExportEmptyCanvas": "Tyhjää piirtoaluetta ei voi viedä.", "cannotExportEmptyCanvas": "Tyhjää piirtoaluetta ei voi viedä.",
"couldNotCopyToClipboard": "Leikepöydälle kopiointi epäonnistui. Kokeile Chrome-selainta.", "couldNotCopyToClipboard": "Leikepöydälle vieminen epäonnistui.",
"decryptFailed": "Salauksen purkaminen epäonnistui.", "decryptFailed": "Salauksen purkaminen epäonnistui.",
"uploadedSecurly": "Lähetys on turvattu päästä-päähän-salauksella. Excalidrawin palvelin ja kolmannet osapuolet eivät voi lukea sisältöä.", "uploadedSecurly": "Lähetys on turvattu päästä-päähän-salauksella. Excalidrawin palvelin ja kolmannet osapuolet eivät voi lukea sisältöä.",
"loadSceneOverridePrompt": "Ulkopuolisen piirroksen lataaminen korvaa nykyisen sisältösi. Jatketaanko?", "loadSceneOverridePrompt": "Ulkopuolisen piirroksen lataaminen korvaa nykyisen sisältösi. Jatketaanko?",
@ -181,7 +189,7 @@
"fileTooBig": "Tiedosto on liian suuri. Suurin sallittu koko on {{maxSize}}.", "fileTooBig": "Tiedosto on liian suuri. Suurin sallittu koko on {{maxSize}}.",
"svgImageInsertError": "SVG- kuvaa ei voitu lisätä. Tiedoston SVG-sisältö näyttää virheelliseltä.", "svgImageInsertError": "SVG- kuvaa ei voitu lisätä. Tiedoston SVG-sisältö näyttää virheelliseltä.",
"invalidSVGString": "Virheellinen SVG.", "invalidSVGString": "Virheellinen SVG.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "Yhteyden muodostaminen collab-palvelimeen epäonnistui. Virkistä sivu ja yritä uudelleen."
}, },
"toolBar": { "toolBar": {
"selection": "Valinta", "selection": "Valinta",
@ -196,7 +204,8 @@
"library": "Kirjasto", "library": "Kirjasto",
"lock": "Pidä valittu työkalu aktiivisena piirron jälkeen", "lock": "Pidä valittu työkalu aktiivisena piirron jälkeen",
"penMode": "Estä nipistyszoomaus ja vastaanota ainoastaan kynällä piirretty", "penMode": "Estä nipistyszoomaus ja vastaanota ainoastaan kynällä piirretty",
"link": "Lisää/päivitä linkki valitulle muodolle" "link": "Lisää/päivitä linkki valitulle muodolle",
"eraser": "Poistotyökalu"
}, },
"headings": { "headings": {
"canvasActions": "Piirtoalueen toiminnot", "canvasActions": "Piirtoalueen toiminnot",
@ -221,7 +230,8 @@
"placeImage": "Klikkaa asettaaksesi kuvan, tai klikkaa ja raahaa asettaaksesi sen koon manuaalisesti", "placeImage": "Klikkaa asettaaksesi kuvan, tai klikkaa ja raahaa asettaaksesi sen koon manuaalisesti",
"publishLibrary": "Julkaise oma kirjasto", "publishLibrary": "Julkaise oma kirjasto",
"bindTextToElement": "Lisää tekstiä painamalla enter", "bindTextToElement": "Lisää tekstiä painamalla enter",
"deepBoxSelect": "" "deepBoxSelect": "Käytä syvävalintaa ja estä raahaus painamalla CtrlOrCmd",
"eraserRevert": "Pidä Alt alaspainettuna, kumotaksesi merkittyjen elementtien poistamisen"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Esikatselua ei voitu näyttää", "cannotShowPreview": "Esikatselua ei voitu näyttää",
@ -268,8 +278,8 @@
"helpDialog": { "helpDialog": {
"blog": "Lue blogiamme", "blog": "Lue blogiamme",
"click": "klikkaa", "click": "klikkaa",
"deepSelect": "", "deepSelect": "Syvävalinta",
"deepBoxSelect": "", "deepBoxSelect": "Käytä syvävalintaa ja estä raahaus",
"curvedArrow": "Kaareva nuoli", "curvedArrow": "Kaareva nuoli",
"curvedLine": "Kaareva viiva", "curvedLine": "Kaareva viiva",
"documentation": "Käyttöohjeet", "documentation": "Käyttöohjeet",
@ -281,14 +291,15 @@
"howto": "Seuraa oppaitamme", "howto": "Seuraa oppaitamme",
"or": "tai", "or": "tai",
"preventBinding": "Estä nuolten kiinnitys", "preventBinding": "Estä nuolten kiinnitys",
"shapes": "Muodot", "tools": "Työkalut",
"shortcuts": "Pikanäppäimet", "shortcuts": "Pikanäppäimet",
"textFinish": "Lopeta muokkaus (tekstieditori)", "textFinish": "Lopeta muokkaus (tekstieditori)",
"textNewLine": "Lisää uusi rivi (tekstieditori)", "textNewLine": "Lisää uusi rivi (tekstieditori)",
"title": "Ohjeet", "title": "Ohjeet",
"view": "Näkymä", "view": "Näkymä",
"zoomToFit": "Näytä kaikki elementit", "zoomToFit": "Näytä kaikki elementit",
"zoomToSelection": "Näytä valinta" "zoomToSelection": "Näytä valinta",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Pyyhi piirtoalue" "title": "Pyyhi piirtoalue"

View File

@ -9,6 +9,7 @@
"copy": "Copier", "copy": "Copier",
"copyAsPng": "Copier dans le presse-papier en PNG", "copyAsPng": "Copier dans le presse-papier en PNG",
"copyAsSvg": "Copier dans le presse-papier en SVG", "copyAsSvg": "Copier dans le presse-papier en SVG",
"copyText": "Copier dans le presse-papiers comme du texte",
"bringForward": "Envoyer vers l'avant", "bringForward": "Envoyer vers l'avant",
"sendToBack": "Mettre en arrière-plan", "sendToBack": "Mettre en arrière-plan",
"bringToFront": "Mettre au premier plan", "bringToFront": "Mettre au premier plan",
@ -64,7 +65,7 @@
"cartoonist": "Caricaturiste", "cartoonist": "Caricaturiste",
"fileTitle": "Nom du fichier", "fileTitle": "Nom du fichier",
"colorPicker": "Sélecteur de couleur", "colorPicker": "Sélecteur de couleur",
"canvasColors": "", "canvasColors": "Utilisé sur la zone de dessin",
"canvasBackground": "Arrière-plan du canevas", "canvasBackground": "Arrière-plan du canevas",
"drawingCanvas": "Zone de dessin", "drawingCanvas": "Zone de dessin",
"layers": "Calques", "layers": "Calques",
@ -107,10 +108,17 @@
"decreaseFontSize": "Réduire la taille de police", "decreaseFontSize": "Réduire la taille de police",
"increaseFontSize": "Augmenter la taille de police", "increaseFontSize": "Augmenter la taille de police",
"unbindText": "Délier le texte", "unbindText": "Délier le texte",
"bindText": "Lier le texte au conteneur",
"link": { "link": {
"edit": "Modifier le lien", "edit": "Modifier le lien",
"create": "Créer un lien", "create": "Créer un lien",
"label": "Lien" "label": "Lien"
},
"elementLock": {
"lock": "Verrouiller",
"unlock": "Déverrouiller",
"lockAll": "Tout verrouiller",
"unlockAll": "Tout déverouiller"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Impossible de charger un fichier invalide", "couldNotLoadInvalidFile": "Impossible de charger un fichier invalide",
"importBackendFailed": "L'importation depuis le backend a échoué.", "importBackendFailed": "L'importation depuis le backend a échoué.",
"cannotExportEmptyCanvas": "Impossible d'exporter un canevas vide.", "cannotExportEmptyCanvas": "Impossible d'exporter un canevas vide.",
"couldNotCopyToClipboard": "Impossible de copier dans le presse-papier. Essayez d'utiliser le navigateur Chrome.", "couldNotCopyToClipboard": "Impossible de copier dans le presse-papiers.",
"decryptFailed": "Les données n'ont pas pu être déchiffrées.", "decryptFailed": "Les données n'ont pas pu être déchiffrées.",
"uploadedSecurly": "Le téléchargement a été sécurisé avec un chiffrement de bout en bout, ce qui signifie que ni Excalidraw ni personne d'autre ne peut en lire le contenu.", "uploadedSecurly": "Le téléchargement a été sécurisé avec un chiffrement de bout en bout, ce qui signifie que ni Excalidraw ni personne d'autre ne peut en lire le contenu.",
"loadSceneOverridePrompt": "Le chargement d'un dessin externe remplacera votre contenu actuel. Souhaitez-vous continuer ?", "loadSceneOverridePrompt": "Le chargement d'un dessin externe remplacera votre contenu actuel. Souhaitez-vous continuer ?",
@ -181,7 +189,7 @@
"fileTooBig": "Le fichier est trop volumineux. La taille maximale autorisée est de {{maxSize}}.", "fileTooBig": "Le fichier est trop volumineux. La taille maximale autorisée est de {{maxSize}}.",
"svgImageInsertError": "Impossible d'insérer l'image SVG. Le balisage SVG semble invalide.", "svgImageInsertError": "Impossible d'insérer l'image SVG. Le balisage SVG semble invalide.",
"invalidSVGString": "SVG invalide.", "invalidSVGString": "SVG invalide.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "Impossible de se connecter au serveur collaboratif. Veuillez recharger la page et réessayer."
}, },
"toolBar": { "toolBar": {
"selection": "Sélection", "selection": "Sélection",
@ -196,7 +204,8 @@
"library": "Bibliothèque", "library": "Bibliothèque",
"lock": "Garder l'outil sélectionné actif après le dessin", "lock": "Garder l'outil sélectionné actif après le dessin",
"penMode": "Empêcher le zoom tactile et accepter la saisie libre uniquement à partir du stylet", "penMode": "Empêcher le zoom tactile et accepter la saisie libre uniquement à partir du stylet",
"link": "Ajouter/mettre à jour le lien pour une forme sélectionnée" "link": "Ajouter/mettre à jour le lien pour une forme sélectionnée",
"eraser": "Gomme"
}, },
"headings": { "headings": {
"canvasActions": "Actions du canevas", "canvasActions": "Actions du canevas",
@ -221,7 +230,8 @@
"placeImage": "Cliquez pour placer l'image, ou cliquez et faites glisser pour définir sa taille manuellement", "placeImage": "Cliquez pour placer l'image, ou cliquez et faites glisser pour définir sa taille manuellement",
"publishLibrary": "Publier votre propre bibliothèque", "publishLibrary": "Publier votre propre bibliothèque",
"bindTextToElement": "Appuyer sur Entrée pour ajouter du texte", "bindTextToElement": "Appuyer sur Entrée pour ajouter du texte",
"deepBoxSelect": "Maintenir CtrlOuCmd pour sélectionner dans les groupes, et empêcher le déplacement" "deepBoxSelect": "Maintenir CtrlOuCmd pour sélectionner dans les groupes, et empêcher le déplacement",
"eraserRevert": "Maintenez Alt enfoncé pour annuler les éléments marqués pour suppression"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Impossible dafficher laperçu", "cannotShowPreview": "Impossible dafficher laperçu",
@ -281,14 +291,15 @@
"howto": "Suivez nos guides", "howto": "Suivez nos guides",
"or": "ou", "or": "ou",
"preventBinding": "Empêcher la liaison de flèche", "preventBinding": "Empêcher la liaison de flèche",
"shapes": "Formes", "tools": "Outils",
"shortcuts": "Raccourcis clavier", "shortcuts": "Raccourcis clavier",
"textFinish": "Terminer l'édition (éditeur de texte)", "textFinish": "Terminer l'édition (éditeur de texte)",
"textNewLine": "Ajouter une nouvelle ligne (éditeur de texte)", "textNewLine": "Ajouter une nouvelle ligne (éditeur de texte)",
"title": "Aide", "title": "Aide",
"view": "Affichage", "view": "Affichage",
"zoomToFit": "Zoomer pour voir tous les éléments", "zoomToFit": "Zoomer pour voir tous les éléments",
"zoomToSelection": "Zoomer sur la sélection" "zoomToSelection": "Zoomer sur la sélection",
"toggleElementLock": "Verrouiller/déverrouiller la sélection"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Effacer la zone de dessin" "title": "Effacer la zone de dessin"

View File

@ -9,6 +9,7 @@
"copy": "העתק", "copy": "העתק",
"copyAsPng": "העתק ללוח כ PNG", "copyAsPng": "העתק ללוח כ PNG",
"copyAsSvg": "העתק ללוח כ SVG", "copyAsSvg": "העתק ללוח כ SVG",
"copyText": "",
"bringForward": "הבא שכבה קדימה", "bringForward": "הבא שכבה קדימה",
"sendToBack": "העבר לסוף", "sendToBack": "העבר לסוף",
"bringToFront": "העבר לחזית", "bringToFront": "העבר לחזית",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "לא ניתן לטעון קובץ שאיננו תואם", "couldNotLoadInvalidFile": "לא ניתן לטעון קובץ שאיננו תואם",
"importBackendFailed": "ייבוא מהשרת נכשל.", "importBackendFailed": "ייבוא מהשרת נכשל.",
"cannotExportEmptyCanvas": "לא ניתן לייצא לוח ריק.", "cannotExportEmptyCanvas": "לא ניתן לייצא לוח ריק.",
"couldNotCopyToClipboard": "לא ניתן להעתיק ללוח. נסה להשתמש בדפדפן Chrome.", "couldNotCopyToClipboard": "",
"decryptFailed": "לא ניתן לפענח מידע.", "decryptFailed": "לא ניתן לפענח מידע.",
"uploadedSecurly": "ההעלאה הוצפנה מקצה לקצה, ולכן שרת Excalidraw וצד שלישי לא יכולים לקרוא את התוכן.", "uploadedSecurly": "ההעלאה הוצפנה מקצה לקצה, ולכן שרת Excalidraw וצד שלישי לא יכולים לקרוא את התוכן.",
"loadSceneOverridePrompt": "טעינה של ציור חיצוני תחליף את התוכן הקיים שלך. האם תרצה להמשיך?", "loadSceneOverridePrompt": "טעינה של ציור חיצוני תחליף את התוכן הקיים שלך. האם תרצה להמשיך?",
@ -196,7 +204,8 @@
"library": "ספריה", "library": "ספריה",
"lock": "השאר את הכלי הנבחר פעיל גם לאחר סיום הציור", "lock": "השאר את הכלי הנבחר פעיל גם לאחר סיום הציור",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "פעולות הלוח", "canvasActions": "פעולות הלוח",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "לא הצלחנו להציג את התצוגה המקדימה", "cannotShowPreview": "לא הצלחנו להציג את התצוגה המקדימה",
@ -281,14 +291,15 @@
"howto": "עקוב אחר המדריכים שלנו", "howto": "עקוב אחר המדריכים שלנו",
"or": "או", "or": "או",
"preventBinding": "למנוע נעיצת חיצים", "preventBinding": "למנוע נעיצת חיצים",
"shapes": "צורות", "tools": "",
"shortcuts": "קיצורי מקלדת", "shortcuts": "קיצורי מקלדת",
"textFinish": "סיים עריכה (טקסט)", "textFinish": "סיים עריכה (טקסט)",
"textNewLine": "הוסף שורה חדשה (טקסט)", "textNewLine": "הוסף שורה חדשה (טקסט)",
"title": "עזרה", "title": "עזרה",
"view": "תצוגה", "view": "תצוגה",
"zoomToFit": "גלילה להצגת כל האלמנטים במסך", "zoomToFit": "גלילה להצגת כל האלמנטים במסך",
"zoomToSelection": "התמקד בבחירה" "zoomToSelection": "התמקד בבחירה",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "प्रतिलिपि", "copy": "प्रतिलिपि",
"copyAsPng": "क्लिपबोर्ड पर कॉपी करें ,पीएनजी के रूप में", "copyAsPng": "क्लिपबोर्ड पर कॉपी करें ,पीएनजी के रूप में",
"copyAsSvg": "क्लिपबोर्ड पर कॉपी करें,एसवीजी के रूप में", "copyAsSvg": "क्लिपबोर्ड पर कॉपी करें,एसवीजी के रूप में",
"copyText": "लेखन के रूप में पटल पर कॉपी करें",
"bringForward": "सामने लाएं", "bringForward": "सामने लाएं",
"sendToBack": "पीछे भेजें", "sendToBack": "पीछे भेजें",
"bringToFront": "सामने लाएँ", "bringToFront": "सामने लाएँ",
@ -64,7 +65,7 @@
"cartoonist": "व्यंग्य चित्रकार", "cartoonist": "व्यंग्य चित्रकार",
"fileTitle": "फ़ाइल का नाम", "fileTitle": "फ़ाइल का नाम",
"colorPicker": "रंग चयन", "colorPicker": "रंग चयन",
"canvasColors": "", "canvasColors": "कॅनवास पर प्रयोगित",
"canvasBackground": "कैनवास बैकग्राउंड", "canvasBackground": "कैनवास बैकग्राउंड",
"drawingCanvas": "कैनवास बना रहे हैं", "drawingCanvas": "कैनवास बना रहे हैं",
"layers": "परतें", "layers": "परतें",
@ -79,7 +80,7 @@
"group": "समूह चयन", "group": "समूह चयन",
"ungroup": "समूह चयन असमूहीकृत करें", "ungroup": "समूह चयन असमूहीकृत करें",
"collaborators": "सहयोगी", "collaborators": "सहयोगी",
"showGrid": "", "showGrid": "ग्रिड दिखाएं",
"addToLibrary": "लाइब्रेरी से जोड़ें", "addToLibrary": "लाइब्रेरी से जोड़ें",
"removeFromLibrary": "लाइब्रेरी से निकालें", "removeFromLibrary": "लाइब्रेरी से निकालें",
"libraryLoadingMessage": "लाइब्रेरी खुल रही है", "libraryLoadingMessage": "लाइब्रेरी खुल रही है",
@ -107,10 +108,17 @@
"decreaseFontSize": "आकार घटाइऐ", "decreaseFontSize": "आकार घटाइऐ",
"increaseFontSize": "फ़ॉन्ट आकार बढ़ाएँ", "increaseFontSize": "फ़ॉन्ट आकार बढ़ाएँ",
"unbindText": "", "unbindText": "",
"bindText": "लेखन को कोश से जोड़े",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "ताले में रखें",
"unlock": "ताले से बाहर",
"lockAll": "सब ताले के अंदर रखे",
"unlockAll": "सब ताले के बाहर निकाले"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "अमान्य फ़ाइल लोड नहीं की जा सकी", "couldNotLoadInvalidFile": "अमान्य फ़ाइल लोड नहीं की जा सकी",
"importBackendFailed": "बैकएंड से आयात करना विफल रहा।", "importBackendFailed": "बैकएंड से आयात करना विफल रहा।",
"cannotExportEmptyCanvas": "खाली कैनवास निर्यात नहीं कर सकता।", "cannotExportEmptyCanvas": "खाली कैनवास निर्यात नहीं कर सकता।",
"couldNotCopyToClipboard": "क्लिपबोर्ड पर कॉपी नहीं किया जा सका। Chrome ब्राउज़र का उपयोग करने का प्रयास करें।", "couldNotCopyToClipboard": "",
"decryptFailed": "डेटा को डिक्रिप्ट नहीं किया जा सका।", "decryptFailed": "डेटा को डिक्रिप्ट नहीं किया जा सका।",
"uploadedSecurly": "अपलोड को एंड-टू-एंड एन्क्रिप्शन के साथ सुरक्षित किया गया है, जिसका मतलब है कि एक्सक्लूसिव सर्वर और थर्ड पार्टी कंटेंट नहीं पढ़ सकते हैं।", "uploadedSecurly": "अपलोड को एंड-टू-एंड एन्क्रिप्शन के साथ सुरक्षित किया गया है, जिसका मतलब है कि एक्सक्लूसिव सर्वर और थर्ड पार्टी कंटेंट नहीं पढ़ सकते हैं।",
"loadSceneOverridePrompt": "लोड हो रहा है बाहरी ड्राइंग आपके मौजूदा सामग्री को बदल देगा। क्या आप जारी रखना चाहते हैं?", "loadSceneOverridePrompt": "लोड हो रहा है बाहरी ड्राइंग आपके मौजूदा सामग्री को बदल देगा। क्या आप जारी रखना चाहते हैं?",
@ -181,7 +189,7 @@
"fileTooBig": "", "fileTooBig": "",
"svgImageInsertError": "", "svgImageInsertError": "",
"invalidSVGString": "", "invalidSVGString": "",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "कॉलेब सर्वर से कनेक्शन नहीं हो पा रहा. कृपया पृष्ठ को पुनः लाने का प्रयास करे."
}, },
"toolBar": { "toolBar": {
"selection": "चयन", "selection": "चयन",
@ -196,7 +204,8 @@
"library": "लाइब्रेरी", "library": "लाइब्रेरी",
"lock": "ड्राइंग के बाद चयनित टूल को सक्रिय रखें", "lock": "ड्राइंग के बाद चयनित टूल को सक्रिय रखें",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": "रबड़"
}, },
"headings": { "headings": {
"canvasActions": "कैनवास क्रिया", "canvasActions": "कैनवास क्रिया",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": "मिटाने के लिए चुने हुए चीजों को ना चुनने के लिए Alt साथ में दबाए"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "पूर्वावलोकन नहीं दिखा सकते हैं", "cannotShowPreview": "पूर्वावलोकन नहीं दिखा सकते हैं",
@ -281,14 +291,15 @@
"howto": "हमारे गाइड का पालन करें", "howto": "हमारे गाइड का पालन करें",
"or": "या", "or": "या",
"preventBinding": "तीर बंधन रोकें", "preventBinding": "तीर बंधन रोकें",
"shapes": "आकृतियाँ", "tools": "औज़ार",
"shortcuts": "कीबोर्ड के शॉर्टकट्स", "shortcuts": "कीबोर्ड के शॉर्टकट्स",
"textFinish": "", "textFinish": "",
"textNewLine": "", "textNewLine": "",
"title": "मदद", "title": "मदद",
"view": "दृश्य", "view": "दृश्य",
"zoomToFit": "सभी तत्वों को फिट करने के लिए ज़ूम करें", "zoomToFit": "सभी तत्वों को फिट करने के लिए ज़ूम करें",
"zoomToSelection": "चयन तक ज़ूम करे" "zoomToSelection": "चयन तक ज़ूम करे",
"toggleElementLock": "ताले के अंदर/बाहर चुनाव"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""
@ -371,15 +382,15 @@
"selection": "" "selection": ""
}, },
"colors": { "colors": {
"ffffff": "", "ffffff": "सफेद",
"f8f9fa": "", "f8f9fa": "",
"f1f3f5": "", "f1f3f5": "",
"fff5f5": "", "fff5f5": "",
"fff0f6": "", "fff0f6": "",
"f8f0fc": "", "f8f0fc": "अंगूरी 0",
"f3f0ff": "", "f3f0ff": "",
"edf2ff": "", "edf2ff": "नील 0",
"e7f5ff": "", "e7f5ff": "नीला 0",
"e3fafc": "", "e3fafc": "",
"e6fcf5": "", "e6fcf5": "",
"ebfbee": "", "ebfbee": "",

View File

@ -9,6 +9,7 @@
"copy": "Másolás", "copy": "Másolás",
"copyAsPng": "Vágólapra másolás mint PNG", "copyAsPng": "Vágólapra másolás mint PNG",
"copyAsSvg": "Vágólapra másolás mint SVG", "copyAsSvg": "Vágólapra másolás mint SVG",
"copyText": "",
"bringForward": "Előrébb hozás", "bringForward": "Előrébb hozás",
"sendToBack": "Hátraküldés", "sendToBack": "Hátraküldés",
"bringToFront": "Előrehozás", "bringToFront": "Előrehozás",
@ -107,10 +108,17 @@
"decreaseFontSize": "Betűméret csökkentése", "decreaseFontSize": "Betűméret csökkentése",
"increaseFontSize": "Betűméret növelése", "increaseFontSize": "Betűméret növelése",
"unbindText": "Szövegkötés feloldása", "unbindText": "Szövegkötés feloldása",
"bindText": "",
"link": { "link": {
"edit": "Hivatkozás szerkesztése", "edit": "Hivatkozás szerkesztése",
"create": "Hivatkozás létrehozása", "create": "Hivatkozás létrehozása",
"label": "Hivatkozás" "label": "Hivatkozás"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Nem sikerült betölteni a helytelen fájlt", "couldNotLoadInvalidFile": "Nem sikerült betölteni a helytelen fájlt",
"importBackendFailed": "Nem sikerült betölteni a szerverről.", "importBackendFailed": "Nem sikerült betölteni a szerverről.",
"cannotExportEmptyCanvas": "Üres vászont nem lehet exportálni.", "cannotExportEmptyCanvas": "Üres vászont nem lehet exportálni.",
"couldNotCopyToClipboard": "Nem sikerült vágólapra menteni. Próbáld meg Chrome böngészővel.", "couldNotCopyToClipboard": "",
"decryptFailed": "Nem sikerült visszafejteni a titkosított adatot.", "decryptFailed": "Nem sikerült visszafejteni a titkosított adatot.",
"uploadedSecurly": "A feltöltést végpontok közötti titkosítással biztosítottuk, ami azt jelenti, hogy egy harmadik fél nem tudja megnézni a tartalmát, beleértve az Excalidraw szervereit is.", "uploadedSecurly": "A feltöltést végpontok közötti titkosítással biztosítottuk, ami azt jelenti, hogy egy harmadik fél nem tudja megnézni a tartalmát, beleértve az Excalidraw szervereit is.",
"loadSceneOverridePrompt": "A betöltött külső rajz felül fogja írnia meglévőt. Szeretnéd folytatni?", "loadSceneOverridePrompt": "A betöltött külső rajz felül fogja írnia meglévőt. Szeretnéd folytatni?",
@ -196,7 +204,8 @@
"library": "Könyvtár", "library": "Könyvtár",
"lock": "Rajzolás után az aktív eszközt tartsa kijelölve", "lock": "Rajzolás után az aktív eszközt tartsa kijelölve",
"penMode": "Akadályozza meg a kicsinyítést, és csak tollról fogadja el a szabadkézi bevitelt", "penMode": "Akadályozza meg a kicsinyítést, és csak tollról fogadja el a szabadkézi bevitelt",
"link": "Hivatkozás hozzáadása/frissítése a kiválasztott alakzathoz" "link": "Hivatkozás hozzáadása/frissítése a kiválasztott alakzathoz",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "Vászon műveletek", "canvasActions": "Vászon műveletek",
@ -221,7 +230,8 @@
"placeImage": "Kattints a kép elhelyezéséhez, vagy kattints és méretezd manuálisan", "placeImage": "Kattints a kép elhelyezéséhez, vagy kattints és méretezd manuálisan",
"publishLibrary": "Tedd közzé saját könyvtáradat", "publishLibrary": "Tedd közzé saját könyvtáradat",
"bindTextToElement": "Nyomd meg az Entert szöveg hozzáadáshoz", "bindTextToElement": "Nyomd meg az Entert szöveg hozzáadáshoz",
"deepBoxSelect": "Tartsd lenyomva a Ctrl/Cmd billentyűt a mély kijelöléshez és a húzás megakadályozásához" "deepBoxSelect": "Tartsd lenyomva a Ctrl/Cmd billentyűt a mély kijelöléshez és a húzás megakadályozásához",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Előnézet nem jeleníthető meg", "cannotShowPreview": "Előnézet nem jeleníthető meg",
@ -281,14 +291,15 @@
"howto": "Kövesd az útmutatóinkat", "howto": "Kövesd az útmutatóinkat",
"or": "vagy", "or": "vagy",
"preventBinding": "A nyíl ne ragadjon", "preventBinding": "A nyíl ne ragadjon",
"shapes": "Alakzatok", "tools": "",
"shortcuts": "Gyorsbillentyűk", "shortcuts": "Gyorsbillentyűk",
"textFinish": "Szerkesztés befejezése (szöveg)", "textFinish": "Szerkesztés befejezése (szöveg)",
"textNewLine": "Új sor hozzáadása (szöveg)", "textNewLine": "Új sor hozzáadása (szöveg)",
"title": "Segítség", "title": "Segítség",
"view": "Nézet", "view": "Nézet",
"zoomToFit": "Az összes elem látótérbe hozása", "zoomToFit": "Az összes elem látótérbe hozása",
"zoomToSelection": "Kijelölésre nagyítás" "zoomToSelection": "Kijelölésre nagyítás",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Rajzvászon alaphelyzetbe" "title": "Rajzvászon alaphelyzetbe"

View File

@ -9,6 +9,7 @@
"copy": "Salin", "copy": "Salin",
"copyAsPng": "Salin ke papan klip sebagai PNG", "copyAsPng": "Salin ke papan klip sebagai PNG",
"copyAsSvg": "Salin ke papan klip sebagai SVG", "copyAsSvg": "Salin ke papan klip sebagai SVG",
"copyText": "Salin ke papan klip sebagai teks",
"bringForward": "Bawa maju", "bringForward": "Bawa maju",
"sendToBack": "Kirim ke belakang", "sendToBack": "Kirim ke belakang",
"bringToFront": "Bawa ke depan", "bringToFront": "Bawa ke depan",
@ -107,10 +108,17 @@
"decreaseFontSize": "Kecilkan ukuran font", "decreaseFontSize": "Kecilkan ukuran font",
"increaseFontSize": "Besarkan ukuran font", "increaseFontSize": "Besarkan ukuran font",
"unbindText": "Lepas teks", "unbindText": "Lepas teks",
"bindText": "Kunci teks ke kontainer",
"link": { "link": {
"edit": "Edit tautan", "edit": "Edit tautan",
"create": "Buat tautan", "create": "Buat tautan",
"label": "Tautan" "label": "Tautan"
},
"elementLock": {
"lock": "Kunci",
"unlock": "Lepas",
"lockAll": "Kunci semua",
"unlockAll": "Lepas semua"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Tidak dapat memuat berkas yang tidak valid", "couldNotLoadInvalidFile": "Tidak dapat memuat berkas yang tidak valid",
"importBackendFailed": "Gagal mengimpor dari backend", "importBackendFailed": "Gagal mengimpor dari backend",
"cannotExportEmptyCanvas": "Tidak bisa mengekspor kanvas kosong", "cannotExportEmptyCanvas": "Tidak bisa mengekspor kanvas kosong",
"couldNotCopyToClipboard": "Tidak bisa menyalin ke papan klip. Coba gunakan Browser Chrome", "couldNotCopyToClipboard": "Tidak bisa menyalin ke papan klip.",
"decryptFailed": "Tidak dapat mengdekripsi data.", "decryptFailed": "Tidak dapat mengdekripsi data.",
"uploadedSecurly": "Pengunggahan ini telah diamankan menggunakan enkripsi end-to-end, artinya server Excalidraw dan pihak ketiga tidak data membaca nya", "uploadedSecurly": "Pengunggahan ini telah diamankan menggunakan enkripsi end-to-end, artinya server Excalidraw dan pihak ketiga tidak data membaca nya",
"loadSceneOverridePrompt": "Memuat gambar external akan mengganti konten Anda yang ada. Apakah Anda ingin melanjutkan?", "loadSceneOverridePrompt": "Memuat gambar external akan mengganti konten Anda yang ada. Apakah Anda ingin melanjutkan?",
@ -196,7 +204,8 @@
"library": "Pustaka", "library": "Pustaka",
"lock": "Biarkan alat yang dipilih aktif setelah menggambar", "lock": "Biarkan alat yang dipilih aktif setelah menggambar",
"penMode": "Cegah jepit perbesar dan terima hanya input freedraw dari pena", "penMode": "Cegah jepit perbesar dan terima hanya input freedraw dari pena",
"link": "Tambah/Perbarui tautan untuk bentuk yang dipilih" "link": "Tambah/Perbarui tautan untuk bentuk yang dipilih",
"eraser": "Penghapus"
}, },
"headings": { "headings": {
"canvasActions": "Opsi Kanvas", "canvasActions": "Opsi Kanvas",
@ -221,7 +230,8 @@
"placeImage": "Klik untuk tempatkan gambar, atau klik dan jatuhkan untuk tetapkan ukuran secara manual", "placeImage": "Klik untuk tempatkan gambar, atau klik dan jatuhkan untuk tetapkan ukuran secara manual",
"publishLibrary": "Terbitkan pustaka Anda", "publishLibrary": "Terbitkan pustaka Anda",
"bindTextToElement": "Tekan enter untuk tambahkan teks", "bindTextToElement": "Tekan enter untuk tambahkan teks",
"deepBoxSelect": "Tekan Ctrl atau Cmd untuk memilih yang di dalam, dan mencegah penggeseran" "deepBoxSelect": "Tekan Ctrl atau Cmd untuk memilih yang di dalam, dan mencegah penggeseran",
"eraserRevert": "Tahan Alt untuk mengembalikan elemen yang ditandai untuk dihapus"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Tidak dapat menampilkan pratinjau", "cannotShowPreview": "Tidak dapat menampilkan pratinjau",
@ -281,14 +291,15 @@
"howto": "Ikuti panduan kami", "howto": "Ikuti panduan kami",
"or": "atau", "or": "atau",
"preventBinding": "Cegah pengikatan panah", "preventBinding": "Cegah pengikatan panah",
"shapes": "Bentuk", "tools": "Alat",
"shortcuts": "Pintasan keyboard", "shortcuts": "Pintasan keyboard",
"textFinish": "Selesai mengedit (editor teks)", "textFinish": "Selesai mengedit (editor teks)",
"textNewLine": "Tambahkan garis baru (editor teks)", "textNewLine": "Tambahkan garis baru (editor teks)",
"title": "Bantuan", "title": "Bantuan",
"view": "Tampilan", "view": "Tampilan",
"zoomToFit": "Perbesar agar sesuai dengan semua elemen", "zoomToFit": "Perbesar agar sesuai dengan semua elemen",
"zoomToSelection": "Perbesar ke seleksi" "zoomToSelection": "Perbesar ke seleksi",
"toggleElementLock": "Kunci/lepas seleksi"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Hapus kanvas" "title": "Hapus kanvas"

View File

@ -9,6 +9,7 @@
"copy": "Copia", "copy": "Copia",
"copyAsPng": "Copia negli appunti come PNG", "copyAsPng": "Copia negli appunti come PNG",
"copyAsSvg": "Copia negli appunti come SVG", "copyAsSvg": "Copia negli appunti come SVG",
"copyText": "Copia negli appunti come testo",
"bringForward": "Porta avanti", "bringForward": "Porta avanti",
"sendToBack": "Manda in fondo", "sendToBack": "Manda in fondo",
"bringToFront": "Porta in cima", "bringToFront": "Porta in cima",
@ -107,10 +108,17 @@
"decreaseFontSize": "Riduci dimensione dei caratteri", "decreaseFontSize": "Riduci dimensione dei caratteri",
"increaseFontSize": "Aumenta la dimensione dei caratteri", "increaseFontSize": "Aumenta la dimensione dei caratteri",
"unbindText": "Scollega testo", "unbindText": "Scollega testo",
"bindText": "Associa il testo al container",
"link": { "link": {
"edit": "Modifica link", "edit": "Modifica link",
"create": "Crea link", "create": "Crea link",
"label": "Link" "label": "Link"
},
"elementLock": {
"lock": "Blocca",
"unlock": "Sblocca",
"lockAll": "Blocca tutto",
"unlockAll": "Sblocca tutto"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Impossibile caricare un file no valido", "couldNotLoadInvalidFile": "Impossibile caricare un file no valido",
"importBackendFailed": "Importazione dal server fallita.", "importBackendFailed": "Importazione dal server fallita.",
"cannotExportEmptyCanvas": "Non è possibile esportare una tela vuota.", "cannotExportEmptyCanvas": "Non è possibile esportare una tela vuota.",
"couldNotCopyToClipboard": "Impossibile copiare negli appunti. Provare usando il browser Chrome.", "couldNotCopyToClipboard": "Impossibile copiare negli appunti.",
"decryptFailed": "Impossibile decriptare i dati.", "decryptFailed": "Impossibile decriptare i dati.",
"uploadedSecurly": "L'upload è stato protetto con la crittografia end-to-end, il che significa che il server Excalidraw e terze parti non possono leggere il contenuto.", "uploadedSecurly": "L'upload è stato protetto con la crittografia end-to-end, il che significa che il server Excalidraw e terze parti non possono leggere il contenuto.",
"loadSceneOverridePrompt": "Se carichi questo disegno esterno, sostituirà quello che hai. Vuoi continuare?", "loadSceneOverridePrompt": "Se carichi questo disegno esterno, sostituirà quello che hai. Vuoi continuare?",
@ -196,7 +204,8 @@
"library": "Libreria", "library": "Libreria",
"lock": "Mantieni lo strumento selezionato attivo dopo aver disegnato", "lock": "Mantieni lo strumento selezionato attivo dopo aver disegnato",
"penMode": "Impedisci il pinch-zoom e accetta l'input di disegno libero solo dalla penna", "penMode": "Impedisci il pinch-zoom e accetta l'input di disegno libero solo dalla penna",
"link": "Aggiungi/ aggiorna il link per una forma selezionata" "link": "Aggiungi/ aggiorna il link per una forma selezionata",
"eraser": "Gomma"
}, },
"headings": { "headings": {
"canvasActions": "Azioni sulla Tela", "canvasActions": "Azioni sulla Tela",
@ -221,7 +230,8 @@
"placeImage": "Fai click per posizionare l'immagine, o click e trascina per impostarne la dimensione manualmente", "placeImage": "Fai click per posizionare l'immagine, o click e trascina per impostarne la dimensione manualmente",
"publishLibrary": "Pubblica la tua libreria", "publishLibrary": "Pubblica la tua libreria",
"bindTextToElement": "Premi invio per aggiungere il testo", "bindTextToElement": "Premi invio per aggiungere il testo",
"deepBoxSelect": "Tieni premuto CtrlOCmd per selezionare in profondità e per impedire il trascinamento" "deepBoxSelect": "Tieni premuto CtrlOCmd per selezionare in profondità e per impedire il trascinamento",
"eraserRevert": "Tieni premuto Alt per ripristinare gli elementi contrassegnati per l'eliminazione"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Impossibile visualizzare l'anteprima", "cannotShowPreview": "Impossibile visualizzare l'anteprima",
@ -281,14 +291,15 @@
"howto": "Segui le nostre guide", "howto": "Segui le nostre guide",
"or": "oppure", "or": "oppure",
"preventBinding": "Impedisci legame della freccia", "preventBinding": "Impedisci legame della freccia",
"shapes": "Forme", "tools": "Stumenti",
"shortcuts": "Scorciatoie da tastiera", "shortcuts": "Scorciatoie da tastiera",
"textFinish": "Completa la modifica (editor di testo)", "textFinish": "Completa la modifica (editor di testo)",
"textNewLine": "Aggiungi nuova riga (editor di testo)", "textNewLine": "Aggiungi nuova riga (editor di testo)",
"title": "Guida", "title": "Guida",
"view": "Vista", "view": "Vista",
"zoomToFit": "Adatta zoom per mostrare tutti gli elementi", "zoomToFit": "Adatta zoom per mostrare tutti gli elementi",
"zoomToSelection": "Zoom alla selezione" "zoomToSelection": "Zoom alla selezione",
"toggleElementLock": "Blocca/sblocca selezione"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Svuota la tela" "title": "Svuota la tela"

View File

@ -9,6 +9,7 @@
"copy": "コピー", "copy": "コピー",
"copyAsPng": "PNGとしてクリップボードへコピー", "copyAsPng": "PNGとしてクリップボードへコピー",
"copyAsSvg": "SVGとしてクリップボードへコピー", "copyAsSvg": "SVGとしてクリップボードへコピー",
"copyText": "",
"bringForward": "前面に移動", "bringForward": "前面に移動",
"sendToBack": "最背面に移動", "sendToBack": "最背面に移動",
"bringToFront": "最前面に移動", "bringToFront": "最前面に移動",
@ -16,17 +17,17 @@
"delete": "削除", "delete": "削除",
"copyStyles": "スタイルのコピー", "copyStyles": "スタイルのコピー",
"pasteStyles": "スタイルの貼り付け", "pasteStyles": "スタイルの貼り付け",
"stroke": "線の色", "stroke": "線",
"background": "背景の色", "background": "背景",
"fill": "塗りつぶし", "fill": "塗りつぶし",
"strokeWidth": "線の", "strokeWidth": "線の太さ",
"strokeStyle": "線の種類", "strokeStyle": "線の種類",
"strokeStyle_solid": "実線", "strokeStyle_solid": "実線",
"strokeStyle_dashed": "破線", "strokeStyle_dashed": "破線",
"strokeStyle_dotted": "点線", "strokeStyle_dotted": "点線",
"sloppiness": "線のばらつき", "sloppiness": "ばらつき加減",
"opacity": "透明度", "opacity": "透明度",
"textAlign": "テキストの配置", "textAlign": "文字の配置",
"edges": "角", "edges": "角",
"sharp": "四角", "sharp": "四角",
"round": "丸", "round": "丸",
@ -64,7 +65,7 @@
"cartoonist": "漫画風", "cartoonist": "漫画風",
"fileTitle": "ファイル名", "fileTitle": "ファイル名",
"colorPicker": "色選択", "colorPicker": "色選択",
"canvasColors": "", "canvasColors": "キャンバス上で使用",
"canvasBackground": "キャンバスの背景", "canvasBackground": "キャンバスの背景",
"drawingCanvas": "キャンバスの描画", "drawingCanvas": "キャンバスの描画",
"layers": "レイヤー", "layers": "レイヤー",
@ -106,11 +107,18 @@
"excalidrawLib": "Excalidrawライブラリ", "excalidrawLib": "Excalidrawライブラリ",
"decreaseFontSize": "フォントサイズを縮小", "decreaseFontSize": "フォントサイズを縮小",
"increaseFontSize": "フォントサイズを拡大", "increaseFontSize": "フォントサイズを拡大",
"unbindText": "", "unbindText": "テキストのバインド解除",
"bindText": "テキストをコンテナにバインド",
"link": { "link": {
"edit": "リンクを編集", "edit": "リンクを編集",
"create": "リンクを作成", "create": "リンクを作成",
"label": "リンク" "label": "リンク"
},
"elementLock": {
"lock": "ロック",
"unlock": "ロック解除",
"lockAll": "すべてロック",
"unlockAll": "すべてのロックを解除"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "無効なファイルを読み込めませんでした。", "couldNotLoadInvalidFile": "無効なファイルを読み込めませんでした。",
"importBackendFailed": "サーバーからの読み込みに失敗しました。", "importBackendFailed": "サーバーからの読み込みに失敗しました。",
"cannotExportEmptyCanvas": "空のキャンバスはエクスポートできません。", "cannotExportEmptyCanvas": "空のキャンバスはエクスポートできません。",
"couldNotCopyToClipboard": "クリップボードにコピーできません。Google Chromeでお試しください。", "couldNotCopyToClipboard": "",
"decryptFailed": "データを復号できませんでした。", "decryptFailed": "データを復号できませんでした。",
"uploadedSecurly": "データのアップロードはエンドツーエンド暗号化によって保護されています。Excalidrawサーバーと第三者はデータの内容を見ることができません。", "uploadedSecurly": "データのアップロードはエンドツーエンド暗号化によって保護されています。Excalidrawサーバーと第三者はデータの内容を見ることができません。",
"loadSceneOverridePrompt": "外部図面を読み込むと、既存のコンテンツが置き換わります。続行しますか?", "loadSceneOverridePrompt": "外部図面を読み込むと、既存のコンテンツが置き換わります。続行しますか?",
@ -181,7 +189,7 @@
"fileTooBig": "ファイルが大きすぎます。許可される最大サイズは {{maxSize}} です。", "fileTooBig": "ファイルが大きすぎます。許可される最大サイズは {{maxSize}} です。",
"svgImageInsertError": "SVGイメージを挿入できませんでした。SVGマークアップは無効に見えます。", "svgImageInsertError": "SVGイメージを挿入できませんでした。SVGマークアップは無効に見えます。",
"invalidSVGString": "無効なSVGです。", "invalidSVGString": "無効なSVGです。",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "コラボレーションサーバに接続できませんでした。ページを再読み込みして、もう一度お試しください。"
}, },
"toolBar": { "toolBar": {
"selection": "選択", "selection": "選択",
@ -196,7 +204,8 @@
"library": "ライブラリ", "library": "ライブラリ",
"lock": "描画後も使用中のツールを選択したままにする", "lock": "描画後も使用中のツールを選択したままにする",
"penMode": "ピンチとズームを抑止し、ペンからのみ自由な入力を受け付けます", "penMode": "ピンチとズームを抑止し、ペンからのみ自由な入力を受け付けます",
"link": "" "link": "選択した図形のリンクを追加/更新",
"eraser": "消しゴム"
}, },
"headings": { "headings": {
"canvasActions": "キャンバス操作", "canvasActions": "キャンバス操作",
@ -221,7 +230,8 @@
"placeImage": "クリックして画像を配置するか、クリックしてドラッグしてサイズを手動で設定します", "placeImage": "クリックして画像を配置するか、クリックしてドラッグしてサイズを手動で設定します",
"publishLibrary": "自分のライブラリを公開", "publishLibrary": "自分のライブラリを公開",
"bindTextToElement": "Enterを押してテキストを追加", "bindTextToElement": "Enterを押してテキストを追加",
"deepBoxSelect": "" "deepBoxSelect": "CtrlOrCmd を押し続けることでドラッグを抑止し、深い選択を行う",
"eraserRevert": "Alt を押し続けることで削除マークされた要素を元に戻す"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "プレビューを表示できません", "cannotShowPreview": "プレビューを表示できません",
@ -268,8 +278,8 @@
"helpDialog": { "helpDialog": {
"blog": "公式ブログを読む", "blog": "公式ブログを読む",
"click": "クリック", "click": "クリック",
"deepSelect": "", "deepSelect": "深い選択",
"deepBoxSelect": "", "deepBoxSelect": "ボックス内の深い選択、およびドラッグの抑止",
"curvedArrow": "カーブした矢印", "curvedArrow": "カーブした矢印",
"curvedLine": "曲線", "curvedLine": "曲線",
"documentation": "ドキュメント", "documentation": "ドキュメント",
@ -281,14 +291,15 @@
"howto": "ヘルプ・マニュアル", "howto": "ヘルプ・マニュアル",
"or": "または", "or": "または",
"preventBinding": "矢印を結合しない", "preventBinding": "矢印を結合しない",
"shapes": "図形", "tools": "ツール",
"shortcuts": "キーボードショートカット", "shortcuts": "キーボードショートカット",
"textFinish": "編集を終了 (テキストエディタ)", "textFinish": "編集を終了 (テキストエディタ)",
"textNewLine": "新しい行を追加 (テキスト)", "textNewLine": "新しい行を追加 (テキスト)",
"title": "ヘルプ", "title": "ヘルプ",
"view": "表示", "view": "表示",
"zoomToFit": "すべての要素が収まるようにズーム", "zoomToFit": "すべての要素が収まるようにズーム",
"zoomToSelection": "選択要素にズーム" "zoomToSelection": "選択要素にズーム",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "キャンバスを消去" "title": "キャンバスを消去"
@ -326,10 +337,10 @@
}, },
"noteLicense": { "noteLicense": {
"pre": "提出することにより、ライブラリが次の下で公開されることに同意します: ", "pre": "提出することにより、ライブラリが次の下で公開されることに同意します: ",
"link": "MIT ライセンス", "link": "MIT ライセンス ",
"post": "つまり誰でも制限なく使えるということです" "post": "つまり誰でも制限なく使えるということです"
}, },
"noteItems": "", "noteItems": "各ライブラリ項目は、フィルタリングのために独自の名前を持つ必要があります。以下のライブラリアイテムが含まれます:",
"atleastOneLibItem": "開始するには少なくとも1つのライブラリ項目を選択してください" "atleastOneLibItem": "開始するには少なくとも1つのライブラリ項目を選択してください"
}, },
"publishSuccessDialog": { "publishSuccessDialog": {

View File

@ -9,6 +9,7 @@
"copy": "Nɣel", "copy": "Nɣel",
"copyAsPng": "Nɣel ɣer tecfawit am PNG", "copyAsPng": "Nɣel ɣer tecfawit am PNG",
"copyAsSvg": "Nɣel ɣer tecfawit am SVG", "copyAsSvg": "Nɣel ɣer tecfawit am SVG",
"copyText": "Nɣel ɣer tecfawit am uḍris",
"bringForward": "Awi ɣer sdat", "bringForward": "Awi ɣer sdat",
"sendToBack": "Awi s agilal", "sendToBack": "Awi s agilal",
"bringToFront": "Err ɣer deffir", "bringToFront": "Err ɣer deffir",
@ -64,7 +65,7 @@
"cartoonist": "", "cartoonist": "",
"fileTitle": "Isem n ufaylu", "fileTitle": "Isem n ufaylu",
"colorPicker": "Amafran n yini", "colorPicker": "Amafran n yini",
"canvasColors": "", "canvasColors": "Yettwaseqdec di teɣzut n usuneɣ",
"canvasBackground": "Agilal n teɣzut n usuneɣ", "canvasBackground": "Agilal n teɣzut n usuneɣ",
"drawingCanvas": "Taɣzut n usuneɣ", "drawingCanvas": "Taɣzut n usuneɣ",
"layers": "Tissiyin", "layers": "Tissiyin",
@ -107,10 +108,17 @@
"decreaseFontSize": "Senqes tiddi n tsefsit", "decreaseFontSize": "Senqes tiddi n tsefsit",
"increaseFontSize": "Sali tiddi n tsefsit", "increaseFontSize": "Sali tiddi n tsefsit",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "Ẓreg aseɣwen", "edit": "Ẓreg aseɣwen",
"create": "Snulfu-d aseɣwen", "create": "Snulfu-d aseɣwen",
"label": "Aseɣwen" "label": "Aseɣwen"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "D awezɣi asali n ufaylu armeɣtu", "couldNotLoadInvalidFile": "D awezɣi asali n ufaylu armeɣtu",
"importBackendFailed": "Takterḍ seg uɣawas n deffir ur teddi ara.", "importBackendFailed": "Takterḍ seg uɣawas n deffir ur teddi ara.",
"cannotExportEmptyCanvas": "D awezɣi asifeḍ n teɣzut n usuneɣ tilemt.", "cannotExportEmptyCanvas": "D awezɣi asifeḍ n teɣzut n usuneɣ tilemt.",
"couldNotCopyToClipboard": "D awezɣi anɣal ɣer tecfawit. Eɛreḍ ad tesqedceḍ iminig Chrome.", "couldNotCopyToClipboard": "Ulamek anɣal ɣer tecfawit.",
"decryptFailed": "D awezɣi tukksa n uwgelhen i yisefka.", "decryptFailed": "D awezɣi tukksa n uwgelhen i yisefka.",
"uploadedSecurly": "Asili yettwasɣelles s uwgelhen ixef s ixef, ayagi yebɣa ad d-yini belli aqeddac n Excalidraw akked medden ur zmiren ara ad ɣren agbur.", "uploadedSecurly": "Asili yettwasɣelles s uwgelhen ixef s ixef, ayagi yebɣa ad d-yini belli aqeddac n Excalidraw akked medden ur zmiren ara ad ɣren agbur.",
"loadSceneOverridePrompt": "Asali n wunuɣ uffiɣ ad isemselsi agbur-inek (m) yellan. Tebɣiḍ ad tkemmeleḍ?", "loadSceneOverridePrompt": "Asali n wunuɣ uffiɣ ad isemselsi agbur-inek (m) yellan. Tebɣiḍ ad tkemmeleḍ?",
@ -181,7 +189,7 @@
"fileTooBig": "Afaylu meqqer aṭas. Tiddi tafellayt yurgen d {{maxSize}}.", "fileTooBig": "Afaylu meqqer aṭas. Tiddi tafellayt yurgen d {{maxSize}}.",
"svgImageInsertError": "D awezɣi tugra n tugna SVG. Acraḍ SVG yettban-d d armeɣtu.", "svgImageInsertError": "D awezɣi tugra n tugna SVG. Acraḍ SVG yettban-d d armeɣtu.",
"invalidSVGString": "SVG armeɣtu.", "invalidSVGString": "SVG armeɣtu.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "Ulamek tuqqna s aqeddac n umyalel. Ma ulac uɣilif ales asali n usebter sakin eɛreḍ tikkelt-nniḍen."
}, },
"toolBar": { "toolBar": {
"selection": "Tafrayt", "selection": "Tafrayt",
@ -196,7 +204,8 @@
"library": "Tamkarḍit", "library": "Tamkarḍit",
"lock": "Eǧǧ afecku n tefrayt yermed mbaɛd asuneɣ", "lock": "Eǧǧ afecku n tefrayt yermed mbaɛd asuneɣ",
"penMode": "", "penMode": "",
"link": "Rnu/leqqem aseɣwen i talɣa yettwafernen" "link": "Rnu/leqqem aseɣwen i talɣa yettwafernen",
"eraser": "Sfeḍ"
}, },
"headings": { "headings": {
"canvasActions": "Tigawin n teɣzut n usuneɣ", "canvasActions": "Tigawin n teɣzut n usuneɣ",
@ -221,7 +230,8 @@
"placeImage": "Ssit akken ad tserseḍ tugna, neɣ ssit u zuɣer akken ad tesbaduḍ tiddi-ines s ufus", "placeImage": "Ssit akken ad tserseḍ tugna, neɣ ssit u zuɣer akken ad tesbaduḍ tiddi-ines s ufus",
"publishLibrary": "Siẓreg tamkarḍit-inek•inem", "publishLibrary": "Siẓreg tamkarḍit-inek•inem",
"bindTextToElement": "Ssed ɣef kcem akken ad ternuḍ aḍris", "bindTextToElement": "Ssed ɣef kcem akken ad ternuḍ aḍris",
"deepBoxSelect": "Ṭṭef CtrlOrCmd akken ad tferneḍ s telqey, yerna ad trewleḍ i uzuɣer" "deepBoxSelect": "Ṭṭef CtrlOrCmd akken ad tferneḍ s telqey, yerna ad trewleḍ i uzuɣer",
"eraserRevert": "Ssed Alt akken ad tsefsxeḍ iferdisen yettwacerḍen i tukksa"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Ulamek abeqqeḍ n teskant", "cannotShowPreview": "Ulamek abeqqeḍ n teskant",
@ -281,14 +291,15 @@
"howto": "Ḍfer imniren-nneɣ", "howto": "Ḍfer imniren-nneɣ",
"or": "neɣ", "or": "neɣ",
"preventBinding": "Seḥbes tuqqna n tneccabin", "preventBinding": "Seḥbes tuqqna n tneccabin",
"shapes": "Talɣiwin", "tools": "Ifecka",
"shortcuts": "Inegzumen n unasiw", "shortcuts": "Inegzumen n unasiw",
"textFinish": "Fak asiẓreg (amaẓrag n uḍris)", "textFinish": "Fak asiẓreg (amaẓrag n uḍris)",
"textNewLine": "Rnu ajerriḍ amaynut (amaẓrag n uḍris)", "textNewLine": "Rnu ajerriḍ amaynut (amaẓrag n uḍris)",
"title": "Tallelt", "title": "Tallelt",
"view": "Tamuɣli", "view": "Tamuɣli",
"zoomToFit": "Simɣur akken ad twliḍ akk iferdisen", "zoomToFit": "Simɣur akken ad twliḍ akk iferdisen",
"zoomToSelection": "Simɣur ɣer tefrayt" "zoomToSelection": "Simɣur ɣer tefrayt",
"toggleElementLock": "Sekkeṛ/kkes asekker i tefrayt"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Sfeḍ taɣzut n usuneɣ" "title": "Sfeḍ taɣzut n usuneɣ"

View File

@ -9,6 +9,7 @@
"copy": "Көшіру", "copy": "Көшіру",
"copyAsPng": "", "copyAsPng": "",
"copyAsSvg": "", "copyAsSvg": "",
"copyText": "",
"bringForward": "", "bringForward": "",
"sendToBack": "", "sendToBack": "",
"bringToFront": "", "bringToFront": "",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -196,7 +204,8 @@
"library": "", "library": "",
"lock": "", "lock": "",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "", "canvasActions": "",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "", "cannotShowPreview": "",
@ -281,14 +291,15 @@
"howto": "Біздің нұсқаулықтарды орындаңыз", "howto": "Біздің нұсқаулықтарды орындаңыз",
"or": "немесе", "or": "немесе",
"preventBinding": "Нұсқарды байланыстыруға жол бермеу", "preventBinding": "Нұсқарды байланыстыруға жол бермеу",
"shapes": "Пішіндер", "tools": "",
"shortcuts": "Пернетақта пәрмендері", "shortcuts": "Пернетақта пәрмендері",
"textFinish": "Өңдеуді аяқтау (мәтіндік редактор)", "textFinish": "Өңдеуді аяқтау (мәтіндік редактор)",
"textNewLine": "Жаңа жолға көшу (мәтіндік редактор)", "textNewLine": "Жаңа жолға көшу (мәтіндік редактор)",
"title": "Көмек", "title": "Көмек",
"view": "Көру", "view": "Көру",
"zoomToFit": "Барлық элементтердің көлеміне сәйкес үлкейту", "zoomToFit": "Барлық элементтердің көлеміне сәйкес үлкейту",
"zoomToSelection": "Таңдалғанды үлкейту" "zoomToSelection": "Таңдалғанды үлкейту",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "복사", "copy": "복사",
"copyAsPng": "클립보드로 PNG 이미지 복사", "copyAsPng": "클립보드로 PNG 이미지 복사",
"copyAsSvg": "클립보드로 SVG 이미지 복사", "copyAsSvg": "클립보드로 SVG 이미지 복사",
"copyText": "",
"bringForward": "앞으로 가져오기", "bringForward": "앞으로 가져오기",
"sendToBack": "맨 뒤로 보내기", "sendToBack": "맨 뒤로 보내기",
"bringToFront": "맨 앞으로 가져오기", "bringToFront": "맨 앞으로 가져오기",
@ -107,10 +108,17 @@
"decreaseFontSize": "폰트 사이즈 줄이기", "decreaseFontSize": "폰트 사이즈 줄이기",
"increaseFontSize": "폰트 사이즈 키우기", "increaseFontSize": "폰트 사이즈 키우기",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "유효하지 않은 파일입니다.", "couldNotLoadInvalidFile": "유효하지 않은 파일입니다.",
"importBackendFailed": "서버로부터 불러 오지 못했습니다.", "importBackendFailed": "서버로부터 불러 오지 못했습니다.",
"cannotExportEmptyCanvas": "빈 캔버스를 내보낼 수 없습니다.", "cannotExportEmptyCanvas": "빈 캔버스를 내보낼 수 없습니다.",
"couldNotCopyToClipboard": "클립 보드에 복사할 수 없습니다. Chrome 브라우저에서 시도해 주세요.", "couldNotCopyToClipboard": "",
"decryptFailed": "데이터를 복호화하지 못했습니다.", "decryptFailed": "데이터를 복호화하지 못했습니다.",
"uploadedSecurly": "업로드는 종단 간 암호화로 보호되므로 Excalidraw 서버 및 타사가 콘텐츠를 읽을 수 없습니다.", "uploadedSecurly": "업로드는 종단 간 암호화로 보호되므로 Excalidraw 서버 및 타사가 콘텐츠를 읽을 수 없습니다.",
"loadSceneOverridePrompt": "외부 파일을 불러 오면 기존 콘텐츠가 대체됩니다. 계속 진행할까요?", "loadSceneOverridePrompt": "외부 파일을 불러 오면 기존 콘텐츠가 대체됩니다. 계속 진행할까요?",
@ -196,7 +204,8 @@
"library": "라이브러리", "library": "라이브러리",
"lock": "선택된 도구 유지하기", "lock": "선택된 도구 유지하기",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "캔버스 동작", "canvasActions": "캔버스 동작",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "미리보기를 볼 수 없습니다", "cannotShowPreview": "미리보기를 볼 수 없습니다",
@ -281,14 +291,15 @@
"howto": "가이드 참고하기", "howto": "가이드 참고하기",
"or": "또는", "or": "또는",
"preventBinding": "화살표가 붙지 않게 하기", "preventBinding": "화살표가 붙지 않게 하기",
"shapes": "도형", "tools": "",
"shortcuts": "키보드 단축키", "shortcuts": "키보드 단축키",
"textFinish": "편집 완료 (텍스트 에디터)", "textFinish": "편집 완료 (텍스트 에디터)",
"textNewLine": "줄바꿈(텍스트 에디터)", "textNewLine": "줄바꿈(텍스트 에디터)",
"title": "도움말", "title": "도움말",
"view": "보기", "view": "보기",
"zoomToFit": "모든 요소가 보이도록 확대/축소", "zoomToFit": "모든 요소가 보이도록 확대/축소",
"zoomToSelection": "선택 영역으로 확대/축소" "zoomToSelection": "선택 영역으로 확대/축소",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "캔버스 지우기" "title": "캔버스 지우기"

View File

@ -9,6 +9,7 @@
"copy": "Kopijuoti", "copy": "Kopijuoti",
"copyAsPng": "", "copyAsPng": "",
"copyAsSvg": "", "copyAsSvg": "",
"copyText": "",
"bringForward": "", "bringForward": "",
"sendToBack": "", "sendToBack": "",
"bringToFront": "", "bringToFront": "",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -196,7 +204,8 @@
"library": "Biblioteka", "library": "Biblioteka",
"lock": "", "lock": "",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "", "canvasActions": "",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "", "cannotShowPreview": "",
@ -281,14 +291,15 @@
"howto": "", "howto": "",
"or": "", "or": "",
"preventBinding": "", "preventBinding": "",
"shapes": "Figūros", "tools": "",
"shortcuts": "", "shortcuts": "",
"textFinish": "", "textFinish": "",
"textNewLine": "", "textNewLine": "",
"title": "", "title": "",
"view": "", "view": "",
"zoomToFit": "", "zoomToFit": "",
"zoomToSelection": "" "zoomToSelection": "",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "Kopēt", "copy": "Kopēt",
"copyAsPng": "Kopēt starpliktuvē kā PNG", "copyAsPng": "Kopēt starpliktuvē kā PNG",
"copyAsSvg": "Kopēt starpliktuvē kā SVG", "copyAsSvg": "Kopēt starpliktuvē kā SVG",
"copyText": "Kopēt starpliktuvē kā tekstu",
"bringForward": "Pārvietot vienu slāni augstāk", "bringForward": "Pārvietot vienu slāni augstāk",
"sendToBack": "Pārvietot uz zemāko slāni", "sendToBack": "Pārvietot uz zemāko slāni",
"bringToFront": "Pārvietot uz virsējo slāni", "bringToFront": "Pārvietot uz virsējo slāni",
@ -107,10 +108,17 @@
"decreaseFontSize": "Samazināt fonta izmēru", "decreaseFontSize": "Samazināt fonta izmēru",
"increaseFontSize": "Palielināt fonta izmēru", "increaseFontSize": "Palielināt fonta izmēru",
"unbindText": "Atdalīt tekstu", "unbindText": "Atdalīt tekstu",
"bindText": "Piesaistīt tekstu figūrai",
"link": { "link": {
"edit": "Rediģēt saiti", "edit": "Rediģēt saiti",
"create": "Izveidot saiti", "create": "Izveidot saiti",
"label": "Saite" "label": "Saite"
},
"elementLock": {
"lock": "Fiksēt",
"unlock": "Atbrīvot",
"lockAll": "Fiksēt visu",
"unlockAll": "Atbrīvot visu"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Nevarēja ielādēt nederīgu datni", "couldNotLoadInvalidFile": "Nevarēja ielādēt nederīgu datni",
"importBackendFailed": "Ielāde no krātuves neizdevās.", "importBackendFailed": "Ielāde no krātuves neizdevās.",
"cannotExportEmptyCanvas": "Nevar eksportēt tukšu tāfeli.", "cannotExportEmptyCanvas": "Nevar eksportēt tukšu tāfeli.",
"couldNotCopyToClipboard": "Neizdevās kopēt starpliktuvē. Mēģiniet vēlreiz, izmantojot pārlūku Chrome.", "couldNotCopyToClipboard": "Nevarēja nokopēt starpliktuvē.",
"decryptFailed": "Nevarēja atšifrēt datus.", "decryptFailed": "Nevarēja atšifrēt datus.",
"uploadedSecurly": "Augšuplāde nodrošināta ar šifrēšanu no gala līdz galam, kas nozīmē, ka Excalidraw serveri un trešās puses nevar lasīt saturu.", "uploadedSecurly": "Augšuplāde nodrošināta ar šifrēšanu no gala līdz galam, kas nozīmē, ka Excalidraw serveri un trešās puses nevar lasīt saturu.",
"loadSceneOverridePrompt": "Ārēja satura ielāde aizstās jūsu pašreizējo saturu. Vai vēlaties turpināt?", "loadSceneOverridePrompt": "Ārēja satura ielāde aizstās jūsu pašreizējo saturu. Vai vēlaties turpināt?",
@ -196,7 +204,8 @@
"library": "Bibliotēka", "library": "Bibliotēka",
"lock": "Paturēt izvēlēto rīku pēc darbības", "lock": "Paturēt izvēlēto rīku pēc darbības",
"penMode": "Lietojot pildspalvu, bloķēt tuvināšanu un atļaut tikai zīmēšanu", "penMode": "Lietojot pildspalvu, bloķēt tuvināšanu un atļaut tikai zīmēšanu",
"link": "Pievienot/rediģēt atlasītās figūras saiti" "link": "Pievienot/rediģēt atlasītās figūras saiti",
"eraser": "Dzēšgumija"
}, },
"headings": { "headings": {
"canvasActions": "Tāfeles darbības", "canvasActions": "Tāfeles darbības",
@ -221,7 +230,8 @@
"placeImage": "Klikšķiniet, lai novietotu attēlu, vai spiediet un velciet, lai iestatītu tā izmēru", "placeImage": "Klikšķiniet, lai novietotu attēlu, vai spiediet un velciet, lai iestatītu tā izmēru",
"publishLibrary": "Publicēt savu bibliotēku", "publishLibrary": "Publicēt savu bibliotēku",
"bindTextToElement": "Spiediet ievades taustiņu, lai pievienotu tekstu", "bindTextToElement": "Spiediet ievades taustiņu, lai pievienotu tekstu",
"deepBoxSelect": "Turient nospiestu Ctrl vai Cmd, lai atlasītu dziļumā un lai nepieļautu objektu pavilkšanu" "deepBoxSelect": "Turient nospiestu Ctrl vai Cmd, lai atlasītu dziļumā un lai nepieļautu objektu pavilkšanu",
"eraserRevert": "Turiet Alt, lai noņemtu elementus no dzēsšanas atlases"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Nevar rādīt priekšskatījumu", "cannotShowPreview": "Nevar rādīt priekšskatījumu",
@ -232,7 +242,7 @@
"headingMain_pre": "Notikusi kļūda. Mēģiniet ", "headingMain_pre": "Notikusi kļūda. Mēģiniet ",
"headingMain_button": "pārlādēt lapu.", "headingMain_button": "pārlādēt lapu.",
"clearCanvasMessage": "Ja pārlādēšana nestrādā, mēģiniet ", "clearCanvasMessage": "Ja pārlādēšana nestrādā, mēģiniet ",
"clearCanvasMessage_button": "notīrīt tāfeli.", "clearCanvasMessage_button": "notīrot tāfeli.",
"clearCanvasCaveat": " Tas novedīs pie darba zaudēšanas ", "clearCanvasCaveat": " Tas novedīs pie darba zaudēšanas ",
"trackedToSentry_pre": "Kļūda ar kodu ", "trackedToSentry_pre": "Kļūda ar kodu ",
"trackedToSentry_post": " tika noteikta mūsu sistēmā.", "trackedToSentry_post": " tika noteikta mūsu sistēmā.",
@ -281,14 +291,15 @@
"howto": "Sekojiet mūsu instrukcijām", "howto": "Sekojiet mūsu instrukcijām",
"or": "vai", "or": "vai",
"preventBinding": "Novērst bultu piesaistīšanos", "preventBinding": "Novērst bultu piesaistīšanos",
"shapes": "Figūras", "tools": "Rīki",
"shortcuts": "Tastatūras saīsnes", "shortcuts": "Tastatūras saīsnes",
"textFinish": "Pabeigt rediģēšanu (teksta redaktorā)", "textFinish": "Pabeigt rediģēšanu (teksta redaktorā)",
"textNewLine": "Nākamā rindiņa (teksta redaktorā)", "textNewLine": "Nākamā rindiņa (teksta redaktorā)",
"title": "Palīdzība", "title": "Palīdzība",
"view": "Skatīt", "view": "Skatīt",
"zoomToFit": "Iestatīt mērogu, kas iekļauj visus elementus", "zoomToFit": "Iestatīt mērogu, kas iekļauj visus elementus",
"zoomToSelection": "Iestatīt mērogu, lai rādītu atlasi" "zoomToSelection": "Iestatīt mērogu, lai rādītu atlasi",
"toggleElementLock": "Fiksēt/atbrīvot atlasīto"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Notīrīt tāfeli" "title": "Notīrīt tāfeli"

View File

@ -1,420 +1,431 @@
{ {
"labels": { "labels": {
"paste": "चिकवा", "paste": "चिकवा",
"pasteCharts": "चार्ट चिकवा", "pasteCharts": "चार्ट चिवा",
"selectAll": "समस्त निवडा", "selectAll": "समस्त निवडा",
"multiSelect": "", "multiSelect": "निवडित तत्व जोडा",
"moveCanvas": "", "moveCanvas": "पटल हलवा",
"cut": "", "cut": "कापा",
"copy": "", "copy": "प्रतिलिपी",
"copyAsPng": "", "copyAsPng": "PNG रूपे फळी वर कॉपी करा",
"copyAsSvg": "", "copyAsSvg": "SVG रूपे फळी वर कॉपी करा",
"bringForward": "", "copyText": "लिखित रूपे फळी वर कॉपी करा",
"sendToBack": "", "bringForward": "पुढे पुढे आणा",
"bringToFront": "", "sendToBack": "सर्वात मागे करा",
"sendBackward": "", "bringToFront": "सर्वात पुढे आणा",
"delete": "", "sendBackward": "मागे मागे करा",
"copyStyles": "", "delete": "हटवा",
"pasteStyles": "", "copyStyles": "शैली कॉपी करा",
"stroke": "", "pasteStyles": "कॉपी केलेली शैली वापरा",
"background": "", "stroke": "रेघे चा रंग",
"fill": "", "background": "पार्श्वभूमी",
"strokeWidth": "", "fill": "भरा",
"strokeStyle": "", "strokeWidth": "रेघ रुंदी",
"strokeStyle_solid": "", "strokeStyle": "रेघ शैली",
"strokeStyle_dashed": "", "strokeStyle_solid": "भरीव",
"strokeStyle_dotted": "", "strokeStyle_dashed": "तुटित तुटित",
"sloppiness": "", "strokeStyle_dotted": "ठिपके ठिपके",
"opacity": "", "sloppiness": "गबाळेपणा",
"textAlign": "", "opacity": "अपारदर्शक्ता",
"edges": "", "textAlign": "मजकूर संरेखन",
"sharp": "", "edges": "किनारी",
"round": "", "sharp": "टोचरं",
"arrowheads": "", "round": "गोलाकार",
"arrowhead_none": "", "arrowheads": "बाण टोक",
"arrowhead_arrow": "", "arrowhead_none": "कुठलाहि नाही",
"arrowhead_bar": "", "arrowhead_arrow": "बाण",
"arrowhead_dot": "", "arrowhead_bar": "दांडुक",
"arrowhead_triangle": "", "arrowhead_dot": "ठिपका",
"fontSize": "", "arrowhead_triangle": "त्रिकोण",
"fontFamily": "", "fontSize": "अक्षर आकार",
"onlySelected": "", "fontFamily": "अक्षर समूह",
"withBackground": "", "onlySelected": "नुसता निवडलेला",
"exportEmbedScene": "", "withBackground": "पार्श्वभूमी",
"exportEmbedScene_details": "", "exportEmbedScene": "दृश्य रुतवून टाका",
"addWatermark": "", "exportEmbedScene_details": "दृश्य डेटा पण एक्सपोर्ट केलेल्या पी-एन-जी/एस-वी-जी फाईलमध्ये जतन केला जाईल जेणेकरून त्यामधून दृश्य परत आणता येईल.\nनिर्यात केलेल्या फाइलचा आकार वाढेल.",
"handDrawn": "", "addWatermark": "\"एक्सकेलीड्रॉ ने बनवलेलं\" जोडा",
"normal": "", "handDrawn": "हातानी बनवलेलं",
"code": "", "normal": "सामान्य",
"small": "", "code": "सांकेतिक लिपि",
"medium": "", "small": "छोटे",
"large": "", "medium": "मध्यम",
"veryLarge": "", "large": "मोठं",
"solid": "", "veryLarge": "फार मोठं",
"hachure": "", "solid": "भरीव",
"crossHatch": "", "hachure": "हैशूर रेखांकन",
"thin": "", "crossHatch": "आडव्या रेघा",
"bold": "", "thin": "पातळ",
"left": "", "bold": "जाड",
"center": "", "left": "डावं",
"right": "", "center": "मधे",
"extraBold": "", "right": "उजवं",
"architect": "", "extraBold": "जास्त जाड",
"artist": "", "architect": "वास्तुविद्याविशारद",
"cartoonist": "", "artist": "कलाकार",
"fileTitle": "", "cartoonist": "व्यंग्य चित्रकार",
"colorPicker": "", "fileTitle": "फाईलचे नाव",
"canvasColors": "", "colorPicker": "रंग निवडक",
"canvasBackground": "", "canvasColors": "कॅनवास वर वापरलेले",
"drawingCanvas": "", "canvasBackground": "पटल पार्श्वभूमि",
"layers": "", "drawingCanvas": "चित्र पटल",
"actions": "", "layers": "स्तर",
"language": "", "actions": "क्रिया",
"liveCollaboration": "", "language": "भाषा",
"duplicateSelection": "", "liveCollaboration": "थेट सहयोग",
"untitled": "", "duplicateSelection": "प्रतिलिपि",
"name": "", "untitled": "अशीर्षकांकित",
"yourName": "", "name": "नाव",
"madeWithExcalidraw": "", "yourName": "तुमचे नाव",
"group": "", "madeWithExcalidraw": "एक्सकेलीड्रॉ ने बनवलेलं",
"ungroup": "", "group": "समूह निवड",
"collaborators": "", "ungroup": "समूह निवड ला रद्द करा",
"showGrid": "", "collaborators": "Sahayog",
"addToLibrary": "", "showGrid": "ग्रिड दाखवा",
"removeFromLibrary": "", "addToLibrary": "संग्रह मधे सम्मिलित करा",
"libraryLoadingMessage": "", "removeFromLibrary": "संग्रहातून काढ़ा",
"libraries": "", "libraryLoadingMessage": "संग्रह लोड होत आहे…",
"loadingScene": "", "libraries": "संग्रह देखे",
"align": "", "loadingScene": "दृश्य लोड होत आहे…",
"alignTop": "", "align": "संरेखित करा",
"alignBottom": "", "alignTop": "वर संरेखित करा",
"alignLeft": "", "alignBottom": "खाली संरेखित करा",
"alignRight": "", "alignLeft": "डावा बाजूला संरेखित करा",
"centerVertically": "", "alignRight": "उजव्या बाजूला संरेखित करा",
"centerHorizontally": "", "centerVertically": "मधल्या मधे उभं संरेखित करा",
"distributeHorizontally": "", "centerHorizontally": "मधल्या मधे आडवं संरेखित करा",
"distributeVertically": "", "distributeHorizontally": "आडवं वितरित करा",
"flipHorizontal": "", "distributeVertically": "उभं वितरित करा",
"flipVertical": "", "flipHorizontal": "आडवं फ्लिप करा",
"viewMode": "", "flipVertical": "उभं फ्लिप करा",
"toggleExportColorScheme": "", "viewMode": "पहायची पद्धत",
"share": "", "toggleExportColorScheme": "रंग शैली जतन पलटा",
"showStroke": "", "share": "सामायिक करा",
"showBackground": "", "showStroke": "रेघ रंग निवड यंत्र दाखवा",
"toggleTheme": "", "showBackground": "पार्श्वभूमि: रंग निवड यंत्र दाखवा",
"personalLib": "", "toggleTheme": "शैली बदला",
"excalidrawLib": "", "personalLib": "वैयक्तिक संग्रह",
"decreaseFontSize": "", "excalidrawLib": "एक्सकेलीड्रॉ संग्रह",
"increaseFontSize": "", "decreaseFontSize": "अक्षर आकार छोटा करा",
"unbindText": "", "increaseFontSize": "अक्षर आकार मोठा करा",
"unbindText": "लेखन संबंध संपवा",
"bindText": "शब्द समूह ला पात्रात घ्या",
"link": { "link": {
"edit": "", "edit": "दुवा संपादन",
"create": "", "create": "दुवा तयार करा",
"label": "" "label": "दुवा"
},
"elementLock": {
"lock": "कुलूपात ठेवा",
"unlock": "कुलूपातून बाहेर",
"lockAll": "सर्व कुलूपात ठेवा",
"unlockAll": "सर्व कुलूपातून बाहेर"
} }
}, },
"buttons": { "buttons": {
"clearReset": "", "clearReset": "पटल पुसा",
"exportJSON": "", "exportJSON": "फ़ाइलमधे बाहेर ठेवा",
"exportImage": "", "exportImage": "प्रतिमेस्वरूप जतन करा",
"export": "", "export": "बाहेर ठेवा",
"exportToPng": "", "exportToPng": "पी-एन-जी स्वरूपात बाहेर ठेवा",
"exportToSvg": "", "exportToSvg": "एस-वी-जी स्वरूपात बाहेर ठेवा",
"copyToClipboard": "", "copyToClipboard": "फळी वर कॉपी करा",
"copyPngToClipboard": "", "copyPngToClipboard": "PNG रूपे फळी वर कॉपी करा",
"scale": "", "scale": "मोजपट्टी",
"save": "", "save": "वर्तमान फ़ाइल मधे जतन करा",
"saveAs": "", "saveAs": "ह्या नावाने जतन करा",
"load": "", "load": "बाहेरुन भरा",
"getShareableLink": "", "getShareableLink": "सामायिके साठी दुवा प्राप्त करा",
"close": "", "close": "बंद करा",
"selectLanguage": "", "selectLanguage": "भाषा निवड करा",
"scrollBackToContent": "", "scrollBackToContent": "पहलेचा मजकुर वर मागे स्क्रॉल करा",
"zoomIn": "", "zoomIn": "मोठं करून पहा",
"zoomOut": "", "zoomOut": "छोटं करून पहा",
"resetZoom": "", "resetZoom": "छोटं मोठं करणं बंद करा",
"menu": "", "menu": "यादि",
"done": "", "done": "झालं",
"edit": "", "edit": "संपादित करा",
"undo": "", "undo": "पूर्ववत करा",
"redo": "", "redo": "पुन्हा करा(&R)",
"resetLibrary": "", "resetLibrary": "संग्रह पुनर्स्थित करा",
"createNewRoom": "", "createNewRoom": "एक नवी खोली बनवा",
"fullScreen": "", "fullScreen": "पूर्ण दृश्यपटल",
"darkMode": "", "darkMode": "अंधार स्थिथि",
"lightMode": "", "lightMode": "उजेड स्थिति",
"zenMode": "", "zenMode": "ध्यानग्र स्थिति",
"exitZenMode": "", "exitZenMode": "ध्यानग्र स्थितितून बाहेर",
"cancel": "", "cancel": "रद्द",
"clear": "", "clear": "स्वछ",
"remove": "", "remove": "हटवा",
"publishLibrary": "", "publishLibrary": "प्रकाशित करा",
"submit": "", "submit": "जमा करा",
"confirm": "" "confirm": "पुष्टि करा"
}, },
"alerts": { "alerts": {
"clearReset": "", "clearReset": "पटल स्वच्छ होणार, तुम्हाला खात्री आहे का?",
"couldNotCreateShareableLink": "", "couldNotCreateShareableLink": "सामायी करण करण्या योग्य दुवा नाही बनवता आला.",
"couldNotCreateShareableLinkTooBig": "", "couldNotCreateShareableLinkTooBig": "सामायी करण करण्या योग्य दुवा नाही बनवता आला: दृश्य फार मोठं आहे",
"couldNotLoadInvalidFile": "", "couldNotLoadInvalidFile": "अवैध फ़ाइल लोड करता आली नाही",
"importBackendFailed": "", "importBackendFailed": "बैकएंड हून मागवणे विफल झाले.",
"cannotExportEmptyCanvas": "", "cannotExportEmptyCanvas": "रिकामा पटल जतन करता येत नाही.",
"couldNotCopyToClipboard": "", "couldNotCopyToClipboard": "पटल वर कॉपी नाही झाली.",
"decryptFailed": "", "decryptFailed": "डीक्रिप्ट करता आले नाही.",
"uploadedSecurly": "", "uploadedSecurly": "अपलोड या टोकापासून त्या टोकापर्यंत कूटबद्धित करून सुरक्षित केले गेले आहे, हयाचा अर्थ असा की एक्सकेलीड्रॉ सर्व्हर आणि तृतीय पक्ष मजकूर वाचू शकत नाहीत.",
"loadSceneOverridePrompt": "", "loadSceneOverridePrompt": "बाह्य रेखाचित्र लोड केल्याने तुमची तुमचा विद्यमान मजकूर बदलेल. हे काम तुम्हाला चालू ठेवायचे आहे का?",
"collabStopOverridePrompt": "", "collabStopOverridePrompt": "सत्र थांबवल्याने तुमचे पूर्वीचे, स्थानिकरित्या संग्रहित रेखाचित्र अधिलिखित होईल. तुला खात्री आहे?\n\n(तुम्हाला तुमचे स्थानिक रेखाचित्र ठेवायचे असल्यास, त्याऐवजी फक्त ब्राउझर टॅब बंद करा.)",
"errorLoadingLibrary": "", "errorLoadingLibrary": "तृतीय पक्ष संग्रह लोड करताना त्रुटी आली होती.",
"errorAddingToLibrary": "", "errorAddingToLibrary": "संग्रहात तत्व जोडू शकलो नाही",
"errorRemovingFromLibrary": "", "errorRemovingFromLibrary": "संग्रहातून तत्व काढू शकलो नाही",
"confirmAddLibrary": "", "confirmAddLibrary": "हे तुमच्या संग्राहात {{numShapes}} आकार (एक किव्हा अनेक) जोडेल. तुला खात्री आहे?",
"imageDoesNotContainScene": "", "imageDoesNotContainScene": "या प्रतिमेमध्ये कोणताही दृश्य डेटा असल्याचे दिसत नाही. बाहेर जतन करताना तुम्ही दृश्य रुतवले होते का?",
"cannotRestoreFromImage": "", "cannotRestoreFromImage": "प्रतिमा फ़ाइल पासून दृश्य पुनः रचित नाही झाला",
"invalidSceneUrl": "", "invalidSceneUrl": "दिलेल्या यू-आर-एल पासून दृश्य आणू शकलो नाही. तो एकतर बरोबार नाही आहे किंवा त्यात वैध एक्सकेलीड्रॉ जेसन डेटा नाही.",
"resetLibrary": "", "resetLibrary": "पटल स्वच्छ होणार, तुम्हाला खात्री आहे का?",
"removeItemsFromsLibrary": "", "removeItemsFromsLibrary": "संग्रहातून {{count}} तत्व (एक किव्हा अनेक) काढू?",
"invalidEncryptionKey": "" "invalidEncryptionKey": "कूटबद्धन कुंजी 22 अक्षरांची असणे आवश्यक आहे. थेट सहयोग अक्षम केले आहे."
}, },
"errors": { "errors": {
"unsupportedFileType": "", "unsupportedFileType": "असमर्थित फाइल प्रकार.",
"imageInsertError": "", "imageInsertError": "प्रतिमा आत घालता येत नाही. नंतर पुन्हा प्रयत्न करा...",
"fileTooBig": "", "fileTooBig": "फाइल फार मोठी आहे. आकाराची कमाल परवानगी {{maxSize}} आहे.",
"svgImageInsertError": "", "svgImageInsertError": "एस-वी-जी प्रतिमा आत घालवू शकलो नाही. एस-वी-जी-मार्क-अप यंत्र अयोग्य आहे.",
"invalidSVGString": "", "invalidSVGString": "अयोग्य एस-वी-जी.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "कॉलेब-सर्वर हे पोहोचत नाही आहे. पान परत लोड करायचा प्रयत्न करावे."
}, },
"toolBar": { "toolBar": {
"selection": "", "selection": "निवड",
"image": "", "image": "प्रतिमा आत घाला",
"rectangle": "", "rectangle": "आयत",
"diamond": "", "diamond": "चौकोन आकाराचा",
"ellipse": "", "ellipse": "अंडाकार",
"arrow": "", "arrow": "बाण",
"line": "", "line": "रेखा",
"freedraw": "", "freedraw": "रेखांकित करा",
"text": "", "text": "टेक्स्ट",
"library": "", "library": "संग्रह",
"lock": "", "lock": "निवडलेले यंत्र चित्रकरण झाल्या नंतर ही सक्रिय ठेवा",
"penMode": "", "penMode": "पिंच-झूम प्रतिबंधित करा आणि फक्त पेन हे यंत्र मुक्त चित्री करण साठी स्वीकारा",
"link": "" "link": "निवडलेल्या आकारासाठी दुवा जोडा/बदल करा",
"eraser": "खोड रबर"
}, },
"headings": { "headings": {
"canvasActions": "", "canvasActions": "पटल क्रिया",
"selectedShapeActions": "", "selectedShapeActions": "निवडित आकार क्रिया",
"shapes": "" "shapes": "आकार"
}, },
"hints": { "hints": {
"canvasPanning": "", "canvasPanning": "पटल हलवण्यासाठी, ड्रैग करताना माउस वील ला पकड़ा किव्हा स्पेसबार दाबून ठेवा",
"linearElement": "", "linearElement": "अनेक बिंदु साठी क्लिक करा, रेघे साठी ड्रैग करा",
"freeDraw": "", "freeDraw": "क्लिक आणि ड्रैग करा, झालं तेव्हा सोडा",
"text": "", "text": "टीप: तुम्हीं निवड यंत्रानी कोठेही दुहेरी क्लिक करून टेक्स्ट जोडू शकता",
"text_selected": "", "text_selected": "लेखन संपादन साठी दुहेरी क्लिक करा किव्हा एंटर दाबा",
"text_editing": "", "text_editing": "संपादन संपवायचं असल्यास एस्केप दाबा किव्हा कंट्रोल या कम्मांड बरोबार एंटर दाबा",
"linearElementMulti": "", "linearElementMulti": "शेवटच्या बिंदु वर क्लिक करा किव्हा एस्केप या एंटर दाबा",
"lockAngle": "", "lockAngle": "शिफ्ट धरून तुम्ही कोन मर्यादित करू शकता",
"resize": "", "resize": "आकार छोटा मोठा करताना SHIFT धरून तुम्ही प्रमाण मर्यादित करू शकता, \nकेंद्रापासून आकार छोटा मोठा करण्यासाठी ALT धरून ठेवा",
"resizeImage": "", "resizeImage": "SHIFT धरून तुम्ही मुक्तपणे आकार मोठा छोटा करु शकता,\nकेंद्रापासून आकार मोठा छोटा करण्यासाठी ALT धरून ठेवा",
"rotate": "", "rotate": "फिरवत असताना शिफ्ट धरून तुम्ही कोन मर्यादित करू शकता",
"lineEditor_info": "", "lineEditor_info": "बिंदु संपादित करण्या साठी दुहेरी क्लिक किव्हा एंटर की दाबा",
"lineEditor_pointSelected": "", "lineEditor_pointSelected": "बिंदु (एक किव्हा अनेक) काढ़ण्या साठी डिलीट की दाबा,\nCtrlOrCmd बरोबार D प्रति साठी,\nकिव्हा ड्रेग हलवण्या साठी",
"lineEditor_nothingSelected": "", "lineEditor_nothingSelected": "संपादित करण्यासाठी एक बिंदू निवडा (अनेक निवडण्यासाठी SHIFT धरून ठेवा),\nकिंवा Alt धरून ठेवा आणि नवीन बिंदू जोडण्यासाठी क्लिक करा",
"placeImage": "", "placeImage": "प्रतिमा ठेवण्यासाठी क्लिक करा, किंवा त्याचा आकार बदलण्या साठी क्लिक करा आणि ड्रॅग करा",
"publishLibrary": "", "publishLibrary": "आपला खाजगी संग्रह प्रकाशित करा",
"bindTextToElement": "", "bindTextToElement": "मजकूर जोडण्यासाठी एंटर की दाबा",
"deepBoxSelect": "" "deepBoxSelect": "खोल निवड ह्या साठी कंट्रोल किव्हा कमांड दाबून ठेवा, आणि बाहेर खेचणे वाचवण्या साठी पण",
"eraserRevert": "खोडण्या साठी घेतलेल्या वस्तु ना घेण्या साठी Alt दाबून ठेवावे"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "", "cannotShowPreview": "पूर्वावलोकन दाखवू शकत नाही",
"canvasTooBig": "", "canvasTooBig": "पटल खूप जास्त मोठा असू शकतो.",
"canvasTooBigTip": "" "canvasTooBigTip": "टीप: दूर चा तत्व थोडं जवळ आणण्याचा प्रयत्न करावा."
}, },
"errorSplash": { "errorSplash": {
"headingMain_pre": "", "headingMain_pre": "त्रुटि आली. परत प्रयत्न करा ",
"headingMain_button": "", "headingMain_button": "ह्या पानाला पुनः लोड करा.",
"clearCanvasMessage": "", "clearCanvasMessage": "रीलोडिंग होत नसल्यास, परत प्रयत्न करा ",
"clearCanvasMessage_button": "", "clearCanvasMessage_button": "पटल स्वच्छ करित आहे.",
"clearCanvasCaveat": "", "clearCanvasCaveat": " त्यामुळे केलेल्या कामाचे नुकसान होईल ",
"trackedToSentry_pre": "", "trackedToSentry_pre": "त्रुटि क्रमांक के साथ त्रुटि ",
"trackedToSentry_post": "", "trackedToSentry_post": " आमच्या प्रणाली नी निरीक्षण केले होते.",
"openIssueMessage_pre": "", "openIssueMessage_pre": "त्रुटीत तुमची दृश्य माहिती समाविष्ट न करण्यासाठी आम्ही खूप सावध होतो. तुमचा सीन खाजगी नसल्यास, कृपया आम्हाला पुढ च्या कारवाई साठी सम्पर्क साधा ",
"openIssueMessage_button": "", "openIssueMessage_button": "त्रुटि व्यवस्थापन.",
"openIssueMessage_post": "", "openIssueMessage_post": " कृपया गिटहब समस्येमध्ये कॉपी आणि पेस्ट करून खालिल माहिती समाविष्ट करा.",
"sceneContent": "" "sceneContent": "दृश्य विषय:"
}, },
"roomDialog": { "roomDialog": {
"desc_intro": "", "desc_intro": "तुम्‍ही तुमच्‍या सध्‍याच्‍या दृश्यासाठी लोकांना आपल्‍यासह सहयोग करण्‍यासाठी आमंत्रित करू शकता.",
"desc_privacy": "", "desc_privacy": "काळजी करू नका, सत्र या टोकापासून त्या टोकापर्यंत कूटबद्धता वापरते, त्यामुळे तुम्ही जे काही काढाल ते खाजगी राहील. तुम्ही काय घेऊन आला आहात हे आमचा सर्व्हर ही देखील पाहू शकत नाही.",
"button_startSession": "", "button_startSession": "सत्र सुरु करा",
"button_stopSession": "", "button_stopSession": "सत्र थाम्बवा",
"desc_inProgressIntro": "", "desc_inProgressIntro": "थेट सहयोग सत्र चालू आहे.",
"desc_shareLink": "", "desc_shareLink": "तुम्ही ज्यांच्याशी सहयोग करू इच्छिता त्यांच्याशी ही दुवा सामायिक करा:",
"desc_exitSession": "", "desc_exitSession": "सत्र थांबवल्याने तुम्हीं खोली तून बाहेर याल, तरिही तुम्ही स्थानिक पातळीवर दृश्यासह काम करु शकाल. लक्षात ठेवा की याचा इतर लोकांवर परिणाम होणार नाही आणि ते त्यांच्या आवृत्तीवर सहयोग करित राहातील.",
"shareTitle": "" "shareTitle": "एक्सकेलीड्रॉ वर थेट सहयोग सत्रात सामील व्हा"
}, },
"errorDialog": { "errorDialog": {
"title": "" "title": "त्रुटि"
}, },
"exportDialog": { "exportDialog": {
"disk_title": "", "disk_title": "डिस्क मधे जतन करा",
"disk_details": "", "disk_details": "सीन डेटा बाहेर एक फ़ाइल मधे जतन करा, त्या फ़ाइल मधुम तो डेटा नंतर परत आणु शकता.",
"disk_button": "", "disk_button": "फ़ाइल मधे जतन करा",
"link_title": "", "link_title": "सामायिके साठी दुवा",
"link_details": "", "link_details": "नुसतं वाचु देणारा दुवा चा स्वरूपे बाहेर ठेवा.",
"link_button": "", "link_button": "दुवा स्वरूपे बाहेर ठेवा",
"excalidrawplus_description": "", "excalidrawplus_description": "दृश्य तुमच्या एक्सकेलीड्रॉ कार्यक्षेत्र मधे जतन करा.",
"excalidrawplus_button": "", "excalidrawplus_button": "बाहेर ठेवा",
"excalidrawplus_exportError": "" "excalidrawplus_exportError": "एक्सकेलीड्रॉ मधे बाहेर ठेवता नाही येत..."
}, },
"helpDialog": { "helpDialog": {
"blog": "", "blog": "आमचा ब्लॉग वाचा",
"click": "", "click": "क्लिक करा",
"deepSelect": "", "deepSelect": "खोल निवड",
"deepBoxSelect": "", "deepBoxSelect": "चौकट मधे खोल निवड करा आणि बाहेर ओढणे वाचवा",
"curvedArrow": "", "curvedArrow": "वक्र बाण",
"curvedLine": "", "curvedLine": "वक्र रेघ",
"documentation": "", "documentation": "कागदपत्रे",
"doubleClick": "", "doubleClick": "दुहेरी क्लिक",
"drag": "", "drag": "ओढा",
"editor": "", "editor": "संपादक",
"editSelectedShape": "", "editSelectedShape": "निवडलेला प्रकार संपादित करा (मजकूर/बाण/रेघ)",
"github": "", "github": "समस्या मिळाली? प्रस्तुत करा",
"howto": "", "howto": "आमच्या मार्गदर्शकाचे अनुसरण करा",
"or": "", "or": "किंवा",
"preventBinding": "", "preventBinding": "बाण बंधन होणं टाळा",
"shapes": "", "tools": "अवजार",
"shortcuts": "", "shortcuts": "कीबोर्ड शॉर्टकट",
"textFinish": "", "textFinish": "संपादन संपले (मजकूर संपादन)",
"textNewLine": "", "textNewLine": "नवी ओळ जोडा (मजकूर संपादक)",
"title": "", "title": "मदत",
"view": "", "view": "दृश्य",
"zoomToFit": "", "zoomToFit": "सर्व तत्व दिसतील असे दृश्यरूप आकार करा",
"zoomToSelection": "" "zoomToSelection": "निवडी प्रयंत दृश्यरूप आकार करा",
"toggleElementLock": "कुलूपातून आत/बाहेर निवड"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": "पटल स्वच्छ करा"
}, },
"publishDialog": { "publishDialog": {
"title": "", "title": "संग्रह प्रकाशित करा",
"itemName": "", "itemName": "वस्तु चे नाव",
"authorName": "", "authorName": "लेखक चे नाव",
"githubUsername": "", "githubUsername": "गिटहब वापरकर्तानाव",
"twitterUsername": "", "twitterUsername": "ट्विटर वापरकर्तानाव",
"libraryName": "", "libraryName": "संग्रहाचे नाव",
"libraryDesc": "", "libraryDesc": "संग्रहाचे वर्णन",
"website": "", "website": "वेबसाइट",
"placeholder": { "placeholder": {
"authorName": "", "authorName": "तुमचे नाव किव्हा वापरकर्तानाव",
"libraryName": "", "libraryName": "तुमचा संग्रहाचे नाव",
"libraryDesc": "", "libraryDesc": "तुमचा संग्रहाचे वर्णन लोकांना संग्रहा बद्दल जाणकारी देतील",
"githubHandle": "", "githubHandle": "गिटहब हैंडल (वैकल्पिक), एकदा संग्रह पुनरावलोकना साठी जमा केल्या नंतर ही तुम्हीं सम्पादित करु शकता",
"twitterHandle": "", "twitterHandle": "ट्विटर वापरकार्यक नाव (वैकल्पिक), त्यामुळे ट्विटर वर ज़हीरांति साठी कोणाला गुण द्यायचे हे आम्हाला समजेल",
"website": "" "website": "दुवा तुमच्या वैयक्तिक वेब-साइट किव्हा कुठे दूसरिकडे (ऐच्छिक) करावा"
}, },
"errors": { "errors": {
"required": "", "required": "आवश्यक आहे",
"website": "" "website": "वैध यू-आर-एल द्या"
}, },
"noteDescription": { "noteDescription": {
"pre": "", "pre": "समाविष्ट करण्या साठी तुमचा संग्रह ह्याचात जमा करा ",
"link": "", "link": "सार्वजनिक संग्रहाचे कोठार",
"post": "" "post": "इतर लोकांना त्यांच्या रेखाचित्रांमधे वापरण्यासाठी."
}, },
"noteGuidelines": { "noteGuidelines": {
"pre": "", "pre": "संग्रहाला आधी स्वहस्ते स्वीकृती मिळणे आवश्यक आहे. कृपया हे वाचा ",
"link": "", "link": "मार्गदर्शक तत्त्वे",
"post": "" "post": " जमा करण्या पूर्वी, तुमच्या जवळ एक गिटहब खाते असणे आवश्यक आहे जे संवादा साठी आणिक बदल करण्या साठी लागेल, तरी हे सर्व अगदी आवश्यक नाही आहे."
}, },
"noteLicense": { "noteLicense": {
"pre": "", "pre": "जमा करताना तुम्हीं सहमति दाखवतात आहे की संग्रह ह्याचा खाली प्रकाशित होईल ",
"link": "", "link": "एम-आइ-टी परवाना, ",
"post": "" "post": "ज्याचा थोडक्यात अर्थ कोणीही निर्बंधांशिवाय वापरू शकतो."
}, },
"noteItems": "", "noteItems": "प्रतैक संग्रहाचे नाव, नीट शोधनासाठी, असणे आवश्यक आहे. खाली दिलेल्या वस्तु समाविष्ट केल्या जातील:",
"atleastOneLibItem": "" "atleastOneLibItem": "सुरु करण्यासाठी, कृपया करून, कमित कमी एक वस्तु तरी निवडा"
}, },
"publishSuccessDialog": { "publishSuccessDialog": {
"title": "", "title": "संग्रह जमा केला",
"content": "", "content": "धन्यवाद {{authorName}}. आपला संग्रह पुनरावलोकना साठी जमा झाला आहे. तुम्हीं स्थिति सारखी तपासू सकता",
"link": "" "link": "इकडे"
}, },
"confirmDialog": { "confirmDialog": {
"resetLibrary": "", "resetLibrary": "संग्रह पुनर्स्थित करा",
"removeItemsFromLib": "" "removeItemsFromLib": "निवडलेले आयटम्स संग्रहातून काढा"
}, },
"encrypted": { "encrypted": {
"tooltip": "", "tooltip": "तुमचे चित्रे या टोकापासून त्या टोकापर्यंत कूटबद्धतित आहेत, त्या कारणांनी ऐक्सकैलिड्रॉ सर्वर्स ह्यानां ते पहाणं कधीच जमणार नाही.",
"link": "" "link": "ब्लॉग पोस्ट ऐक्सकैलिड्रॉ मधे या टोकापासून त्या टोकापर्यंत कूटबद्धतित आहेत"
}, },
"stats": { "stats": {
"angle": "", "angle": "कोण",
"element": "", "element": "वस्तु",
"elements": "", "elements": "वस्तु",
"height": "", "height": "उंची",
"scene": "", "scene": "दृश्य",
"selected": "", "selected": "निवडलेले",
"storage": "", "storage": "साठवण",
"title": "", "title": "अभ्यासू लोगो के लिये आंकडे",
"total": "", "total": "योग",
"version": "", "version": "आवृत्ती",
"versionCopy": "", "versionCopy": "कॉपी करायला क्लिक करा",
"versionNotAvailable": "", "versionNotAvailable": "आवृति उपलब्ध नाही",
"width": "" "width": "रुंदी"
}, },
"toast": { "toast": {
"addedToLibrary": "", "addedToLibrary": "संग्रह मधे सम्मिलित",
"copyStyles": "", "copyStyles": "कॉपी केलेली शैली.",
"copyToClipboard": "", "copyToClipboard": "फळी वर कॉपी झाली.",
"copyToClipboardAsPng": "", "copyToClipboardAsPng": "{{exportSelection}} फळी वर पी-एन-जी स्वरूपात कॉपी झाली\n({{exportColorScheme}})",
"fileSaved": "", "fileSaved": "फ़ाइल जतन झाली.",
"fileSavedToFilename": "", "fileSavedToFilename": "{filename} मधे जतन झाली",
"canvas": "", "canvas": "पटल",
"selection": "" "selection": "निवड"
}, },
"colors": { "colors": {
"ffffff": "", "ffffff": "पांढरा",
"f8f9fa": "", "f8f9fa": "करडा 0",
"f1f3f5": "", "f1f3f5": "करडा 1",
"fff5f5": "", "fff5f5": "लाल 0",
"fff0f6": "", "fff0f6": "गुलाबी 0",
"f8f0fc": "", "f8f0fc": "अंगूरी 0",
"f3f0ff": "", "f3f0ff": "जांभळा 0",
"edf2ff": "", "edf2ff": "बैंगनी 0",
"e7f5ff": "", "e7f5ff": "नीळा 0",
"e3fafc": "", "e3fafc": "आसमानी 0",
"e6fcf5": "", "e6fcf5": "पाचू 0",
"ebfbee": "", "ebfbee": "हिरवा 0",
"f4fce3": "", "f4fce3": "लिंबु 0",
"fff9db": "", "fff9db": "पिवळा 0",
"fff4e6": "", "fff4e6": "नारंगी 0",
"transparent": "", "transparent": "पारदर्शक",
"ced4da": "", "ced4da": "करडा 4",
"868e96": "", "868e96": "करडा 6",
"fa5252": "", "fa5252": "लाल 6",
"e64980": "", "e64980": "गुलाबी 6",
"be4bdb": "", "be4bdb": "अंगूरी 6",
"7950f2": "", "7950f2": "जांभळा 6",
"4c6ef5": "", "4c6ef5": "बैंगनी 6",
"228be6": "", "228be6": "नीळा 6",
"15aabf": "", "15aabf": "आसमानी 6",
"12b886": "", "12b886": "पाचू 6",
"40c057": "", "40c057": "हिरवा 6",
"82c91e": "", "82c91e": "लिंबु 6",
"fab005": "", "fab005": "पिवळा 6",
"fd7e14": "", "fd7e14": "नारंगी 6",
"000000": "", "000000": "काळा",
"343a40": "", "343a40": "करडा 8",
"495057": "", "495057": "करडा 7",
"c92a2a": "", "c92a2a": "लाल 9",
"a61e4d": "", "a61e4d": "गुलाबी 9",
"862e9c": "", "862e9c": "अंगूरी 9",
"5f3dc4": "", "5f3dc4": "जामुनी 9",
"364fc7": "", "364fc7": "बैंगनी 9",
"1864ab": "", "1864ab": "नीला 9",
"0b7285": "", "0b7285": "आसमानी 9",
"087f5b": "", "087f5b": "पाचू 9",
"2b8a3e": "", "2b8a3e": "हरा 9",
"5c940d": "", "5c940d": "नीबू 9",
"e67700": "", "e67700": "पीला 9",
"d9480f": "" "d9480f": "नारंगी 9"
} }
} }

View File

@ -9,6 +9,7 @@
"copy": "ကူး", "copy": "ကူး",
"copyAsPng": "PNG အနေဖြင့်ကူး", "copyAsPng": "PNG အနေဖြင့်ကူး",
"copyAsSvg": "SVG အနေဖြင့်ကူး", "copyAsSvg": "SVG အနေဖြင့်ကူး",
"copyText": "",
"bringForward": "ရှေ့ပို့", "bringForward": "ရှေ့ပို့",
"sendToBack": "နောက်ဆုံးထား", "sendToBack": "နောက်ဆုံးထား",
"bringToFront": "ရှေ့ဆုံးထား", "bringToFront": "ရှေ့ဆုံးထား",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "လွဲမှားနေသောဖိုင်အား တင်၍မရပါ။", "couldNotLoadInvalidFile": "လွဲမှားနေသောဖိုင်အား တင်၍မရပါ။",
"importBackendFailed": "Backend မှမလုပ်ဆောင်နိုင်သေးပါ။", "importBackendFailed": "Backend မှမလုပ်ဆောင်နိုင်သေးပါ။",
"cannotExportEmptyCanvas": "ကားချပ်အလွတ်အားထုတ်ယူ၍မရပါ။", "cannotExportEmptyCanvas": "ကားချပ်အလွတ်အားထုတ်ယူ၍မရပါ။",
"couldNotCopyToClipboard": "ကူးယူ၍မရပါ။ Google Chrome တွင်စမ်းကြည့်ပါ။", "couldNotCopyToClipboard": "",
"decryptFailed": "အချက်အလက်ဖော်ယူ၍မရပါ။", "decryptFailed": "အချက်အလက်ဖော်ယူ၍မရပါ။",
"uploadedSecurly": "တင်သွင်းအချက်အလက်များအား နှစ်ဘက်စွန်းတိုင်လျှို့ဝှက်စနစ်အသုံးပြု၍လုံခြုံစွာထိန်းသိမ်းထားပါသဖြင့် Excalidraw ဆာဗာနှင့်ဆက်စပ်အဖွဲ့အစည်းများပင်လျှင်မဖတ်ရှုနိုင်ပါ။", "uploadedSecurly": "တင်သွင်းအချက်အလက်များအား နှစ်ဘက်စွန်းတိုင်လျှို့ဝှက်စနစ်အသုံးပြု၍လုံခြုံစွာထိန်းသိမ်းထားပါသဖြင့် Excalidraw ဆာဗာနှင့်ဆက်စပ်အဖွဲ့အစည်းများပင်လျှင်မဖတ်ရှုနိုင်ပါ။",
"loadSceneOverridePrompt": "လက်ရှိရေးဆွဲထားသမျှအား ပြင်ပမှတင်သွင်းသောပုံနှင့်အစားထိုးပါမည်။ ဆက်လက်ဆောင်ရွက်လိုပါသလား။", "loadSceneOverridePrompt": "လက်ရှိရေးဆွဲထားသမျှအား ပြင်ပမှတင်သွင်းသောပုံနှင့်အစားထိုးပါမည်။ ဆက်လက်ဆောင်ရွက်လိုပါသလား။",
@ -196,7 +204,8 @@
"library": "မှတ်တမ်း", "library": "မှတ်တမ်း",
"lock": "ရွေးချယ်ထားသောကိရိယာကိုသာဆက်သုံး", "lock": "ရွေးချယ်ထားသောကိရိယာကိုသာဆက်သုံး",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "ကားချပ်လုပ်ဆောင်ချက်", "canvasActions": "ကားချပ်လုပ်ဆောင်ချက်",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "နမူနာမပြသနိုင်ပါ", "cannotShowPreview": "နမူနာမပြသနိုင်ပါ",
@ -281,14 +291,15 @@
"howto": "", "howto": "",
"or": "", "or": "",
"preventBinding": "", "preventBinding": "",
"shapes": "", "tools": "",
"shortcuts": "", "shortcuts": "",
"textFinish": "", "textFinish": "",
"textNewLine": "", "textNewLine": "",
"title": "", "title": "",
"view": "", "view": "",
"zoomToFit": "", "zoomToFit": "",
"zoomToSelection": "" "zoomToSelection": "",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "Kopier", "copy": "Kopier",
"copyAsPng": "Kopier til PNG", "copyAsPng": "Kopier til PNG",
"copyAsSvg": "Kopier til utklippstavlen som SVG", "copyAsSvg": "Kopier til utklippstavlen som SVG",
"copyText": "Kopier til utklippstavlen som tekst",
"bringForward": "Flytt framover", "bringForward": "Flytt framover",
"sendToBack": "Send bakerst", "sendToBack": "Send bakerst",
"bringToFront": "Flytt forrest", "bringToFront": "Flytt forrest",
@ -107,10 +108,17 @@
"decreaseFontSize": "Reduser skriftstørrelse", "decreaseFontSize": "Reduser skriftstørrelse",
"increaseFontSize": "Øk skriftstørrelse", "increaseFontSize": "Øk skriftstørrelse",
"unbindText": "Avbind tekst", "unbindText": "Avbind tekst",
"bindText": "Bind tekst til beholderen",
"link": { "link": {
"edit": "Rediger lenke", "edit": "Rediger lenke",
"create": "Opprett lenke", "create": "Opprett lenke",
"label": "Lenke" "label": "Lenke"
},
"elementLock": {
"lock": "Lås",
"unlock": "Lås opp",
"lockAll": "Lås alle",
"unlockAll": "Lås opp alle"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Kunne ikke laste inn ugyldig fil", "couldNotLoadInvalidFile": "Kunne ikke laste inn ugyldig fil",
"importBackendFailed": "Importering av backend feilet.", "importBackendFailed": "Importering av backend feilet.",
"cannotExportEmptyCanvas": "Kan ikke eksportere et tomt lerret.", "cannotExportEmptyCanvas": "Kan ikke eksportere et tomt lerret.",
"couldNotCopyToClipboard": "Kunne ikke kopiere til utklippstavlen. Prøv med nettleseren Chrome.", "couldNotCopyToClipboard": "Kunne ikke kopiere til utklippstavlen.",
"decryptFailed": "Kunne ikke dekryptere data.", "decryptFailed": "Kunne ikke dekryptere data.",
"uploadedSecurly": "Opplastingen er kryptert og kan ikke leses av Excalidraw-serveren eller tredjeparter.", "uploadedSecurly": "Opplastingen er kryptert og kan ikke leses av Excalidraw-serveren eller tredjeparter.",
"loadSceneOverridePrompt": "Å laste inn ekstern tegning vil erstatte det eksisterende innholdet. Ønsker du å fortsette?", "loadSceneOverridePrompt": "Å laste inn ekstern tegning vil erstatte det eksisterende innholdet. Ønsker du å fortsette?",
@ -196,7 +204,8 @@
"library": "Bibliotek", "library": "Bibliotek",
"lock": "Behold merket verktøy som aktivt", "lock": "Behold merket verktøy som aktivt",
"penMode": "Forhindre zoom ved kniping og godta frihåndstegning kun fra penn", "penMode": "Forhindre zoom ved kniping og godta frihåndstegning kun fra penn",
"link": "Legg til / oppdater link for en valgt figur" "link": "Legg til / oppdater link for en valgt figur",
"eraser": "Viskelær"
}, },
"headings": { "headings": {
"canvasActions": "Handlinger: lerret", "canvasActions": "Handlinger: lerret",
@ -221,7 +230,8 @@
"placeImage": "Klikk for å plassere bildet, eller klikk og dra for å angi størrelsen manuelt", "placeImage": "Klikk for å plassere bildet, eller klikk og dra for å angi størrelsen manuelt",
"publishLibrary": "Publiser ditt eget bibliotek", "publishLibrary": "Publiser ditt eget bibliotek",
"bindTextToElement": "Trykk Enter for å legge til tekst", "bindTextToElement": "Trykk Enter for å legge til tekst",
"deepBoxSelect": "Hold CTRL/CMD for å markere dypt og forhindre flytting" "deepBoxSelect": "Hold CTRL/CMD for å markere dypt og forhindre flytting",
"eraserRevert": "Hold Alt for å reversere elementene merket for sletting"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Kan ikke vise forhåndsvisning", "cannotShowPreview": "Kan ikke vise forhåndsvisning",
@ -281,14 +291,15 @@
"howto": "Følg våre veiledninger", "howto": "Følg våre veiledninger",
"or": "eller", "or": "eller",
"preventBinding": "Forhindre pilbinding", "preventBinding": "Forhindre pilbinding",
"shapes": "Former", "tools": "Verktøy",
"shortcuts": "Tastatursnarveier", "shortcuts": "Tastatursnarveier",
"textFinish": "Fullfør redigering (teksteditor)", "textFinish": "Fullfør redigering (teksteditor)",
"textNewLine": "Legg til ny linje (teksteditor)", "textNewLine": "Legg til ny linje (teksteditor)",
"title": "Hjelp", "title": "Hjelp",
"view": "Vis", "view": "Vis",
"zoomToFit": "Zoom for å se alle elementer", "zoomToFit": "Zoom for å se alle elementer",
"zoomToSelection": "Zoom til utvalg" "zoomToSelection": "Zoom til utvalg",
"toggleElementLock": "Lås/lås opp utvalg"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Tøm lerret" "title": "Tøm lerret"

View File

@ -9,6 +9,7 @@
"copy": "Kopiëren", "copy": "Kopiëren",
"copyAsPng": "Kopieer als PNG", "copyAsPng": "Kopieer als PNG",
"copyAsSvg": "Kopieer naar klembord als SVG", "copyAsSvg": "Kopieer naar klembord als SVG",
"copyText": "Kopiëren naar klembord als tekst",
"bringForward": "Breng naar voren", "bringForward": "Breng naar voren",
"sendToBack": "Stuur naar achtergrond", "sendToBack": "Stuur naar achtergrond",
"bringToFront": "Breng naar voorgrond", "bringToFront": "Breng naar voorgrond",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "Ontkoppel tekst", "unbindText": "Ontkoppel tekst",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Kan ongeldig bestand niet laden", "couldNotLoadInvalidFile": "Kan ongeldig bestand niet laden",
"importBackendFailed": "Importeren vanuit backend mislukt.", "importBackendFailed": "Importeren vanuit backend mislukt.",
"cannotExportEmptyCanvas": "Kan geen leeg canvas exporteren.", "cannotExportEmptyCanvas": "Kan geen leeg canvas exporteren.",
"couldNotCopyToClipboard": "Kan niet kopiëren. Probeer in de Chrome-browser.", "couldNotCopyToClipboard": "Kon niet naar klembord kopiëren.",
"decryptFailed": "Kan gegevens niet decoderen.", "decryptFailed": "Kan gegevens niet decoderen.",
"uploadedSecurly": "De upload is beveiligd met end-to-end encryptie, wat betekent dat de Excalidraw server en derden de inhoud niet kunnen lezen.", "uploadedSecurly": "De upload is beveiligd met end-to-end encryptie, wat betekent dat de Excalidraw server en derden de inhoud niet kunnen lezen.",
"loadSceneOverridePrompt": "Het laden van externe tekening zal uw bestaande inhoud vervangen. Wil je doorgaan?", "loadSceneOverridePrompt": "Het laden van externe tekening zal uw bestaande inhoud vervangen. Wil je doorgaan?",
@ -196,7 +204,8 @@
"library": "Bibliotheek", "library": "Bibliotheek",
"lock": "Geselecteerde tool actief houden na tekenen", "lock": "Geselecteerde tool actief houden na tekenen",
"penMode": "Voorkom pinch-zoom en accepteer freedraw invoer alleen van pen", "penMode": "Voorkom pinch-zoom en accepteer freedraw invoer alleen van pen",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "Canvasacties", "canvasActions": "Canvasacties",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "Publiceer je eigen bibliotheek", "publishLibrary": "Publiceer je eigen bibliotheek",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Kan voorbeeld niet tonen", "cannotShowPreview": "Kan voorbeeld niet tonen",
@ -281,14 +291,15 @@
"howto": "Volg onze handleidingen", "howto": "Volg onze handleidingen",
"or": "of", "or": "of",
"preventBinding": "Pijlbinding voorkomen", "preventBinding": "Pijlbinding voorkomen",
"shapes": "Vormen", "tools": "",
"shortcuts": "Sneltoetsen", "shortcuts": "Sneltoetsen",
"textFinish": "Voltooi het bewerken (teksteditor)", "textFinish": "Voltooi het bewerken (teksteditor)",
"textNewLine": "Nieuwe regel toevoegen (teksteditor)", "textNewLine": "Nieuwe regel toevoegen (teksteditor)",
"title": "Help", "title": "Help",
"view": "Weergave", "view": "Weergave",
"zoomToFit": "Zoom in op alle elementen", "zoomToFit": "Zoom in op alle elementen",
"zoomToSelection": "Inzoomen op selectie" "zoomToSelection": "Inzoomen op selectie",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "Kopier", "copy": "Kopier",
"copyAsPng": "Kopier til utklippstavla som PNG", "copyAsPng": "Kopier til utklippstavla som PNG",
"copyAsSvg": "Kopier til utklippstavla som SVG", "copyAsSvg": "Kopier til utklippstavla som SVG",
"copyText": "",
"bringForward": "Flytt framover", "bringForward": "Flytt framover",
"sendToBack": "Send heilt bak", "sendToBack": "Send heilt bak",
"bringToFront": "Flytt heilt fram", "bringToFront": "Flytt heilt fram",
@ -35,7 +36,7 @@
"arrowhead_arrow": "Pil", "arrowhead_arrow": "Pil",
"arrowhead_bar": "Stolpe", "arrowhead_bar": "Stolpe",
"arrowhead_dot": "Prikk", "arrowhead_dot": "Prikk",
"arrowhead_triangle": "", "arrowhead_triangle": "Trekant",
"fontSize": "Skriftstorleik", "fontSize": "Skriftstorleik",
"fontFamily": "Skrifttype", "fontFamily": "Skrifttype",
"onlySelected": "Kun valde", "onlySelected": "Kun valde",
@ -64,7 +65,7 @@
"cartoonist": "Teiknar", "cartoonist": "Teiknar",
"fileTitle": "Filnamn", "fileTitle": "Filnamn",
"colorPicker": "Fargeveljar", "colorPicker": "Fargeveljar",
"canvasColors": "", "canvasColors": "Brukt på lerretet",
"canvasBackground": "Lerretsbakgrunn", "canvasBackground": "Lerretsbakgrunn",
"drawingCanvas": "Lerret", "drawingCanvas": "Lerret",
"layers": "Lag", "layers": "Lag",
@ -102,15 +103,22 @@
"showStroke": "Vis fargeveljar for linjer", "showStroke": "Vis fargeveljar for linjer",
"showBackground": "Vis fargeveljar for bakgrunn", "showBackground": "Vis fargeveljar for bakgrunn",
"toggleTheme": "Veksle tema", "toggleTheme": "Veksle tema",
"personalLib": "", "personalLib": "Personleg bibliotek",
"excalidrawLib": "", "excalidrawLib": "Excalidraw-bibliotek",
"decreaseFontSize": "", "decreaseFontSize": "Gjer skriftstorleik mindre",
"increaseFontSize": "", "increaseFontSize": "Gjer skriftstorleik større",
"unbindText": "", "unbindText": "Avbind tekst",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "Rediger lenke",
"create": "", "create": "Lag lenke",
"label": "" "label": "Lenke"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -147,10 +155,10 @@
"exitZenMode": "Avslutt zen-modus", "exitZenMode": "Avslutt zen-modus",
"cancel": "Avbryt", "cancel": "Avbryt",
"clear": "Tøm", "clear": "Tøm",
"remove": "", "remove": "Fjern",
"publishLibrary": "", "publishLibrary": "Publiser",
"submit": "", "submit": "Send inn",
"confirm": "" "confirm": "Stadfest"
}, },
"alerts": { "alerts": {
"clearReset": "Dette vil tømme lerretet. Er du sikker?", "clearReset": "Dette vil tømme lerretet. Er du sikker?",
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Kunne ikkje laste inn ugyldig fil", "couldNotLoadInvalidFile": "Kunne ikkje laste inn ugyldig fil",
"importBackendFailed": "Importering av backend feila.", "importBackendFailed": "Importering av backend feila.",
"cannotExportEmptyCanvas": "Kan ikkje eksportere eit tomt lerret.", "cannotExportEmptyCanvas": "Kan ikkje eksportere eit tomt lerret.",
"couldNotCopyToClipboard": "Kunne ikkje kopiere til utklippstavla. Prøv med nettlesaren Chrome.", "couldNotCopyToClipboard": "",
"decryptFailed": "Kunne ikkje dekryptere data.", "decryptFailed": "Kunne ikkje dekryptere data.",
"uploadedSecurly": "Opplastinga er kryptert og er ikkje mogleg å lese av Excalidraw-serveren eller tredjepartar.", "uploadedSecurly": "Opplastinga er kryptert og er ikkje mogleg å lese av Excalidraw-serveren eller tredjepartar.",
"loadSceneOverridePrompt": "Innlasting av ekstern teikning erstattar ditt eksisterande innhald. Ynskjer du å fortsette?", "loadSceneOverridePrompt": "Innlasting av ekstern teikning erstattar ditt eksisterande innhald. Ynskjer du å fortsette?",
@ -172,7 +180,7 @@
"cannotRestoreFromImage": "Scena kunne ikkje gjenopprettast frå denne biletfila", "cannotRestoreFromImage": "Scena kunne ikkje gjenopprettast frå denne biletfila",
"invalidSceneUrl": "Kunne ikkje hente noko scene frå den URL-en. Ho er anten øydelagd eller inneheld ikkje gyldig Excalidraw JSON-data.", "invalidSceneUrl": "Kunne ikkje hente noko scene frå den URL-en. Ho er anten øydelagd eller inneheld ikkje gyldig Excalidraw JSON-data.",
"resetLibrary": "Dette vil fjerne alt innhald frå biblioteket. Er du sikker?", "resetLibrary": "Dette vil fjerne alt innhald frå biblioteket. Er du sikker?",
"removeItemsFromsLibrary": "", "removeItemsFromsLibrary": "Slette {{count}} element frå biblioteket?",
"invalidEncryptionKey": "Krypteringsnøkkelen må ha 22 teikn. Sanntidssamarbeid er deaktivert." "invalidEncryptionKey": "Krypteringsnøkkelen må ha 22 teikn. Sanntidssamarbeid er deaktivert."
}, },
"errors": { "errors": {
@ -180,8 +188,8 @@
"imageInsertError": "Kunne ikkje sette inn biletet. Prøv igjen seinare...", "imageInsertError": "Kunne ikkje sette inn biletet. Prøv igjen seinare...",
"fileTooBig": "Fila er for stor. Maksimal tillate storleik er {{maxSize}}.", "fileTooBig": "Fila er for stor. Maksimal tillate storleik er {{maxSize}}.",
"svgImageInsertError": "Kunne ikkje sette inn SVG-biletet. SVG-koden ser ugyldig ut.", "svgImageInsertError": "Kunne ikkje sette inn SVG-biletet. SVG-koden ser ugyldig ut.",
"invalidSVGString": "", "invalidSVGString": "Ugyldig SVG.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "Kunne ikkje kople til samarbeidsserveren. Ver vennleg å oppdatere inn sida og prøv på nytt."
}, },
"toolBar": { "toolBar": {
"selection": "Vel", "selection": "Vel",
@ -195,8 +203,9 @@
"text": "Tekst", "text": "Tekst",
"library": "Bibliotek", "library": "Bibliotek",
"lock": "Hald fram med valt verktøy", "lock": "Hald fram med valt verktøy",
"penMode": "", "penMode": "Forhindre zoom ved kniping og godta frihandsteikning kun frå penn",
"link": "" "link": "Legg til/ oppdater lenke til valt figur",
"eraser": "Viskelêr"
}, },
"headings": { "headings": {
"canvasActions": "Handlingar: lerret", "canvasActions": "Handlingar: lerret",
@ -204,7 +213,7 @@
"shapes": "Formar" "shapes": "Formar"
}, },
"hints": { "hints": {
"canvasPanning": "", "canvasPanning": "For å flytte lerretet, hald inne musehjulet eller mellomromstasten medan du dreg",
"linearElement": "Klikk for å starte linje med fleire punkt, eller drag for ei enkel linje", "linearElement": "Klikk for å starte linje med fleire punkt, eller drag for ei enkel linje",
"freeDraw": "Klikk og drag, slepp når du er ferdig", "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": "Tips: du kan òg leggje til tekst ved å dobbeltklikke kor som helst med utvalgsverktyet",
@ -216,12 +225,13 @@
"resizeImage": "Du kan endre storleiken fritt ved å halde inne SHIFT,\nhald ALT for å endre storleik frå sentrum", "resizeImage": "Du kan endre storleiken fritt ved å halde inne SHIFT,\nhald ALT for å endre storleik frå sentrum",
"rotate": "Du kan låse vinklane ved å halde SHIFT medan du roterer", "rotate": "Du kan låse vinklane ved å halde SHIFT medan du roterer",
"lineEditor_info": "Dobbeltklikk eller trykk Enter for å redigere punkt", "lineEditor_info": "Dobbeltklikk eller trykk Enter for å redigere punkt",
"lineEditor_pointSelected": "", "lineEditor_pointSelected": "Trykk på Slett for å fjerne punkt(a),\nCtrl / Cmd+D for å duplisere, eller drag for å flytte",
"lineEditor_nothingSelected": "", "lineEditor_nothingSelected": "Vel eit punkt å redigere (hald inne SHIFT for å velje fleire),\neller hald inne Alt og klikk for å legge til nye punkt",
"placeImage": "Klikk for å plassere biletet, eller klikk og drag for å velje storleik manuelt", "placeImage": "Klikk for å plassere biletet, eller klikk og drag for å velje storleik manuelt",
"publishLibrary": "", "publishLibrary": "Publiser ditt eige bibliotek",
"bindTextToElement": "", "bindTextToElement": "Trykk på enter for å legge til tekst",
"deepBoxSelect": "" "deepBoxSelect": "Hald inne Ctrl / Cmd for å velje djupt, og forhindre flytting",
"eraserRevert": "Hald inne Alt for å reversere markering av element for sletting"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Kan ikkje vise førehandsvising", "cannotShowPreview": "Kan ikkje vise førehandsvising",
@ -268,8 +278,8 @@
"helpDialog": { "helpDialog": {
"blog": "Les bloggen vår", "blog": "Les bloggen vår",
"click": "klikk", "click": "klikk",
"deepSelect": "", "deepSelect": "Marker djupt",
"deepBoxSelect": "", "deepBoxSelect": "Marker djupt inni boksen og forhindr flytting",
"curvedArrow": "Boga pil", "curvedArrow": "Boga pil",
"curvedLine": "Boga linje", "curvedLine": "Boga linje",
"documentation": "Dokumentasjon", "documentation": "Dokumentasjon",
@ -281,65 +291,66 @@
"howto": "Følg vegleiinga vår", "howto": "Følg vegleiinga vår",
"or": "eller", "or": "eller",
"preventBinding": "Hindre pilkopling", "preventBinding": "Hindre pilkopling",
"shapes": "Formar", "tools": "",
"shortcuts": "Tastatursnarvegar", "shortcuts": "Tastatursnarvegar",
"textFinish": "Fullfør redigering (teksthandsamar)", "textFinish": "Fullfør redigering (teksthandsamar)",
"textNewLine": "Legg til ny linje (teksthandsamar)", "textNewLine": "Legg til ny linje (teksthandsamar)",
"title": "Hjelp", "title": "Hjelp",
"view": "Vising", "view": "Vising",
"zoomToFit": "Zoom for å sjå alle elementa", "zoomToFit": "Zoom for å sjå alle elementa",
"zoomToSelection": "Zoom til utval" "zoomToSelection": "Zoom til utval",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": "Tøm lerretet"
}, },
"publishDialog": { "publishDialog": {
"title": "", "title": "Publiser bibliotek",
"itemName": "", "itemName": "Elementnamn",
"authorName": "", "authorName": "Eigaren sitt namn",
"githubUsername": "", "githubUsername": "GitHub-brukarnamn",
"twitterUsername": "", "twitterUsername": "Twitter-brukarnamn",
"libraryName": "", "libraryName": "Biblioteknamn",
"libraryDesc": "", "libraryDesc": "Bibliotekskildring",
"website": "", "website": "Nettstad",
"placeholder": { "placeholder": {
"authorName": "", "authorName": "Namnet eller brukarnamnet ditt",
"libraryName": "", "libraryName": "Namnet på biblioteket ditt",
"libraryDesc": "", "libraryDesc": "Skildring av biblioteket ditt sånn at andre forstår bruken av det",
"githubHandle": "", "githubHandle": "GitHub-brukarnamn (valfritt), slik at du kan redigere bibiloteket når det er sendt inn til vurdering",
"twitterHandle": "", "twitterHandle": "Twitter-brukarnamn (valfritt), så vi veit kven vi skal kreditere på Twitter",
"website": "" "website": "Lenke til den personlege nettstaden din eller ein anna stad (valfritt)"
}, },
"errors": { "errors": {
"required": "", "required": "Kravt",
"website": "" "website": "Fyll inn ein gyldig URL"
}, },
"noteDescription": { "noteDescription": {
"pre": "", "pre": "Send inn biblioteket ditt til inkludering i ",
"link": "", "link": "den offentlege bibliotek-kjeldekoda",
"post": "" "post": "slik at andre kan bruke det i teikningane deira."
}, },
"noteGuidelines": { "noteGuidelines": {
"pre": "", "pre": "Biblioteket må godkjennast manuelt fyrst. Ver vennleg å lese ",
"link": "", "link": "retningslinjene",
"post": "" "post": " før du sender inn. Du kjem til å trenge ein GitHub-konto for å kommunisere og gjere endringar dersom kravt, men det er ikkje strengt naudsynt."
}, },
"noteLicense": { "noteLicense": {
"pre": "", "pre": "Ved å sende inn godkjenner du at biblioteket vert publisert under ",
"link": "", "link": "MIT-lisensen, ",
"post": "" "post": "som kort sagt betyr at kven som helst kan bruke det utan avgrensingar."
}, },
"noteItems": "", "noteItems": "Kvart bibliotekselement må ha eit eige namn, slik at det er mogleg å filtrere. Dei følgande bibliotekselementa blir inkludert:",
"atleastOneLibItem": "" "atleastOneLibItem": "Ver vennleg å markere minst eitt bibliotekselement for å starte"
}, },
"publishSuccessDialog": { "publishSuccessDialog": {
"title": "", "title": "Bibliotek innsendt",
"content": "", "content": "Tusen takk {{authorName}}! Biblioteket ditt har blitt sendt inn til gjennomgang. Du kan halde styr på status",
"link": "" "link": "her"
}, },
"confirmDialog": { "confirmDialog": {
"resetLibrary": "", "resetLibrary": "Tilbakestill bibliotek",
"removeItemsFromLib": "" "removeItemsFromLib": "Fjern valde element frå biblioteket"
}, },
"encrypted": { "encrypted": {
"tooltip": "Teikningane dine er ende-til-ende-krypterte slik at Excalidraw sine serverar aldri får sjå dei.", "tooltip": "Teikningane dine er ende-til-ende-krypterte slik at Excalidraw sine serverar aldri får sjå dei.",
@ -361,7 +372,7 @@
"width": "Breidde" "width": "Breidde"
}, },
"toast": { "toast": {
"addedToLibrary": "", "addedToLibrary": "Lagt til i bibliotek",
"copyStyles": "Kopierte stilane.", "copyStyles": "Kopierte stilane.",
"copyToClipboard": "Kopiert til utklippstavla.", "copyToClipboard": "Kopiert til utklippstavla.",
"copyToClipboardAsPng": "Kopierte {{exportSelection}} til utklippstavla som PNG\n({{exportColorScheme}})", "copyToClipboardAsPng": "Kopierte {{exportSelection}} til utklippstavla som PNG\n({{exportColorScheme}})",

View File

@ -9,6 +9,7 @@
"copy": "Copiar", "copy": "Copiar",
"copyAsPng": "Copiar al quichapapièrs coma PNG", "copyAsPng": "Copiar al quichapapièrs coma PNG",
"copyAsSvg": "Copiar al quichapapièrs coma SVG", "copyAsSvg": "Copiar al quichapapièrs coma SVG",
"copyText": "",
"bringForward": "En avant", "bringForward": "En avant",
"sendToBack": "En arrièr", "sendToBack": "En arrièr",
"bringToFront": "A lendavant", "bringToFront": "A lendavant",
@ -64,7 +65,7 @@
"cartoonist": "Dessenhaire", "cartoonist": "Dessenhaire",
"fileTitle": "Nom del fichièr", "fileTitle": "Nom del fichièr",
"colorPicker": "Selector de color", "colorPicker": "Selector de color",
"canvasColors": "", "canvasColors": "Utilizada suls canabassses",
"canvasBackground": "Rèireplan del canabàs", "canvasBackground": "Rèireplan del canabàs",
"drawingCanvas": "Zòna de dessenh", "drawingCanvas": "Zòna de dessenh",
"layers": "Calques", "layers": "Calques",
@ -106,11 +107,18 @@
"excalidrawLib": "Bibliotèca Excalidraw", "excalidrawLib": "Bibliotèca Excalidraw",
"decreaseFontSize": "Reduire talha poliça", "decreaseFontSize": "Reduire talha poliça",
"increaseFontSize": "Aumentar talha poliça", "increaseFontSize": "Aumentar talha poliça",
"unbindText": "", "unbindText": "Dessociar lo tèxte",
"bindText": "",
"link": { "link": {
"edit": "Modificar lo ligam", "edit": "Modificar lo ligam",
"create": "Crear un ligam", "create": "Crear un ligam",
"label": "Ligam" "label": "Ligam"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Cargament impossible dun fichièr invalid", "couldNotLoadInvalidFile": "Cargament impossible dun fichièr invalid",
"importBackendFailed": "Importacion fracassada.", "importBackendFailed": "Importacion fracassada.",
"cannotExportEmptyCanvas": "Impossible dexportar los canabasses voids.", "cannotExportEmptyCanvas": "Impossible dexportar los canabasses voids.",
"couldNotCopyToClipboard": "Còpia impossibla al quichapapièrs. Ensajatz dutilizar lo navegador Chrome.", "couldNotCopyToClipboard": "",
"decryptFailed": "Deschiframent impossible de las donadas.", "decryptFailed": "Deschiframent impossible de las donadas.",
"uploadedSecurly": "Lo telecargament es estat securizat amb un chiframent del cap a la fin, significa que los servidors dExcalidraw o que quina tèrça part que siá pòdon pas legir lo contengut.", "uploadedSecurly": "Lo telecargament es estat securizat amb un chiframent del cap a la fin, significa que los servidors dExcalidraw o que quina tèrça part que siá pòdon pas legir lo contengut.",
"loadSceneOverridePrompt": "Cargar un dessenh extèrn remplaçarà vòstre contengut existent. Volètz contunhar?", "loadSceneOverridePrompt": "Cargar un dessenh extèrn remplaçarà vòstre contengut existent. Volètz contunhar?",
@ -181,7 +189,7 @@
"fileTooBig": "Fichièr tròp pesuc. La talha maximala autorizada es {{maxSize}}.", "fileTooBig": "Fichièr tròp pesuc. La talha maximala autorizada es {{maxSize}}.",
"svgImageInsertError": "Insercion dimatge SVG impossibla. Las balisas SVG semblan invalidas.", "svgImageInsertError": "Insercion dimatge SVG impossibla. Las balisas SVG semblan invalidas.",
"invalidSVGString": "SVG invalid.", "invalidSVGString": "SVG invalid.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "Connexion impossibla al servidor collab. Mercés de recargar la pagina e tornar ensajar."
}, },
"toolBar": { "toolBar": {
"selection": "Seleccion", "selection": "Seleccion",
@ -196,7 +204,8 @@
"library": "Bibliotèca", "library": "Bibliotèca",
"lock": "Mantenir activa laisina aprèp dessenhar", "lock": "Mantenir activa laisina aprèp dessenhar",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": "Goma"
}, },
"headings": { "headings": {
"canvasActions": "Accions del canabàs", "canvasActions": "Accions del canabàs",
@ -220,8 +229,9 @@
"lineEditor_nothingSelected": "Seleccionar un punt deditar (manténer Maj. per ne seleccionar mantun),\no manténer Alt e clicar per napondre de novèls", "lineEditor_nothingSelected": "Seleccionar un punt deditar (manténer Maj. per ne seleccionar mantun),\no manténer Alt e clicar per napondre de novèls",
"placeImage": "Clicatz per plaçar limatge, o clicatz e lisatz per definir sa talha manualament", "placeImage": "Clicatz per plaçar limatge, o clicatz e lisatz per definir sa talha manualament",
"publishLibrary": "Publicar vòstra pròpria bibliotèca", "publishLibrary": "Publicar vòstra pròpria bibliotèca",
"bindTextToElement": "", "bindTextToElement": "Quichatz Entrada per apondre de tèxte",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Afichatge impossible de lapercebut", "cannotShowPreview": "Afichatge impossible de lapercebut",
@ -281,14 +291,15 @@
"howto": "Seguissètz nòstras guidas", "howto": "Seguissètz nòstras guidas",
"or": "o", "or": "o",
"preventBinding": "Empachar la fixacion de sagetas", "preventBinding": "Empachar la fixacion de sagetas",
"shapes": "Formas", "tools": "Aisinas",
"shortcuts": "Acorchis clavièr", "shortcuts": "Acorchis clavièr",
"textFinish": "Terminar ledicion (editor de tèxt)", "textFinish": "Terminar ledicion (editor de tèxt)",
"textNewLine": "Apondre linha novèl (editor de tèxt)", "textNewLine": "Apondre linha novèl (editor de tèxt)",
"title": "Ajuda", "title": "Ajuda",
"view": "Vista", "view": "Vista",
"zoomToFit": "Zoomar per veire totes los elements", "zoomToFit": "Zoomar per veire totes los elements",
"zoomToSelection": "Zoomar la seleccion" "zoomToSelection": "Zoomar la seleccion",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Escafar canabàs" "title": "Escafar canabàs"

View File

@ -9,6 +9,7 @@
"copy": "ਕਾਪੀ ਕਰੋ", "copy": "ਕਾਪੀ ਕਰੋ",
"copyAsPng": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ PNG ਵਜੋਂ ਕਾਪੀ ਕਰੋ", "copyAsPng": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ PNG ਵਜੋਂ ਕਾਪੀ ਕਰੋ",
"copyAsSvg": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ SVG ਵਜੋਂ ਕਾਪੀ ਕਰੋ", "copyAsSvg": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ SVG ਵਜੋਂ ਕਾਪੀ ਕਰੋ",
"copyText": "",
"bringForward": "ਅੱਗੇ ਲਿਆਓ", "bringForward": "ਅੱਗੇ ਲਿਆਓ",
"sendToBack": "ਸਭ ਤੋਂ ਪਿੱਛੇ ਭੇਜੋ", "sendToBack": "ਸਭ ਤੋਂ ਪਿੱਛੇ ਭੇਜੋ",
"bringToFront": "ਸਭ ਤੋਂ ਅੱਗੇ ਲਿਆਓ", "bringToFront": "ਸਭ ਤੋਂ ਅੱਗੇ ਲਿਆਓ",
@ -64,7 +65,7 @@
"cartoonist": "ਕਾਰਟੂਨਿਸਟ", "cartoonist": "ਕਾਰਟੂਨਿਸਟ",
"fileTitle": "ਫਾਈਲ ਦਾ ਨਾਂ", "fileTitle": "ਫਾਈਲ ਦਾ ਨਾਂ",
"colorPicker": "ਰੰਗ ਚੋਣਕਾਰ", "colorPicker": "ਰੰਗ ਚੋਣਕਾਰ",
"canvasColors": "", "canvasColors": "ਕੈਨਵਸ 'ਤੇ ਵਰਤਿਆ",
"canvasBackground": "ਕੈਨਵਸ ਦਾ ਬੈਕਗਰਾਉਂਡ", "canvasBackground": "ਕੈਨਵਸ ਦਾ ਬੈਕਗਰਾਉਂਡ",
"drawingCanvas": "ਡਰਾਇੰਗ ਕੈਨਵਸ", "drawingCanvas": "ਡਰਾਇੰਗ ਕੈਨਵਸ",
"layers": "ਪਰਤਾਂ", "layers": "ਪਰਤਾਂ",
@ -104,13 +105,20 @@
"toggleTheme": "ਥੀਮ ਬਦਲੋ", "toggleTheme": "ਥੀਮ ਬਦਲੋ",
"personalLib": "ਨਿੱਜੀ ਲਾਇਬ੍ਰੇਰੀ", "personalLib": "ਨਿੱਜੀ ਲਾਇਬ੍ਰੇਰੀ",
"excalidrawLib": "ਐਕਸਕਲੀਡਰਾਅ ਲਾਇਬ੍ਰੇਰੀ", "excalidrawLib": "ਐਕਸਕਲੀਡਰਾਅ ਲਾਇਬ੍ਰੇਰੀ",
"decreaseFontSize": "", "decreaseFontSize": "ਫੌਂਟ ਦਾ ਅਕਾਰ ਘਟਾਓ",
"increaseFontSize": "", "increaseFontSize": "ਫੌਂਟ ਦਾ ਅਕਾਰ ਵਧਾਓ",
"unbindText": "", "unbindText": "",
"bindText": "ਪਾਠ ਨੂੰ ਕੰਟੇਨਰ ਨਾਲ ਬੰਨ੍ਹੋ",
"link": { "link": {
"edit": "", "edit": "ਕੜੀ ਸੋਧੋ",
"create": "", "create": "ਕੜੀ ਬਣਾਓ",
"label": "" "label": "ਕੜੀ"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "ਨਜਾਇਜ਼ ਫਾਈਲ ਲੋਡ ਨਹੀਂ ਕਰ ਸਕੇ", "couldNotLoadInvalidFile": "ਨਜਾਇਜ਼ ਫਾਈਲ ਲੋਡ ਨਹੀਂ ਕਰ ਸਕੇ",
"importBackendFailed": "ਬੈਕਐੱਨਡ ਤੋਂ ਆਯਾਤ ਕਰਨ ਵਿੱਚ ਅਸਫਲ ਰਹੇ।", "importBackendFailed": "ਬੈਕਐੱਨਡ ਤੋਂ ਆਯਾਤ ਕਰਨ ਵਿੱਚ ਅਸਫਲ ਰਹੇ।",
"cannotExportEmptyCanvas": "ਖਾਲੀ ਕੈਨਵਸ ਨਿਰਯਾਤ ਨਹੀਂ ਕਰ ਸਕਦੇ।", "cannotExportEmptyCanvas": "ਖਾਲੀ ਕੈਨਵਸ ਨਿਰਯਾਤ ਨਹੀਂ ਕਰ ਸਕਦੇ।",
"couldNotCopyToClipboard": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਨਹੀਂ ਕਰ ਸਕੇ। ਕਰੋਮ ਬਰਾਉਜ਼ਰ ਵਰਤ ਕੇ ਦੇਖੋ।", "couldNotCopyToClipboard": "",
"decryptFailed": "ਡਾਟਾ ਡੀਕਰਿਪਟ ਨਹੀਂ ਕਰ ਸਕੇ।", "decryptFailed": "ਡਾਟਾ ਡੀਕਰਿਪਟ ਨਹੀਂ ਕਰ ਸਕੇ।",
"uploadedSecurly": "ਅੱਪਲੋਡ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕਰਿਪਸ਼ਨ ਨਾਲ ਸੁਰੱਖਿਅਤ ਕੀਤੀ ਹੋਈ ਹੈ, ਜਿਸਦਾ ਮਤਲਬ ਇਹ ਹੈ ਕਿ Excalidraw ਸਰਵਰ ਅਤੇ ਤੀਜੀ ਧਿਰ ਦੇ ਬੰਦੇ ਸਮੱਗਰੀ ਨੂੰ ਪੜ੍ਹ ਨਹੀਂ ਸਕਦੇ।", "uploadedSecurly": "ਅੱਪਲੋਡ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕਰਿਪਸ਼ਨ ਨਾਲ ਸੁਰੱਖਿਅਤ ਕੀਤੀ ਹੋਈ ਹੈ, ਜਿਸਦਾ ਮਤਲਬ ਇਹ ਹੈ ਕਿ Excalidraw ਸਰਵਰ ਅਤੇ ਤੀਜੀ ਧਿਰ ਦੇ ਬੰਦੇ ਸਮੱਗਰੀ ਨੂੰ ਪੜ੍ਹ ਨਹੀਂ ਸਕਦੇ।",
"loadSceneOverridePrompt": "ਬਾਹਰੀ ਡਰਾਇੰਗ ਨੂੰ ਲੋਡ ਕਰਨਾ ਤੁਹਾਡੀ ਮੌਜੂਦਾ ਸਮੱਗਰੀ ਦੀ ਥਾਂ ਲੈ ਲਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?", "loadSceneOverridePrompt": "ਬਾਹਰੀ ਡਰਾਇੰਗ ਨੂੰ ਲੋਡ ਕਰਨਾ ਤੁਹਾਡੀ ਮੌਜੂਦਾ ਸਮੱਗਰੀ ਦੀ ਥਾਂ ਲੈ ਲਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?",
@ -168,11 +176,11 @@
"errorAddingToLibrary": "ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਸਮੱਗਰੀ ਨਹੀਂ ਜੋੜ ਸਕੇ", "errorAddingToLibrary": "ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਸਮੱਗਰੀ ਨਹੀਂ ਜੋੜ ਸਕੇ",
"errorRemovingFromLibrary": "ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚੋਂ ਸਮੱਗਰੀ ਨਹੀਂ ਹਟਾ ਸਕੇ", "errorRemovingFromLibrary": "ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚੋਂ ਸਮੱਗਰੀ ਨਹੀਂ ਹਟਾ ਸਕੇ",
"confirmAddLibrary": "ਇਹ ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ {{numShapes}} ਆਕ੍ਰਿਤੀ(ਆਂ) ਨੂੰ ਜੋੜ ਦੇਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", "confirmAddLibrary": "ਇਹ ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ {{numShapes}} ਆਕ੍ਰਿਤੀ(ਆਂ) ਨੂੰ ਜੋੜ ਦੇਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?",
"imageDoesNotContainScene": "", "imageDoesNotContainScene": "ਇਸ ਤਸਵੀਰ ਵਿੱਚ ਦ੍ਰਿਸ਼ ਦਾ ਕੋਈ ਵੀ ਡਾਟਾ ਨਜ਼ਰ ਨਹੀਂ ਆ ਰਿਹਾ। ਕੀ ਤੁਸੀਂ ਨਿਰਯਾਤ ਕਰਦੇ ਸਮੇਂ ਦ੍ਰਿਸ਼ ਨੂੰ ਮੜ੍ਹਣਾ ਸਮਰੱਥ ਕੀਤਾ ਸੀ?",
"cannotRestoreFromImage": "ਇਸ ਤਸਵੀਰ ਫਾਈਲ ਤੋਂ ਦ੍ਰਿਸ਼ ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ", "cannotRestoreFromImage": "ਇਸ ਤਸਵੀਰ ਫਾਈਲ ਤੋਂ ਦ੍ਰਿਸ਼ ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ",
"invalidSceneUrl": "ਦਿੱਤੀ ਗਈ URL 'ਚੋਂ ਦ੍ਰਿਸ਼ ਨੂੰ ਆਯਾਤ ਨਹੀਂ ਕਰ ਸਕੇ। ਇਹ ਜਾਂ ਤਾਂ ਖਰਾਬ ਹੈ, ਜਾਂ ਇਸ ਵਿੱਚ ਜਾਇਜ਼ Excalidraw JSON ਡਾਟਾ ਸ਼ਾਮਲ ਨਹੀਂ ਹੈ।", "invalidSceneUrl": "ਦਿੱਤੀ ਗਈ URL 'ਚੋਂ ਦ੍ਰਿਸ਼ ਨੂੰ ਆਯਾਤ ਨਹੀਂ ਕਰ ਸਕੇ। ਇਹ ਜਾਂ ਤਾਂ ਖਰਾਬ ਹੈ, ਜਾਂ ਇਸ ਵਿੱਚ ਜਾਇਜ਼ Excalidraw JSON ਡਾਟਾ ਸ਼ਾਮਲ ਨਹੀਂ ਹੈ।",
"resetLibrary": "ਇਹ ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਸਾਫ ਕਰ ਦੇਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", "resetLibrary": "ਇਹ ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਸਾਫ ਕਰ ਦੇਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?",
"removeItemsFromsLibrary": "", "removeItemsFromsLibrary": "ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚੋਂ {{count}} ਚੀਜ਼(-ਜ਼ਾਂ) ਮਿਟਾਉਣੀਆਂ ਹਨ?",
"invalidEncryptionKey": "" "invalidEncryptionKey": ""
}, },
"errors": { "errors": {
@ -196,7 +204,8 @@
"library": "ਲਾਇਬ੍ਰੇਰੀ", "library": "ਲਾਇਬ੍ਰੇਰੀ",
"lock": "ਡਰਾਇੰਗ ਤੋਂ ਬਾਅਦ ਵੀ ਚੁਣੇ ਹੋਏ ਸੰਦ ਨੂੰ ਸਰਗਰਮ ਰੱਖੋ ", "lock": "ਡਰਾਇੰਗ ਤੋਂ ਬਾਅਦ ਵੀ ਚੁਣੇ ਹੋਏ ਸੰਦ ਨੂੰ ਸਰਗਰਮ ਰੱਖੋ ",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": "ਰਬੜ"
}, },
"headings": { "headings": {
"canvasActions": "ਕੈਨਵਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ", "canvasActions": "ਕੈਨਵਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ",
@ -219,9 +228,10 @@
"lineEditor_pointSelected": "", "lineEditor_pointSelected": "",
"lineEditor_nothingSelected": "", "lineEditor_nothingSelected": "",
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "ਆਪਣੀ ਲਾਇਬ੍ਰੇਰੀ ਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ",
"bindTextToElement": "", "bindTextToElement": "ਪਾਠ ਜੋੜਨ ਲਈ ਐੰਟਰ ਦਬਾਓ",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "ਝਲਕ ਨਹੀਂ ਦਿਖਾ ਸਕਦੇ", "cannotShowPreview": "ਝਲਕ ਨਹੀਂ ਦਿਖਾ ਸਕਦੇ",
@ -281,31 +291,32 @@
"howto": "ਸਾਡੀਆਂ ਗਾਈਡਾਂ ਦੀ ਪਾਲਣਾ ਕਰੋ", "howto": "ਸਾਡੀਆਂ ਗਾਈਡਾਂ ਦੀ ਪਾਲਣਾ ਕਰੋ",
"or": "ਜਾਂ", "or": "ਜਾਂ",
"preventBinding": "ਤੀਰ ਬੱਝਣਾ ਰੋਕੋ", "preventBinding": "ਤੀਰ ਬੱਝਣਾ ਰੋਕੋ",
"shapes": "ਆਕ੍ਰਿਤੀਆਂ", "tools": "ਟੂਲ",
"shortcuts": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ", "shortcuts": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ",
"textFinish": "ਸੋਧਣਾ ਮੁਕੰਮਲ ਕਰੋ (ਪਾਠ ਸੋਧਕ)", "textFinish": "ਸੋਧਣਾ ਮੁਕੰਮਲ ਕਰੋ (ਪਾਠ ਸੋਧਕ)",
"textNewLine": "ਨਵੀਂ ਪੰਕਤੀ ਜੋੜੋ (ਪਾਠ ਸੋਧਕ)", "textNewLine": "ਨਵੀਂ ਪੰਕਤੀ ਜੋੜੋ (ਪਾਠ ਸੋਧਕ)",
"title": "ਮਦਦ", "title": "ਮਦਦ",
"view": "ਦਿੱਖ", "view": "ਦਿੱਖ",
"zoomToFit": "ਸਾਰੇ ਐਲੀਮੈਂਟਾਂ ਨੂੰ ਫਿੱਟ ਕਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ", "zoomToFit": "ਸਾਰੇ ਐਲੀਮੈਂਟਾਂ ਨੂੰ ਫਿੱਟ ਕਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ",
"zoomToSelection": "ਚੋਣ ਤੱਕ ਜ਼ੂਮ ਕਰੋ" "zoomToSelection": "ਚੋਣ ਤੱਕ ਜ਼ੂਮ ਕਰੋ",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "ਕੈਨਵਸ ਨੂੰ ਸਾਫ਼ ਕਰੋ" "title": "ਕੈਨਵਸ ਨੂੰ ਸਾਫ਼ ਕਰੋ"
}, },
"publishDialog": { "publishDialog": {
"title": "ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਪ੍ਰਕਾਸ਼ਤ ਕਰੋ", "title": "ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਪ੍ਰਕਾਸ਼ਤ ਕਰੋ",
"itemName": "", "itemName": "ਚੀਜ਼ ਦਾ ਨਾਂ",
"authorName": "ਲੇਖਕ ਦਾ ਨਾਂ", "authorName": "ਲੇਖਕ ਦਾ ਨਾਂ",
"githubUsername": "ਗਿੱਟਹੱਬ ਵਰਤੋਂਕਾਰ ਨਾਂ", "githubUsername": "ਗਿੱਟਹੱਬ ਵਰਤੋਂਕਾਰ ਨਾਂ",
"twitterUsername": "", "twitterUsername": "ਟਵਿੱਟਰ ਦਾ ਵਰਤੋਂਕਾਰ-ਨਾਂ",
"libraryName": "", "libraryName": "ਲਾਇਬ੍ਰੇਰੀ ਦਾ ਨਾਂ",
"libraryDesc": "", "libraryDesc": "ਲਾਇਬ੍ਰੇਰੀ ਦਾ ਵੇਰਵਾ",
"website": "", "website": "ਵੈੱਬਸਾਇਟ",
"placeholder": { "placeholder": {
"authorName": "", "authorName": "ਤੁਹਾਡਾ ਨਾਂ ਜਾਂ ਵਰਤੋਂਕਾਰ-ਨਾਂ",
"libraryName": "", "libraryName": "ਤੁਹਾਡੀ ਲਾਇਬਰ੍ਰੀ ਦਾ ਨਾਂ",
"libraryDesc": "", "libraryDesc": "ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਦਾ ਵੇਰਵਾ ਤਾਂ ਜੋ ਲੋਕਾਂ ਨੂੰ ਇਸ ਤੋੰਂ ਇਸਦੀ ਵਰਤੋਂ ਕਰਨ ਸਬੰਧੀ ਮਦਦ ਮਿਲ ਸਕੇ",
"githubHandle": "", "githubHandle": "",
"twitterHandle": "", "twitterHandle": "",
"website": "" "website": ""
@ -316,7 +327,7 @@
}, },
"noteDescription": { "noteDescription": {
"pre": "", "pre": "",
"link": "", "link": "ਜਨਤਕ ਲਾਇਬ੍ਰੇਰੀ ਦੀ ਰਿਪਾਜ਼ੀਟਰੀ",
"post": "" "post": ""
}, },
"noteGuidelines": { "noteGuidelines": {

View File

@ -1,48 +1,49 @@
{ {
"ar-SA": 94, "ar-SA": 93,
"bg-BG": 61, "bg-BG": 59,
"bn-BD": 0, "bn-BD": 0,
"ca-ES": 99, "ca-ES": 96,
"cs-CZ": 24, "cs-CZ": 23,
"da-DK": 17, "da-DK": 16,
"de-DE": 99, "de-DE": 100,
"el-GR": 86, "el-GR": 83,
"en": 100, "en": 100,
"es-ES": 99, "es-ES": 98,
"eu-ES": 99, "eu-ES": 98,
"fa-IR": 63, "fa-IR": 61,
"fi-FI": 98, "fi-FI": 98,
"fr-FR": 99, "fr-FR": 100,
"he-IL": 80, "he-IL": 77,
"hi-IN": 58, "hi-IN": 61,
"hu-HU": 99, "hu-HU": 96,
"id-ID": 100, "id-ID": 100,
"it-IT": 100, "it-IT": 100,
"ja-JP": 97, "ja-JP": 99,
"kab-KAB": 95, "kab-KAB": 94,
"kk-KZ": 23, "kk-KZ": 22,
"ko-KR": 72, "ko-KR": 69,
"lt-LT": 23, "lt-LT": 23,
"lv-LV": 100, "lv-LV": 100,
"mr-IN": 0, "mr-IN": 100,
"my-MM": 46, "my-MM": 45,
"nb-NO": 100, "nb-NO": 100,
"nl-NL": 90, "nl-NL": 87,
"nn-NO": 83, "nn-NO": 97,
"oc-FR": 97, "oc-FR": 96,
"pa-IN": 86, "pa-IN": 89,
"pl-PL": 93, "pl-PL": 90,
"pt-BR": 99, "pt-BR": 97,
"pt-PT": 83, "pt-PT": 80,
"ro-RO": 100, "ro-RO": 100,
"ru-RU": 99, "ru-RU": 100,
"si-LK": 9, "si-LK": 9,
"sk-SK": 99, "sk-SK": 100,
"sv-SE": 100, "sl-SI": 34,
"ta-IN": 99, "sv-SE": 98,
"tr-TR": 84, "ta-IN": 98,
"uk-UA": 81, "tr-TR": 100,
"uk-UA": 91,
"zh-CN": 100, "zh-CN": 100,
"zh-HK": 28, "zh-HK": 27,
"zh-TW": 100 "zh-TW": 100
} }

View File

@ -9,6 +9,7 @@
"copy": "Kopiuj", "copy": "Kopiuj",
"copyAsPng": "Skopiuj do schowka jako plik PNG", "copyAsPng": "Skopiuj do schowka jako plik PNG",
"copyAsSvg": "Skopiuj do schowka jako plik SVG", "copyAsSvg": "Skopiuj do schowka jako plik SVG",
"copyText": "",
"bringForward": "Przenieś wyżej", "bringForward": "Przenieś wyżej",
"sendToBack": "Przenieś na spód", "sendToBack": "Przenieś na spód",
"bringToFront": "Przenieś na wierzch", "bringToFront": "Przenieś na wierzch",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Nie udało się otworzyć pliku. Wybrany plik jest nieprawidłowy.", "couldNotLoadInvalidFile": "Nie udało się otworzyć pliku. Wybrany plik jest nieprawidłowy.",
"importBackendFailed": "Wystąpił błąd podczas importowania pliku.", "importBackendFailed": "Wystąpił błąd podczas importowania pliku.",
"cannotExportEmptyCanvas": "Najpierw musisz coś narysować, aby zapisać dokument.", "cannotExportEmptyCanvas": "Najpierw musisz coś narysować, aby zapisać dokument.",
"couldNotCopyToClipboard": "Błąd podczas kopiowania. Spróbuj użyć Google Chrome.", "couldNotCopyToClipboard": "",
"decryptFailed": "Nie udało się odszyfrować danych.", "decryptFailed": "Nie udało się odszyfrować danych.",
"uploadedSecurly": "By zapewnić Ci prywatność, udostępnianie projektu jest zabezpieczone szyfrowaniem end-to-end, co oznacza, że poza tobą i osobą z którą podzielisz się linkiem, nikt nie ma dostępu do tego co udostępniasz.", "uploadedSecurly": "By zapewnić Ci prywatność, udostępnianie projektu jest zabezpieczone szyfrowaniem end-to-end, co oznacza, że poza tobą i osobą z którą podzielisz się linkiem, nikt nie ma dostępu do tego co udostępniasz.",
"loadSceneOverridePrompt": "Wczytanie zewnętrznego rysunku zastąpi istniejącą zawartość. Czy chcesz kontynuować?", "loadSceneOverridePrompt": "Wczytanie zewnętrznego rysunku zastąpi istniejącą zawartość. Czy chcesz kontynuować?",
@ -196,7 +204,8 @@
"library": "Biblioteka", "library": "Biblioteka",
"lock": "Zablokuj wybrane narzędzie", "lock": "Zablokuj wybrane narzędzie",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "Narzędzia", "canvasActions": "Narzędzia",
@ -221,7 +230,8 @@
"placeImage": "Kliknij, aby umieścić obraz, lub kliknij i przeciągnij, aby ustawić jego rozmiar ręcznie", "placeImage": "Kliknij, aby umieścić obraz, lub kliknij i przeciągnij, aby ustawić jego rozmiar ręcznie",
"publishLibrary": "Opublikuj własną bibliotekę", "publishLibrary": "Opublikuj własną bibliotekę",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Nie można wyświetlić podglądu", "cannotShowPreview": "Nie można wyświetlić podglądu",
@ -281,14 +291,15 @@
"howto": "Skorzystaj z instrukcji", "howto": "Skorzystaj z instrukcji",
"or": "lub", "or": "lub",
"preventBinding": "Zapobiegaj wiązaniu strzałek", "preventBinding": "Zapobiegaj wiązaniu strzałek",
"shapes": "Kształty", "tools": "",
"shortcuts": "Skróty klawiszowe", "shortcuts": "Skróty klawiszowe",
"textFinish": "Zakończ edycję (edytor tekstu)", "textFinish": "Zakończ edycję (edytor tekstu)",
"textNewLine": "Dodaj nowy wiersz (edytor tekstu)", "textNewLine": "Dodaj nowy wiersz (edytor tekstu)",
"title": "Pomoc", "title": "Pomoc",
"view": "Widok", "view": "Widok",
"zoomToFit": "Powiększ, aby wyświetlić wszystkie elementy", "zoomToFit": "Powiększ, aby wyświetlić wszystkie elementy",
"zoomToSelection": "Przybliż do zaznaczenia" "zoomToSelection": "Przybliż do zaznaczenia",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Wyczyść płótno" "title": "Wyczyść płótno"

View File

@ -9,6 +9,7 @@
"copy": "Copiar", "copy": "Copiar",
"copyAsPng": "Copiar para a área de transferência como PNG", "copyAsPng": "Copiar para a área de transferência como PNG",
"copyAsSvg": "Copiar para a área de transferência como SVG", "copyAsSvg": "Copiar para a área de transferência como SVG",
"copyText": "",
"bringForward": "Trazer para a frente", "bringForward": "Trazer para a frente",
"sendToBack": "Enviar para o fundo", "sendToBack": "Enviar para o fundo",
"bringToFront": "Trazer para o primeiro plano", "bringToFront": "Trazer para o primeiro plano",
@ -107,10 +108,17 @@
"decreaseFontSize": "Diminuir o tamanho da fonte", "decreaseFontSize": "Diminuir o tamanho da fonte",
"increaseFontSize": "Aumentar o tamanho da fonte", "increaseFontSize": "Aumentar o tamanho da fonte",
"unbindText": "Desvincular texto", "unbindText": "Desvincular texto",
"bindText": "",
"link": { "link": {
"edit": "Editar link", "edit": "Editar link",
"create": "Criar link", "create": "Criar link",
"label": "Link" "label": "Link"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Não foi possível carregar o arquivo inválido", "couldNotLoadInvalidFile": "Não foi possível carregar o arquivo inválido",
"importBackendFailed": "A importação do servidor falhou.", "importBackendFailed": "A importação do servidor falhou.",
"cannotExportEmptyCanvas": "Não é possível exportar um canvas vazio.", "cannotExportEmptyCanvas": "Não é possível exportar um canvas vazio.",
"couldNotCopyToClipboard": "Não foi possível copiar para a área de transferência. Experimente usando o navegador Chrome.", "couldNotCopyToClipboard": "",
"decryptFailed": "Não foi possível descriptografar os dados.", "decryptFailed": "Não foi possível descriptografar 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.", "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": "Carregar um desenho externo substituirá o seu conteúdo existente. Deseja continuar?",
@ -181,7 +189,7 @@
"fileTooBig": "O arquivo é muito grande. O tamanho máximo permitido é {{maxSize}}.", "fileTooBig": "O arquivo é muito grande. O tamanho máximo permitido é {{maxSize}}.",
"svgImageInsertError": "Não foi possível inserir a imagem SVG. A marcação SVG parece inválida.", "svgImageInsertError": "Não foi possível inserir a imagem SVG. A marcação SVG parece inválida.",
"invalidSVGString": "SVG Inválido.", "invalidSVGString": "SVG Inválido.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "Não foi possível conectar-se ao servidor colaborativo. Por favor, recarregue a página e tente novamente."
}, },
"toolBar": { "toolBar": {
"selection": "Seleção", "selection": "Seleção",
@ -196,7 +204,8 @@
"library": "Biblioteca", "library": "Biblioteca",
"lock": "Manter ativa a ferramenta selecionada após desenhar", "lock": "Manter ativa a ferramenta selecionada após desenhar",
"penMode": "Prevenir a ação de tocar-ampliar e permitir apenas interações da caneta", "penMode": "Prevenir a ação de tocar-ampliar e permitir apenas interações da caneta",
"link": "Adicionar/Atualizar link para uma forma selecionada" "link": "Adicionar/Atualizar link para uma forma selecionada",
"eraser": "Borracha"
}, },
"headings": { "headings": {
"canvasActions": "Ações da tela", "canvasActions": "Ações da tela",
@ -221,7 +230,8 @@
"placeImage": "Clique para colocar a imagem, ou clique e arraste para definir manualmente o seu tamanho", "placeImage": "Clique para colocar a imagem, ou clique e arraste para definir manualmente o seu tamanho",
"publishLibrary": "Publicar sua própria biblioteca", "publishLibrary": "Publicar sua própria biblioteca",
"bindTextToElement": "Pressione Enter para adicionar o texto", "bindTextToElement": "Pressione Enter para adicionar o texto",
"deepBoxSelect": "Segure Ctrl/Cmd para seleção profunda e para evitar arrastar" "deepBoxSelect": "Segure Ctrl/Cmd para seleção profunda e para evitar arrastar",
"eraserRevert": "Segure a tecla Alt para inverter os elementos marcados para exclusão"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Não é possível mostrar pré-visualização", "cannotShowPreview": "Não é possível mostrar pré-visualização",
@ -281,14 +291,15 @@
"howto": "Siga nossos guias", "howto": "Siga nossos guias",
"or": "ou", "or": "ou",
"preventBinding": "Evitar fixação de seta", "preventBinding": "Evitar fixação de seta",
"shapes": "Formas", "tools": "",
"shortcuts": "Atalhos de teclado", "shortcuts": "Atalhos de teclado",
"textFinish": "Encerrar edição (editor de texto)", "textFinish": "Encerrar edição (editor de texto)",
"textNewLine": "Adicionar nova linha (editor de texto)", "textNewLine": "Adicionar nova linha (editor de texto)",
"title": "Ajudar", "title": "Ajudar",
"view": "Visualizar", "view": "Visualizar",
"zoomToFit": "Ampliar para encaixar todos os elementos", "zoomToFit": "Ampliar para encaixar todos os elementos",
"zoomToSelection": "Ampliar a seleção" "zoomToSelection": "Ampliar a seleção",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Limpar a tela" "title": "Limpar a tela"

View File

@ -9,6 +9,7 @@
"copy": "Copiar", "copy": "Copiar",
"copyAsPng": "Copiar para a área de transferência como PNG", "copyAsPng": "Copiar para a área de transferência como PNG",
"copyAsSvg": "Copiar para a área de transferência como SVG", "copyAsSvg": "Copiar para a área de transferência como SVG",
"copyText": "",
"bringForward": "Trazer para o primeiro plano", "bringForward": "Trazer para o primeiro plano",
"sendToBack": "Enviar para o plano de fundo", "sendToBack": "Enviar para o plano de fundo",
"bringToFront": "Trazer para o primeiro plano", "bringToFront": "Trazer para o primeiro plano",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Não foi possível carregar o ficheiro inválido", "couldNotLoadInvalidFile": "Não foi possível carregar o ficheiro inválido",
"importBackendFailed": "A importação do servidor falhou.", "importBackendFailed": "A importação do servidor falhou.",
"cannotExportEmptyCanvas": "Não é possível exportar uma área de desenho vazia.", "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.", "couldNotCopyToClipboard": "",
"decryptFailed": "Não foi possível desencriptar os dados.", "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.", "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": "Se carregar um desenho externo substituirá o conteúdo existente. Quer continuar?", "loadSceneOverridePrompt": "Se carregar um desenho externo substituirá o conteúdo existente. Quer continuar?",
@ -196,7 +204,8 @@
"library": "Biblioteca", "library": "Biblioteca",
"lock": "Manter a ferramenta selecionada ativa após desenhar", "lock": "Manter a ferramenta selecionada ativa após desenhar",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "Ações da área de desenho", "canvasActions": "Ações da área de desenho",
@ -221,7 +230,8 @@
"placeImage": "Clique para colocar a imagem ou clique e arraste para definir o seu tamanho manualmente", "placeImage": "Clique para colocar a imagem ou clique e arraste para definir o seu tamanho manualmente",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Não é possível mostrar uma pré-visualização", "cannotShowPreview": "Não é possível mostrar uma pré-visualização",
@ -281,14 +291,15 @@
"howto": "Siga os nossos guias", "howto": "Siga os nossos guias",
"or": "ou", "or": "ou",
"preventBinding": "Prevenir fixação de seta", "preventBinding": "Prevenir fixação de seta",
"shapes": "Formas", "tools": "",
"shortcuts": "Atalhos de teclado", "shortcuts": "Atalhos de teclado",
"textFinish": "Finalizar edição (editor texto)", "textFinish": "Finalizar edição (editor texto)",
"textNewLine": "Adicionar nova linha (editor de texto)", "textNewLine": "Adicionar nova linha (editor de texto)",
"title": "Ajuda", "title": "Ajuda",
"view": "Visualizar", "view": "Visualizar",
"zoomToFit": "Ajustar para todos os elementos caberem", "zoomToFit": "Ajustar para todos os elementos caberem",
"zoomToSelection": "Ampliar a seleção" "zoomToSelection": "Ampliar a seleção",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "Copiere", "copy": "Copiere",
"copyAsPng": "Copiere în memoria temporară ca PNG", "copyAsPng": "Copiere în memoria temporară ca PNG",
"copyAsSvg": "Copiere în memoria temporară ca SVG", "copyAsSvg": "Copiere în memoria temporară ca SVG",
"copyText": "Copiere în memoria temporară ca text",
"bringForward": "Aducere în plan apropiat", "bringForward": "Aducere în plan apropiat",
"sendToBack": "Trimitere în ultimul plan", "sendToBack": "Trimitere în ultimul plan",
"bringToFront": "Aducere în prim plan", "bringToFront": "Aducere în prim plan",
@ -107,10 +108,17 @@
"decreaseFontSize": "Micșorează dimensiunea fontului", "decreaseFontSize": "Micșorează dimensiunea fontului",
"increaseFontSize": "Mărește dimensiunea fontului", "increaseFontSize": "Mărește dimensiunea fontului",
"unbindText": "Deconectare text", "unbindText": "Deconectare text",
"bindText": "Legare text de container",
"link": { "link": {
"edit": "Editare URL", "edit": "Editare URL",
"create": "Creare URL", "create": "Creare URL",
"label": "URL" "label": "URL"
},
"elementLock": {
"lock": "Blocare",
"unlock": "Deblocare",
"lockAll": "Blocare toate",
"unlockAll": "Deblocare toate"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Fișierul invalid nu a putut fi încărcat", "couldNotLoadInvalidFile": "Fișierul invalid nu a putut fi încărcat",
"importBackendFailed": "Importarea de la nivel de server a eșuat.", "importBackendFailed": "Importarea de la nivel de server a eșuat.",
"cannotExportEmptyCanvas": "Nu se poate exporta pânza goală.", "cannotExportEmptyCanvas": "Nu se poate exporta pânza goală.",
"couldNotCopyToClipboard": "Nu s-a putut copia în memoria temporară. Încearcă să utilizezi navigatorul Chrome.", "couldNotCopyToClipboard": "Nu s-a putut copia în memoria temporară.",
"decryptFailed": "Datele nu au putut fi decriptate.", "decryptFailed": "Datele nu au putut fi decriptate.",
"uploadedSecurly": "Încărcarea a fost securizată prin criptare integrală, însemnând că serverul Excalidraw și terții nu pot citi conținutul.", "uploadedSecurly": "Încărcarea a fost securizată prin criptare integrală, însemnând că serverul Excalidraw și terții nu pot citi conținutul.",
"loadSceneOverridePrompt": "Încărcarea desenului extern va înlocui conținutul existent. Dorești să continui?", "loadSceneOverridePrompt": "Încărcarea desenului extern va înlocui conținutul existent. Dorești să continui?",
@ -196,7 +204,8 @@
"library": "Bibliotecă", "library": "Bibliotecă",
"lock": "Menține activ instrumentul selectat după desenare", "lock": "Menține activ instrumentul selectat după desenare",
"penMode": "Împiedică mărirea prin ciupire și acceptă desenarea liberă doar de la stilou", "penMode": "Împiedică mărirea prin ciupire și acceptă desenarea liberă doar de la stilou",
"link": "Adăugare/actualizare URL pentru forma selectată" "link": "Adăugare/actualizare URL pentru forma selectată",
"eraser": "Radieră"
}, },
"headings": { "headings": {
"canvasActions": "Acțiuni pentru pânză", "canvasActions": "Acțiuni pentru pânză",
@ -221,7 +230,8 @@
"placeImage": "Dă clic pentru a poziționa imaginea sau dă clic și glisează pentru a seta manual dimensiunea imaginii", "placeImage": "Dă clic pentru a poziționa imaginea sau dă clic și glisează pentru a seta manual dimensiunea imaginii",
"publishLibrary": "Publică propria bibliotecă", "publishLibrary": "Publică propria bibliotecă",
"bindTextToElement": "Apasă tasta Enter pentru a adăuga text", "bindTextToElement": "Apasă tasta Enter pentru a adăuga text",
"deepBoxSelect": "Ține apăsată tasta Ctrl sau Cmd pentru a efectua selectarea de adâncime și pentru a preveni glisarea" "deepBoxSelect": "Ține apăsată tasta Ctrl sau Cmd pentru a efectua selectarea de adâncime și pentru a preveni glisarea",
"eraserRevert": "Ține apăsată tasta Alt pentru a anula elementele marcate pentru ștergere"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Nu se poate afișa previzualizarea", "cannotShowPreview": "Nu se poate afișa previzualizarea",
@ -281,14 +291,15 @@
"howto": "Urmărește ghidurile noastre", "howto": "Urmărește ghidurile noastre",
"or": "sau", "or": "sau",
"preventBinding": "Împiedică legarea săgeții", "preventBinding": "Împiedică legarea săgeții",
"shapes": "Forme", "tools": "Instrumente",
"shortcuts": "Comenzi rapide de la tastatură", "shortcuts": "Comenzi rapide de la tastatură",
"textFinish": "Finalizează editarea (editor de text)", "textFinish": "Finalizează editarea (editor de text)",
"textNewLine": "Adaugă o linie nouă (editor de text)", "textNewLine": "Adaugă o linie nouă (editor de text)",
"title": "Ajutor", "title": "Ajutor",
"view": "Vizualizare", "view": "Vizualizare",
"zoomToFit": "Transfocare pentru a cuprinde totul", "zoomToFit": "Transfocare pentru a cuprinde totul",
"zoomToSelection": "Transfocare la selecție" "zoomToSelection": "Transfocare la selecție",
"toggleElementLock": "Blocare/deblocare selecție"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Ștergere pânză" "title": "Ștergere pânză"

View File

@ -9,6 +9,7 @@
"copy": "Копировать", "copy": "Копировать",
"copyAsPng": "Скопировать в буфер обмена как PNG", "copyAsPng": "Скопировать в буфер обмена как PNG",
"copyAsSvg": "Скопировать в буфер обмена как SVG", "copyAsSvg": "Скопировать в буфер обмена как SVG",
"copyText": "Скопировать в буфер обмена как текст",
"bringForward": "Переместить вперед", "bringForward": "Переместить вперед",
"sendToBack": "На задний план", "sendToBack": "На задний план",
"bringToFront": "На передний план", "bringToFront": "На передний план",
@ -64,7 +65,7 @@
"cartoonist": "Карикатурист", "cartoonist": "Карикатурист",
"fileTitle": "Имя файла", "fileTitle": "Имя файла",
"colorPicker": "Выбор цвета", "colorPicker": "Выбор цвета",
"canvasColors": "", "canvasColors": "Используется на холсте",
"canvasBackground": "Фон холста", "canvasBackground": "Фон холста",
"drawingCanvas": "Полотно", "drawingCanvas": "Полотно",
"layers": "Слои", "layers": "Слои",
@ -107,10 +108,17 @@
"decreaseFontSize": "Уменьшить шрифт", "decreaseFontSize": "Уменьшить шрифт",
"increaseFontSize": "Увеличить шрифт", "increaseFontSize": "Увеличить шрифт",
"unbindText": "Отвязать текст", "unbindText": "Отвязать текст",
"bindText": "Привязать текст к контейнеру",
"link": { "link": {
"edit": "Редактировать ссылку", "edit": "Редактировать ссылку",
"create": "Создать ссылку", "create": "Создать ссылку",
"label": "Ссылка" "label": "Ссылка"
},
"elementLock": {
"lock": "Блокировать",
"unlock": "Разблокировать",
"lockAll": "Заблокировать все",
"unlockAll": "Разблокировать все"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Не удалось загрузить недопустимый файл", "couldNotLoadInvalidFile": "Не удалось загрузить недопустимый файл",
"importBackendFailed": "Не удалось импортировать из бэкэнда.", "importBackendFailed": "Не удалось импортировать из бэкэнда.",
"cannotExportEmptyCanvas": "Не может экспортировать пустой холст.", "cannotExportEmptyCanvas": "Не может экспортировать пустой холст.",
"couldNotCopyToClipboard": "Не удалось скопировать в буфер обмена. Попробуйте использовать веб-браузер Chrome.", "couldNotCopyToClipboard": "Не удалось скопировать в буфер обмена.",
"decryptFailed": "Не удалось расшифровать данные.", "decryptFailed": "Не удалось расшифровать данные.",
"uploadedSecurly": "Загружаемые данные защищена сквозным шифрованием, что означает, что сервер Excalidraw и третьи стороны не могут прочитать содержимое.", "uploadedSecurly": "Загружаемые данные защищена сквозным шифрованием, что означает, что сервер Excalidraw и третьи стороны не могут прочитать содержимое.",
"loadSceneOverridePrompt": "Загрузка рисунка приведёт к замене имеющегося содержимого. Вы хотите продолжить?", "loadSceneOverridePrompt": "Загрузка рисунка приведёт к замене имеющегося содержимого. Вы хотите продолжить?",
@ -181,7 +189,7 @@
"fileTooBig": "Очень большой файл. Максимально разрешенный размер {{maxSize}}.", "fileTooBig": "Очень большой файл. Максимально разрешенный размер {{maxSize}}.",
"svgImageInsertError": "Не удалось вставить изображение SVG. Разметка SVG выглядит недействительной.", "svgImageInsertError": "Не удалось вставить изображение SVG. Разметка SVG выглядит недействительной.",
"invalidSVGString": "Некорректный SVG.", "invalidSVGString": "Некорректный SVG.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "Не удалось подключиться к серверу совместного редактирования. Перезагрузите страницу и повторите попытку."
}, },
"toolBar": { "toolBar": {
"selection": "Выделение области", "selection": "Выделение области",
@ -195,8 +203,9 @@
"text": "Текст", "text": "Текст",
"library": "Библиотека", "library": "Библиотека",
"lock": "Сохранять выбранный инструмент активным после рисования", "lock": "Сохранять выбранный инструмент активным после рисования",
"penMode": "", "penMode": "Отключить масштабирование щипком и рисовать только с помощью пера",
"link": "Добавить/обновить ссылку для выбранной фигуры" "link": "Добавить/обновить ссылку для выбранной фигуры",
"eraser": "Ластик"
}, },
"headings": { "headings": {
"canvasActions": "Операции холста", "canvasActions": "Операции холста",
@ -221,7 +230,8 @@
"placeImage": "Щелкните, чтобы разместить изображение, или нажмите и перетащите, чтобы установить его размер вручную", "placeImage": "Щелкните, чтобы разместить изображение, или нажмите и перетащите, чтобы установить его размер вручную",
"publishLibrary": "Опубликовать свою собственную библиотеку", "publishLibrary": "Опубликовать свою собственную библиотеку",
"bindTextToElement": "Нажмите Enter для добавления текста", "bindTextToElement": "Нажмите Enter для добавления текста",
"deepBoxSelect": "Удерживайте Ctrl или Cmd для глубокого выделения, чтобы предотвратить перетаскивание" "deepBoxSelect": "Удерживайте Ctrl или Cmd для глубокого выделения, чтобы предотвратить перетаскивание",
"eraserRevert": "Удерживайте Alt, чтобы вернуть элементы, отмеченные для удаления"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Не удается отобразить предпросмотр", "cannotShowPreview": "Не удается отобразить предпросмотр",
@ -281,14 +291,15 @@
"howto": "Следуйте нашим инструкциям", "howto": "Следуйте нашим инструкциям",
"or": "или", "or": "или",
"preventBinding": "Предотвращать привязку стрелок", "preventBinding": "Предотвращать привязку стрелок",
"shapes": "Фигуры", "tools": "Инструменты",
"shortcuts": "Горячие клавиши", "shortcuts": "Горячие клавиши",
"textFinish": "Закончить редактирование (текстовый редактор)", "textFinish": "Закончить редактирование (текстовый редактор)",
"textNewLine": "Добавить новую строку (текстовый редактор)", "textNewLine": "Добавить новую строку (текстовый редактор)",
"title": "Помощь", "title": "Помощь",
"view": "Просмотр", "view": "Просмотр",
"zoomToFit": "Отмастштабировать, чтобы поместились все элементы", "zoomToFit": "Отмастштабировать, чтобы поместились все элементы",
"zoomToSelection": "Увеличить до выделенного" "zoomToSelection": "Увеличить до выделенного",
"toggleElementLock": "Заблокировать/разблокировать выделение"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Очистить холст" "title": "Очистить холст"

View File

@ -9,6 +9,7 @@
"copy": "පිටපත් කරන්න", "copy": "පිටපත් කරන්න",
"copyAsPng": "PNG ලෙස පිටපත් කරන්න", "copyAsPng": "PNG ලෙස පිටපත් කරන්න",
"copyAsSvg": "SVG ලෙස පිටපත් කරන්න", "copyAsSvg": "SVG ලෙස පිටපත් කරන්න",
"copyText": "",
"bringForward": "ඉදිරියට ගෙන්න", "bringForward": "ඉදිරියට ගෙන්න",
"sendToBack": "පසුපසටම ගෙනියන්න", "sendToBack": "පසුපසටම ගෙනියන්න",
"bringToFront": "ඉදිරියටම ගෙන්න", "bringToFront": "ඉදිරියටම ගෙන්න",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -196,7 +204,8 @@
"library": "", "library": "",
"lock": "", "lock": "",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "", "canvasActions": "",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "", "cannotShowPreview": "",
@ -281,14 +291,15 @@
"howto": "", "howto": "",
"or": "", "or": "",
"preventBinding": "", "preventBinding": "",
"shapes": "", "tools": "",
"shortcuts": "", "shortcuts": "",
"textFinish": "", "textFinish": "",
"textNewLine": "", "textNewLine": "",
"title": "", "title": "",
"view": "", "view": "",
"zoomToFit": "", "zoomToFit": "",
"zoomToSelection": "" "zoomToSelection": "",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "Kopírovať", "copy": "Kopírovať",
"copyAsPng": "Kopírovať do schránky ako PNG", "copyAsPng": "Kopírovať do schránky ako PNG",
"copyAsSvg": "Kopírovať do schránky ako SVG", "copyAsSvg": "Kopírovať do schránky ako SVG",
"copyText": "Kopírovať do schránky ako text",
"bringForward": "Presunúť o úroveň dopredu", "bringForward": "Presunúť o úroveň dopredu",
"sendToBack": "Presunúť dozadu", "sendToBack": "Presunúť dozadu",
"bringToFront": "Presunúť dopredu", "bringToFront": "Presunúť dopredu",
@ -107,10 +108,17 @@
"decreaseFontSize": "Zmenšiť veľkosť písma", "decreaseFontSize": "Zmenšiť veľkosť písma",
"increaseFontSize": "Zväčšiť veľkosť písma", "increaseFontSize": "Zväčšiť veľkosť písma",
"unbindText": "Zrušiť previazanie textu", "unbindText": "Zrušiť previazanie textu",
"bindText": "Previazať text s kontajnerom",
"link": { "link": {
"edit": "Upraviť odkaz", "edit": "Upraviť odkaz",
"create": "Vytvoriť odkaz", "create": "Vytvoriť odkaz",
"label": "Odkaz" "label": "Odkaz"
},
"elementLock": {
"lock": "Zamknúť",
"unlock": "Odomknúť",
"lockAll": "Zamknúť všetko",
"unlockAll": "Odomknúť všetko"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Nepodarilo sa načítať nevalidný súbor", "couldNotLoadInvalidFile": "Nepodarilo sa načítať nevalidný súbor",
"importBackendFailed": "Nepdarilo sa importovanie zo serveru.", "importBackendFailed": "Nepdarilo sa importovanie zo serveru.",
"cannotExportEmptyCanvas": "Nie je možné exportovať prázdne plátno.", "cannotExportEmptyCanvas": "Nie je možné exportovať prázdne plátno.",
"couldNotCopyToClipboard": "Nepodarilo sa kopírovanie do schránky. Skúste použiť prehliadač Chrome.", "couldNotCopyToClipboard": "Kopírovanie do schránky sa nepodarilo.",
"decryptFailed": "Nepodarilo sa rozšifrovať údaje.", "decryptFailed": "Nepodarilo sa rozšifrovať údaje.",
"uploadedSecurly": "Nahratie je zabezpečené end-to-end šifrovaním, takže Excalidraw server a tretie strany nedokážu prečítať jeho obsah.", "uploadedSecurly": "Nahratie je zabezpečené end-to-end šifrovaním, takže Excalidraw server a tretie strany nedokážu prečítať jeho obsah.",
"loadSceneOverridePrompt": "Nahratie externej kresby nahradí existujúci obsah. Prajete si pokračovať?", "loadSceneOverridePrompt": "Nahratie externej kresby nahradí existujúci obsah. Prajete si pokračovať?",
@ -181,7 +189,7 @@
"fileTooBig": "Súbor je príliš veľký. Maximálna povolená veľkosť je {{maxSize}}.", "fileTooBig": "Súbor je príliš veľký. Maximálna povolená veľkosť je {{maxSize}}.",
"svgImageInsertError": "Nepodarilo sa vložiť SVG obrázok. SVG formát je pravdepodobne nevalidný.", "svgImageInsertError": "Nepodarilo sa vložiť SVG obrázok. SVG formát je pravdepodobne nevalidný.",
"invalidSVGString": "Nevalidné SVG.", "invalidSVGString": "Nevalidné SVG.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "Nepodarilo sa pripojiť ku kolaboračnému serveru. Prosím obnovte stránku a skúste to znovu."
}, },
"toolBar": { "toolBar": {
"selection": "Výber", "selection": "Výber",
@ -196,7 +204,8 @@
"library": "Knižnica", "library": "Knižnica",
"lock": "Nechať zvolený nástroj aktívny po skončení kreslenia", "lock": "Nechať zvolený nástroj aktívny po skončení kreslenia",
"penMode": "Zabrániť priblíženiu potiahnutím a povoliť vstup voľnou rokou iba z pera", "penMode": "Zabrániť priblíženiu potiahnutím a povoliť vstup voľnou rokou iba z pera",
"link": "Pridať/ Upraviť odkaz pre vybraný tvar" "link": "Pridať/ Upraviť odkaz pre vybraný tvar",
"eraser": "Guma"
}, },
"headings": { "headings": {
"canvasActions": "Akcie plátna", "canvasActions": "Akcie plátna",
@ -221,7 +230,8 @@
"placeImage": "Kliknite pre umiestnenie obrázka alebo kliknite a ťahajte pre zmenu jeho veľkosti", "placeImage": "Kliknite pre umiestnenie obrázka alebo kliknite a ťahajte pre zmenu jeho veľkosti",
"publishLibrary": "Uverejniť vašu knižnicu", "publishLibrary": "Uverejniť vašu knižnicu",
"bindTextToElement": "Stlačte enter na pridanie textu", "bindTextToElement": "Stlačte enter na pridanie textu",
"deepBoxSelect": "Podržte CtrlOrCmd na výber v skupine alebo zamedzeniu poťiahnutia" "deepBoxSelect": "Podržte CtrlOrCmd na výber v skupine alebo zamedzeniu poťiahnutia",
"eraserRevert": "Podržte Alt pre prehodenie položiek určených na vymazanie"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Nie je možné zobraziť náhľad plátna", "cannotShowPreview": "Nie je možné zobraziť náhľad plátna",
@ -281,14 +291,15 @@
"howto": "Postupujte podľa naších návodov", "howto": "Postupujte podľa naších návodov",
"or": "alebo", "or": "alebo",
"preventBinding": "Zakázať pripájanie šípky", "preventBinding": "Zakázať pripájanie šípky",
"shapes": "Tvary", "tools": "Nástroje",
"shortcuts": "Klávesové skratky", "shortcuts": "Klávesové skratky",
"textFinish": "Ukončenie editovania (text editor)", "textFinish": "Ukončenie editovania (text editor)",
"textNewLine": "Vložiť nový riadok (text editor)", "textNewLine": "Vložiť nový riadok (text editor)",
"title": "Pomocník", "title": "Pomocník",
"view": "Zobrazenie", "view": "Zobrazenie",
"zoomToFit": "Priblížiť aby boli zahrnuté všetky prvky", "zoomToFit": "Priblížiť aby boli zahrnuté všetky prvky",
"zoomToSelection": "Priblížiť na výber" "zoomToSelection": "Priblížiť na výber",
"toggleElementLock": "Zamknúť/odomknúť vybrané"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Vyčistiť plátno" "title": "Vyčistiť plátno"

431
src/locales/sl-SI.json Normal file
View File

@ -0,0 +1,431 @@
{
"labels": {
"paste": "Prilepi",
"pasteCharts": "Prilepi grafikon",
"selectAll": "Izberi vse",
"multiSelect": "Dodaj element v izbor",
"moveCanvas": "Premakni platno",
"cut": "Izreži",
"copy": "Kopiraj",
"copyAsPng": "Kopiraj v odložišče kot PNG",
"copyAsSvg": "Kopiraj v odložišče kot SVG",
"copyText": "",
"bringForward": "Postavi naprej",
"sendToBack": "Pomakni v ozadje",
"bringToFront": "Pomakni v ospredje",
"sendBackward": "Pošlji nazaj",
"delete": "Izbriši",
"copyStyles": "Kopiraj slog",
"pasteStyles": "Prilepi slog",
"stroke": "Poteza",
"background": "Ozadje",
"fill": "Polnilo",
"strokeWidth": "Debelina poteze",
"strokeStyle": "Slog poteze",
"strokeStyle_solid": "Polna",
"strokeStyle_dashed": "Črtkana",
"strokeStyle_dotted": "Pikasta",
"sloppiness": "Površnost",
"opacity": "Prekrivnost",
"textAlign": "Poravnava besedila",
"edges": "Robovi",
"sharp": "Ostri",
"round": "Okrogli",
"arrowheads": "Puščice",
"arrowhead_none": "Brez",
"arrowhead_arrow": "Puščica",
"arrowhead_bar": "Palica",
"arrowhead_dot": "Pika",
"arrowhead_triangle": "Trikotnik",
"fontSize": "Velikost pisave",
"fontFamily": "Družina pisave",
"onlySelected": "Samo izbor",
"withBackground": "Ozadje",
"exportEmbedScene": "Vdelaj sceno",
"exportEmbedScene_details": "Podatki o sceni bodo shranjeni v izvoženo datoteko PNG/SVG, tako da bo sceno mogoče obnoviti iz nje.\nTo bo povečalo velikost izvožene datoteke.",
"addWatermark": "Dodaj \"Izdelano z Excalidraw\"",
"handDrawn": "Ročno narisano",
"normal": "Običajno",
"code": "Koda",
"small": "Majhna",
"medium": "Srednja",
"large": "Velika",
"veryLarge": "Zelo velika",
"solid": "Polno",
"hachure": "Šrafura",
"crossHatch": "Križno",
"thin": "Tanko",
"bold": "Krepko",
"left": "Levo",
"center": "Sredina",
"right": "Desno",
"extraBold": "Ekstra krepko",
"architect": "Arhitekt",
"artist": "Umetnik",
"cartoonist": "Risar",
"fileTitle": "Ime datoteke",
"colorPicker": "Izbor barve",
"canvasColors": "",
"canvasBackground": "",
"drawingCanvas": "",
"layers": "Plasti",
"actions": "Dejanja",
"language": "Jezik",
"liveCollaboration": "",
"duplicateSelection": "Podvoji",
"untitled": "Neimenovana",
"name": "Ime",
"yourName": "Vaše ime",
"madeWithExcalidraw": "Izdelano z Excalidraw",
"group": "",
"ungroup": "",
"collaborators": "",
"showGrid": "Prikaži mrežo",
"addToLibrary": "Dodaj v knjižnico",
"removeFromLibrary": "Odstrani iz knjižnice",
"libraryLoadingMessage": "Nalaganje knjižnice ...",
"libraries": "",
"loadingScene": "",
"align": "Poravnava",
"alignTop": "Poravnaj na vrh",
"alignBottom": "Poravnaj na dno",
"alignLeft": "Poravnaj levo",
"alignRight": "Poravnaj desno",
"centerVertically": "",
"centerHorizontally": "",
"distributeHorizontally": "",
"distributeVertically": "",
"flipHorizontal": "",
"flipVertical": "",
"viewMode": "",
"toggleExportColorScheme": "",
"share": "",
"showStroke": "",
"showBackground": "",
"toggleTheme": "",
"personalLib": "",
"excalidrawLib": "Knjižnica Escalidraw",
"decreaseFontSize": "Zmanjšaj velikost pisave",
"increaseFontSize": "Povečaj velikost pisave",
"unbindText": "",
"bindText": "",
"link": {
"edit": "Uredi povezavo",
"create": "Ustvari povezavo",
"label": "Povezava"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
}
},
"buttons": {
"clearReset": "",
"exportJSON": "Izvozi v datoteko",
"exportImage": "Shrani kot sliko",
"export": "Izvoz",
"exportToPng": "Izvozi v PNG",
"exportToSvg": "Izvozi v SVG",
"copyToClipboard": "Kopiraj v odložišče",
"copyPngToClipboard": "Kopiraj PNG v odložišče",
"scale": "Povečava",
"save": "Shrani v trenutno datoteko",
"saveAs": "Shrani kot",
"load": "Naloži",
"getShareableLink": "Pridobi povezavo za deljenje",
"close": "Zapri",
"selectLanguage": "Izberite jezik",
"scrollBackToContent": "",
"zoomIn": "Povečaj",
"zoomOut": "Pomanjšaj",
"resetZoom": "Ponastavi povečavo",
"menu": "Meni",
"done": "Končano",
"edit": "Uredi",
"undo": "Razveljavi",
"redo": "Ponovi",
"resetLibrary": "Ponastavi knjižnico",
"createNewRoom": "Ustvari novo sobo",
"fullScreen": "Celozaslonski način",
"darkMode": "Temni način",
"lightMode": "Svetli način",
"zenMode": "Zen način",
"exitZenMode": "Zapri zen način",
"cancel": "Prekliči",
"clear": "Počisti",
"remove": "Odstrani",
"publishLibrary": "Objavi",
"submit": "Pošlji",
"confirm": "Potrdi"
},
"alerts": {
"clearReset": "",
"couldNotCreateShareableLink": "",
"couldNotCreateShareableLinkTooBig": "",
"couldNotLoadInvalidFile": "",
"importBackendFailed": "",
"cannotExportEmptyCanvas": "",
"couldNotCopyToClipboard": "",
"decryptFailed": "",
"uploadedSecurly": "",
"loadSceneOverridePrompt": "",
"collabStopOverridePrompt": "",
"errorLoadingLibrary": "",
"errorAddingToLibrary": "",
"errorRemovingFromLibrary": "",
"confirmAddLibrary": "",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": "",
"invalidSceneUrl": "",
"resetLibrary": "",
"removeItemsFromsLibrary": "",
"invalidEncryptionKey": ""
},
"errors": {
"unsupportedFileType": "",
"imageInsertError": "",
"fileTooBig": "",
"svgImageInsertError": "",
"invalidSVGString": "",
"cannotResolveCollabServer": ""
},
"toolBar": {
"selection": "Izbor",
"image": "Vstavi sliko",
"rectangle": "Pravokotnik",
"diamond": "Diamant",
"ellipse": "Elipsa",
"arrow": "",
"line": "",
"freedraw": "",
"text": "",
"library": "",
"lock": "",
"penMode": "",
"link": "",
"eraser": ""
},
"headings": {
"canvasActions": "",
"selectedShapeActions": "",
"shapes": ""
},
"hints": {
"canvasPanning": "",
"linearElement": "",
"freeDraw": "",
"text": "",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "",
"lockAngle": "",
"resize": "",
"resizeImage": "",
"rotate": "",
"lineEditor_info": "",
"lineEditor_pointSelected": "",
"lineEditor_nothingSelected": "",
"placeImage": "",
"publishLibrary": "",
"bindTextToElement": "",
"deepBoxSelect": "",
"eraserRevert": ""
},
"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": "",
"excalidrawplus_button": "",
"excalidrawplus_exportError": ""
},
"helpDialog": {
"blog": "",
"click": "",
"deepSelect": "",
"deepBoxSelect": "",
"curvedArrow": "",
"curvedLine": "",
"documentation": "",
"doubleClick": "",
"drag": "",
"editor": "",
"editSelectedShape": "",
"github": "",
"howto": "",
"or": "",
"preventBinding": "",
"tools": "",
"shortcuts": "",
"textFinish": "",
"textNewLine": "",
"title": "",
"view": "",
"zoomToFit": "",
"zoomToSelection": "",
"toggleElementLock": ""
},
"clearCanvasDialog": {
"title": ""
},
"publishDialog": {
"title": "",
"itemName": "",
"authorName": "",
"githubUsername": "",
"twitterUsername": "",
"libraryName": "",
"libraryDesc": "",
"website": "",
"placeholder": {
"authorName": "",
"libraryName": "",
"libraryDesc": "",
"githubHandle": "",
"twitterHandle": "",
"website": ""
},
"errors": {
"required": "",
"website": ""
},
"noteDescription": {
"pre": "",
"link": "",
"post": ""
},
"noteGuidelines": {
"pre": "",
"link": "",
"post": ""
},
"noteLicense": {
"pre": "",
"link": "",
"post": ""
},
"noteItems": "",
"atleastOneLibItem": ""
},
"publishSuccessDialog": {
"title": "",
"content": "",
"link": ""
},
"confirmDialog": {
"resetLibrary": "",
"removeItemsFromLib": ""
},
"encrypted": {
"tooltip": "",
"link": ""
},
"stats": {
"angle": "",
"element": "",
"elements": "",
"height": "",
"scene": "",
"selected": "",
"storage": "",
"title": "",
"total": "",
"version": "",
"versionCopy": "",
"versionNotAvailable": "",
"width": ""
},
"toast": {
"addedToLibrary": "",
"copyStyles": "",
"copyToClipboard": "",
"copyToClipboardAsPng": "",
"fileSaved": "",
"fileSavedToFilename": "",
"canvas": "",
"selection": ""
},
"colors": {
"ffffff": "",
"f8f9fa": "",
"f1f3f5": "",
"fff5f5": "",
"fff0f6": "",
"f8f0fc": "",
"f3f0ff": "",
"edf2ff": "",
"e7f5ff": "",
"e3fafc": "",
"e6fcf5": "",
"ebfbee": "",
"f4fce3": "",
"fff9db": "",
"fff4e6": "",
"transparent": "",
"ced4da": "",
"868e96": "",
"fa5252": "",
"e64980": "",
"be4bdb": "",
"7950f2": "",
"4c6ef5": "",
"228be6": "",
"15aabf": "",
"12b886": "",
"40c057": "",
"82c91e": "",
"fab005": "",
"fd7e14": "",
"000000": "",
"343a40": "",
"495057": "",
"c92a2a": "",
"a61e4d": "",
"862e9c": "",
"5f3dc4": "",
"364fc7": "",
"1864ab": "",
"0b7285": "",
"087f5b": "",
"2b8a3e": "",
"5c940d": "",
"e67700": "",
"d9480f": ""
}
}

View File

@ -9,6 +9,7 @@
"copy": "Kopiera", "copy": "Kopiera",
"copyAsPng": "Kopiera till urklipp som PNG", "copyAsPng": "Kopiera till urklipp som PNG",
"copyAsSvg": "Kopiera till urklipp som SVG", "copyAsSvg": "Kopiera till urklipp som SVG",
"copyText": "Kopiera till urklipp som text",
"bringForward": "Flytta framåt", "bringForward": "Flytta framåt",
"sendToBack": "Flytta underst", "sendToBack": "Flytta underst",
"bringToFront": "Flytta främst", "bringToFront": "Flytta främst",
@ -107,10 +108,17 @@
"decreaseFontSize": "Minska fontstorleken", "decreaseFontSize": "Minska fontstorleken",
"increaseFontSize": "Öka fontstorleken", "increaseFontSize": "Öka fontstorleken",
"unbindText": "Koppla bort text", "unbindText": "Koppla bort text",
"bindText": "Bind texten till behållaren",
"link": { "link": {
"edit": "Redigera länk", "edit": "Redigera länk",
"create": "Skapa länk", "create": "Skapa länk",
"label": "Länk" "label": "Länk"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Kunde inte ladda ogiltig fil", "couldNotLoadInvalidFile": "Kunde inte ladda ogiltig fil",
"importBackendFailed": "Importering från backend misslyckades.", "importBackendFailed": "Importering från backend misslyckades.",
"cannotExportEmptyCanvas": "Kan inte exportera tom canvas.", "cannotExportEmptyCanvas": "Kan inte exportera tom canvas.",
"couldNotCopyToClipboard": "Det gick inte att kopiera till urklipp. Prova att använda en annan webbläsare.", "couldNotCopyToClipboard": "Kunde inte kopiera till urklipp.",
"decryptFailed": "Kunde inte avkryptera data.", "decryptFailed": "Kunde inte avkryptera data.",
"uploadedSecurly": "Uppladdning har säkrats med kryptering från ände till ände. vilket innebär att Excalidraw server och tredje part inte kan läsa innehållet.", "uploadedSecurly": "Uppladdning har säkrats med kryptering från ände till ände. vilket innebär att Excalidraw server och tredje part inte kan läsa innehållet.",
"loadSceneOverridePrompt": "Laddning av extern skiss kommer att ersätta ditt befintliga innehåll. Vill du fortsätta?", "loadSceneOverridePrompt": "Laddning av extern skiss kommer att ersätta ditt befintliga innehåll. Vill du fortsätta?",
@ -196,7 +204,8 @@
"library": "Bibliotek", "library": "Bibliotek",
"lock": "Håll valt verktyg aktivt efter ritande", "lock": "Håll valt verktyg aktivt efter ritande",
"penMode": "Förhindra nypzoom och acceptera endast frihandsteckning från penna", "penMode": "Förhindra nypzoom och acceptera endast frihandsteckning från penna",
"link": "Lägg till / Uppdatera länk för en vald form" "link": "Lägg till / Uppdatera länk för en vald form",
"eraser": "Radergummi"
}, },
"headings": { "headings": {
"canvasActions": "Canvas-åtgärder", "canvasActions": "Canvas-åtgärder",
@ -221,7 +230,8 @@
"placeImage": "Klicka för att placera bilden, eller klicka och dra för att ställa in dess storlek manuellt", "placeImage": "Klicka för att placera bilden, eller klicka och dra för att ställa in dess storlek manuellt",
"publishLibrary": "Publicera ditt eget bibliotek", "publishLibrary": "Publicera ditt eget bibliotek",
"bindTextToElement": "Tryck på Enter för att lägga till text", "bindTextToElement": "Tryck på Enter för att lägga till text",
"deepBoxSelect": "Håll Ctrl eller Cmd för att djupvälja, och för att förhindra att dra" "deepBoxSelect": "Håll Ctrl eller Cmd för att djupvälja, och för att förhindra att dra",
"eraserRevert": "Håll Alt för att återställa de element som är markerade för borttagning"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Kan inte visa förhandsgranskning", "cannotShowPreview": "Kan inte visa förhandsgranskning",
@ -281,14 +291,15 @@
"howto": "Följ våra guider", "howto": "Följ våra guider",
"or": "eller", "or": "eller",
"preventBinding": "Förhindra pilbindning", "preventBinding": "Förhindra pilbindning",
"shapes": "Former", "tools": "Verktyg",
"shortcuts": "Tangentbordsgenvägar", "shortcuts": "Tangentbordsgenvägar",
"textFinish": "Slutför redigering (text)", "textFinish": "Slutför redigering (text)",
"textNewLine": "Lägg till ny rad (text)", "textNewLine": "Lägg till ny rad (text)",
"title": "Hjälp", "title": "Hjälp",
"view": "Visa", "view": "Visa",
"zoomToFit": "Zooma för att rymma alla element", "zoomToFit": "Zooma för att rymma alla element",
"zoomToSelection": "Zooma till markering" "zoomToSelection": "Zooma till markering",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Rensa canvas" "title": "Rensa canvas"

View File

@ -9,6 +9,7 @@
"copy": "நகலெடு", "copy": "நகலெடு",
"copyAsPng": "நகலகத்திற்கு PNG ஆக நகலெடு", "copyAsPng": "நகலகத்திற்கு PNG ஆக நகலெடு",
"copyAsSvg": "நகலகத்திற்கு SVG ஆக நகலெடு", "copyAsSvg": "நகலகத்திற்கு SVG ஆக நகலெடு",
"copyText": "நகலகத்திற்கு உரையாக நகலெடு",
"bringForward": "முன்நோக்கி கொண்டுவா", "bringForward": "முன்நோக்கி கொண்டுவா",
"sendToBack": "பின்னே அனுப்பு", "sendToBack": "பின்னே அனுப்பு",
"bringToFront": "முன்னே கொண்டுவா", "bringToFront": "முன்னே கொண்டுவா",
@ -107,10 +108,17 @@
"decreaseFontSize": "எழுத்துரு அளவைக் குறை", "decreaseFontSize": "எழுத்துரு அளவைக் குறை",
"increaseFontSize": "எழுத்துரு அளவை அதிகரி", "increaseFontSize": "எழுத்துரு அளவை அதிகரி",
"unbindText": "உரையைப் பிணைவவிழ்", "unbindText": "உரையைப் பிணைவவிழ்",
"bindText": "",
"link": { "link": {
"edit": "தொடுப்பைத் திருத்து", "edit": "தொடுப்பைத் திருத்து",
"create": "தொடுப்பைப் படை", "create": "தொடுப்பைப் படை",
"label": "தொடுப்பு" "label": "தொடுப்பு"
},
"elementLock": {
"lock": "பூட்டு",
"unlock": "பூட்டவிழ்",
"lockAll": "எல்லாம் பூட்டு",
"unlockAll": "எல்லாம் பூட்டவிழ்"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "செல்லாத கோப்பை ஏற்ற முடியவில்லை", "couldNotLoadInvalidFile": "செல்லாத கோப்பை ஏற்ற முடியவில்லை",
"importBackendFailed": "தேகத்திலிருந்து இறக்குமதி தோல்வி.", "importBackendFailed": "தேகத்திலிருந்து இறக்குமதி தோல்வி.",
"cannotExportEmptyCanvas": "காலியான கித்தானை ஏற்றுமதிசெய்ய முடியாது.", "cannotExportEmptyCanvas": "காலியான கித்தானை ஏற்றுமதிசெய்ய முடியாது.",
"couldNotCopyToClipboard": "நகலகத்திற்கு நகலெடுக்க முடியவில்லை. குரோம் உலாவி பயன்படுத்தி முயல்க.", "couldNotCopyToClipboard": "நகலகத்திற்கு நகலெடுக்க முடியவில்லை.",
"decryptFailed": "தரவை மறைநீக்க முடியவில்லை.", "decryptFailed": "தரவை மறைநீக்க முடியவில்லை.",
"uploadedSecurly": "பதிவேற்றம் இருமுனை மறையாகத்தால் பாதுகாக்கப்பட்டுள்ளது, எனவே எக்ஸ்கேலிட்ரா சேவையகமும் மூன்றாம் தரப்பினரும் உள்ளடக்கத்தை வாசிக்கமுடியாது.", "uploadedSecurly": "பதிவேற்றம் இருமுனை மறையாகத்தால் பாதுகாக்கப்பட்டுள்ளது, எனவே எக்ஸ்கேலிட்ரா சேவையகமும் மூன்றாம் தரப்பினரும் உள்ளடக்கத்தை வாசிக்கமுடியாது.",
"loadSceneOverridePrompt": "வெளிப்புறச்சித்திரமேற்றல் இருக்கிற உள்ளடக்கத்தை இடங்கொள்ளும். தொடர விருப்பமா?", "loadSceneOverridePrompt": "வெளிப்புறச்சித்திரமேற்றல் இருக்கிற உள்ளடக்கத்தை இடங்கொள்ளும். தொடர விருப்பமா?",
@ -196,7 +204,8 @@
"library": "நூலகம்", "library": "நூலகம்",
"lock": "தேர்ந்த கருவியை வரைந்த பின்பும் வைத்திரு", "lock": "தேர்ந்த கருவியை வரைந்த பின்பும் வைத்திரு",
"penMode": "கிள்ளிப்பெரிதாக்குவதைத் தவிர் மற்றும் பேனாவிலிருந்து மட்டும் கட்டற்றவரைவை ஏல்", "penMode": "கிள்ளிப்பெரிதாக்குவதைத் தவிர் மற்றும் பேனாவிலிருந்து மட்டும் கட்டற்றவரைவை ஏல்",
"link": "தேர்தெடுத்த வடிவத்திற்குத் தொடுப்பைச் சேர்/ புதுப்பி" "link": "தேர்தெடுத்த வடிவத்திற்குத் தொடுப்பைச் சேர்/ புதுப்பி",
"eraser": "அழிப்பி"
}, },
"headings": { "headings": {
"canvasActions": "கித்தான் செயல்கள்", "canvasActions": "கித்தான் செயல்கள்",
@ -221,7 +230,8 @@
"placeImage": "படத்தை வைக்கச் சொடுக்கு, அ கைமுறையாக அளவு அமைக்க சொடுக்கி பிடித்திழு", "placeImage": "படத்தை வைக்கச் சொடுக்கு, அ கைமுறையாக அளவு அமைக்க சொடுக்கி பிடித்திழு",
"publishLibrary": "உம் சொந்த நூலகத்தைப் பிரசுரி", "publishLibrary": "உம் சொந்த நூலகத்தைப் பிரசுரி",
"bindTextToElement": "உரையைச் சேர்க்க enterஐ அழுத்து", "bindTextToElement": "உரையைச் சேர்க்க enterஐ அழுத்து",
"deepBoxSelect": "ஆழ்ந்துத் தேரவும் பிடித்திழுத்தலைத் தவிர்க்கவும் CtrlOrCmdஐ அழுத்திப்பிடி" "deepBoxSelect": "ஆழ்ந்துத் தேரவும் பிடித்திழுத்தலைத் தவிர்க்கவும் CtrlOrCmdஐ அழுத்திப்பிடி",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "முன்னோட்டம் காட்ட இயலவில்லை", "cannotShowPreview": "முன்னோட்டம் காட்ட இயலவில்லை",
@ -281,14 +291,15 @@
"howto": "எங்கள் கையேடுகளைப் பின்பற்றுக", "howto": "எங்கள் கையேடுகளைப் பின்பற்றுக",
"or": "அ", "or": "அ",
"preventBinding": "அம்பு பிணைதலைத் தவிர்", "preventBinding": "அம்பு பிணைதலைத் தவிர்",
"shapes": "வடிவங்கள்", "tools": "கருவிகள்",
"shortcuts": "விசைப்பலகை குறுக்குவழிகள்", "shortcuts": "விசைப்பலகை குறுக்குவழிகள்",
"textFinish": "திருத்துதலை முடி (உரை திருத்தி)", "textFinish": "திருத்துதலை முடி (உரை திருத்தி)",
"textNewLine": "புதிய வரியைச் சேர் (உரை திருத்தி)", "textNewLine": "புதிய வரியைச் சேர் (உரை திருத்தி)",
"title": "உதவி", "title": "உதவி",
"view": "பார்", "view": "பார்",
"zoomToFit": "அனைத்துறுப்புகளும் பொருந்தும்படி விரிவாக்கு", "zoomToFit": "அனைத்துறுப்புகளும் பொருந்தும்படி விரிவாக்கு",
"zoomToSelection": "தெரிவுக்கு விரிவாக்கு" "zoomToSelection": "தெரிவுக்கு விரிவாக்கு",
"toggleElementLock": "தேர்ந்தெடுப்பைப் பூட்டு/பூட்டவிழ்"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "கித்தானைத் துடை" "title": "கித்தானைத் துடை"

View File

@ -9,6 +9,7 @@
"copy": "Kopyala", "copy": "Kopyala",
"copyAsPng": "Panoya PNG olarak kopyala", "copyAsPng": "Panoya PNG olarak kopyala",
"copyAsSvg": "Panoya SVG olarak kopyala", "copyAsSvg": "Panoya SVG olarak kopyala",
"copyText": "Panoya metin olarak kopyala",
"bringForward": "Bir öne getir", "bringForward": "Bir öne getir",
"sendToBack": "Arkaya gönder", "sendToBack": "Arkaya gönder",
"bringToFront": "En öne getir", "bringToFront": "En öne getir",
@ -41,7 +42,7 @@
"onlySelected": "Sadece seçilen", "onlySelected": "Sadece seçilen",
"withBackground": "Arka plan", "withBackground": "Arka plan",
"exportEmbedScene": "Gömülü sahne", "exportEmbedScene": "Gömülü sahne",
"exportEmbedScene_details": "Sahne datası, daha sonra geri kullanılabilmesi için çıktı alınan PNG/SVG dosyasına dahil edicelek. Bu işlem dosya boyutunu arttıracaktır.", "exportEmbedScene_details": "Sahne verileri, sahnenin geri yüklenebilmesi için dışa aktarılan PNG/SVG dosyasına kaydedilecektir.\nDışa aktarılan dosya boyutunu artıracaktır.",
"addWatermark": "\"Excalidraw ile yapıldı\" yazısını ekle", "addWatermark": "\"Excalidraw ile yapıldı\" yazısını ekle",
"handDrawn": "El-yazısı", "handDrawn": "El-yazısı",
"normal": "Normal", "normal": "Normal",
@ -64,7 +65,7 @@
"cartoonist": "Karikatürist", "cartoonist": "Karikatürist",
"fileTitle": "Dosya adı", "fileTitle": "Dosya adı",
"colorPicker": "Renk seçici", "colorPicker": "Renk seçici",
"canvasColors": "", "canvasColors": "Tuvallerin üzerinde kullanıldı",
"canvasBackground": "Tuval arka planı", "canvasBackground": "Tuval arka planı",
"drawingCanvas": "Çizim tuvali", "drawingCanvas": "Çizim tuvali",
"layers": "Katmanlar", "layers": "Katmanlar",
@ -84,7 +85,7 @@
"removeFromLibrary": "Kütüphaneden kaldır", "removeFromLibrary": "Kütüphaneden kaldır",
"libraryLoadingMessage": "Kütüphane yükleniyor…", "libraryLoadingMessage": "Kütüphane yükleniyor…",
"libraries": "Kütüphanelere gözat", "libraries": "Kütüphanelere gözat",
"loadingScene": "Çalışma alanı yükleniyor…", "loadingScene": "Sahne yükleniyor…",
"align": "Hizala", "align": "Hizala",
"alignTop": "Yukarı hizala", "alignTop": "Yukarı hizala",
"alignBottom": "Aşağı hizala", "alignBottom": "Aşağı hizala",
@ -104,13 +105,20 @@
"toggleTheme": "Temayı etkinleştir/devre dışı bırak", "toggleTheme": "Temayı etkinleştir/devre dışı bırak",
"personalLib": "Kişisel Kitaplık", "personalLib": "Kişisel Kitaplık",
"excalidrawLib": "Excalidraw Kitaplığı", "excalidrawLib": "Excalidraw Kitaplığı",
"decreaseFontSize": "", "decreaseFontSize": "Yazı Tipi Boyutunu Küçült",
"increaseFontSize": "", "increaseFontSize": "Yazı Tipi Boyutunu Büyült",
"unbindText": "", "unbindText": "Metni çöz",
"bindText": "Metni taşıyıcıya bağla",
"link": { "link": {
"edit": "", "edit": "Bağlantıyı düzenle",
"create": "", "create": "Bağlantı oluştur",
"label": "" "label": "Bağlantı"
},
"elementLock": {
"lock": "Kilitle",
"unlock": "Kilidi Kaldır",
"lockAll": "Hepsini kilitle",
"unlockAll": "Hepsinin kilidini kaldır"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Bilinmeyen dosya yüklenemiyor", "couldNotLoadInvalidFile": "Bilinmeyen dosya yüklenemiyor",
"importBackendFailed": "Sunucudan içe aktarma başarısız.", "importBackendFailed": "Sunucudan içe aktarma başarısız.",
"cannotExportEmptyCanvas": "Boş tuval dışarıya aktarılamaz.", "cannotExportEmptyCanvas": "Boş tuval dışarıya aktarılamaz.",
"couldNotCopyToClipboard": "Panoya kopyalanamadı. Chrome tarayıcısını deneyiniz.", "couldNotCopyToClipboard": "Panoya kopyalanamıyor.",
"decryptFailed": "Şifrelenmiş veri çözümlenemedi.", "decryptFailed": "Şifrelenmiş veri çözümlenemedi.",
"uploadedSecurly": "Yükleme uçtan uca şifreleme ile korunmaktadır. Excalidraw sunucusu ve üçüncül şahıslar içeriği okuyamayacaktır.", "uploadedSecurly": "Yükleme uçtan uca şifreleme ile korunmaktadır. Excalidraw sunucusu ve üçüncül şahıslar içeriği okuyamayacaktır.",
"loadSceneOverridePrompt": "Harici çizimler yüklemek mevcut olan içeriği değiştirecektir. Devam etmek istiyor musunuz?", "loadSceneOverridePrompt": "Harici çizimler yüklemek mevcut olan içeriği değiştirecektir. Devam etmek istiyor musunuz?",
@ -169,8 +177,8 @@
"errorRemovingFromLibrary": "Öğe kütüphaneden silinemedi", "errorRemovingFromLibrary": "Öğe kütüphaneden silinemedi",
"confirmAddLibrary": "Bu, kitaplığınıza {{numShapes}} tane şekil ekleyecek. Emin misiniz?", "confirmAddLibrary": "Bu, kitaplığınıza {{numShapes}} tane şekil ekleyecek. Emin misiniz?",
"imageDoesNotContainScene": "Bu görüntü herhangi bir sahne verisi içermiyor gibi görünüyor. Dışa aktarma sırasında sahne yerleştirmeyi etkinleştirdiniz mi?", "imageDoesNotContainScene": "Bu görüntü herhangi bir sahne verisi içermiyor gibi görünüyor. Dışa aktarma sırasında sahne yerleştirmeyi etkinleştirdiniz mi?",
"cannotRestoreFromImage": "Sahne bu dosyadan oluşturulamıyor", "cannotRestoreFromImage": "Sahne bu resim dosyasından geri yüklenemedi",
"invalidSceneUrl": "Verilen URL'den çalışma alanı yüklenemedi. Dosya bozuk olabilir veya geçerli bir Excalidraw JSON verisi bulundurmuyor olabilir.", "invalidSceneUrl": "Verilen bağlantıdan çalışma alanı yüklenemedi. Dosya bozuk olabilir veya geçerli bir Excalidraw JSON verisi bulundurmuyor olabilir.",
"resetLibrary": "Bu işlem kütüphanenizi sıfırlayacak. Emin misiniz?", "resetLibrary": "Bu işlem kütüphanenizi sıfırlayacak. Emin misiniz?",
"removeItemsFromsLibrary": "{{count}} öğe(ler) kitaplıktan kaldırılsın mı?", "removeItemsFromsLibrary": "{{count}} öğe(ler) kitaplıktan kaldırılsın mı?",
"invalidEncryptionKey": "Şifreleme anahtarı 22 karakter olmalı. Canlı işbirliği devre dışı bırakıldı." "invalidEncryptionKey": "Şifreleme anahtarı 22 karakter olmalı. Canlı işbirliği devre dışı bırakıldı."
@ -181,7 +189,7 @@
"fileTooBig": "Dosya çok büyük. İzin verilen maksimum boyut {{maxSize}}.", "fileTooBig": "Dosya çok büyük. İzin verilen maksimum boyut {{maxSize}}.",
"svgImageInsertError": "SVG resmi eklenemedi. SVG işaretlemesi geçersiz görünüyor.", "svgImageInsertError": "SVG resmi eklenemedi. SVG işaretlemesi geçersiz görünüyor.",
"invalidSVGString": "Geçersiz SVG.", "invalidSVGString": "Geçersiz SVG.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": "İş birliği sunucusuna bağlanılamıyor. Lütfen sayfayı yenileyip tekrar deneyin."
}, },
"toolBar": { "toolBar": {
"selection": "Seçme", "selection": "Seçme",
@ -195,8 +203,9 @@
"text": "Yazı", "text": "Yazı",
"library": "Kütüphane", "library": "Kütüphane",
"lock": "Seçilen aracı çizimden sonra aktif tut", "lock": "Seçilen aracı çizimden sonra aktif tut",
"penMode": "", "penMode": "Çift parmak sıkıştırmayı önle ve serbest çizimi yalnızca kalemle yap",
"link": "" "link": "Seçilen şekil için bağlantı Ekle/Güncelle",
"eraser": "Silgi"
}, },
"headings": { "headings": {
"canvasActions": "Tuval eylemleri", "canvasActions": "Tuval eylemleri",
@ -210,18 +219,19 @@
"text": "İpucu: seçme aracıyla herhangi bir yere çift tıklayarak da yazı ekleyebilirsin", "text": "İpucu: seçme aracıyla herhangi bir yere çift tıklayarak da yazı ekleyebilirsin",
"text_selected": "Metni düzenlemek için çift tıklayın veya ENTER'a basın", "text_selected": "Metni düzenlemek için çift tıklayın veya ENTER'a basın",
"text_editing": "Düzenlemeyi bitirmek için ESC veya Ctrl/Cmd+ENTER tuşlarına basın", "text_editing": "Düzenlemeyi bitirmek için ESC veya Ctrl/Cmd+ENTER tuşlarına basın",
"linearElementMulti": "Tamamlamak için son noktayı seçin veya Escape ve Enter'dan birine basın", "linearElementMulti": "Bitirmek için son noktaya tıklayın ya da Escape veya Enter tuşuna basın",
"lockAngle": "SHIFT tuşuna basılı tutarak açıyı koruyabilirsiniz", "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", "resize": "Yeniden boyutlandırırken SHIFT tuşunu basılı tutarak oranları sınırlayabilirsiniz,\nmerkezden yeniden boyutlandırmak için ALT tuşunu basılı tutun",
"resizeImage": "SHIFT'e basılı tutarak serbestçe yeniden boyutlandırabilirsiniz, merkezden yeniden boyutlandırmak için ALT tuşunu basılı tutun", "resizeImage": "SHIFT'e basılı tutarak serbestçe yeniden boyutlandırabilirsiniz, merkezden yeniden boyutlandırmak için ALT tuşunu basılı tutun",
"rotate": "Döndürürken SHIFT tuşuna basılı tutarak açıları koruyabilirsiniz", "rotate": "Döndürürken SHIFT tuşuna basılı tutarak açıları koruyabilirsiniz",
"lineEditor_info": "Noktaları düzenlemek için çift-tıklayın veya Enter'a basın", "lineEditor_info": "Noktaları düzenlemek için çift-tıklayın veya Enter'a basın",
"lineEditor_pointSelected": "", "lineEditor_pointSelected": "Sil tuşuna basarak noktaları silin,\nCtrl/Cmd + D ile çoğaltın, ya da sürükleyerek taşıyın",
"lineEditor_nothingSelected": "", "lineEditor_nothingSelected": "Düzenlemek için bir nokta seçin (birden fazla seçmek için SHIFT tuşunu basılı tutun),\nveya Alt tuşunu basılı tutun ve yeni noktalar eklemek için tıklayın",
"placeImage": "Resmi yerleştirmek için tıklayın ya da boyutunu manuel olarak ayarlamak için tıklayıp sürükleyin", "placeImage": "Resmi yerleştirmek için tıklayın ya da boyutunu manuel olarak ayarlamak için tıklayıp sürükleyin",
"publishLibrary": "Kendi kitaplığınızı yayınlayın", "publishLibrary": "Kendi kitaplığınızı yayınlayın",
"bindTextToElement": "", "bindTextToElement": "Enter tuşuna basarak metin ekleyin",
"deepBoxSelect": "" "deepBoxSelect": "Ctrl/Cmd tuşuna basılı tutarak derin seçim yapın ya da sürüklemeyi engelleyin",
"eraserRevert": "Alt tuşuna basılı tutarak silinme için işaretlenmiş ögeleri tersine çevirin"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Önizleme gösterilemiyor", "cannotShowPreview": "Önizleme gösterilemiyor",
@ -268,8 +278,8 @@
"helpDialog": { "helpDialog": {
"blog": "Blog'umuzu okuyun", "blog": "Blog'umuzu okuyun",
"click": "tıkla", "click": "tıkla",
"deepSelect": "", "deepSelect": "Derin seçim",
"deepBoxSelect": "", "deepBoxSelect": "Kutu içerisinde derin seçim yapın, sürüklemeyi engelleyin",
"curvedArrow": "Eğri ok", "curvedArrow": "Eğri ok",
"curvedLine": "Eğri çizgi", "curvedLine": "Eğri çizgi",
"documentation": "Dokümantasyon", "documentation": "Dokümantasyon",
@ -281,14 +291,15 @@
"howto": "Rehberlerimizi takip edin", "howto": "Rehberlerimizi takip edin",
"or": "veya", "or": "veya",
"preventBinding": "Ok bağlamayı önleyin", "preventBinding": "Ok bağlamayı önleyin",
"shapes": "Şekiller", "tools": "Araçlar",
"shortcuts": "Klavye kısayolları", "shortcuts": "Klavye kısayolları",
"textFinish": "Düzenlemeyi bitir (metin düzenleyici)", "textFinish": "Düzenlemeyi bitir (metin düzenleyici)",
"textNewLine": "Yeni satır ekle (metin düzenleyici)", "textNewLine": "Yeni satır ekle (metin düzenleyici)",
"title": "Yardım", "title": "Yardım",
"view": "Görünüm", "view": "Görünüm",
"zoomToFit": "Tüm öğeleri sığdırmak için yakınlaştır", "zoomToFit": "Tüm öğeleri sığdırmak için yakınlaştır",
"zoomToSelection": "Seçime yakınlaş" "zoomToSelection": "Seçime yakınlaş",
"toggleElementLock": "Seçimi Kilitle/çöz"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Tuvali temizle" "title": "Tuvali temizle"
@ -306,40 +317,40 @@
"authorName": "Adınız ya da kullanıcı adınız", "authorName": "Adınız ya da kullanıcı adınız",
"libraryName": "Kitaplığınızın adı", "libraryName": "Kitaplığınızın adı",
"libraryDesc": "İnsanların kullanımını anlamasına yardımcı olmak için kitaplığınızın açıklaması", "libraryDesc": "İnsanların kullanımını anlamasına yardımcı olmak için kitaplığınızın açıklaması",
"githubHandle": "", "githubHandle": "Github bağlantısı ( tercihe bağlı), kütüphane gözden geçirme için onaylandığında düzenleyebiliesiniz diye",
"twitterHandle": "", "twitterHandle": "Twitter kullanıcı adı ( tercihe bağlı), bu sayede Twitter üzerinde paylaşıren çalışmanızı size atfedebiliriz",
"website": "" "website": "Kişisel web sayfanızı ya da başka bir yeri bağlayın (tercihe bağlı)"
}, },
"errors": { "errors": {
"required": "", "required": "Gerekli",
"website": "" "website": "Geçerli bir URL girin"
}, },
"noteDescription": { "noteDescription": {
"pre": "", "pre": "Submit your library to be included in the ",
"link": "", "link": "genel kütüphane reposu",
"post": "" "post": "diğer insanlar çizimlerinde kullanabilsin diye."
}, },
"noteGuidelines": { "noteGuidelines": {
"pre": "", "pre": "Önce kütüphane elle onaylanmalı. şunu okuyun ",
"link": "", "link": "yönergeler",
"post": "" "post": " onaylamadan önce. gerekli olması halinde iletişim kurmak için ve değişiklik için Github hesabı gerekli, ama çok da illaki olmalı değil."
}, },
"noteLicense": { "noteLicense": {
"pre": "", "pre": "Bunu onaylayarak, kütüğhanenin şu lisansla yayınlanmasını onaylıyorsunuz ",
"link": "", "link": "MIT Lisans, ",
"post": "" "post": "ki bu kısaca herkesin onu kısıtlama olmaksızın kullanabileceği anlamına gelmektedir."
}, },
"noteItems": "", "noteItems": "Her kütüphane kendi ismine sahip olmalı ki tarama yapabilelim. Şu kütüphane ögeleri dahil edilecek:",
"atleastOneLibItem": "" "atleastOneLibItem": "Lütfen başlamak için en az bir tane kütüphane ögesi seçin"
}, },
"publishSuccessDialog": { "publishSuccessDialog": {
"title": "", "title": "Kütüphane gönderildi",
"content": "", "content": "Teşekkürler {{authorName}}. Kütüphaneniz gözden geçirme için alındı. Durumu takip edebilirsiniz",
"link": "" "link": "burada"
}, },
"confirmDialog": { "confirmDialog": {
"resetLibrary": "", "resetLibrary": "Kütüphaneyi sıfırla",
"removeItemsFromLib": "" "removeItemsFromLib": "Seçilen ögeleri kütüphaneden kaldır"
}, },
"encrypted": { "encrypted": {
"tooltip": "Çizimleriniz uçtan-uca şifrelenmiştir, Excalidraw'ın sunucuları bile onları göremez.", "tooltip": "Çizimleriniz uçtan-uca şifrelenmiştir, Excalidraw'ın sunucuları bile onları göremez.",
@ -361,7 +372,7 @@
"width": "Genişlik" "width": "Genişlik"
}, },
"toast": { "toast": {
"addedToLibrary": "", "addedToLibrary": "Kütüphaneye eklendi",
"copyStyles": "Stiller kopyalandı.", "copyStyles": "Stiller kopyalandı.",
"copyToClipboard": "Panoya kopyalandı.", "copyToClipboard": "Panoya kopyalandı.",
"copyToClipboardAsPng": "{{exportSelection}} panoya PNG olarak\n({{exportColorScheme}}) kopyalandı", "copyToClipboardAsPng": "{{exportSelection}} panoya PNG olarak\n({{exportColorScheme}}) kopyalandı",
@ -376,14 +387,14 @@
"f1f3f5": "Gri 1", "f1f3f5": "Gri 1",
"fff5f5": "Kırmızı 0", "fff5f5": "Kırmızı 0",
"fff0f6": "Pembe 0", "fff0f6": "Pembe 0",
"f8f0fc": "", "f8f0fc": "Koyu Mor 0",
"f3f0ff": "", "f3f0ff": "Mor 0",
"edf2ff": "", "edf2ff": "Çivit 0",
"e7f5ff": "Mavi 0", "e7f5ff": "Mavi 0",
"e3fafc": "", "e3fafc": "Camgöbeği 0",
"e6fcf5": "", "e6fcf5": "Deniz Mavisi 0",
"ebfbee": "Yeşil 0", "ebfbee": "Yeşil 0",
"f4fce3": "", "f4fce3": "Yeşil 0",
"fff9db": "Sarı 0", "fff9db": "Sarı 0",
"fff4e6": "Turuncu 0", "fff4e6": "Turuncu 0",
"transparent": "Şeffaf", "transparent": "Şeffaf",
@ -391,14 +402,14 @@
"868e96": "Gri 6", "868e96": "Gri 6",
"fa5252": "Kırmızı 6", "fa5252": "Kırmızı 6",
"e64980": "Pembe 6", "e64980": "Pembe 6",
"be4bdb": "", "be4bdb": "Koyu Mor 6",
"7950f2": "", "7950f2": "Mor 6",
"4c6ef5": "", "4c6ef5": "Çivit 6",
"228be6": "Mavi 6", "228be6": "Mavi 6",
"15aabf": "", "15aabf": "Camgöbeği 6",
"12b886": "", "12b886": "Deniz Mavisi 6",
"40c057": "Yeşil 6", "40c057": "Yeşil 6",
"82c91e": "", "82c91e": "Green 6",
"fab005": "Sarı 6", "fab005": "Sarı 6",
"fd7e14": "Turuncu 6", "fd7e14": "Turuncu 6",
"000000": "Siyah", "000000": "Siyah",
@ -406,14 +417,14 @@
"495057": "Gri 7", "495057": "Gri 7",
"c92a2a": "Kırmızı 9", "c92a2a": "Kırmızı 9",
"a61e4d": "Pembe 9", "a61e4d": "Pembe 9",
"862e9c": "", "862e9c": "Koyu Mor 9",
"5f3dc4": "", "5f3dc4": "Mor 9",
"364fc7": "", "364fc7": "Çivit 9",
"1864ab": "Mavi 9", "1864ab": "Mavi 9",
"0b7285": "", "0b7285": "Camgöbeği 9",
"087f5b": "", "087f5b": "Deniz Mavisi 9",
"2b8a3e": "Yeşil 9", "2b8a3e": "Yeşil 9",
"5c940d": "", "5c940d": "Yeşil 9",
"e67700": "Sarı 9", "e67700": "Sarı 9",
"d9480f": "Turuncu 9" "d9480f": "Turuncu 9"
} }

View File

@ -9,6 +9,7 @@
"copy": "Копіювати", "copy": "Копіювати",
"copyAsPng": "Копіювати як PNG", "copyAsPng": "Копіювати як PNG",
"copyAsSvg": "Копіювати як SVG", "copyAsSvg": "Копіювати як SVG",
"copyText": "Копіювати в буфер обміну як текст",
"bringForward": "Перемістити вперед", "bringForward": "Перемістити вперед",
"sendToBack": "На задній план", "sendToBack": "На задній план",
"bringToFront": "На передній план", "bringToFront": "На передній план",
@ -64,7 +65,7 @@
"cartoonist": "Карикатурист", "cartoonist": "Карикатурист",
"fileTitle": "Назва файла", "fileTitle": "Назва файла",
"colorPicker": "Палітра кольорів", "colorPicker": "Палітра кольорів",
"canvasColors": "", "canvasColors": "Використовується на полотні",
"canvasBackground": "Тло полотна", "canvasBackground": "Тло полотна",
"drawingCanvas": "Полотно", "drawingCanvas": "Полотно",
"layers": "Шари", "layers": "Шари",
@ -102,15 +103,22 @@
"showStroke": "Показати палітру для контура", "showStroke": "Показати палітру для контура",
"showBackground": "Показати палітру для фону", "showBackground": "Показати палітру для фону",
"toggleTheme": "Перемкнути тему", "toggleTheme": "Перемкнути тему",
"personalLib": "", "personalLib": "Персональна бібліотека",
"excalidrawLib": "", "excalidrawLib": "Бібліотека Excalidraw",
"decreaseFontSize": "", "decreaseFontSize": "Зменшити розмір шрифту",
"increaseFontSize": "", "increaseFontSize": "Збільшити розмір шрифту",
"unbindText": "", "unbindText": "Відв'язати текст",
"bindText": "Прив’язати текст до контейнера",
"link": { "link": {
"edit": "", "edit": "Редагування посилання",
"create": "", "create": "Створити посилання",
"label": "" "label": "Посилання"
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -147,10 +155,10 @@
"exitZenMode": "Вийти з дзен-режиму", "exitZenMode": "Вийти з дзен-режиму",
"cancel": "Скасувати", "cancel": "Скасувати",
"clear": "Очистити", "clear": "Очистити",
"remove": "", "remove": "Видалити",
"publishLibrary": "", "publishLibrary": "Опублікувати",
"submit": "", "submit": "Надіслати",
"confirm": "" "confirm": "Підтвердити"
}, },
"alerts": { "alerts": {
"clearReset": "Це очистить все полотно. Впевнені?", "clearReset": "Це очистить все полотно. Впевнені?",
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "Файл з помилками не відкрився", "couldNotLoadInvalidFile": "Файл з помилками не відкрився",
"importBackendFailed": "Імпортування невдале.", "importBackendFailed": "Імпортування невдале.",
"cannotExportEmptyCanvas": "Не вийшло експортувати пусте полотно.", "cannotExportEmptyCanvas": "Не вийшло експортувати пусте полотно.",
"couldNotCopyToClipboard": "Не копіюється до буферу обміну. Спробуйте в браузері Chrome.", "couldNotCopyToClipboard": "Не вдалося скопіювати до буфера обміну.",
"decryptFailed": "Не вдалося розшифрувати дані.", "decryptFailed": "Не вдалося розшифрувати дані.",
"uploadedSecurly": "Це завантаження було захищене наскрізним шифруванням, а це означає що сервер Excalidraw та інші не зможуть прочитати вміст.", "uploadedSecurly": "Це завантаження було захищене наскрізним шифруванням, а це означає що сервер Excalidraw та інші не зможуть прочитати вміст.",
"loadSceneOverridePrompt": "Завантаження зовнішнього креслення замінить ваш наявний контент. Продовжити?", "loadSceneOverridePrompt": "Завантаження зовнішнього креслення замінить ваш наявний контент. Продовжити?",
@ -180,7 +188,7 @@
"imageInsertError": "Не вдалося вставити зображення. Повторіть спробу пізніше...", "imageInsertError": "Не вдалося вставити зображення. Повторіть спробу пізніше...",
"fileTooBig": "Занадто великий розмір файлу, максимальний розмір файлу {{maxSize}}.", "fileTooBig": "Занадто великий розмір файлу, максимальний розмір файлу {{maxSize}}.",
"svgImageInsertError": "Не вдалося вставити SVG-зображення. Помилка розмітки SVG.", "svgImageInsertError": "Не вдалося вставити SVG-зображення. Помилка розмітки SVG.",
"invalidSVGString": "", "invalidSVGString": "Недійсний SVG.",
"cannotResolveCollabServer": "" "cannotResolveCollabServer": ""
}, },
"toolBar": { "toolBar": {
@ -196,7 +204,8 @@
"library": "Бібліотека", "library": "Бібліотека",
"lock": "Залишити обраний інструмент після креслення", "lock": "Залишити обраний інструмент після креслення",
"penMode": "", "penMode": "",
"link": "" "link": "Додати/Оновити посилання для вибраної форми",
"eraser": "Очищувач"
}, },
"headings": { "headings": {
"canvasActions": "Дії з полотном", "canvasActions": "Дії з полотном",
@ -219,9 +228,10 @@
"lineEditor_pointSelected": "", "lineEditor_pointSelected": "",
"lineEditor_nothingSelected": "", "lineEditor_nothingSelected": "",
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "Опублікувати свою власну бібліотеку",
"bindTextToElement": "", "bindTextToElement": "Натисніть Enter, щоб додати текст",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "Не вдається показати попередній перегляд", "cannotShowPreview": "Не вдається показати попередній перегляд",
@ -268,7 +278,7 @@
"helpDialog": { "helpDialog": {
"blog": "Наш блог", "blog": "Наш блог",
"click": "натиснути", "click": "натиснути",
"deepSelect": "", "deepSelect": "Глибокий вибір",
"deepBoxSelect": "", "deepBoxSelect": "",
"curvedArrow": "Крива стрілка", "curvedArrow": "Крива стрілка",
"curvedLine": "Крива лінія", "curvedLine": "Крива лінія",
@ -281,65 +291,66 @@
"howto": "Дотримуйтесь наших інструкцій", "howto": "Дотримуйтесь наших інструкцій",
"or": "або", "or": "або",
"preventBinding": "Запобігти зв'язування зі стрілками", "preventBinding": "Запобігти зв'язування зі стрілками",
"shapes": "Фігури", "tools": "Інструменти",
"shortcuts": "Гарячі клавіші", "shortcuts": "Гарячі клавіші",
"textFinish": "Завершити редагування (текстовий редактор)", "textFinish": "Завершити редагування (текстовий редактор)",
"textNewLine": "Додати новий рядок (текстовий редактор)", "textNewLine": "Додати новий рядок (текстовий редактор)",
"title": "Допомога", "title": "Допомога",
"view": "Вигляд", "view": "Вигляд",
"zoomToFit": "Збільшити щоб умістити всі елементи", "zoomToFit": "Збільшити щоб умістити всі елементи",
"zoomToSelection": "Наблизити вибране" "zoomToSelection": "Наблизити вибране",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "Очистити полотно" "title": "Очистити полотно"
}, },
"publishDialog": { "publishDialog": {
"title": "", "title": "Опублікувати бібліотеку",
"itemName": "", "itemName": "",
"authorName": "", "authorName": "Ім'я автора",
"githubUsername": "", "githubUsername": "Ім'я користувача Github",
"twitterUsername": "", "twitterUsername": "Ім'я користувача Твитер",
"libraryName": "", "libraryName": "Назва бібліотеки",
"libraryDesc": "", "libraryDesc": "Опис бібліотеки",
"website": "", "website": "Вебсайт",
"placeholder": { "placeholder": {
"authorName": "", "authorName": "Ваше ім'я або ім'я користувача",
"libraryName": "", "libraryName": "Назва вашої бібліотеки",
"libraryDesc": "", "libraryDesc": "Опис вашої бібліотеки, щоб допомогти людям зрозуміти її використання",
"githubHandle": "", "githubHandle": "",
"twitterHandle": "", "twitterHandle": "",
"website": "" "website": ""
}, },
"errors": { "errors": {
"required": "", "required": "",
"website": "" "website": "Введіть дійсну URL-адресу"
}, },
"noteDescription": { "noteDescription": {
"pre": "", "pre": "Подати бібліотеку, щоб вона була включена до ",
"link": "", "link": "публічного репозиторія бібліотек",
"post": "" "post": ""
}, },
"noteGuidelines": { "noteGuidelines": {
"pre": "", "pre": "",
"link": "", "link": "настанови",
"post": "" "post": ""
}, },
"noteLicense": { "noteLicense": {
"pre": "", "pre": "",
"link": "", "link": "Ліцензія MIT, ",
"post": "" "post": ""
}, },
"noteItems": "", "noteItems": "",
"atleastOneLibItem": "" "atleastOneLibItem": ""
}, },
"publishSuccessDialog": { "publishSuccessDialog": {
"title": "", "title": "Бібліотека відправлена",
"content": "", "content": "Дякуємо, {{authorName}}. Ваша бібліотека була відправлена для розгляду. Ви можете відстежувати статус",
"link": "" "link": "тут"
}, },
"confirmDialog": { "confirmDialog": {
"resetLibrary": "", "resetLibrary": "Скинути бібліотеку",
"removeItemsFromLib": "" "removeItemsFromLib": "Видалити вибрані елементи з бібліотеки"
}, },
"encrypted": { "encrypted": {
"tooltip": "Ваші креслення захищені наскрізним шифруванням — сервери Excalidraw ніколи їх не побачать.", "tooltip": "Ваші креслення захищені наскрізним шифруванням — сервери Excalidraw ніколи їх не побачать.",
@ -361,7 +372,7 @@
"width": "Ширина" "width": "Ширина"
}, },
"toast": { "toast": {
"addedToLibrary": "", "addedToLibrary": "Додано до бібліотеки",
"copyStyles": "Скопійовані стилі.", "copyStyles": "Скопійовані стилі.",
"copyToClipboard": "Скопіювати до буферу обміну.", "copyToClipboard": "Скопіювати до буферу обміну.",
"copyToClipboardAsPng": "Скопійовано {{exportSelection}} до буфера обміну як PNG\n({{exportColorScheme}})", "copyToClipboardAsPng": "Скопійовано {{exportSelection}} до буфера обміну як PNG\n({{exportColorScheme}})",

View File

@ -9,6 +9,7 @@
"copy": "拷贝", "copy": "拷贝",
"copyAsPng": "复制为 PNG 到剪贴板", "copyAsPng": "复制为 PNG 到剪贴板",
"copyAsSvg": "复制为 SVG 到剪贴板", "copyAsSvg": "复制为 SVG 到剪贴板",
"copyText": "复制文本到剪贴板",
"bringForward": "上移一层", "bringForward": "上移一层",
"sendToBack": "置于底层", "sendToBack": "置于底层",
"bringToFront": "置于顶层", "bringToFront": "置于顶层",
@ -76,8 +77,8 @@
"name": "名字", "name": "名字",
"yourName": "您的姓名", "yourName": "您的姓名",
"madeWithExcalidraw": "使用 Excalidraw 创建", "madeWithExcalidraw": "使用 Excalidraw 创建",
"group": "", "group": "组",
"ungroup": "取消组选", "ungroup": "解除编组",
"collaborators": "协作者", "collaborators": "协作者",
"showGrid": "显示网格", "showGrid": "显示网格",
"addToLibrary": "添加到素材库中", "addToLibrary": "添加到素材库中",
@ -107,10 +108,17 @@
"decreaseFontSize": "缩小字体大小", "decreaseFontSize": "缩小字体大小",
"increaseFontSize": "放大字体大小", "increaseFontSize": "放大字体大小",
"unbindText": "取消文本绑定", "unbindText": "取消文本绑定",
"bindText": "将文本绑定到容器",
"link": { "link": {
"edit": "编辑链接", "edit": "编辑链接",
"create": "新建链接", "create": "新建链接",
"label": "链接" "label": "链接"
},
"elementLock": {
"lock": "锁定",
"unlock": "解锁​​​​",
"lockAll": "全部锁定",
"unlockAll": "全部解锁"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "无法加载无效的文件", "couldNotLoadInvalidFile": "无法加载无效的文件",
"importBackendFailed": "从后端导入失败。", "importBackendFailed": "从后端导入失败。",
"cannotExportEmptyCanvas": "无法导出空白画布。", "cannotExportEmptyCanvas": "无法导出空白画布。",
"couldNotCopyToClipboard": "无法复制到剪贴板,请尝试使用 Chrome 浏览器。", "couldNotCopyToClipboard": "无法复制到剪贴板。",
"decryptFailed": "无法解密数据。", "decryptFailed": "无法解密数据。",
"uploadedSecurly": "上传已被端到端加密保护,这意味着 Excalidraw 的服务器和第三方都无法读取内容。", "uploadedSecurly": "上传已被端到端加密保护,这意味着 Excalidraw 的服务器和第三方都无法读取内容。",
"loadSceneOverridePrompt": "加载外部绘图将取代您现有的内容。您想要继续吗?", "loadSceneOverridePrompt": "加载外部绘图将取代您现有的内容。您想要继续吗?",
@ -196,7 +204,8 @@
"library": "素材库", "library": "素材库",
"lock": "绘制后保持所选的工具栏状态", "lock": "绘制后保持所选的工具栏状态",
"penMode": "禁用手势缩放并只接收来自触控笔的输入", "penMode": "禁用手势缩放并只接收来自触控笔的输入",
"link": "为选中的形状添加/更新链接" "link": "为选中的形状添加/更新链接",
"eraser": "橡皮"
}, },
"headings": { "headings": {
"canvasActions": "画布动作", "canvasActions": "画布动作",
@ -221,7 +230,8 @@
"placeImage": "点击放置图像,或者点击并拖动以手动设置图像大小", "placeImage": "点击放置图像,或者点击并拖动以手动设置图像大小",
"publishLibrary": "发布您自己的素材库", "publishLibrary": "发布您自己的素材库",
"bindTextToElement": "按下 Enter 以添加文本", "bindTextToElement": "按下 Enter 以添加文本",
"deepBoxSelect": "按住 CtrlOrCmd 以深度选择,并避免拖拽" "deepBoxSelect": "按住 CtrlOrCmd 以深度选择,并避免拖拽",
"eraserRevert": "按住 Alt 以反选被标记删除的元素"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "无法显示预览", "cannotShowPreview": "无法显示预览",
@ -281,14 +291,15 @@
"howto": "帮助文档", "howto": "帮助文档",
"or": "或", "or": "或",
"preventBinding": "禁用箭头吸附", "preventBinding": "禁用箭头吸附",
"shapes": "形状", "tools": "工具",
"shortcuts": "快捷键列表", "shortcuts": "快捷键列表",
"textFinish": "完成编辑 (文本编辑器)", "textFinish": "完成编辑 (文本编辑器)",
"textNewLine": "添加新行(文本编辑器)", "textNewLine": "添加新行(文本编辑器)",
"title": "帮助", "title": "帮助",
"view": "视图", "view": "视图",
"zoomToFit": "缩放以适应所有元素", "zoomToFit": "缩放以适应所有元素",
"zoomToSelection": "缩放到选区" "zoomToSelection": "缩放到选区",
"toggleElementLock": "锁定/解锁"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "清除画布" "title": "清除画布"

View File

@ -9,6 +9,7 @@
"copy": "複製", "copy": "複製",
"copyAsPng": "以 PNG 格式複製", "copyAsPng": "以 PNG 格式複製",
"copyAsSvg": "以 SVG 格式複製", "copyAsSvg": "以 SVG 格式複製",
"copyText": "",
"bringForward": "往上一層移動", "bringForward": "往上一層移動",
"sendToBack": "移到最底層", "sendToBack": "移到最底層",
"bringToFront": "移到最上層", "bringToFront": "移到最上層",
@ -107,10 +108,17 @@
"decreaseFontSize": "", "decreaseFontSize": "",
"increaseFontSize": "", "increaseFontSize": "",
"unbindText": "", "unbindText": "",
"bindText": "",
"link": { "link": {
"edit": "", "edit": "",
"create": "", "create": "",
"label": "" "label": ""
},
"elementLock": {
"lock": "",
"unlock": "",
"lockAll": "",
"unlockAll": ""
} }
}, },
"buttons": { "buttons": {
@ -196,7 +204,8 @@
"library": "", "library": "",
"lock": "", "lock": "",
"penMode": "", "penMode": "",
"link": "" "link": "",
"eraser": ""
}, },
"headings": { "headings": {
"canvasActions": "畫布動作", "canvasActions": "畫布動作",
@ -221,7 +230,8 @@
"placeImage": "", "placeImage": "",
"publishLibrary": "", "publishLibrary": "",
"bindTextToElement": "", "bindTextToElement": "",
"deepBoxSelect": "" "deepBoxSelect": "",
"eraserRevert": ""
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "無法顯示預覽", "cannotShowPreview": "無法顯示預覽",
@ -281,14 +291,15 @@
"howto": "", "howto": "",
"or": "", "or": "",
"preventBinding": "", "preventBinding": "",
"shapes": "", "tools": "",
"shortcuts": "", "shortcuts": "",
"textFinish": "", "textFinish": "",
"textNewLine": "", "textNewLine": "",
"title": "", "title": "",
"view": "", "view": "",
"zoomToFit": "", "zoomToFit": "",
"zoomToSelection": "" "zoomToSelection": "",
"toggleElementLock": ""
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "" "title": ""

View File

@ -9,6 +9,7 @@
"copy": "複製", "copy": "複製",
"copyAsPng": "以PNG格式儲存到剪貼板", "copyAsPng": "以PNG格式儲存到剪貼板",
"copyAsSvg": "以SVG格式複製到剪貼板", "copyAsSvg": "以SVG格式複製到剪貼板",
"copyText": "以文字格式複製至剪貼簿",
"bringForward": "上移一層", "bringForward": "上移一層",
"sendToBack": "移到最底層", "sendToBack": "移到最底層",
"bringToFront": "置於最頂層", "bringToFront": "置於最頂層",
@ -107,10 +108,17 @@
"decreaseFontSize": "縮小文字", "decreaseFontSize": "縮小文字",
"increaseFontSize": "放大文字", "increaseFontSize": "放大文字",
"unbindText": "取消綁定文字", "unbindText": "取消綁定文字",
"bindText": "結合文字至容器",
"link": { "link": {
"edit": "編輯連結", "edit": "編輯連結",
"create": "建立連結", "create": "建立連結",
"label": "連結" "label": "連結"
},
"elementLock": {
"lock": "鎖定",
"unlock": "解鎖",
"lockAll": "全部鎖定",
"unlockAll": "全部解鎖"
} }
}, },
"buttons": { "buttons": {
@ -159,7 +167,7 @@
"couldNotLoadInvalidFile": "無法讀取失效的檔案。", "couldNotLoadInvalidFile": "無法讀取失效的檔案。",
"importBackendFailed": "後端讀取失敗。", "importBackendFailed": "後端讀取失敗。",
"cannotExportEmptyCanvas": "無法輸出空白的 canvas。", "cannotExportEmptyCanvas": "無法輸出空白的 canvas。",
"couldNotCopyToClipboard": "無法複製至剪貼簿。請使用 Chrome 瀏覽器再試試看。", "couldNotCopyToClipboard": "無法複製到剪貼簿",
"decryptFailed": "無法解密資料。", "decryptFailed": "無法解密資料。",
"uploadedSecurly": "上傳已通過 end-to-end 加密Excalidraw 伺服器和第三方無法皆讀取其內容。", "uploadedSecurly": "上傳已通過 end-to-end 加密Excalidraw 伺服器和第三方無法皆讀取其內容。",
"loadSceneOverridePrompt": "讀取外部圖樣將取代目前的內容。是否要繼續?", "loadSceneOverridePrompt": "讀取外部圖樣將取代目前的內容。是否要繼續?",
@ -196,7 +204,8 @@
"library": "資料庫", "library": "資料庫",
"lock": "可連續使用選取的工具", "lock": "可連續使用選取的工具",
"penMode": "停止使用手勢縮放並接受以繪圖筆繪圖輸入", "penMode": "停止使用手勢縮放並接受以繪圖筆繪圖輸入",
"link": "為所選的形狀增加\b/更新連結" "link": "為所選的形狀增加\b/更新連結",
"eraser": "橡皮擦"
}, },
"headings": { "headings": {
"canvasActions": "canvas 動作", "canvasActions": "canvas 動作",
@ -221,7 +230,8 @@
"placeImage": "點擊以放置圖片,或點擊並拖曳以手動調整其尺寸。", "placeImage": "點擊以放置圖片,或點擊並拖曳以手動調整其尺寸。",
"publishLibrary": "發布個人資料庫", "publishLibrary": "發布個人資料庫",
"bindTextToElement": "按下 Enter 以加入文字。", "bindTextToElement": "按下 Enter 以加入文字。",
"deepBoxSelect": "按住 Ctrl 或 Cmd 以深度選取並避免拖曳" "deepBoxSelect": "按住 Ctrl 或 Cmd 以深度選取並避免拖曳",
"eraserRevert": "按住 Alt 以反選取已標記待刪除的元素"
}, },
"canvasError": { "canvasError": {
"cannotShowPreview": "無法顯示預覽", "cannotShowPreview": "無法顯示預覽",
@ -281,14 +291,15 @@
"howto": "參照我們的說明", "howto": "參照我們的說明",
"or": "或", "or": "或",
"preventBinding": "避免箭號連結", "preventBinding": "避免箭號連結",
"shapes": "形狀", "tools": "工具",
"shortcuts": "鍵盤快速鍵", "shortcuts": "鍵盤快速鍵",
"textFinish": "完成編輯(文字編輯器)", "textFinish": "完成編輯(文字編輯器)",
"textNewLine": "換行(文字編輯器)", "textNewLine": "換行(文字編輯器)",
"title": "說明", "title": "說明",
"view": "檢視", "view": "檢視",
"zoomToFit": "放大至填滿畫面", "zoomToFit": "放大至填滿畫面",
"zoomToSelection": "縮放至選取區" "zoomToSelection": "縮放至選取區",
"toggleElementLock": "鎖定/解鎖已選的項目"
}, },
"clearCanvasDialog": { "clearCanvasDialog": {
"title": "清除畫布" "title": "清除畫布"

View File

@ -15,9 +15,19 @@ Please add the latest change on the top under the correct section.
### Excalidraw API ### Excalidraw API
#### Features
- The `exportToBlob` utility now supports the `exportEmbedScene` option when generating a png image [#5047](https://github.com/excalidraw/excalidraw/pull/5047).
- Exported [`restoreLibraryItems`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#restoreLibraryItems) API [#4995](https://github.com/excalidraw/excalidraw/pull/4995).
#### Fixes
- Library menu now properly rerenders if open when library is updated using `updateScene({ libraryItems })` [#4995](https://github.com/excalidraw/excalidraw/pull/4995).
#### Refactor #### Refactor
- Rename `appState.elementLocked` to `appState.activeTool.locked` [#4983](https://github.com/excalidraw/excalidraw/pull/4983). - Rename `appState.elementLocked` to `appState.activeTool.locked` [#4983](https://github.com/excalidraw/excalidraw/pull/4983).
- Expose [`serializeLibraryAsJSON`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#serializeLibraryAsJSON) helper that we use when saving Excalidraw Library to a file.
##### BREAKING CHANGE ##### BREAKING CHANGE
@ -29,6 +39,26 @@ You will need to pass `activeTool.locked` instead of `elementType` from now onwa
You will need to pass `activeTool` instead of `elementType` from now onwards in `appState` You will need to pass `activeTool` instead of `elementType` from now onwards in `appState`
### Build
- Use only named exports [#5045](https://github.com/excalidraw/excalidraw/pull/5045).
#### BREAKING CHANGE
You will need to import the named export from now onwards to use the component
Using bundler :point_down:
```js
import { Excalidraw } from "@excalidraw/excalidraw";
```
In Browser :point_down:
```js
React.createElement(ExcalidrawLib.Excalidraw, opts);
```
## 0.11.0 (2022-02-17) ## 0.11.0 (2022-02-17)
## Excalidraw API ## Excalidraw API

View File

@ -48,7 +48,7 @@ If you are using a Web bundler (for instance, Webpack), you can import it as an
```js ```js
import React, { useEffect, useState, useRef } from "react"; import React, { useEffect, useState, useRef } from "react";
import Excalidraw from "@excalidraw/excalidraw-next"; import { Excalidraw } from "@excalidraw/excalidraw-next";
import InitialData from "./initialData"; import InitialData from "./initialData";
import "./styles.scss"; import "./styles.scss";
@ -328,7 +328,7 @@ const App = () => {
className: "excalidraw-wrapper", className: "excalidraw-wrapper",
ref: excalidrawWrapperRef, ref: excalidrawWrapperRef,
}, },
React.createElement(Excalidraw.default, { React.createElement(ExcalidrawLib.Excalidraw, {
initialData: InitialData, initialData: InitialData,
onChange: (elements, state) => onChange: (elements, state) =>
console.log("Elements :", elements, "State : ", state), console.log("Elements :", elements, "State : ", state),
@ -802,6 +802,24 @@ import { restore } from "@excalidraw/excalidraw-next";
This function makes sure elements and state is set to appropriate values and set to default value if not present. It is a combination of [restoreElements](#restoreElements) and [restoreAppState](#restoreAppState). This function makes sure elements and state is set to appropriate values and set to default value if not present. It is a combination of [restoreElements](#restoreElements) and [restoreAppState](#restoreAppState).
#### `restoreLibraryItems`
**_Signature_**
<pre>
restoreLibraryItems(libraryItems: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L22">ImportedDataState["libraryItems"]</a>, defaultStatus: "published" | "unpublished")
</pre>
**_How to use_**
```js
import { restoreLibraryItems } from "@excalidraw/excalidraw-next";
restoreLibraryItems(libraryItems, "unpublished");
```
This function normalizes library items elements, adding missing values when needed.
### Export utilities ### Export utilities
#### `exportToCanvas` #### `exportToCanvas`
@ -889,7 +907,7 @@ This function returns a promise which resolves to svg of the exported drawing.
| exportBackground | boolean | true | Indicates whether background should be exported | | exportBackground | boolean | true | Indicates whether background should be exported |
| viewBackgroundColor | string | #fff | The default background color | | viewBackgroundColor | string | #fff | The default background color |
| exportWithDarkMode | boolean | false | Indicates whether to export with dark mode | | exportWithDarkMode | boolean | false | Indicates whether to export with dark mode |
| exportEmbedScene | boolean | false | Indicates whether scene data should be embedded in svg. This will increase the svg size. | | exportEmbedScene | boolean | false | Indicates whether scene data should be embedded in svg/png. This will increase the image size. |
### Extra API's ### Extra API's
@ -906,6 +924,17 @@ serializeAsJSON({
Takes the scene elements and state and returns a JSON string. Deleted `elements`as well as most properties from `AppState` are removed from the resulting JSON. (see [`serializeAsJSON()`](https://github.com/excalidraw/excalidraw/blob/master/src/data/json.ts#L16) source for details). Takes the scene elements and state and returns a JSON string. Deleted `elements`as well as most properties from `AppState` are removed from the resulting JSON. (see [`serializeAsJSON()`](https://github.com/excalidraw/excalidraw/blob/master/src/data/json.ts#L16) source for details).
#### `serializeLibraryAsJSON`
**_Signature_**
<pre>
serializeLibraryAsJSON({
libraryItems: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L191">LibraryItems[]</a>,
</pre>
Takes the library items and returns a JSON string.
#### `getSceneVersion` #### `getSceneVersion`
**How to use** **How to use**

View File

@ -2,5 +2,5 @@ import Excalidraw from "./index";
import "../../../public/fonts.css"; import "../../../public/fonts.css";
export default Excalidraw; export { Excalidraw };
export * from "./index"; export * from "./index";

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