You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2026-01-14 00:29:38 +02:00
Compare commits
12 Commits
android-v2
...
codemirror
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07ddeab667 | ||
|
|
ca4602f47b | ||
|
|
40886892c9 | ||
|
|
58c4f9eded | ||
|
|
2c525c2163 | ||
|
|
68f119efbd | ||
|
|
e88753c609 | ||
|
|
8395d5daa9 | ||
|
|
56c85b0713 | ||
|
|
8387b446b6 | ||
|
|
82a90bef91 | ||
|
|
6b2f33c45f |
@@ -53,6 +53,7 @@ packages/app-mobile/locales
|
||||
packages/app-mobile/node_modules
|
||||
packages/app-mobile/pluginAssets/
|
||||
packages/app-mobile/lib/rnInjectedJs/
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror.bundle.js
|
||||
packages/lib/assets/
|
||||
packages/lib/rnInjectedJs/
|
||||
packages/lib/vendor/
|
||||
@@ -701,6 +702,12 @@ packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.js.ma
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useSource.d.ts
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useSource.js
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useSource.js.map
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror.d.ts
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror.js.map
|
||||
packages/app-mobile/components/NoteEditor/NoteEditor.d.ts
|
||||
packages/app-mobile/components/NoteEditor/NoteEditor.js
|
||||
packages/app-mobile/components/NoteEditor/NoteEditor.js.map
|
||||
packages/app-mobile/components/SelectDateTimeDialog.d.ts
|
||||
packages/app-mobile/components/SelectDateTimeDialog.js
|
||||
packages/app-mobile/components/SelectDateTimeDialog.js.map
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -687,6 +687,12 @@ packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.js.ma
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useSource.d.ts
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useSource.js
|
||||
packages/app-mobile/components/NoteBodyViewer/hooks/useSource.js.map
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror.d.ts
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror.js
|
||||
packages/app-mobile/components/NoteEditor/CodeMirror.js.map
|
||||
packages/app-mobile/components/NoteEditor/NoteEditor.d.ts
|
||||
packages/app-mobile/components/NoteEditor/NoteEditor.js
|
||||
packages/app-mobile/components/NoteEditor/NoteEditor.js.map
|
||||
packages/app-mobile/components/SelectDateTimeDialog.d.ts
|
||||
packages/app-mobile/components/SelectDateTimeDialog.js
|
||||
packages/app-mobile/components/SelectDateTimeDialog.js.map
|
||||
|
||||
@@ -396,7 +396,9 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
|
||||
color: inherit !important;
|
||||
background-color: inherit !important;
|
||||
position: absolute !important;
|
||||
-webkit-box-shadow: none !important; // Some themes add a box shadow for some reason
|
||||
/* Some themes add a box shadow for some reason */
|
||||
-webkit-box-shadow: none !important;
|
||||
line-height: ${theme.lineHeight} !important;
|
||||
}
|
||||
|
||||
.CodeMirror-lines {
|
||||
@@ -422,20 +424,54 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
|
||||
font-family: ${monospaceFonts.join(', ')} !important;
|
||||
}
|
||||
|
||||
.cm-header-1 {
|
||||
.CodeMirror .cm-header-1 {
|
||||
font-size: 1.5em;
|
||||
color: ${theme.color};
|
||||
}
|
||||
|
||||
.cm-header-2 {
|
||||
.CodeMirror .cm-header-2 {
|
||||
font-size: 1.3em;
|
||||
color: ${theme.color};
|
||||
}
|
||||
|
||||
.cm-header-3 {
|
||||
.CodeMirror .cm-header-3 {
|
||||
font-size: 1.1em;
|
||||
color: ${theme.color};
|
||||
}
|
||||
|
||||
.cm-header-4, .cm-header-5, .cm-header-6 {
|
||||
.CodeMirror .cm-header-4, .CodeMirror .cm-header-5, .CodeMirror .cm-header-6 {
|
||||
font-size: 1em;
|
||||
color: ${theme.color};
|
||||
}
|
||||
|
||||
.CodeMirror .cm-quote {
|
||||
color: ${theme.color};
|
||||
opacity: ${theme.blockQuoteOpacity};
|
||||
}
|
||||
|
||||
div.CodeMirror span.cm-link-text {
|
||||
color: ${theme.urlColor};
|
||||
}
|
||||
|
||||
div.CodeMirror span.cm-url {
|
||||
color: ${theme.urlColor};
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.CodeMirror .cm-variable-2, .CodeMirror .cm-variable-3, .CodeMirror .cm-keyword {
|
||||
color: ${theme.color};
|
||||
}
|
||||
|
||||
div.CodeMirror span.cm-comment {
|
||||
color: ${theme.codeColor};
|
||||
}
|
||||
|
||||
div.CodeMirror span.cm-strong {
|
||||
color: ${theme.colorBright};
|
||||
}
|
||||
|
||||
div.CodeMirror span.cm-hr {
|
||||
color: ${theme.dividerColor};
|
||||
}
|
||||
|
||||
.cm-header-1, .cm-header-2, .cm-header-3, .cm-header-4, .cm-header-5, .cm-header-6 {
|
||||
@@ -467,6 +503,8 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
|
||||
}
|
||||
|
||||
/* The default dark theme colors don't have enough contrast with the background */
|
||||
|
||||
/*
|
||||
.cm-s-nord span.cm-comment {
|
||||
color: #9aa4b6 !important;
|
||||
}
|
||||
@@ -486,6 +524,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
|
||||
.cm-s-solarized.cm-s-dark span.cm-comment {
|
||||
color: #8ba1a7 !important;
|
||||
}
|
||||
*/
|
||||
|
||||
${selectionColorCss}
|
||||
`));
|
||||
|
||||
4
packages/app-mobile/.gitignore
vendored
4
packages/app-mobile/.gitignore
vendored
@@ -61,4 +61,6 @@ buck-out/
|
||||
# Custom
|
||||
lib/csstojs/
|
||||
lib/rnInjectedJs/
|
||||
dist/
|
||||
dist/
|
||||
components/NoteEditor/CodeMirror.bundle.js
|
||||
components/NoteEditor/CodeMirror.bundle.min.js
|
||||
|
||||
@@ -141,8 +141,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 2097639
|
||||
versionName "2.2.0"
|
||||
versionCode 2097640
|
||||
versionName "2.2.1"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
||||
}
|
||||
|
||||
160
packages/app-mobile/components/NoteEditor/CodeMirror.ts
Normal file
160
packages/app-mobile/components/NoteEditor/CodeMirror.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
|
||||
// This contains the CodeMirror instance, which needs to be built into a bundle
|
||||
// using `npm run buildInjectedJs`. This bundle is then loaded from
|
||||
// NoteEditor.tsx into the webview.
|
||||
//
|
||||
// In general, since this file is harder to debug due to the intermediate built
|
||||
// step, it's better to keep it as light as possible - it shoud just be a light
|
||||
// wrapper to access CodeMirror functionalities. Anything else should be done
|
||||
// from NoteEditor.tsx.
|
||||
|
||||
import { EditorState, Extension } from '@codemirror/state';
|
||||
import { EditorView, drawSelection, highlightSpecialChars, ViewUpdate } from '@codemirror/view';
|
||||
import { markdown } from '@codemirror/lang-markdown';
|
||||
import { defaultHighlightStyle, HighlightStyle, tags } from '@codemirror/highlight';
|
||||
import { undo, redo, history, undoDepth, redoDepth } from '@codemirror/history';
|
||||
|
||||
interface CodeMirrorResult {
|
||||
editor: EditorView;
|
||||
undo: Function;
|
||||
redo: Function;
|
||||
}
|
||||
|
||||
function postMessage(name: string, data: any) {
|
||||
(window as any).ReactNativeWebView.postMessage(JSON.stringify({
|
||||
data,
|
||||
name,
|
||||
}));
|
||||
}
|
||||
|
||||
function logMessage(...msg: any[]) {
|
||||
postMessage('onLog', { value: msg });
|
||||
}
|
||||
|
||||
const createTheme = (theme: any): Extension => {
|
||||
const baseTheme = EditorView.baseTheme({
|
||||
'&': {
|
||||
color: theme.color,
|
||||
backgroundColor: theme.backgroundColor,
|
||||
fontFamily: theme.fontFamily,
|
||||
fontSize: `${theme.fontSize}px`,
|
||||
},
|
||||
});
|
||||
|
||||
const appearanceTheme = EditorView.theme({}, { dark: theme.appearance === 'dark' });
|
||||
|
||||
const baseHeadingStyle = {
|
||||
fontWeight: 'bold',
|
||||
fontFamily: theme.fontFamily,
|
||||
};
|
||||
|
||||
const syntaxHighlighting = HighlightStyle.define([
|
||||
{
|
||||
tag: tags.strong,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
{
|
||||
tag: tags.emphasis,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
{
|
||||
...baseHeadingStyle,
|
||||
tag: tags.heading1,
|
||||
fontSize: '1.6em',
|
||||
borderBottom: `1px solid ${theme.dividerColor}`,
|
||||
},
|
||||
{
|
||||
...baseHeadingStyle,
|
||||
tag: tags.heading2,
|
||||
fontSize: '1.4em',
|
||||
},
|
||||
{
|
||||
...baseHeadingStyle,
|
||||
tag: tags.heading3,
|
||||
fontSize: '1.3em',
|
||||
},
|
||||
{
|
||||
...baseHeadingStyle,
|
||||
tag: tags.heading4,
|
||||
fontSize: '1.2em',
|
||||
},
|
||||
{
|
||||
...baseHeadingStyle,
|
||||
tag: tags.heading5,
|
||||
fontSize: '1.1em',
|
||||
},
|
||||
{
|
||||
...baseHeadingStyle,
|
||||
tag: tags.heading6,
|
||||
fontSize: '1.0em',
|
||||
},
|
||||
{
|
||||
tag: tags.list,
|
||||
fontFamily: theme.fontFamily,
|
||||
},
|
||||
]);
|
||||
|
||||
return [
|
||||
baseTheme,
|
||||
appearanceTheme,
|
||||
syntaxHighlighting,
|
||||
];
|
||||
};
|
||||
|
||||
export function initCodeMirror(parentElement: any, initialText: string, theme: any): CodeMirrorResult {
|
||||
logMessage('Initializing CodeMirror...');
|
||||
|
||||
let schedulePostUndoRedoDepthChangeId_: any = 0;
|
||||
function schedulePostUndoRedoDepthChange(editor: EditorView, doItNow: boolean = false) {
|
||||
if (schedulePostUndoRedoDepthChangeId_) {
|
||||
if (doItNow) {
|
||||
clearTimeout(schedulePostUndoRedoDepthChangeId_);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
schedulePostUndoRedoDepthChangeId_ = setTimeout(() => {
|
||||
schedulePostUndoRedoDepthChangeId_ = null;
|
||||
postMessage('onUndoRedoDepthChange', {
|
||||
undoDepth: undoDepth(editor.state),
|
||||
redoDepth: redoDepth(editor.state),
|
||||
});
|
||||
}, doItNow ? 0 : 1000);
|
||||
}
|
||||
|
||||
const editor = new EditorView({
|
||||
state: EditorState.create({
|
||||
extensions: [
|
||||
markdown(),
|
||||
createTheme(theme),
|
||||
history(),
|
||||
drawSelection(),
|
||||
highlightSpecialChars(),
|
||||
EditorView.lineWrapping,
|
||||
defaultHighlightStyle.fallback,
|
||||
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
||||
if (viewUpdate.docChanged) {
|
||||
postMessage('onChange', { value: editor.state.doc.toString() });
|
||||
schedulePostUndoRedoDepthChange(editor);
|
||||
}
|
||||
}),
|
||||
],
|
||||
doc: initialText,
|
||||
}),
|
||||
parent: parentElement,
|
||||
});
|
||||
|
||||
return {
|
||||
editor,
|
||||
undo: () => {
|
||||
undo(editor);
|
||||
schedulePostUndoRedoDepthChange(editor, true);
|
||||
},
|
||||
redo: () => {
|
||||
redo(editor);
|
||||
schedulePostUndoRedoDepthChange(editor, true);
|
||||
},
|
||||
};
|
||||
}
|
||||
333
packages/app-mobile/components/NoteEditor/NoteEditor.tsx
Normal file
333
packages/app-mobile/components/NoteEditor/NoteEditor.tsx
Normal file
@@ -0,0 +1,333 @@
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import { themeStyle } from '@joplin/lib/theme';
|
||||
const React = require('react');
|
||||
const { forwardRef, useImperativeHandle, useEffect, useState, useCallback, useRef } = require('react');
|
||||
const { WebView } = require('react-native-webview');
|
||||
const { editorFont } = require('../global-style');
|
||||
|
||||
export interface ChangeEvent {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface UndoRedoDepthChangeEvent {
|
||||
undoDepth: number;
|
||||
redoDepth: number;
|
||||
}
|
||||
|
||||
type ChangeEventHandler = (event: ChangeEvent)=> void;
|
||||
type UndoRedoDepthChangeHandler = (event: UndoRedoDepthChangeEvent)=> void;
|
||||
|
||||
interface Props {
|
||||
themeId: number;
|
||||
initialText: string;
|
||||
style: any;
|
||||
onChange: ChangeEventHandler;
|
||||
onUndoRedoDepthChange: UndoRedoDepthChangeHandler;
|
||||
}
|
||||
|
||||
function fontFamilyFromSettings() {
|
||||
const f = editorFont(Setting.value('style.editor.fontFamily'));
|
||||
return [f, 'sans-serif'].join(', ');
|
||||
}
|
||||
|
||||
// function useCss(themeId:number):string {
|
||||
// const [css, setCss] = useState('');
|
||||
|
||||
// // useEffect(() => {
|
||||
// // const theme = themeStyle(themeId);
|
||||
|
||||
// // // Selection in dark mode is hard to see so make it brighter.
|
||||
// // // https://discourse.joplinapp.org/t/dragging-in-dark-theme/12433/4?u=laurent
|
||||
// // const selectionColorCss = theme.appearance === ThemeAppearance.Dark ?
|
||||
// // `.CodeMirror-selected {
|
||||
// // background: #6b6b6b !important;
|
||||
// // }` : '';
|
||||
// // const monospaceFonts = [];
|
||||
// // // if (Setting.value('style.editor.monospaceFontFamily')) monospaceFonts.push(`"${Setting.value('style.editor.monospaceFontFamily')}"`);
|
||||
// // monospaceFonts.push('monospace');
|
||||
|
||||
// // const fontSize = 15;
|
||||
// // const fontFamily = fontFamilyFromSettings();
|
||||
|
||||
// // // BUG: caret-color seems to be ignored for some reason
|
||||
// // const caretColor = theme.appearance === ThemeAppearance.Dark ? "white" : 'black';
|
||||
|
||||
// // setCss(`
|
||||
// // /* These must be important to prevent the codemirror defaults from taking over*/
|
||||
// // .CodeMirror {
|
||||
// // font-family: ${fontFamily};
|
||||
// // font-size: ${fontSize}px;
|
||||
// // height: 100% !important;
|
||||
// // width: 100% !important;
|
||||
// // color: ${theme.color};
|
||||
// // background-color: ${theme.backgroundColor};
|
||||
// // position: absolute !important;
|
||||
// // -webkit-box-shadow: none !important; // Some themes add a box shadow for some reason
|
||||
// // }
|
||||
|
||||
// // .CodeMirror-lines {
|
||||
// // /* This is used to enable the scroll-past end behaviour. The same height should */
|
||||
// // /* be applied to the viewer. */
|
||||
// // padding-bottom: 400px !important;
|
||||
// // }
|
||||
|
||||
// // /* Left padding is applied at the editor component level, so we should remove it from the lines */
|
||||
// // .CodeMirror pre.CodeMirror-line,
|
||||
// // .CodeMirror pre.CodeMirror-line-like {
|
||||
// // padding-left: 0;
|
||||
// // }
|
||||
|
||||
// // .CodeMirror-sizer {
|
||||
// // /* Add a fixed right padding to account for the appearance (and disappearance) */
|
||||
// // /* of the sidebar */
|
||||
// // padding-right: 10px !important;
|
||||
// // }
|
||||
|
||||
// // /* This enforces monospace for certain elements (code, tables, etc.) */
|
||||
// // .cm-jn-monospace {
|
||||
// // font-family: ${monospaceFonts.join(', ')} !important;
|
||||
// // }
|
||||
|
||||
// // .cm-header-1 {
|
||||
// // font-size: 1.5em;
|
||||
// // }
|
||||
|
||||
// // .cm-header-2 {
|
||||
// // font-size: 1.3em;
|
||||
// // }
|
||||
|
||||
// // .cm-header-3 {
|
||||
// // font-size: 1.1em;
|
||||
// // }
|
||||
|
||||
// // .cm-header-4, .cm-header-5, .cm-header-6 {
|
||||
// // font-size: 1em;
|
||||
// // }
|
||||
|
||||
// // .cm-header-1, .cm-header-2, .cm-header-3, .cm-header-4, .cm-header-5, .cm-header-6 {
|
||||
// // line-height: 1.5em;
|
||||
// // }
|
||||
|
||||
// // .cm-search-marker {
|
||||
// // background: ${theme.searchMarkerBackgroundColor};
|
||||
// // color: ${theme.searchMarkerColor} !important;
|
||||
// // }
|
||||
|
||||
// // .cm-search-marker-selected {
|
||||
// // background: ${theme.selectedColor2};
|
||||
// // color: ${theme.color2} !important;
|
||||
// // }
|
||||
|
||||
// // .cm-search-marker-scrollbar {
|
||||
// // background: ${theme.searchMarkerBackgroundColor};
|
||||
// // -moz-box-sizing: border-box;
|
||||
// // box-sizing: border-box;
|
||||
// // opacity: .5;
|
||||
// // }
|
||||
|
||||
// // /* We need to use important to override theme specific values */
|
||||
// // .cm-error {
|
||||
// // color: inherit !important;
|
||||
// // background-color: inherit !important;
|
||||
// // border-bottom: 1px dotted #dc322f;
|
||||
// // }
|
||||
|
||||
// // /* The default dark theme colors don't have enough contrast with the background */
|
||||
// // .cm-s-nord span.cm-comment {
|
||||
// // color: #9aa4b6 !important;
|
||||
// // }
|
||||
|
||||
// // .cm-s-dracula span.cm-comment {
|
||||
// // color: #a1abc9 !important;
|
||||
// // }
|
||||
|
||||
// // .cm-s-monokai span.cm-comment {
|
||||
// // color: #908b74 !important;
|
||||
// // }
|
||||
|
||||
// // .cm-s-material-darker span.cm-comment {
|
||||
// // color: #878787 !important;
|
||||
// // }
|
||||
|
||||
// // .cm-s-solarized.cm-s-dark span.cm-comment {
|
||||
// // color: #8ba1a7 !important;
|
||||
// // }
|
||||
|
||||
// // /* MOBILE SPECIFIC */
|
||||
|
||||
// // .CodeMirror .cm-scroller,
|
||||
// // .CodeMirror .cm-line {
|
||||
// // font-family: ${fontFamily};
|
||||
// // caret-color: ${caretColor};
|
||||
// // }
|
||||
|
||||
// // ${selectionColorCss}
|
||||
// // `);
|
||||
// // }, [themeId]);
|
||||
|
||||
// return css;
|
||||
// }
|
||||
|
||||
function useHtml(css: string): string {
|
||||
const [html, setHtml] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
setHtml(
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<style>
|
||||
.cm-editor {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
${css}
|
||||
</style>
|
||||
</head>
|
||||
<body style="margin:0; height:100vh; width:100vh; width:100vw; min-width:100vw;">
|
||||
<div class="CodeMirror" style="height:100%;"></div>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
);
|
||||
}, [css]);
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function editorTheme(themeId: number) {
|
||||
return {
|
||||
...themeStyle(themeId),
|
||||
fontSize: 15,
|
||||
fontFamily: fontFamilyFromSettings(),
|
||||
};
|
||||
}
|
||||
|
||||
function NoteEditor(props: Props, ref: any) {
|
||||
const [source, setSource] = useState(undefined);
|
||||
const webviewRef = useRef(null);
|
||||
|
||||
const injectedJavaScript = `
|
||||
function postMessage(name, data) {
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({
|
||||
data,
|
||||
name,
|
||||
}));
|
||||
}
|
||||
|
||||
function logMessage(...msg) {
|
||||
postMessage('onLog', { value: msg });
|
||||
}
|
||||
|
||||
// This variable is not used within this script
|
||||
// but is called using "injectJavaScript" from
|
||||
// the wrapper component.
|
||||
let cm = null;
|
||||
|
||||
try {
|
||||
${shim.injectedJs('codeMirrorBundle')};
|
||||
|
||||
const parentElement = document.getElementsByClassName('CodeMirror')[0];
|
||||
const theme = ${JSON.stringify(editorTheme(props.themeId))};
|
||||
const initialText = ${JSON.stringify(props.initialText)};
|
||||
|
||||
cm = codeMirrorBundle.initCodeMirror(parentElement, initialText, theme);
|
||||
} catch (e) {
|
||||
window.ReactNativeWebView.postMessage("error:" + e.message + ": " + JSON.stringify(e))
|
||||
} finally {
|
||||
true;
|
||||
}
|
||||
`;
|
||||
|
||||
// const css = useCss(props.themeId);
|
||||
const html = useHtml('');
|
||||
|
||||
useImperativeHandle(ref, () => {
|
||||
return {
|
||||
undo: function() {
|
||||
webviewRef.current.injectJavaScript('cm.undo(); true;');
|
||||
},
|
||||
redo: function() {
|
||||
webviewRef.current.injectJavaScript('cm.redo(); true;');
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
async function createHtmlFile() {
|
||||
const tempFile = `${Setting.value('resourceDir')}/NoteEditor.html`;
|
||||
await shim.fsDriver().writeFile(tempFile, html, 'utf8');
|
||||
if (cancelled) return;
|
||||
|
||||
setSource({
|
||||
uri: `file://${tempFile}?r=${Math.round(Math.random() * 100000000)}`,
|
||||
baseUrl: `file://${Setting.value('resourceDir')}/`,
|
||||
});
|
||||
}
|
||||
|
||||
void createHtmlFile();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [html]);
|
||||
|
||||
const onMessage = useCallback((event: any) => {
|
||||
const data = event.nativeEvent.data;
|
||||
|
||||
if (data.indexOf('error:') === 0) {
|
||||
console.error('CodeMirror:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
const msg = JSON.parse(data);
|
||||
|
||||
const handlers: Record<string, Function> = {
|
||||
onLog: (event: any) => {
|
||||
console.info('CodeMirror:', ...event.value);
|
||||
},
|
||||
|
||||
onChange: (event: ChangeEvent) => {
|
||||
props.onChange(event);
|
||||
},
|
||||
|
||||
onUndoRedoDepthChange: (event: UndoRedoDepthChangeEvent) => {
|
||||
console.info('onUndoRedoDepthChange', event);
|
||||
props.onUndoRedoDepthChange(event);
|
||||
},
|
||||
};
|
||||
|
||||
if (handlers[msg.name]) {
|
||||
handlers[msg.name](msg.data);
|
||||
} else {
|
||||
console.info('Unsupported CodeMirror message:', msg);
|
||||
}
|
||||
}, [props.onChange]);
|
||||
|
||||
const onError = useCallback(() => {
|
||||
console.error('NoteEditor: webview error');
|
||||
});
|
||||
|
||||
// - `setSupportMultipleWindows` must be `true` for security reasons:
|
||||
// https://github.com/react-native-webview/react-native-webview/releases/tag/v11.0.0
|
||||
return <WebView
|
||||
style={props.style}
|
||||
ref={webviewRef}
|
||||
useWebKit={true}
|
||||
source={source}
|
||||
setSupportMultipleWindows={true}
|
||||
allowingReadAccessToURL={`file://${Setting.value('resourceDir')}`}
|
||||
originWhitelist={['file://*', './*', 'http://*', 'https://*']}
|
||||
allowFileAccess={true}
|
||||
injectedJavaScript={injectedJavaScript}
|
||||
onMessage={onMessage}
|
||||
onError={onError}
|
||||
/>;
|
||||
}
|
||||
|
||||
export default forwardRef(NoteEditor);
|
||||
@@ -1,10 +1,11 @@
|
||||
import AsyncActionQueue from '@joplin/lib/AsyncActionQueue';
|
||||
import UndoRedoService from '@joplin/lib/services/UndoRedoService';
|
||||
import uuid from '@joplin/lib/uuid';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import UndoRedoService from '@joplin/lib/services/UndoRedoService';
|
||||
import NoteBodyViewer from '../NoteBodyViewer/NoteBodyViewer';
|
||||
import checkPermissions from '../../utils/checkPermissions';
|
||||
import NoteEditor, { ChangeEvent, UndoRedoDepthChangeEvent } from '../NoteEditor/NoteEditor';
|
||||
|
||||
const FileViewer = require('react-native-file-viewer').default;
|
||||
const React = require('react');
|
||||
@@ -42,6 +43,7 @@ const ImagePicker = require('react-native-image-picker').default;
|
||||
import SelectDateTimeDialog from '../SelectDateTimeDialog';
|
||||
import ShareExtension from '../../utils/ShareExtension.js';
|
||||
import CameraView from '../CameraView';
|
||||
import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||
const urlUtils = require('@joplin/lib/urlUtils');
|
||||
|
||||
const emptyArray: any[] = [];
|
||||
@@ -95,6 +97,8 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
|
||||
this.styles_ = {};
|
||||
|
||||
this.editorRef = React.createRef();
|
||||
|
||||
const saveDialog = async () => {
|
||||
if (this.isModified()) {
|
||||
const buttonId = await dialogs.pop(this, _('This note has been modified:'), [{ text: _('Save changes'), id: 'save' }, { text: _('Discard changes'), id: 'discard' }, { text: _('Cancel'), id: 'cancel' }]);
|
||||
@@ -230,16 +234,38 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
this.body_selectionChange = this.body_selectionChange.bind(this);
|
||||
this.onBodyViewerLoadEnd = this.onBodyViewerLoadEnd.bind(this);
|
||||
this.onBodyViewerCheckboxChange = this.onBodyViewerCheckboxChange.bind(this);
|
||||
this.onBodyChange = this.onBodyChange.bind(this);
|
||||
this.onUndoRedoDepthChange = this.onUndoRedoDepthChange.bind(this);
|
||||
}
|
||||
|
||||
undoRedoService_stackChange() {
|
||||
this.setState({ undoRedoButtonState: {
|
||||
canUndo: this.undoRedoService_.canUndo,
|
||||
canRedo: this.undoRedoService_.canRedo,
|
||||
} });
|
||||
private useEditorBeta(): boolean {
|
||||
return this.props.useEditorBeta;
|
||||
}
|
||||
|
||||
async undoRedo(type: string) {
|
||||
private onBodyChange(event: ChangeEvent) {
|
||||
shared.noteComponent_change(this, 'body', event.value);
|
||||
this.scheduleSave();
|
||||
}
|
||||
|
||||
private onUndoRedoDepthChange(event: UndoRedoDepthChangeEvent) {
|
||||
if (this.useEditorBeta()) {
|
||||
this.setState({ undoRedoButtonState: {
|
||||
canUndo: !!event.undoDepth,
|
||||
canRedo: !!event.redoDepth,
|
||||
} });
|
||||
}
|
||||
}
|
||||
|
||||
private undoRedoService_stackChange() {
|
||||
if (!this.useEditorBeta()) {
|
||||
this.setState({ undoRedoButtonState: {
|
||||
canUndo: this.undoRedoService_.canUndo,
|
||||
canRedo: this.undoRedoService_.canRedo,
|
||||
} });
|
||||
}
|
||||
}
|
||||
|
||||
private async undoRedo(type: string) {
|
||||
const undoState = await this.undoRedoService_[type](this.undoState());
|
||||
if (!undoState) return;
|
||||
|
||||
@@ -253,11 +279,25 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
|
||||
screenHeader_undoButtonPress() {
|
||||
void this.undoRedo('undo');
|
||||
if (this.useEditorBeta()) {
|
||||
this.editorRef.current.undo();
|
||||
} else {
|
||||
void this.undoRedo('undo');
|
||||
}
|
||||
}
|
||||
|
||||
screenHeader_redoButtonPress() {
|
||||
void this.undoRedo('redo');
|
||||
if (this.useEditorBeta()) {
|
||||
this.editorRef.current.redo();
|
||||
} else {
|
||||
void this.undoRedo('redo');
|
||||
}
|
||||
}
|
||||
|
||||
undoState(noteBody: string = null) {
|
||||
return {
|
||||
body: noteBody === null ? this.state.note.body : noteBody,
|
||||
};
|
||||
}
|
||||
|
||||
styles() {
|
||||
@@ -355,12 +395,6 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
return shared.isModified(this);
|
||||
}
|
||||
|
||||
undoState(noteBody: string = null) {
|
||||
return {
|
||||
body: noteBody === null ? this.state.note.body : noteBody,
|
||||
};
|
||||
}
|
||||
|
||||
async requestGeoLocationPermissions() {
|
||||
if (!Setting.value('trackLocation')) return;
|
||||
|
||||
@@ -448,6 +482,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
} else {
|
||||
this.undoRedoService_.schedulePush(this.undoState());
|
||||
}
|
||||
|
||||
shared.noteComponent_change(this, 'body', text);
|
||||
this.scheduleSave();
|
||||
}
|
||||
@@ -844,6 +879,11 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
output.push({
|
||||
title: _('Attach...'),
|
||||
onPress: async () => {
|
||||
if (this.state.mode === 'edit' && this.useEditorBeta()) {
|
||||
alert('Attaching files from the beta editor is not yet supported. You may do so from the viewer mode instead.');
|
||||
return;
|
||||
}
|
||||
|
||||
const buttons = [];
|
||||
|
||||
// On iOS, it will show "local files", which means certain files saved from the browser
|
||||
@@ -1017,7 +1057,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
|
||||
const theme = themeStyle(this.props.themeId);
|
||||
const note = this.state.note;
|
||||
const note: NoteEntity = this.state.note;
|
||||
const isTodo = !!Number(note.is_todo);
|
||||
|
||||
if (this.state.showCamera) {
|
||||
@@ -1066,25 +1106,37 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
// abcd|
|
||||
// abcde|
|
||||
// abcde|f
|
||||
bodyComponent = (
|
||||
<TextInput
|
||||
autoCapitalize="sentences"
|
||||
|
||||
if (!this.useEditorBeta()) {
|
||||
bodyComponent = (
|
||||
<TextInput
|
||||
autoCapitalize="sentences"
|
||||
style={this.styles().bodyTextInput}
|
||||
ref="noteBodyTextField"
|
||||
multiline={true}
|
||||
value={note.body}
|
||||
onChangeText={(text: string) => this.body_changeText(text)}
|
||||
onSelectionChange={this.body_selectionChange}
|
||||
blurOnSubmit={false}
|
||||
selectionColor={theme.textSelectionColor}
|
||||
keyboardAppearance={theme.keyboardAppearance}
|
||||
placeholder={_('Add body')}
|
||||
placeholderTextColor={theme.colorFaded}
|
||||
// need some extra padding for iOS so that the keyboard won't cover last line of the note
|
||||
// see https://github.com/laurent22/joplin/issues/3607
|
||||
paddingBottom={ Platform.OS === 'ios' ? 40 : 0}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
bodyComponent = <NoteEditor
|
||||
ref={this.editorRef}
|
||||
themeId={this.props.themeId}
|
||||
initialText={note.body}
|
||||
onChange={this.onBodyChange}
|
||||
onUndoRedoDepthChange={this.onUndoRedoDepthChange}
|
||||
style={this.styles().bodyTextInput}
|
||||
ref="noteBodyTextField"
|
||||
multiline={true}
|
||||
value={note.body}
|
||||
onChangeText={(text: string) => this.body_changeText(text)}
|
||||
onSelectionChange={this.body_selectionChange}
|
||||
blurOnSubmit={false}
|
||||
selectionColor={theme.textSelectionColor}
|
||||
keyboardAppearance={theme.keyboardAppearance}
|
||||
placeholder={_('Add body')}
|
||||
placeholderTextColor={theme.colorFaded}
|
||||
// need some extra padding for iOS so that the keyboard won't cover last line of the note
|
||||
// see https://github.com/laurent22/joplin/issues/3607
|
||||
paddingBottom={ Platform.OS === 'ios' ? 40 : 0}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
}
|
||||
}
|
||||
|
||||
const renderActionButton = () => {
|
||||
@@ -1187,6 +1239,7 @@ const NoteScreen = connect((state: any) => {
|
||||
showSideMenu: state.showSideMenu,
|
||||
provisionalNoteIds: state.provisionalNoteIds,
|
||||
highlightedWords: state.highlightedWords,
|
||||
useEditorBeta: state.settings['editor.beta'],
|
||||
};
|
||||
})(NoteScreenComponent);
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ const tasks = {
|
||||
encodeAssets: {
|
||||
fn: require('./tools/encodeAssets'),
|
||||
},
|
||||
buildReactNativeInjectedJs: {
|
||||
fn: require('./tools/buildReactNativeInjectedJs'),
|
||||
buildInjectedJs: {
|
||||
fn: require('./tools/buildInjectedJs'),
|
||||
},
|
||||
podInstall: {
|
||||
fn: require('./tools/podInstall'),
|
||||
@@ -16,7 +16,7 @@ const tasks = {
|
||||
utils.registerGulpTasks(gulp, tasks);
|
||||
|
||||
gulp.task('build', gulp.series(
|
||||
'buildReactNativeInjectedJs',
|
||||
'buildInjectedJs',
|
||||
'encodeAssets',
|
||||
'podInstall'
|
||||
));
|
||||
|
||||
1148
packages/app-mobile/package-lock.json
generated
1148
packages/app-mobile/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,11 +10,13 @@
|
||||
"tsc": "node node_modules/typescript/bin/tsc --project tsconfig.json",
|
||||
"watch": "node node_modules/typescript/bin/tsc --watch --project tsconfig.json",
|
||||
"clean": "node tools/clean.js",
|
||||
"buildInjectedJs": "gulp buildInjectedJs",
|
||||
"watchInjectedJs": "nodemon --verbose --watch components/NoteEditor/CodeMirror.ts --exec \"npm run buildInjectedJs\"",
|
||||
"postinstall": "jetify && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@joplin/lib": "^1.0.9",
|
||||
"@joplin/renderer": "^1.0.17",
|
||||
"@joplin/lib": "^2.2.0",
|
||||
"@joplin/renderer": "^2.2.0",
|
||||
"@react-native-community/clipboard": "^1.5.0",
|
||||
"@react-native-community/datetimepicker": "^3.0.3",
|
||||
"@react-native-community/geolocation": "^2.0.2",
|
||||
@@ -62,7 +64,14 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.11.6",
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"@codemirror/highlight": "^0.18.4",
|
||||
"@codemirror/history": "^0.18.1",
|
||||
"@codemirror/lang-markdown": "^0.18.4",
|
||||
"@codemirror/state": "^0.18.7",
|
||||
"@codemirror/view": "^0.18.19",
|
||||
"@joplin/tools": "^1.0.9",
|
||||
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||
"@rollup/plugin-typescript": "^8.2.1",
|
||||
"@types/node": "^14.14.6",
|
||||
"@types/react": "^16.9.55",
|
||||
"@types/react-native": "^0.64.4",
|
||||
@@ -71,6 +80,9 @@
|
||||
"gulp": "^4.0.2",
|
||||
"jetifier": "^1.6.5",
|
||||
"metro-react-native-babel-preset": "^0.63.0",
|
||||
"typescript": "^4.0.5"
|
||||
"nodemon": "^2.0.12",
|
||||
"rollup": "^2.53.1",
|
||||
"typescript": "^4.0.5",
|
||||
"uglify-js": "^3.13.10"
|
||||
}
|
||||
}
|
||||
|
||||
37
packages/app-mobile/tools/buildInjectedJs.js
Normal file
37
packages/app-mobile/tools/buildInjectedJs.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// React Native WebView cannot load external JS files, however it can load
|
||||
// arbitrary JS via the injectedJavaScript property. So we use this to load external
|
||||
// files: First here we convert the JS file to a plain string, and that string
|
||||
// is then loaded by eg. the Mermaid plugin, and finally injected in the WebView.
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const exec = require('child_process').exec;
|
||||
const path = require('path');
|
||||
|
||||
const rootDir = path.dirname(path.dirname(path.dirname(__dirname)));
|
||||
const mobileDir = `${rootDir}/packages/app-mobile`;
|
||||
const outputDir = `${mobileDir}/lib/rnInjectedJs`;
|
||||
const codeMirrorBundleFile = `${mobileDir}/components/NoteEditor/CodeMirror.bundle.min.js`;
|
||||
|
||||
async function copyJs(name, filePath) {
|
||||
const js = await fs.readFile(filePath, 'utf-8');
|
||||
const json = `module.exports = ${JSON.stringify(js)};`;
|
||||
const outputPath = `${outputDir}/${name}.js`;
|
||||
console.info(`Creating: ${outputPath}`);
|
||||
await fs.writeFile(outputPath, json);
|
||||
}
|
||||
|
||||
async function buildCodeMirrorBundle() {
|
||||
const sourceFile = `${mobileDir}/components/NoteEditor/CodeMirror.ts`;
|
||||
const fullBundleFile = `${mobileDir}/components/NoteEditor/CodeMirror.bundle.js`;
|
||||
await exec(`./node_modules/rollup/dist/bin/rollup "${sourceFile}" --name codeMirrorBundle -f iife -o "${fullBundleFile}" -p @rollup/plugin-node-resolve -p @rollup/plugin-typescript`, { stdio: 'pipe' });
|
||||
await exec(`./node_modules/uglify-js/bin/uglifyjs --compress -o "${codeMirrorBundleFile}" -- "${fullBundleFile}"`, { stdio: 'pipe' });
|
||||
}
|
||||
|
||||
async function main() {
|
||||
await fs.mkdirp(outputDir);
|
||||
await buildCodeMirrorBundle();
|
||||
await copyJs('webviewLib', `${mobileDir}/node_modules/@joplin/lib/renderers/webviewLib.js`);
|
||||
await copyJs('CodeMirror.bundle', `${mobileDir}/components/NoteEditor/CodeMirror.bundle.min.js`);
|
||||
}
|
||||
|
||||
module.exports = main;
|
||||
@@ -1,23 +0,0 @@
|
||||
// React Native WebView cannot load external JS files, however it can load
|
||||
// arbitrary JS via the injectedJavaScript property. So we use this to load external
|
||||
// files: First here we convert the JS file to a plain string, and that string
|
||||
// is then loaded by eg. the Mermaid plugin, and finally injected in the WebView.
|
||||
|
||||
const fs = require('fs-extra');
|
||||
|
||||
const rnDir = `${__dirname}/..`;
|
||||
const outputDir = `${rnDir}/lib/rnInjectedJs`;
|
||||
|
||||
async function copyJs(name, filePath) {
|
||||
const js = await fs.readFile(filePath, 'utf-8');
|
||||
const json = `module.exports = ${JSON.stringify(js)};`;
|
||||
const outputPath = `${outputDir}/${name}.js`;
|
||||
await fs.writeFile(outputPath, json);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
await fs.mkdirp(outputDir);
|
||||
await copyJs('webviewLib', `${rnDir}/node_modules/@joplin/lib/renderers/webviewLib.js`);
|
||||
}
|
||||
|
||||
module.exports = main;
|
||||
@@ -14,6 +14,7 @@ const Resource = require('@joplin/lib/models/Resource').default;
|
||||
|
||||
const injectedJs = {
|
||||
webviewLib: require('@joplin/lib/rnInjectedJs/webviewLib'),
|
||||
codeMirrorBundle: require('../lib/rnInjectedJs/CodeMirror.bundle'),
|
||||
};
|
||||
|
||||
function shimInit() {
|
||||
|
||||
@@ -785,10 +785,10 @@ class Setting extends BaseModel {
|
||||
value: false,
|
||||
type: SettingItemType.Bool,
|
||||
section: 'note',
|
||||
public: false, // mobilePlatform === 'ios',
|
||||
public: true,
|
||||
appTypes: [AppType.Mobile],
|
||||
label: () => 'Opt-in to the editor beta',
|
||||
description: () => 'This beta adds list continuation, Markdown preview, and Markdown shortcuts. If you find bugs, please report them in the Discourse forum.',
|
||||
description: () => 'This beta adds list continuation and syntax highlighting. If you find bugs, please report them in the Discourse forum.',
|
||||
},
|
||||
|
||||
newTodoFocus: {
|
||||
@@ -915,7 +915,7 @@ class Setting extends BaseModel {
|
||||
// Deprecated in favour of windowContentZoomFactor
|
||||
'style.zoom': { value: 100, type: SettingItemType.Int, public: false, storage: SettingStorage.File, appTypes: [AppType.Desktop], section: 'appearance', label: () => '', minimum: 50, maximum: 500, step: 10 },
|
||||
|
||||
'style.editor.fontSize': { value: 13, type: SettingItemType.Int, public: true, storage: SettingStorage.File, appTypes: [AppType.Desktop], section: 'appearance', label: () => _('Editor font size'), minimum: 4, maximum: 50, step: 1 },
|
||||
'style.editor.fontSize': { value: 15, type: SettingItemType.Int, public: true, storage: SettingStorage.File, appTypes: [AppType.Desktop], section: 'appearance', label: () => _('Editor font size'), minimum: 4, maximum: 50, step: 1 },
|
||||
'style.editor.fontFamily':
|
||||
(mobilePlatform) ?
|
||||
({
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { Theme, ThemeAppearance } from './type';
|
||||
import lightTheme from './light';
|
||||
|
||||
// This is the default dark theme in Joplin
|
||||
const theme: Theme = {
|
||||
...lightTheme,
|
||||
|
||||
appearance: ThemeAppearance.Dark,
|
||||
|
||||
// Color scheme "1" is the basic one, like used to display the note
|
||||
|
||||
@@ -50,6 +50,8 @@ const theme: Theme = {
|
||||
codeBorderColor: 'rgb(220, 220, 220)',
|
||||
codeColor: 'rgb(0,0,0)',
|
||||
|
||||
blockQuoteOpacity: 0.7,
|
||||
|
||||
codeMirrorTheme: 'default',
|
||||
codeThemeCss: 'atom-one-light.css',
|
||||
};
|
||||
|
||||
@@ -52,6 +52,8 @@ export interface Theme {
|
||||
codeBorderColor: string;
|
||||
codeColor: string;
|
||||
|
||||
blockQuoteOpacity: number;
|
||||
|
||||
codeMirrorTheme: string;
|
||||
codeThemeCss: string;
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ export default function(theme: any) {
|
||||
border-left: 4px solid ${theme.codeBorderColor};
|
||||
padding-left: 1.2em;
|
||||
margin-left: 0;
|
||||
opacity: .7;
|
||||
opacity: ${theme.blockQuoteOpacity};
|
||||
}
|
||||
|
||||
.jop-tinymce table,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,8 +13,10 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 2.3\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
|
||||
#: packages/app-desktop/bridge.js:106 packages/app-desktop/bridge.js:110
|
||||
#: packages/app-desktop/bridge.js:126 packages/app-desktop/bridge.js:134
|
||||
@@ -124,11 +126,11 @@ msgstr "Herunterladen"
|
||||
|
||||
#: packages/app-desktop/checkForUpdates.js:189
|
||||
msgid "Skip this version"
|
||||
msgstr ""
|
||||
msgstr "Überspringe diese Version"
|
||||
|
||||
#: packages/app-desktop/checkForUpdates.js:189
|
||||
msgid "Full changelog"
|
||||
msgstr ""
|
||||
msgstr "Komplettes Änderungsprotokoll"
|
||||
|
||||
#: packages/app-desktop/gui/NoteRevisionViewer.min.js:100
|
||||
msgid "This note has no history"
|
||||
@@ -270,14 +272,12 @@ msgid "Retry"
|
||||
msgstr "Erneut versuchen"
|
||||
|
||||
#: packages/app-desktop/gui/StatusScreen/StatusScreen.js:137
|
||||
#, fuzzy
|
||||
msgid "Advanced tools"
|
||||
msgstr "Erweiterte Optionen"
|
||||
|
||||
#: packages/app-desktop/gui/StatusScreen/StatusScreen.js:139
|
||||
#, fuzzy
|
||||
msgid "Export debug report"
|
||||
msgstr "Fehlerbericht exportieren"
|
||||
msgstr "Ereignisprotokoll exportieren"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/CodeMirror.js:183
|
||||
msgid "strong text"
|
||||
@@ -521,9 +521,8 @@ msgid "Delete line"
|
||||
msgstr "Zeile löschen"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.js:92
|
||||
#, fuzzy
|
||||
msgid "Duplicate line"
|
||||
msgstr "Duplizieren"
|
||||
msgstr "Dupliziere Zeile"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.js:96
|
||||
msgid "Undo"
|
||||
@@ -718,10 +717,12 @@ msgid ""
|
||||
"Safe mode is currently active. Note rendering and all plugins are "
|
||||
"temporarily disabled."
|
||||
msgstr ""
|
||||
"Sicherer Modus aktiv. Notizdarstellung und alle Plugins werden vorübergehend "
|
||||
"deaktiviert."
|
||||
|
||||
#: packages/app-desktop/gui/MainScreen/MainScreen.js:447
|
||||
msgid "Disable safe mode and restart"
|
||||
msgstr ""
|
||||
msgstr "Sicheren Modus beenden und neu starten"
|
||||
|
||||
#: packages/app-desktop/gui/MainScreen/MainScreen.js:451
|
||||
msgid ""
|
||||
@@ -767,15 +768,15 @@ msgstr "Weitere Information"
|
||||
#: packages/app-desktop/gui/MainScreen/MainScreen.js:477
|
||||
#, javascript-format
|
||||
msgid "%s (%s) would like to share a notebook with you."
|
||||
msgstr ""
|
||||
msgstr "%s (%s) möchte ein Notizbuch mit dir teilen."
|
||||
|
||||
#: packages/app-desktop/gui/MainScreen/MainScreen.js:479
|
||||
msgid "Accept"
|
||||
msgstr ""
|
||||
msgstr "Akzeptieren"
|
||||
|
||||
#: packages/app-desktop/gui/MainScreen/MainScreen.js:481
|
||||
msgid "Reject"
|
||||
msgstr ""
|
||||
msgstr "Ablehnen"
|
||||
|
||||
#: packages/app-desktop/gui/MainScreen/MainScreen.js:485
|
||||
msgid "Some items cannot be synchronised."
|
||||
@@ -861,9 +862,8 @@ msgid "Toggle editors"
|
||||
msgstr "Editoren umschalten"
|
||||
|
||||
#: packages/app-desktop/gui/MainScreen/commands/showShareFolderDialog.js:16
|
||||
#, fuzzy
|
||||
msgid "Share notebook..."
|
||||
msgstr "Notiz teilen ..."
|
||||
msgstr "Notizbuch teilen ..."
|
||||
|
||||
#: packages/app-desktop/gui/MainScreen/commands/toggleLayoutMoveMode.js:16
|
||||
msgid "Change application layout"
|
||||
@@ -1122,7 +1122,6 @@ msgid "&Go"
|
||||
msgstr "&Gehe zu"
|
||||
|
||||
#: packages/app-desktop/gui/MenuBar.js:631
|
||||
#, fuzzy
|
||||
msgid "Note&book"
|
||||
msgstr "Notizbücher"
|
||||
|
||||
@@ -1531,13 +1530,12 @@ msgid "You do not have any installed plugin."
|
||||
msgstr "Es sind keine Erweiterungen installiert."
|
||||
|
||||
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js:232
|
||||
#, fuzzy
|
||||
msgid "Could not connect to plugin repository"
|
||||
msgstr "Erweiterung konnte nicht installiert werden: %s"
|
||||
msgstr "Konnte keine Verbindung zum Plugin-Repository herstellen"
|
||||
|
||||
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js:234
|
||||
msgid "Try again"
|
||||
msgstr ""
|
||||
msgstr "Versuche es erneut"
|
||||
|
||||
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js:242
|
||||
msgid "Plugin tools"
|
||||
@@ -1565,7 +1563,6 @@ msgid "Install"
|
||||
msgstr "Installieren"
|
||||
|
||||
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js:132
|
||||
#, fuzzy
|
||||
msgid "Installing..."
|
||||
msgstr "Wird installiert ..."
|
||||
|
||||
@@ -1574,12 +1571,10 @@ msgid "Installed"
|
||||
msgstr "Installiert"
|
||||
|
||||
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js:140
|
||||
#, fuzzy
|
||||
msgid "Update"
|
||||
msgstr "Aktualisieren"
|
||||
|
||||
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.js:142
|
||||
#, fuzzy
|
||||
msgid "Updating..."
|
||||
msgstr "Wird aktualisiert ..."
|
||||
|
||||
@@ -1732,9 +1727,8 @@ msgstr ""
|
||||
"(Obergrenze: %s)."
|
||||
|
||||
#: packages/app-desktop/gui/ShareNoteDialog.js:141
|
||||
#, fuzzy
|
||||
msgid "Unshare note"
|
||||
msgstr "Teilen"
|
||||
msgstr "Notiz nicht mehr teilen"
|
||||
|
||||
#: packages/app-desktop/gui/ShareNoteDialog.js:168
|
||||
msgid "Synchronising..."
|
||||
@@ -1770,19 +1764,20 @@ msgstr[0] "Teilbaren Link kopieren"
|
||||
msgstr[1] "Teilbare Links kopieren"
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:138
|
||||
#, fuzzy
|
||||
msgid "Unshare"
|
||||
msgstr "Teilen"
|
||||
msgstr "Nicht mehr teilen"
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:180
|
||||
msgid ""
|
||||
"Delete this invitation? The recipient will no longer have access to this "
|
||||
"shared notebook."
|
||||
msgstr ""
|
||||
"Einladung löschen? Der Empfänger hat dann keinen Zugriff mehr auf dieses "
|
||||
"freigegebene Notizbuch."
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:194
|
||||
msgid "Add recipient:"
|
||||
msgstr ""
|
||||
msgstr "Füge Empfänger hinzu:"
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:197
|
||||
#: packages/app-mobile/components/NoteBodyViewer/hooks/useOnResourceLongPress.js:28
|
||||
@@ -1792,45 +1787,43 @@ msgstr "Teilen"
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:206
|
||||
msgid "Recipient has not yet accepted the invitation"
|
||||
msgstr ""
|
||||
msgstr "Empfänger hat die Einladung noch nicht akzeptiert"
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:207
|
||||
msgid "Recipient has rejected the invitation"
|
||||
msgstr ""
|
||||
msgstr "Empfänger hat die Einladung abgewiesen"
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:208
|
||||
msgid "Recipient has accepted the invitation"
|
||||
msgstr ""
|
||||
msgstr "Empfänger hat die Einladung akzeptiert"
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:218
|
||||
msgid "Recipients:"
|
||||
msgstr ""
|
||||
msgstr "Empfänger:"
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:230
|
||||
#, fuzzy
|
||||
msgid "Synchronizing..."
|
||||
msgstr "Wird synchronisiert ..."
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:231
|
||||
#, fuzzy
|
||||
msgid "Sharing notebook..."
|
||||
msgstr "Notiz teilen ..."
|
||||
msgstr "Notizbuch wird geteilt ..."
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:241
|
||||
msgid ""
|
||||
"Unshare this notebook? The recipients will no longer have access to its "
|
||||
"content."
|
||||
msgstr ""
|
||||
"Teilen des Notizbuch beenden? Der Empfänger wird keinen Zugriff mehr auf den "
|
||||
"Inhalt haben."
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:251
|
||||
#, fuzzy
|
||||
msgid "Share Notebook"
|
||||
msgstr "Notizen teilen"
|
||||
msgstr "Notizbuch teilen"
|
||||
|
||||
#: packages/app-desktop/commands/toggleSafeMode.js:18
|
||||
#, fuzzy
|
||||
msgid "Toggle safe mode"
|
||||
msgstr "Seitenleiste ein-/ausschalten"
|
||||
msgstr "Sicheren Modus ein-/ausschalten"
|
||||
|
||||
#: packages/app-desktop/commands/toggleExternalEditing.js:18
|
||||
msgid "Toggle external editing"
|
||||
@@ -2055,7 +2048,7 @@ msgstr ""
|
||||
|
||||
#: packages/app-mobile/components/screens/ConfigScreen.js:406
|
||||
msgid "Feature flags"
|
||||
msgstr ""
|
||||
msgstr "Feature Flags"
|
||||
|
||||
#: packages/app-mobile/components/screens/ConfigScreen.js:408
|
||||
msgid "More information"
|
||||
@@ -2089,7 +2082,7 @@ msgstr ""
|
||||
|
||||
#: packages/app-mobile/components/screens/ConfigScreen.js:428
|
||||
msgid "Joplin website"
|
||||
msgstr "Joplin-Webseite"
|
||||
msgstr "Joplin Webseite"
|
||||
|
||||
#: packages/app-mobile/components/screens/ConfigScreen.js:433
|
||||
msgid "Privacy Policy"
|
||||
@@ -2288,15 +2281,15 @@ msgstr ""
|
||||
"[Jetzt ändern](%s)"
|
||||
|
||||
#: packages/server/dist/models/UserModel.js:175
|
||||
#, fuzzy
|
||||
msgid "attachment"
|
||||
msgstr "Anhänge"
|
||||
msgstr "Anhang"
|
||||
|
||||
#: packages/server/dist/models/UserModel.js:175
|
||||
#, javascript-format
|
||||
msgid ""
|
||||
"Cannot save %s \"%s\" because it is larger than than the allowed limit (%s)"
|
||||
msgstr ""
|
||||
"Kann %s \"%s\" nicht speichern, da es größer ist als das erlaubte Limit (%s)"
|
||||
|
||||
#: packages/lib/onedrive-api-node-utils.js:46
|
||||
#, javascript-format
|
||||
@@ -2339,7 +2332,7 @@ msgstr "Dropbox"
|
||||
|
||||
#: packages/lib/SyncTargetJoplinServer.js:57
|
||||
msgid "Joplin Server"
|
||||
msgstr "Joplin-Server"
|
||||
msgstr "Joplin Server"
|
||||
|
||||
#: packages/lib/shim-init-node.js:212
|
||||
#, javascript-format
|
||||
@@ -2484,26 +2477,23 @@ msgstr "AWS-Geheimnis"
|
||||
|
||||
#: packages/lib/models/Setting.js:315
|
||||
msgid "Joplin Server URL"
|
||||
msgstr "Joplin-Server-URL"
|
||||
msgstr "Joplin Server-URL"
|
||||
|
||||
#: packages/lib/models/Setting.js:333
|
||||
#, fuzzy
|
||||
msgid "Joplin Server email"
|
||||
msgstr "Joplin-Server"
|
||||
msgstr "Joplin Server E-Mail"
|
||||
|
||||
#: packages/lib/models/Setting.js:344
|
||||
msgid "Joplin Server password"
|
||||
msgstr "Joplin-Server-Passwort"
|
||||
msgstr "Joplin Server-Passwort"
|
||||
|
||||
#: packages/lib/models/Setting.js:371
|
||||
#, fuzzy
|
||||
msgid "Joplin Cloud email"
|
||||
msgstr "Joplin-Server"
|
||||
msgstr "Joplin Cloud E-Mail"
|
||||
|
||||
#: packages/lib/models/Setting.js:382
|
||||
#, fuzzy
|
||||
msgid "Joplin Cloud password"
|
||||
msgstr "Joplin-Server-Passwort"
|
||||
msgstr "Joplin Server Passwort"
|
||||
|
||||
#: packages/lib/models/Setting.js:394
|
||||
msgid "Attachment download behaviour"
|
||||
@@ -2756,6 +2746,9 @@ msgid ""
|
||||
"Used for most text in the markdown editor. If not found, a generic "
|
||||
"proportional (variable width) font is used."
|
||||
msgstr ""
|
||||
"Hauptsächlich für Text im Markdown-Editor verwendet. Falls nicht vorhanden "
|
||||
"wird eine generische Proportional-Schriftart (mit variabler Breite) "
|
||||
"verwendet."
|
||||
|
||||
#: packages/lib/models/Setting.js:764
|
||||
msgid "Editor monospace font family"
|
||||
@@ -2767,6 +2760,9 @@ msgid ""
|
||||
"tables, checkboxes, code). If not found, a generic monospace (fixed width) "
|
||||
"font is used."
|
||||
msgstr ""
|
||||
"Verwendete Schriftart mit fester Breite, um Text lesbar zu machen (z.B. in "
|
||||
"Tabellen, Kontrollkästchen, Code). Falls nicht vorhanden wird eine Monotype-"
|
||||
"Scrhiftart (mit fester Breite) verwendet."
|
||||
|
||||
#: packages/lib/models/Setting.js:786
|
||||
msgid "Custom stylesheet for rendered Markdown"
|
||||
@@ -2778,11 +2774,11 @@ msgstr "Benutzerdefinierte Formatvorlagen für Joplin-weite Anwendungsstile"
|
||||
|
||||
#: packages/lib/models/Setting.js:812
|
||||
msgid "Re-upload local data to sync target"
|
||||
msgstr ""
|
||||
msgstr "Lade lokale Daten erneut auf das Synchronisierungsziel hoch"
|
||||
|
||||
#: packages/lib/models/Setting.js:822
|
||||
msgid "Delete local data and re-download from sync target"
|
||||
msgstr ""
|
||||
msgstr "Lösche lokale Daten und lade Daten erneut vom Synchronisierungsziel"
|
||||
|
||||
#: packages/lib/models/Setting.js:827
|
||||
msgid "Automatically update the application"
|
||||
@@ -3108,9 +3104,8 @@ msgid "Encrypted items cannot be modified"
|
||||
msgstr "Verschlüsselte Elemente können nicht verändert werden"
|
||||
|
||||
#: packages/lib/SyncTargetJoplinCloud.js:28
|
||||
#, fuzzy
|
||||
msgid "Joplin Cloud"
|
||||
msgstr "Joplin Forum"
|
||||
msgstr "Joplin Cloud"
|
||||
|
||||
#: packages/lib/BaseApplication.js:152 packages/lib/BaseApplication.js:164
|
||||
#: packages/lib/BaseApplication.js:196
|
||||
@@ -3243,9 +3238,9 @@ msgid "Cancelling..."
|
||||
msgstr "Wird abgebrochen ..."
|
||||
|
||||
#: packages/lib/Synchronizer.js:156
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "Completed: %s (%s)"
|
||||
msgstr "Abgeschlossen: %s"
|
||||
msgstr "Abgeschlossen: %s (%s)"
|
||||
|
||||
#: packages/lib/Synchronizer.js:158
|
||||
#, javascript-format
|
||||
@@ -3967,6 +3962,7 @@ msgid ""
|
||||
"Runs the commands contained in the text file. There should be one command "
|
||||
"per line."
|
||||
msgstr ""
|
||||
"Führe Befehle aus Textdatei aus. Jede Zeile darf nur einen Befehl enthalten."
|
||||
|
||||
#: packages/app-cli/app/command-version.js:11
|
||||
msgid "Displays version information"
|
||||
|
||||
@@ -20,9 +20,11 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
"X-Generator: Poedit 2.4.3\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
|
||||
#: packages/app-desktop/bridge.js:106 packages/app-desktop/bridge.js:110
|
||||
#: packages/app-desktop/bridge.js:126 packages/app-desktop/bridge.js:134
|
||||
@@ -337,7 +339,7 @@ msgstr "Casillas"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js:17
|
||||
msgid "Highlight"
|
||||
msgstr "Destacar"
|
||||
msgstr "Resaltado"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js:22
|
||||
msgid "Strikethrough"
|
||||
@@ -377,7 +379,7 @@ msgstr "Código Integrado"
|
||||
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js:654
|
||||
#: packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.js:83
|
||||
msgid "Insert Date Time"
|
||||
msgstr "Introducir fecha"
|
||||
msgstr "Insertar Fecha y Hora"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js:1103
|
||||
msgid "Drop notes or files here"
|
||||
@@ -520,7 +522,7 @@ msgstr "Borrar línea"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.js:92
|
||||
msgid "Duplicate line"
|
||||
msgstr "Duplicar linea"
|
||||
msgstr "Duplicar línea"
|
||||
|
||||
#: packages/app-desktop/gui/NoteEditor/commands/editorCommandDeclarations.js:96
|
||||
msgid "Undo"
|
||||
@@ -713,8 +715,8 @@ msgid ""
|
||||
"Safe mode is currently active. Note rendering and all plugins are "
|
||||
"temporarily disabled."
|
||||
msgstr ""
|
||||
"El modo seguro está activo actualmente. La representación de notas y todos "
|
||||
"los complementos están temporalmente deshabilitados."
|
||||
"El modo seguro está actualmente activo. El renderizado de notas y todos los "
|
||||
"plugins están temporalmente deshabilitados."
|
||||
|
||||
#: packages/app-desktop/gui/MainScreen/MainScreen.js:447
|
||||
msgid "Disable safe mode and restart"
|
||||
@@ -764,7 +766,7 @@ msgstr "Más información"
|
||||
#: packages/app-desktop/gui/MainScreen/MainScreen.js:477
|
||||
#, javascript-format
|
||||
msgid "%s (%s) would like to share a notebook with you."
|
||||
msgstr "%s (%s) le gustaría compartir una libreta contigo."
|
||||
msgstr "A %s (%s) le gustaría compartir una libreta contigo."
|
||||
|
||||
#: packages/app-desktop/gui/MainScreen/MainScreen.js:479
|
||||
msgid "Accept"
|
||||
@@ -1516,11 +1518,11 @@ msgstr "No tiene ningún plugin instalado."
|
||||
|
||||
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js:232
|
||||
msgid "Could not connect to plugin repository"
|
||||
msgstr "No se pudo conectar con el repositorio del plugin: %s"
|
||||
msgstr "No se pudo conectar con el repositorio de plugins"
|
||||
|
||||
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js:234
|
||||
msgid "Try again"
|
||||
msgstr "Intenta nuevamente"
|
||||
msgstr "Vuelva a intentarlo"
|
||||
|
||||
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.js:242
|
||||
msgid "Plugin tools"
|
||||
@@ -1787,7 +1789,7 @@ msgstr "Sincronizando..."
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:231
|
||||
msgid "Sharing notebook..."
|
||||
msgstr "Compartir libreta..."
|
||||
msgstr "Compartiendo libreta..."
|
||||
|
||||
#: packages/app-desktop/gui/ShareFolderDialog/ShareFolderDialog.js:241
|
||||
msgid ""
|
||||
@@ -1896,7 +1898,7 @@ msgstr "Configuración"
|
||||
|
||||
#: packages/app-mobile/components/side-menu-content.js:351
|
||||
msgid "Mobile data - auto-sync disabled"
|
||||
msgstr "Datos móviles: sincronización automática deshabilitada"
|
||||
msgstr "Datos móviles - sincronización automática deshabilitada"
|
||||
|
||||
#: packages/app-mobile/components/note-list.js:97
|
||||
msgid "You currently have no notebooks."
|
||||
@@ -2026,7 +2028,7 @@ msgstr ""
|
||||
|
||||
#: packages/app-mobile/components/screens/ConfigScreen.js:406
|
||||
msgid "Feature flags"
|
||||
msgstr ""
|
||||
msgstr "Feature flags"
|
||||
|
||||
#: packages/app-mobile/components/screens/ConfigScreen.js:408
|
||||
msgid "More information"
|
||||
@@ -2460,7 +2462,7 @@ msgstr "URL del Servidor de Joplin"
|
||||
|
||||
#: packages/lib/models/Setting.js:333
|
||||
msgid "Joplin Server email"
|
||||
msgstr "Email del servidor Joplin"
|
||||
msgstr "Email del Servidor de Joplin"
|
||||
|
||||
#: packages/lib/models/Setting.js:344
|
||||
msgid "Joplin Server password"
|
||||
@@ -2468,11 +2470,11 @@ msgstr "Contraseña del Servidor de Joplin"
|
||||
|
||||
#: packages/lib/models/Setting.js:371
|
||||
msgid "Joplin Cloud email"
|
||||
msgstr "Email del servidor Joplin"
|
||||
msgstr "Email de Joplin Cloud"
|
||||
|
||||
#: packages/lib/models/Setting.js:382
|
||||
msgid "Joplin Cloud password"
|
||||
msgstr "Contraseña del servidor Joplin"
|
||||
msgstr "Contraseña de Joplin Cloud"
|
||||
|
||||
#: packages/lib/models/Setting.js:394
|
||||
msgid "Attachment download behaviour"
|
||||
@@ -2727,7 +2729,7 @@ msgid ""
|
||||
"tables, checkboxes, code). If not found, a generic monospace (fixed width) "
|
||||
"font is used."
|
||||
msgstr ""
|
||||
"Se utiliza cuando se necesita una fuente de ancho fijo para presentar el "
|
||||
"Se utiliza donde se necesita una fuente de ancho fijo para presentar el "
|
||||
"texto de manera legible (por ejemplo, tablas, casillas de verificación, "
|
||||
"código). Si no se encuentra, se utiliza una fuente genérica monoespaciada "
|
||||
"(ancho fijo)."
|
||||
@@ -2742,12 +2744,12 @@ msgstr "Hoja de estilos para personalizar todo Joplin"
|
||||
|
||||
#: packages/lib/models/Setting.js:812
|
||||
msgid "Re-upload local data to sync target"
|
||||
msgstr "Vuelva a cargar datos locales para sincronizar el destino"
|
||||
msgstr "Volver a cargar datos locales al objetivo de sincronización"
|
||||
|
||||
#: packages/lib/models/Setting.js:822
|
||||
msgid "Delete local data and re-download from sync target"
|
||||
msgstr ""
|
||||
"Elimine los datos locales y vuelva a descargarlos desde el destino de "
|
||||
"Eliminar datos locales y volver a descargarlos desde el objetivo de "
|
||||
"sincronización"
|
||||
|
||||
#: packages/lib/models/Setting.js:827
|
||||
@@ -3072,7 +3074,7 @@ msgstr "Los elementos cifrados no pueden ser modificados"
|
||||
|
||||
#: packages/lib/SyncTargetJoplinCloud.js:28
|
||||
msgid "Joplin Cloud"
|
||||
msgstr "Nube de Joplin"
|
||||
msgstr "Joplin Cloud"
|
||||
|
||||
#: packages/lib/BaseApplication.js:152 packages/lib/BaseApplication.js:164
|
||||
#: packages/lib/BaseApplication.js:196
|
||||
@@ -3205,9 +3207,9 @@ msgid "Cancelling..."
|
||||
msgstr "Cancelando..."
|
||||
|
||||
#: packages/lib/Synchronizer.js:156
|
||||
#, fuzzy, javascript-format
|
||||
#, javascript-format
|
||||
msgid "Completed: %s (%s)"
|
||||
msgstr "Completado: %s"
|
||||
msgstr "Completado: %s (%s)"
|
||||
|
||||
#: packages/lib/Synchronizer.js:158
|
||||
#, javascript-format
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# Joplin Android app changelog
|
||||
|
||||
## [android-v2.2.1](https://github.com/laurent22/joplin/releases/tag/android-v2.2.1) (Pre-release) - 2021-07-13T17:37:38Z
|
||||
|
||||
- New: Added improved editor (beta)
|
||||
- Improved: Disable backup to Google Drive (#5114 by Roman Musin)
|
||||
- Improved: Interpret only valid search filters (#5103) (#3871 by [@JackGruber](https://github.com/JackGruber))
|
||||
- Improved: Removed old editor code (e01a175)
|
||||
|
||||
## [android-v2.1.4](https://github.com/laurent22/joplin/releases/tag/android-v2.1.4) - 2021-07-03T08:31:36Z
|
||||
|
||||
- Fixed: Fixes #5133: Items keep being uploaded to Joplin Server after a note has been shared.
|
||||
|
||||
Reference in New Issue
Block a user