diff --git a/src/lib/Installer.svelte b/src/lib/Installer.svelte
index 0d85412..6dab851 100644
--- a/src/lib/Installer.svelte
+++ b/src/lib/Installer.svelte
@@ -4,6 +4,7 @@
import { getCurrentWindow } from '@tauri-apps/api/window';
import { onMount } from 'svelte';
import iconUrl from '../assets/icon.png';
+ import { t } from './utils/i18n.js';
let installing = $state(false);
let error = $state('');
@@ -65,7 +66,7 @@
error = e.toString();
installing = false;
if (error.includes('Access is denied') && (isInstalled ? installedAllUsers : allUsers)) {
- error = 'Access denied. Please run as Administrator.';
+ error = t('installer.accessDenied');
}
}
}
@@ -97,7 +98,7 @@
([]);
let isFocused = $state(true);
@@ -238,8 +245,8 @@ import { processMarkdownHtml } from './utils/markdown';
if (settings.restoreStateOnReopen) {
const hasUnsaved = tabManager.tabs.some((t) => t.isDirty || (t.path === '' && t.rawContent.trim() !== ''));
if (hasUnsaved) {
- const response = await askCustom(`Are you sure you want to exit? All unsaved tabs and local history will be lost.`, {
- title: 'Confirm Exit',
+ const response = await askCustom(t('modal.exit.unsaved.message'), {
+ title: t('modal.exit.unsaved.title'),
kind: 'warning',
showSave: false,
});
@@ -1048,8 +1055,8 @@ import { processMarkdownHtml } from './utils/markdown';
if (!tab.isDirty) return true;
- const response = await askCustom(`You have unsaved changes in "${tab.title}". Do you want to save them before closing?`, {
- title: 'Unsaved Changes',
+ const response = await askCustom(t('modal.youHaveUnsavedChanges', settings.language).replace('{title}', tab.title), {
+ title: t('modal.unsavedChanges.title'),
kind: 'warning',
showSave: true,
});
@@ -1070,14 +1077,14 @@ import { processMarkdownHtml } from './utils/markdown';
// Switch back to view
if (tab.isDirty && tab.path !== '') {
if (autoSave) {
- const success = await saveContent();
- if (!success) return; // If save fails, stay in edit mode?
- } else {
- const response = await askCustom('You have unsaved changes. Do you want to save them before returning to view mode?', {
- title: 'Unsaved Changes',
- kind: 'warning',
- showSave: true,
- });
+ const success = await saveContent();
+ if (!success) return; // If save fails, stay in edit mode?
+ } else {
+ const response = await askCustom(t('modal.unsavedChanges.viewMode.message'), {
+ title: t('modal.unsavedChanges.title'),
+ kind: 'warning',
+ showSave: true,
+ });
if (response === 'cancel') return;
if (response === 'save') {
@@ -1319,7 +1326,7 @@ import { processMarkdownHtml } from './utils/markdown';
const filename = tab?.path ? tab.path.split(/[/\\]/).pop()?.replace(/\.[^.]+$/, '') || '' : '';
const ref = filename ? `[[${filename}#${text}]]` : `#${text}`;
copyRefItem = [
- { label: 'Copy Reference', onClick: () => invoke('clipboard_write_text', { text: ref }) },
+ { label: t('menu.copyReference', uiLanguage), onClick: () => invoke('clipboard_write_text', { text: ref }) },
{ separator: true },
];
}
@@ -1328,7 +1335,7 @@ import { processMarkdownHtml } from './utils/markdown';
let mediaItems: any[] = [];
if (img) {
mediaItems = [
- { label: 'Save Image As...', onClick: () => saveImageAs(img.src) },
+ { label: t('menu.saveImageAs', uiLanguage), onClick: () => saveImageAs(img.src) },
{ separator: true }
];
}
@@ -1336,7 +1343,7 @@ import { processMarkdownHtml } from './utils/markdown';
const mermaidDiag = (e.target as HTMLElement).closest('.mermaid-diagram');
if (mermaidDiag) {
mediaItems = [
- { label: 'Save Diagram As SVG...', onClick: () => saveDiagramAs(mermaidDiag as HTMLElement) },
+ { label: t('menu.saveDiagramAsSvg', uiLanguage), onClick: () => saveDiagramAs(mermaidDiag as HTMLElement) },
{ separator: true }
];
}
@@ -1350,16 +1357,16 @@ import { processMarkdownHtml } from './utils/markdown';
...mediaItems,
...(isEditing && isInsideEditor
? [
- { label: 'Undo', shortcut: 'Ctrl+Z', onClick: () => editorPane?.undo() },
- { label: 'Redo', shortcut: 'Ctrl+Y', onClick: () => editorPane?.redo() },
+ { label: t('menu.undo', uiLanguage), shortcut: 'Ctrl+Z', onClick: () => editorPane?.undo() },
+ { label: t('menu.redo', uiLanguage), shortcut: 'Ctrl+Y', onClick: () => editorPane?.redo() },
{ separator: true }
]
: []),
- ...(hasSelection ? [{ label: 'Copy', onClick: () => {
+ ...(hasSelection ? [{ label: t('menu.copy', uiLanguage), onClick: () => {
const selection = window.getSelection()?.toString();
if (selection) invoke('clipboard_write_text', { text: selection });
} }] : []),
- { label: 'Select All', onClick: () => {
+ { label: t('menu.selectAll', uiLanguage), onClick: () => {
if (!markdownBody) return;
const range = document.createRange();
range.selectNodeContents(markdownBody);
@@ -1368,10 +1375,10 @@ import { processMarkdownHtml } from './utils/markdown';
selection?.addRange(range);
} },
{ separator: true },
- { label: 'Open File Location', onClick: openFileLocation, disabled: !currentFile },
- { label: 'Edit', onClick: () => toggleEdit() },
+ { label: t('menu.openLocation', uiLanguage), onClick: openFileLocation, disabled: !currentFile },
+ { label: t('menu.edit', uiLanguage), onClick: () => toggleEdit() },
{ separator: true },
- { label: 'Close File', onClick: closeFile },
+ { label: t('menu.closeFile', uiLanguage), onClick: closeFile },
],
};
}
@@ -1521,8 +1528,8 @@ import { processMarkdownHtml } from './utils/markdown';
const success = await saveContent();
if (!success) return;
} else {
- const response = await askCustom('You have unsaved changes. Do you want to save them before closing split view?', {
- title: 'Unsaved Changes',
+ const response = await askCustom(t('modal.unsavedChanges.splitView.message'), {
+ title: t('modal.unsavedChanges.title'),
kind: 'warning',
showSave: true,
});
@@ -1797,7 +1804,7 @@ import { processMarkdownHtml } from './utils/markdown';
const tab = tabManager.tabs.find((t) => t.id === tabId);
if (!tab || !tab.path) return;
- const newName = window.prompt('Rename file:', tab.title);
+ const newName = window.prompt(t('menu.renameFile', settings.language), tab.title);
if (newName && newName !== tab.title) {
const oldPath = tab.path;
const newPath = oldPath.replace(/[/\\][^/\\]+$/, (m) => m.charAt(0) + newName);
@@ -1865,12 +1872,12 @@ import { processMarkdownHtml } from './utils/markdown';
console.log('Dirty tabs:', dirtyTabs.length);
if (dirtyTabs.length > 0) {
console.log('Preventing default close');
- event.preventDefault();
- const response = await askCustom(`You have ${dirtyTabs.length} unsaved file(s). Do you want to save your changes?`, {
- title: 'Unsaved Changes',
- kind: 'warning',
- showSave: true,
- });
+ event.preventDefault();
+ const response = await askCustom(t('modal.youHaveUnsavedFiles', settings.language).replace('{{count}}', dirtyTabs.length.toString()), {
+ title: t('modal.unsavedChanges', settings.language),
+ kind: 'warning',
+ showSave: true,
+ });
if (response === 'save') {
// Attempt to save all dirty tabs
@@ -1940,8 +1947,8 @@ import { processMarkdownHtml } from './utils/markdown';
if (ext && ['md', 'markdown', 'txt'].includes(ext)) {
loadMarkdown(path);
} else {
- const filename = path.split(/[/\\]/).pop() || 'File';
- addToast(`Unsupported file type: ${filename}`, 'error');
+ const filename = path.split(/[\/\\]/).pop() || 'File';
+ addToast(t('toast.unsupportedFile').replace('{{filename}}', filename), 'error');
}
});
}
@@ -2191,7 +2198,7 @@ import { processMarkdownHtml } from './utils/markdown';
y: e.clientY,
items: [
{
- label: 'Copy Reference',
+ label: t('menu.copyReference', uiLanguage),
onClick: () => {
const tab = tabManager.activeTab;
const fn = tab?.path ? tab.path.split(/[/\\]/).pop()?.replace(/\.[^.]+$/, '') || '' : '';
@@ -2272,17 +2279,17 @@ import { processMarkdownHtml } from './utils/markdown';
{#if isSplit || isEditing}
+
+ {t('dragAndDrop.embed')}
+
+
{/if}
{#if isSplit || !isEditing}
+
+ {t('dragAndDrop.open')}
+
+
{/if}
diff --git a/src/lib/Uninstaller.svelte b/src/lib/Uninstaller.svelte
index 0b3f7db..1d65f8f 100644
--- a/src/lib/Uninstaller.svelte
+++ b/src/lib/Uninstaller.svelte
@@ -2,6 +2,7 @@
import { invoke } from '@tauri-apps/api/core';
import { getCurrentWindow } from '@tauri-apps/api/window';
import iconUrl from '../assets/icon.png';
+ import { t } from './utils/i18n.js';
let uninstalling = $state(false);
let error = $state('');
@@ -27,7 +28,7 @@
@@ -35,8 +36,8 @@
{#if !uninstalling}
@@ -46,14 +47,14 @@
{/if}
-
-
+
+
{:else}
-
Removing Markpad...
+
{t('uninstaller.removingMarkpad')}
{/if}
diff --git a/src/lib/components/Editor.svelte b/src/lib/components/Editor.svelte
index be08bb8..e4f7b35 100644
--- a/src/lib/components/Editor.svelte
+++ b/src/lib/components/Editor.svelte
@@ -2,6 +2,7 @@
import { onMount, onDestroy } from "svelte";
import { tabManager } from "../stores/tabs.svelte.js";
import { settings } from "../stores/settings.svelte.js";
+ import { t } from '../utils/i18n.js';
import * as monaco from "monaco-editor";
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
@@ -68,6 +69,11 @@
let wordCount = $state(0);
let currentLanguage = $state("markdown");
let currentTabId = $state(tabManager.activeTabId);
+ let uiLanguage = $state(settings.language);
+
+ $effect(() => {
+ uiLanguage = settings.language;
+ });
self.MonacoEnvironment = {
getWorker: function (_moduleId: any, label: string) {
@@ -218,7 +224,7 @@
editor.addAction({
id: "toggle-minimap",
- label: "Toggle Minimap",
+ label: t('settings.minimap', uiLanguage),
run: () => {
settings.toggleMinimap();
},
@@ -226,7 +232,7 @@
editor.addAction({
id: "toggle-word-wrap",
- label: "Toggle Word Wrap",
+ label: t('settings.wordWrap', uiLanguage),
run: () => {
settings.toggleWordWrap();
},
@@ -234,7 +240,7 @@
editor.addAction({
id: "toggle-line-numbers",
- label: "Toggle Line Numbers",
+ label: t('settings.lineNumbers', uiLanguage),
run: () => {
settings.toggleLineNumbers();
},
@@ -242,7 +248,7 @@
editor.addAction({
id: "toggle-vim-mode",
- label: "Toggle Vim Mode",
+ label: t('settings.vimMode', uiLanguage),
run: () => {
settings.toggleVimMode();
},
@@ -250,7 +256,7 @@
editor.addAction({
id: "toggle-status-bar",
- label: "Toggle Status Bar",
+ label: t('settings.statusBar', uiLanguage),
run: () => {
settings.toggleStatusBar();
},
@@ -258,7 +264,7 @@
editor.addAction({
id: "toggle-word-count",
- label: "Toggle Word Count",
+ label: t('settings.wordCount', uiLanguage),
run: () => {
settings.toggleWordCount();
},
@@ -266,7 +272,7 @@
editor.addAction({
id: "toggle-line-highlight",
- label: "Toggle Line Highlight",
+ label: t('settings.lineHighlight', uiLanguage),
run: () => {
settings.toggleLineHighlight();
},
@@ -274,7 +280,7 @@
editor.addAction({
id: "toggle-occurrences-highlight",
- label: "Toggle Occurrences Highlight",
+ label: t('settings.showWhitespace', uiLanguage),
run: () => {
settings.toggleOccurrencesHighlight();
},
@@ -282,7 +288,7 @@
editor.addAction({
id: "toggle-whitespace",
- label: "Toggle Show Whitespace",
+ label: t('settings.showWhitespace', uiLanguage),
run: () => {
settings.toggleShowWhitespace();
},
@@ -290,7 +296,7 @@
editor.addAction({
id: "toggle-tabs",
- label: "Toggle Tabs",
+ label: t('settings.showTabs', uiLanguage),
keybindings: [
monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyB,
],
@@ -301,7 +307,7 @@
editor.addAction({
id: "toggle-zen-mode",
- label: "Toggle Zen Mode",
+ label: t('settings.zenMode', uiLanguage),
keybindings: [
monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyZ,
],
@@ -431,28 +437,28 @@
editor.addAction({
id: "fmt-bold",
- label: "Format: Bold",
+ label: t('menu.bold', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyB],
run: () => toggleFormat("**"),
});
editor.addAction({
id: "fmt-italic",
- label: "Format: Italic",
+ label: t('menu.italic', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyI],
run: () => toggleFormat("*"),
});
editor.addAction({
id: "fmt-underline",
- label: "Format: Underline",
+ label: t('menu.underline', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyU],
run: () => toggleFormat("|", "tag"),
});
editor.addAction({
id: "insert-table-simple",
- label: "Insert Table",
+ label: t('menu.insertTable', uiLanguage),
keybindings: [
monaco.KeyMod.chord(
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK,
@@ -485,7 +491,7 @@
editor.addAction({
id: "file-new",
- label: "New File",
+ label: t('menu.newFile', uiLanguage),
keybindings: [
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyN,
monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyT,
@@ -495,28 +501,28 @@
editor.addAction({
id: "file-open",
- label: "Open File",
+ label: t('menu.openFile', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyO],
run: () => onopen?.(),
});
editor.addAction({
id: "file-save",
- label: "Save File",
+ label: t('menu.save', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
run: () => onsave?.(),
});
editor.addAction({
id: "file-close",
- label: "Close File",
+ label: t('menu.closeFile', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyW],
run: () => onclose?.(),
});
editor.addAction({
id: "file-reveal",
- label: "Open File Location",
+ label: t('menu.openLocation', uiLanguage),
keybindings: [
monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyR,
],
@@ -525,35 +531,35 @@
editor.addAction({
id: "view-toggle-edit",
- label: "Toggle Edit Mode",
+ label: t('menu.toggleEditMode', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyE],
run: () => ontoggleEdit?.(),
});
editor.addAction({
id: "view-toggle-live",
- label: "Toggle Live Mode",
+ label: t('menu.toggleLiveMode', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyL],
run: () => ontoggleLive?.(),
});
editor.addAction({
id: "view-toggle-split",
- label: "Toggle Split View",
+ label: t('menu.toggleSplitView', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyH],
run: () => ontoggleSplit?.(),
});
editor.addAction({
id: "tab-next",
- label: "Next Tab",
+ label: t('menu.nextTab', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Tab],
run: () => onnextTab?.(),
});
editor.addAction({
id: "tab-prev",
- label: "Previous Tab",
+ label: t('menu.previousTab', uiLanguage),
keybindings: [
monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.Tab,
],
@@ -562,7 +568,7 @@
editor.addAction({
id: "tab-undo-close",
- label: "Undo Close Tab",
+ label: t('menu.undoCloseTab', uiLanguage),
keybindings: [
monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyT,
],
@@ -571,7 +577,7 @@
editor.addAction({
id: "app-command-palette",
- label: "Command Palette",
+ label: t('menu.commandPalette', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyP],
run: (ed) => {
ed.trigger("keyboard", "editor.action.quickCommand", {});
@@ -678,7 +684,7 @@
// clipboard handling: override Ctrl+C and Ctrl+V to use Rust backend
editor.addAction({
id: "custom-copy",
- label: "Copy",
+ label: t('menu.copy', uiLanguage),
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyC],
run: async (ed) => {
const selection = ed.getSelection();
@@ -1124,20 +1130,20 @@
{#if settings.statusBar}
- Ln {cursorPosition?.lineNumber ?? 1}, Col {cursorPosition?.column ?? 1}
-
+ {t('editor.status.lineCol', settings.language).replace('{{line}}', (cursorPosition?.lineNumber ?? 1).toString()).replace('{{col}}', (cursorPosition?.column ?? 1).toString())}
+
{#if selectionCount > 0}
- {selectionCount} selected
+ {t('editor.status.selected', settings.language).replace('{{count}}', selectionCount.toString())}
{:else if cursorCount > 1}
- {cursorCount} selections
+ {t('editor.status.selections', settings.language).replace('{{count}}', cursorCount.toString())}
{/if}
{#if settings.wordCount}
- {wordCount} words
+ {t('editor.status.words', settings.language).replace('{{count}}', wordCount.toString())}
{/if}
@@ -1146,8 +1152,8 @@
{currentLanguage}
-
CRLF
-
UTF-8
+
{t('editor.status.crlf')}
+
{t('editor.status.utf8')}
{/if}
diff --git a/src/lib/components/HomePage.svelte b/src/lib/components/HomePage.svelte
index cf04197..0f043fd 100644
--- a/src/lib/components/HomePage.svelte
+++ b/src/lib/components/HomePage.svelte
@@ -1,6 +1,8 @@
-
Open a Markdown file
+
{t('home.welcomeToMarkpad', settings.language)}
-
Recent Files
+
{t('home.recentFiles', settings.language)}
{#if recentFiles.length > 0}
{#each recentFiles as file}
@@ -103,7 +105,7 @@
{/each}
{:else}
-
Your recently opened files will appear here.
+
{t('home.noRecentFiles', settings.language)}
{/if}
diff --git a/src/lib/components/Modal.svelte b/src/lib/components/Modal.svelte
index feb3c03..a4c45ce 100644
--- a/src/lib/components/Modal.svelte
+++ b/src/lib/components/Modal.svelte
@@ -1,5 +1,7 @@
-