From d599811d8d6734ae5b572271ec9bb53898c0657d Mon Sep 17 00:00:00 2001 From: phibr0 Date: Tue, 5 Jul 2022 15:10:05 +0200 Subject: [PATCH] Add translations among smaller fixes --- locale/ar.json | 1 + locale/cz.json | 1 + locale/da.json | 1 + locale/de.json | 49 ++++++++++++++ locale/en-gb.json | 1 + locale/en.json | 49 ++++++++++++++ locale/es.json | 1 + locale/fr.json | 1 + locale/hi.json | 1 + locale/id.json | 1 + locale/it.json | 1 + locale/ja.json | 1 + locale/ko.json | 1 + locale/nl.json | 1 + locale/no.json | 1 + locale/pl.json | 1 + locale/pt-br.json | 1 + locale/pt.json | 1 + locale/ro.json | 1 + locale/ru.json | 1 + locale/tr.json | 1 + locale/zh-cn.json | 1 + locale/zh-tw.json | 1 + manifest.json | 2 +- package.json | 2 +- scripts/esbuild.config.mjs | 5 +- src/l10n.ts | 60 +++++++++++++++++ src/main.ts | 43 ++++++------ src/manager/_commandManager.ts | 1 - src/manager/menuManager.ts | 11 +-- src/manager/pageHeaderManager.ts | 14 ++-- src/manager/ribbonManager.ts | 13 ++-- src/manager/statusBarManager.ts | 15 +++-- src/manager/titleBarManager.ts | 11 +-- src/styles.scss | 1 + src/ui/addCommandModal.ts | 25 +++---- src/ui/chooseCustomNameModal.ts | 9 +-- src/ui/chooseIconModal.ts | 9 +-- src/ui/components/ChangeableText.tsx | 3 +- src/ui/components/commandComponent.tsx | 15 +++-- src/ui/components/commandViewerComponent.tsx | 11 +-- src/ui/components/confirmDeleteComponent.tsx | 9 +-- src/ui/components/settingTabComponent.tsx | 70 +++++++++++--------- src/ui/confirmDeleteModal.ts | 3 +- src/util.tsx | 4 +- tsconfig.json | 3 +- 46 files changed, 329 insertions(+), 129 deletions(-) create mode 100755 locale/ar.json create mode 100755 locale/cz.json create mode 100755 locale/da.json create mode 100755 locale/de.json create mode 100755 locale/en-gb.json create mode 100755 locale/en.json create mode 100755 locale/es.json create mode 100755 locale/fr.json create mode 100755 locale/hi.json create mode 100755 locale/id.json create mode 100755 locale/it.json create mode 100755 locale/ja.json create mode 100755 locale/ko.json create mode 100755 locale/nl.json create mode 100755 locale/no.json create mode 100755 locale/pl.json create mode 100755 locale/pt-br.json create mode 100755 locale/pt.json create mode 100755 locale/ro.json create mode 100755 locale/ru.json create mode 100755 locale/tr.json create mode 100755 locale/zh-cn.json create mode 100755 locale/zh-tw.json create mode 100644 src/l10n.ts diff --git a/locale/ar.json b/locale/ar.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/ar.json @@ -0,0 +1 @@ +{} diff --git a/locale/cz.json b/locale/cz.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/cz.json @@ -0,0 +1 @@ +{} diff --git a/locale/da.json b/locale/da.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/da.json @@ -0,0 +1 @@ +{} diff --git a/locale/de.json b/locale/de.json new file mode 100755 index 0000000..c404356 --- /dev/null +++ b/locale/de.json @@ -0,0 +1,49 @@ +{ + "Open Commander Settings": "Commander Einstellungen öffnen", + "Open Macro Builder": "Makro Baukasten öffnen", + "Change Icon": "Symbol verändern", + "Rename": "Umbenennen", + "Delete": "Löschen", + "Add command": "Befehl hinzufügen", + "Add new": "Neu hinzufügen", + "This Command seems to have been removed. {{command_name}}": "Dieser Befehl wurde entfernt. {{command_name}}", + "Choose a Command to add": "Wähle einen Befehl zum hinzufügen", + "to navigate": "zum navigieren", + "to choose an icon": "um ein symbol auszuwählen", + "to cancel": "zum abbrechen", + "Use a custom name": "Nutze einen benutzerdefinierten Namen", + "Choose a custom Name for your new Command": "Wähle einen benutzerdefinierten Namen für deinen neuen Befehl", + "to save": "zum speichern", + "Choose a Icon for your new Command": "Wähle ein Symbol für deinen neuen Befehl", + "to choose a custom icon": "um ein benutzerdefiniertes Symbol auszuwählen", + "Remove Command": "Befehl entfernen", + "Double click to rename": "Zum umbenennen doppelklicken", + "This device": "Dieses Gerät", + "Added by {{plugin_name}}.": "Hinzugefügt von {{plugin_name}}.", + "Warning: This is a checked Command, meaning it might not run under every circumstance.": "Warnung: Dieser Befehl wird nur unter bestimmten Vorraussetzungen ausgeführt.", + "Move down": "Nach unten", + "Move up": "Nach oben", + "Change Mode (Currently: {{current_mode}})": "Modus verändern (Momentan: {{current_mode}})", + "Are you sure you want to delete the Command?": "Bist du dir sicher, dass du diesen Befehl entfernen möchtest?", + "Remove and don't ask again": "Entfernen und Auswahl speichern", + "Remove": "Entfernen", + "Cancel": "Abbrechen", + "Always ask before removing?": "Immer fragen, bevor ein Befehl gelöscht wird?", + "Always show a Popup to confirm deletion of a Command.": "Zeige immer ein Popup um Löschen zu bestätigen.", + "Show \"Add Command\" Button": "Zeige \"Befehl hinzufügen\" Knopf", + "Show the \"Add Command\" Button in every Menu. Requires restart.": "Zeige den \"Befehl hinzufügen\" Knopf in jedem Menü. Erfordert neustart.", + "Please restart Obsidian for these changes to take effect.": "Bitte starte Obsidian neu, damit diese Änderungen in Kraft treten.", + "Enable debugging": "Aktiviere debugging", + "Enable console output.": "Aktiviere Konsolen-Output (Für Entwickler)", + "General": "Allgemein", + "Editor Menu": "Editor-Menü", + "File Menu": "Datei-Menü", + "Left Ribbon": "Linkes Band", + "Right Ribbon": "Rechtes Band", + "Titlebar": "Titelleiste", + "Statusbar": "Statusleiste", + "Page Header": "Kopfzeile", + "Support development": "Entwicklung unterstützen", + "No commands here!": "Keine Befehle da!", + "Would you like to add one now?": "Möchtest du jetzt einen hinzufügen?" +} diff --git a/locale/en-gb.json b/locale/en-gb.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/en-gb.json @@ -0,0 +1 @@ +{} diff --git a/locale/en.json b/locale/en.json new file mode 100755 index 0000000..7ec1115 --- /dev/null +++ b/locale/en.json @@ -0,0 +1,49 @@ +{ + "Open Commander Settings": "Open Commander Settings", + "Open Macro Builder": "Open Macro Builder", + "Change Icon": "Change Icon", + "Rename": "Rename", + "Delete": "Delete", + "Add command": "Add command", + "Add new": "Add new", + "This Command seems to have been removed. {{command_name}}": "This Command seems to have been removed. {{command_name}}", + "Choose a Command to add": "Choose a Command to add", + "to navigate": "to navigate", + "to choose an icon": "to choose an icon", + "to cancel": "to cancel", + "Use a custom name": "Use a custom name", + "Choose a custom Name for your new Command": "Choose a custom Name for your new Command", + "to save": "to save", + "Choose a Icon for your new Command": "Choose a Icon for your new Command", + "to choose a custom icon": "to choose a custom icon", + "Remove Command": "Remove Command", + "Double click to rename": "Double click to rename", + "This device": "This device", + "Added by {{plugin_name}}.": "Added by {{plugin_name}}.", + "Warning: This is a checked Command, meaning it might not run under every circumstance.": "Warning: This is a checked Command, meaning it might not run under every circumstance.", + "Move down": "Move down", + "Move up": "Move up", + "Change Mode (Currently: {{current_mode}})": "Change Mode (Currently: {{current_mode}})", + "Are you sure you want to delete the Command?": "Are you sure you want to delete the Command?", + "Remove and don't ask again": "Remove and don't ask again", + "Remove": "Remove", + "Cancel": "Cancel", + "Always ask before removing?": "Always ask before removing?", + "Always show a Popup to confirm deletion of a Command.": "Always show a Popup to confirm deletion of a Command.", + "Show \"Add Command\" Button": "Show \"Add Command\" Button", + "Show the \"Add Command\" Button in every Menu. Requires restart.": "Show the \"Add Command\" Button in every Menu. Requires restart.", + "Please restart Obsidian for these changes to take effect.": "Please restart Obsidian for these changes to take effect.", + "Enable debugging": "Enable debugging", + "Enable console output.": "Enable console output.", + "General": "General", + "Editor Menu": "Editor Menu", + "File Menu": "File Menu", + "Left Ribbon": "Left Ribbon", + "Right Ribbon": "Right Ribbon", + "Titlebar": "Titlebar", + "Statusbar": "Statusbar", + "Page Header": "Page Header", + "Support development": "Support development", + "No commands here!": "No commands here!", + "Would you like to add one now?": "Would you like to add one now?" +} diff --git a/locale/es.json b/locale/es.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/es.json @@ -0,0 +1 @@ +{} diff --git a/locale/fr.json b/locale/fr.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/fr.json @@ -0,0 +1 @@ +{} diff --git a/locale/hi.json b/locale/hi.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/hi.json @@ -0,0 +1 @@ +{} diff --git a/locale/id.json b/locale/id.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/id.json @@ -0,0 +1 @@ +{} diff --git a/locale/it.json b/locale/it.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/it.json @@ -0,0 +1 @@ +{} diff --git a/locale/ja.json b/locale/ja.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/ja.json @@ -0,0 +1 @@ +{} diff --git a/locale/ko.json b/locale/ko.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/ko.json @@ -0,0 +1 @@ +{} diff --git a/locale/nl.json b/locale/nl.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/nl.json @@ -0,0 +1 @@ +{} diff --git a/locale/no.json b/locale/no.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/no.json @@ -0,0 +1 @@ +{} diff --git a/locale/pl.json b/locale/pl.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/pl.json @@ -0,0 +1 @@ +{} diff --git a/locale/pt-br.json b/locale/pt-br.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/pt-br.json @@ -0,0 +1 @@ +{} diff --git a/locale/pt.json b/locale/pt.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/pt.json @@ -0,0 +1 @@ +{} diff --git a/locale/ro.json b/locale/ro.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/ro.json @@ -0,0 +1 @@ +{} diff --git a/locale/ru.json b/locale/ru.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/ru.json @@ -0,0 +1 @@ +{} diff --git a/locale/tr.json b/locale/tr.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/tr.json @@ -0,0 +1 @@ +{} diff --git a/locale/zh-cn.json b/locale/zh-cn.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/zh-cn.json @@ -0,0 +1 @@ +{} diff --git a/locale/zh-tw.json b/locale/zh-tw.json new file mode 100755 index 0000000..0967ef4 --- /dev/null +++ b/locale/zh-tw.json @@ -0,0 +1 @@ +{} diff --git a/manifest.json b/manifest.json index 569d046..420127a 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "cmdr", "name": "Commander", - "version": "0.0.7", + "version": "0.0.8", "minAppVersion": "0.12.0", "description": "Customize your workspace by adding commands /everywhere/.", "author": "jsmorabito & phibr0", diff --git a/package.json b/package.json index bd5700d..92c31aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cmdr", - "version": "0.0.7", + "version": "0.0.8", "description": "Customize your workspace by adding commands /everywhere/.", "main": "main.js", "scripts": { diff --git a/scripts/esbuild.config.mjs b/scripts/esbuild.config.mjs index 463f2a1..b5a8c54 100644 --- a/scripts/esbuild.config.mjs +++ b/scripts/esbuild.config.mjs @@ -3,14 +3,13 @@ import process from "process"; import builtins from 'builtin-modules'; import alias from "esbuild-plugin-alias"; import { sassPlugin } from 'esbuild-sass-plugin'; - import { createRequire } from 'module'; import { renameSync } from "fs"; const require = createRequire(import.meta.url); const banner = `/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD -if you want to view the source, please visit the github repository of this plugin +if you want to view the source, please visit the github repository of this plugin (https://github.com/phibr0/obsidian-commander) */ `; @@ -76,7 +75,7 @@ esbuild.build({ try { renameSync("main.css", "styles.css") } catch (error) { - console.log(error); + console.error(error); } }); }, diff --git a/src/l10n.ts b/src/l10n.ts new file mode 100644 index 0000000..b0d0679 --- /dev/null +++ b/src/l10n.ts @@ -0,0 +1,60 @@ +import { moment } from "obsidian"; +import ar from "../locale/ar.json"; +import cz from "../locale/cz.json"; +import da from "../locale/da.json"; +import de from "../locale/de.json"; +import en from "../locale/en.json"; +import enGB from "../locale/en-gb.json"; +import es from "../locale/es.json"; +import fr from "../locale/fr.json"; +import hi from "../locale/hi.json"; +import id from "../locale/id.json"; +import it from "../locale/it.json"; +import ja from "../locale/ja.json"; +import ko from "../locale/ko.json"; +import nl from "../locale/nl.json"; +import no from "../locale/no.json"; +import pl from "../locale/pl.json"; +import pt from "../locale/pt.json"; +import ptBR from "../locale/pt-br.json"; +import ro from "../locale/ro.json"; +import ru from "../locale/ru.json"; +import tr from "../locale/tr.json"; +import zhCN from "../locale/zh-cn.json"; +import zhTW from "../locale/zh-tw.json"; + +const localeMap = { + ar, + cs: cz, + da, + de, + en, + "en-gb": enGB, + es, + fr, + hi, + id, + it, + ja, + ko, + nl, + nn: no, + pl, + pt, + "pt-br": ptBR, + ro, + ru, + tr, + "zh-cn": zhCN, + "zh-tw": zhTW, +}; + +const locale = localeMap[moment.locale() as keyof typeof localeMap]; + +export default function t(str: string): string { + if (!locale) { + console.error("Error: dictionary locale not found", moment.locale()); + } + + return (locale && locale[str as keyof typeof locale]) || en[str as keyof typeof en]; +} diff --git a/src/main.ts b/src/main.ts index adb260e..c3f3d54 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,17 +1,18 @@ import { Plugin } from 'obsidian'; import { DEFAULT_SETTINGS } from './constants'; -import CommanderSettingTab from './ui/settingTab'; -import { CommanderSettings, Macro } from './types'; +import t from './l10n'; import { EditorMenuCommandManager, FileMenuCommandManager } from './manager/menuManager'; -import SettingTabModal from './ui/settingTabModal'; -import RibbonManager from './manager/ribbonManager'; -import TitleBarManager from './manager/titleBarManager'; -import StatusBarManager from './manager/statusBarManager'; import PageHeaderManager from './manager/pageHeaderManager'; +import RibbonManager from './manager/ribbonManager'; +import StatusBarManager from './manager/statusBarManager'; +import TitleBarManager from './manager/titleBarManager'; +import { CommanderSettings, Macro } from './types'; import MacroModal from './ui/macroModal'; +import CommanderSettingTab from './ui/settingTab'; +import SettingTabModal from './ui/settingTabModal'; -import "./styles.scss"; import 'beautiful-react-diagrams/styles.css'; +import "./styles.scss"; export default class CommanderPlugin extends Plugin { public settings: CommanderSettings; @@ -28,20 +29,6 @@ export default class CommanderPlugin extends Plugin { public async onload(): Promise { await this.loadSettings(); - this.addSettingTab(new CommanderSettingTab(this)); - - this.addCommand({ - name: "Open Commander Settings", - id: "open-commander-settings", - callback: () => new SettingTabModal(this).open(), - }); - - this.addCommand({ - name: "Open Macro Builder", - id: "open-macro-builder", - callback: () => new MacroModal(this).open(), - }); - this.manager = { editorMenu: new EditorMenuCommandManager(this, this.settings.editorMenu), fileMenu: new FileMenuCommandManager(this, this.settings.fileMenu), @@ -52,6 +39,20 @@ export default class CommanderPlugin extends Plugin { pageHeader: new PageHeaderManager(this, this.settings.pageHeader), }; + this.addSettingTab(new CommanderSettingTab(this)); + + this.addCommand({ + name: t("Open Commander Settings"), + id: "open-commander-settings", + callback: () => new SettingTabModal(this).open(), + }); + + this.addCommand({ + name: t("Open Macro Builder"), + id: "open-macro-builder", + callback: () => new MacroModal(this).open(), + }); + this.registerEvent( app.workspace.on('editor-menu', this.manager.editorMenu.applyEditorMenuCommands(this)), ); diff --git a/src/manager/_commandManager.ts b/src/manager/_commandManager.ts index 233c3ee..d5a55ab 100644 --- a/src/manager/_commandManager.ts +++ b/src/manager/_commandManager.ts @@ -16,6 +16,5 @@ export default abstract class CommandManager { // eslint-disable-next-line no-unused-vars public abstract removeCommand(pair: CommandIconPair): Promise | void; - // eslint-disable-nextline no-unused-vars public abstract reorder(): Promise | void; } diff --git a/src/manager/menuManager.ts b/src/manager/menuManager.ts index 13d408b..303c180 100644 --- a/src/manager/menuManager.ts +++ b/src/manager/menuManager.ts @@ -6,6 +6,7 @@ import ConfirmDeleteModal from "../ui/confirmDeleteModal"; import { chooseNewCommand, getCommandFromId, isModeActive } from "../util"; import ChooseCustomNameModal from "src/ui/chooseCustomNameModal"; import ChooseIconModal from "src/ui/chooseIconModal"; +import t from "src/l10n"; abstract class Base extends CommandManager { public async addCommand(pair: CommandIconPair): Promise { @@ -39,7 +40,7 @@ abstract class Base extends CommandManager { new Menu() .addItem(item => { item - .setTitle("Change Icon") + .setTitle(t("Change Icon")) .setIcon("box") .onClick(async () => { const newIcon = await (new ChooseIconModal(plugin)).awaitSelection(); @@ -51,7 +52,7 @@ abstract class Base extends CommandManager { }) .addItem(item => { item - .setTitle("Rename") + .setTitle(t("Rename")) .setIcon("text-cursor-input") .onClick(async () => { const newName = await (new ChooseCustomNameModal(cmdPair.name)).awaitSelection(); @@ -64,7 +65,7 @@ abstract class Base extends CommandManager { .addItem(item => { item.dom.addClass("is-warning"); item - .setTitle("Delete") + .setTitle(t("Delete")) .setIcon("lucide-trash") .onClick(async () => { if (!plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(plugin).didChooseRemove())) { @@ -87,7 +88,7 @@ abstract class Base extends CommandManager { }; const setRemovable = (): void => { optionEl.style.display = "block"; - item.setTitle("Delete").setIcon("trash").onClick(async (event) => { + item.setTitle(t("Delete")).setIcon("trash").onClick(async (event) => { event.preventDefault(); event.stopImmediatePropagation(); if (!plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(plugin).didChooseRemove())) { @@ -125,7 +126,7 @@ abstract class Base extends CommandManager { if (plugin.settings.showAddCommand) { menu.addItem((item: MenuItem) => { item - .setTitle("Add command") + .setTitle(t("Add command")) .setIcon("plus-circle") .setSection("cmdr") .onClick(async () => { diff --git a/src/manager/pageHeaderManager.ts b/src/manager/pageHeaderManager.ts index 6830a59..9eea5a9 100644 --- a/src/manager/pageHeaderManager.ts +++ b/src/manager/pageHeaderManager.ts @@ -1,4 +1,5 @@ import { Menu, setIcon } from "obsidian"; +import t from "src/l10n"; import CommanderPlugin from "src/main"; import { CommandIconPair } from "src/types"; import ChooseCustomNameModal from "src/ui/chooseCustomNameModal"; @@ -8,7 +9,7 @@ import { chooseNewCommand, isModeActive } from "src/util"; import CommandManager from "./_commandManager"; export default class PageHeaderManager extends CommandManager { - private addBtn = createDiv({ cls: "cmdr view-action cmdr-adder", attr: { "aria-label": "Add new" } }); + private addBtn = createDiv({ cls: "cmdr view-action cmdr-adder", attr: { "aria-label": t("Add new") } }); public constructor(plugin: CommanderPlugin, pairArray: CommandIconPair[]) { super(plugin, pairArray); @@ -23,12 +24,11 @@ export default class PageHeaderManager extends CommandManager { classes: string[], tag: 'a' | 'div' = 'a' ): HTMLElement { - const tooltip = name; const buttonClasses = classes.concat([id]); const buttonIcon = createEl(tag, { cls: buttonClasses, - attr: { 'aria-label-position': 'bottom', 'aria-label': tooltip }, + attr: { 'aria-label-position': 'bottom', 'aria-label': name }, }); setIcon(buttonIcon, icon, iconSize); return buttonIcon; @@ -57,7 +57,7 @@ export default class PageHeaderManager extends CommandManager { new Menu() .addItem(item => { item - .setTitle("Add Command") + .setTitle(t("Add Command")) .setIcon("command") .onClick(async () => { const pair = await chooseNewCommand(this.plugin); @@ -67,7 +67,7 @@ export default class PageHeaderManager extends CommandManager { .addSeparator() .addItem(item => { item - .setTitle("Change Icon") + .setTitle(t("Change Icon")) .setIcon("box") .onClick(async () => { const newIcon = await (new ChooseIconModal(this.plugin)).awaitSelection(); @@ -80,7 +80,7 @@ export default class PageHeaderManager extends CommandManager { }) .addItem(item => { item - .setTitle("Rename") + .setTitle(t("Rename")) .setIcon("text-cursor-input") .onClick(async () => { const newName = await (new ChooseCustomNameModal(pair.name)).awaitSelection(); @@ -94,7 +94,7 @@ export default class PageHeaderManager extends CommandManager { .addItem(item => { item.dom.addClass("is-warning"); item - .setTitle("Delete") + .setTitle(t("Delete")) .setIcon("lucide-trash") .onClick(async () => { if (!this.plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(this.plugin).didChooseRemove())) { diff --git a/src/manager/ribbonManager.ts b/src/manager/ribbonManager.ts index 9b3b731..0a50f58 100644 --- a/src/manager/ribbonManager.ts +++ b/src/manager/ribbonManager.ts @@ -7,6 +7,7 @@ import ConfirmDeleteModal from "../ui/confirmDeleteModal"; import { chooseNewCommand, getCommandFromId } from "../util"; import ChooseCustomNameModal from "src/ui/chooseCustomNameModal"; import ChooseIconModal from "src/ui/chooseIconModal"; +import t from 'src/l10n'; export default class RibbonManager extends CommandManager { private actions: { @@ -27,7 +28,7 @@ export default class RibbonManager extends CommandManager { if (this.side === "right") { this.addActionContainer(); } - this.addBtn = createDiv({ cls: "cmdr side-dock-ribbon-action cmdr-adder", attr: { "aria-label-position": side === "left" ? "right" : "left", "aria-label": "Add new" } }); + this.addBtn = createDiv({ cls: "cmdr side-dock-ribbon-action cmdr-adder", attr: { "aria-label-position": side === "left" ? "right" : "left", "aria-label": t("Add new") } }); this.init(); }); @@ -39,7 +40,7 @@ export default class RibbonManager extends CommandManager { if (cmd) { this.addAction(pair.name ?? cmd.name, pair.icon, pair, () => app.commands.executeCommandById(pair.id)); } else { - this.addAction(`This Command seems to have been removed. ${pair.name ? "(" + pair.name + ")" : ""}`, "trash", pair, (event: MouseEvent) => { + this.addAction(t("This Command seems to have been removed. {{command_name}}").replace("{{command_name}}", pair.name || ""), "trash", pair, (event: MouseEvent) => { this.removeAction((event.target as HTMLElement).getAttribute("aria-label") + "trash"); }); } @@ -119,7 +120,7 @@ export default class RibbonManager extends CommandManager { new Menu() .addItem(item => { item - .setTitle("Add Command") + .setTitle(t("Add Command")) .setIcon("command") .onClick(async () => { const pair = await chooseNewCommand(this.plugin); @@ -129,7 +130,7 @@ export default class RibbonManager extends CommandManager { .addSeparator() .addItem(item => { item - .setTitle("Change Icon") + .setTitle(t("Change Icon")) .setIcon("box") .onClick(async () => { const newIcon = await (new ChooseIconModal(this.plugin)).awaitSelection(); @@ -142,7 +143,7 @@ export default class RibbonManager extends CommandManager { }) .addItem(item => { item - .setTitle("Rename") + .setTitle(t("Rename")) .setIcon("text-cursor-input") .onClick(async () => { const newName = await (new ChooseCustomNameModal(pair.name)).awaitSelection(); @@ -156,7 +157,7 @@ export default class RibbonManager extends CommandManager { .addItem(item => { item.dom.addClass("is-warning"); item - .setTitle("Delete") + .setTitle(t("Delete")) .setIcon("lucide-trash") .onClick(async () => { if (!this.plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(this.plugin).didChooseRemove())) { diff --git a/src/manager/statusBarManager.ts b/src/manager/statusBarManager.ts index fdf2ec8..8d06fe3 100644 --- a/src/manager/statusBarManager.ts +++ b/src/manager/statusBarManager.ts @@ -1,4 +1,5 @@ import { Menu, setIcon } from "obsidian"; +import t from "src/l10n"; import CommanderPlugin from "src/main"; import { CommandIconPair } from "src/types"; import ChooseCustomNameModal from "src/ui/chooseCustomNameModal"; @@ -10,7 +11,7 @@ import CommandManager from "./_commandManager"; export default class StatusBarManager extends CommandManager { private container: HTMLElement; private readonly actions = new Map(); - private addBtn = createDiv({ cls: "cmdr status-bar-item cmdr-adder", attr: { "aria-label-position": "top", "aria-label": "Add new" } }); + private addBtn = createDiv({ cls: "cmdr status-bar-item cmdr-adder", attr: { "aria-label-position": "top", "aria-label": t("Add new") } }); public constructor(plugin: CommanderPlugin, pairs: CommandIconPair[]) { super(plugin, pairs); @@ -41,7 +42,7 @@ export default class StatusBarManager extends CommandManager { new Menu() .addItem(item => { item - .setTitle("Add Command") + .setTitle(t("Add Command")) .setIcon("command") .onClick(async () => { const pair = await chooseNewCommand(this.plugin); @@ -81,7 +82,7 @@ export default class StatusBarManager extends CommandManager { } private addAction(pair: CommandIconPair): void { - const btn = createDiv({ cls: "cmdr status-bar-item", attr: { "aria-label-position": "top", "aria-label": pair.name } }); + const btn = createDiv({ cls: "cmdr status-bar-item clickable-icon", attr: { "aria-label-position": "top", "aria-label": pair.name, "style": "margin: 0" } }); this.actions.set(pair, btn); let isRemovable = false; @@ -118,7 +119,7 @@ export default class StatusBarManager extends CommandManager { new Menu() .addItem(item => { item - .setTitle("Add Command") + .setTitle(t("Add Command")) .setIcon("command") .onClick(async () => { const pair = await chooseNewCommand(this.plugin); @@ -128,7 +129,7 @@ export default class StatusBarManager extends CommandManager { .addSeparator() .addItem(item => { item - .setTitle("Change Icon") + .setTitle(t("Change Icon")) .setIcon("box") .onClick(async () => { const newIcon = await (new ChooseIconModal(this.plugin)).awaitSelection(); @@ -141,7 +142,7 @@ export default class StatusBarManager extends CommandManager { }) .addItem(item => { item - .setTitle("Rename") + .setTitle(t("Rename")) .setIcon("text-cursor-input") .onClick(async () => { const newName = await (new ChooseCustomNameModal(pair.name)).awaitSelection(); @@ -155,7 +156,7 @@ export default class StatusBarManager extends CommandManager { .addItem(item => { item.dom.addClass("is-warning"); item - .setTitle("Delete") + .setTitle(t("Delete")) .setIcon("lucide-trash") .onClick(async () => { if (!this.plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(this.plugin).didChooseRemove())) { diff --git a/src/manager/titleBarManager.ts b/src/manager/titleBarManager.ts index 0e7a2ad..039eeba 100644 --- a/src/manager/titleBarManager.ts +++ b/src/manager/titleBarManager.ts @@ -1,4 +1,5 @@ import { Menu, setIcon } from "obsidian"; +import t from "src/l10n"; import CommanderPlugin from "src/main"; import { CommandIconPair } from "src/types"; import ChooseCustomNameModal from "src/ui/chooseCustomNameModal"; @@ -10,7 +11,7 @@ import CommandManager from "./_commandManager"; export default class TitleBarManager extends CommandManager { private container: HTMLElement; private readonly actions = new Map(); - private addBtn = createDiv({ cls: "cmdr titlebar-button cmdr-adder", attr: { "aria-label": "Add new" } }); + private addBtn = createDiv({ cls: "cmdr titlebar-button cmdr-adder", attr: { "aria-label": t("Add new") } }); public constructor(plugin: CommanderPlugin, pairArray: CommandIconPair[]) { super(plugin, pairArray); @@ -95,7 +96,7 @@ export default class TitleBarManager extends CommandManager { new Menu() .addItem(item => { item - .setTitle("Add Command") + .setTitle(t("Add Command")) .setIcon("command") .onClick(async () => { const pair = await chooseNewCommand(this.plugin); @@ -105,7 +106,7 @@ export default class TitleBarManager extends CommandManager { .addSeparator() .addItem(item => { item - .setTitle("Change Icon") + .setTitle(t("Change Icon")) .setIcon("box") .onClick(async () => { const newIcon = await (new ChooseIconModal(this.plugin)).awaitSelection(); @@ -118,7 +119,7 @@ export default class TitleBarManager extends CommandManager { }) .addItem(item => { item - .setTitle("Rename") + .setTitle(t("Rename")) .setIcon("text-cursor-input") .onClick(async () => { const newName = await (new ChooseCustomNameModal(pair.name)).awaitSelection(); @@ -132,7 +133,7 @@ export default class TitleBarManager extends CommandManager { .addItem(item => { item.dom.addClass("is-warning"); item - .setTitle("Delete") + .setTitle(t("Delete")) .setIcon("lucide-trash") .onClick(async () => { if (!this.plugin.settings.confirmDeletion || (await new ConfirmDeleteModal(this.plugin).didChooseRemove())) { diff --git a/src/styles.scss b/src/styles.scss index 00f7b80..c0ff63e 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -74,6 +74,7 @@ .cmdr-add-new-wrapper { width: 100%; margin-top: 12px; + margin-bottom: 2rem; display: flex; justify-content: center; diff --git a/src/ui/addCommandModal.ts b/src/ui/addCommandModal.ts index f0000fd..03211a5 100644 --- a/src/ui/addCommandModal.ts +++ b/src/ui/addCommandModal.ts @@ -1,33 +1,34 @@ import { Command, setIcon, FuzzySuggestModal, FuzzyMatch } from "obsidian"; +import t from "src/l10n"; import CommanderPlugin from "src/main"; export default class AddCommandModal extends FuzzySuggestModal { - plugin: CommanderPlugin; - commands: Command[]; + private plugin: CommanderPlugin; + private commands: Command[]; - constructor(plugin: CommanderPlugin) { + public constructor(plugin: CommanderPlugin) { super(app); this.plugin = plugin; this.commands = Object.values(app.commands.commands); - this.setPlaceholder("Choose a Command to add"); + this.setPlaceholder(t("Choose a Command to add")); this.setInstructions([ { command: "↑↓", - purpose: "to navigate" + purpose: t("to navigate") }, { command: "↵", - purpose: "to choose an icon" + purpose: t("to choose an icon") }, { command: "esc", - purpose: "to cancel" + purpose: t("to cancel") }, ]); } - async awaitSelection(): Promise { + public async awaitSelection(): Promise { this.open(); return new Promise((resolve, reject) => { this.onChooseItem = (item): void => resolve(item); @@ -36,7 +37,7 @@ export default class AddCommandModal extends FuzzySuggestModal { }); } - renderSuggestion(item: FuzzyMatch, el: HTMLElement): void { + public renderSuggestion(item: FuzzyMatch, el: HTMLElement): void { super.renderSuggestion(item, el); //Append the icon if available @@ -45,15 +46,15 @@ export default class AddCommandModal extends FuzzySuggestModal { } } - getItems(): Command[] { + public getItems(): Command[] { return this.commands; } - getItemText(item: Command): string { + public getItemText(item: Command): string { return item.name; } // This will be overriden anyway, but typescript complains if it's not declared // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-empty-function - onChooseItem(item: Command, evt: MouseEvent | KeyboardEvent): void { } + public onChooseItem(item: Command, evt: MouseEvent | KeyboardEvent): void { } } diff --git a/src/ui/chooseCustomNameModal.ts b/src/ui/chooseCustomNameModal.ts index cec5493..fa28d39 100644 --- a/src/ui/chooseCustomNameModal.ts +++ b/src/ui/chooseCustomNameModal.ts @@ -1,4 +1,5 @@ import { SuggestModal } from "obsidian"; +import t from "src/l10n"; export default class ChooseCustomNameModal extends SuggestModal { @@ -6,21 +7,21 @@ export default class ChooseCustomNameModal extends SuggestModal { // eslint-disable-next-line no-unused-vars public constructor(private defaultName: string) { super(app); - this.setPlaceholder("Use a custom name"); + this.setPlaceholder(t("Use a custom name")); this.resultContainerEl.style.display = "none"; this.setInstructions([ { command: "", - purpose: "Choose a custom Name for your new Command" + purpose: t("Choose a custom Name for your new Command") }, { command: "↵", - purpose: "to save" + purpose: t("to save") }, { command: "esc", - purpose: "to cancel" + purpose: t("to cancel") }, ]); } diff --git a/src/ui/chooseIconModal.ts b/src/ui/chooseIconModal.ts index ba73765..1cfa1e7 100644 --- a/src/ui/chooseIconModal.ts +++ b/src/ui/chooseIconModal.ts @@ -1,6 +1,7 @@ import { ICON_LIST } from './../constants'; import { setIcon, FuzzySuggestModal, FuzzyMatch } from "obsidian"; import CommanderPlugin from "src/main"; +import t from 'src/l10n'; export default class ChooseIconModal extends FuzzySuggestModal { private plugin: CommanderPlugin; @@ -8,20 +9,20 @@ export default class ChooseIconModal extends FuzzySuggestModal { public constructor(plugin: CommanderPlugin) { super(app); this.plugin = plugin; - this.setPlaceholder("Choose a Icon for your new Command"); + this.setPlaceholder(t("Choose a Icon for your new Command")); this.setInstructions([ { command: "↑↓", - purpose: "to navigate" + purpose: t("to navigate") }, { command: "↵", - purpose: "to choose a custom name" + purpose: t("to choose a custom icon") }, { command: "esc", - purpose: "to cancel" + purpose: t("to cancel") }, ]); } diff --git a/src/ui/components/ChangeableText.tsx b/src/ui/components/ChangeableText.tsx index e5cb9ff..6d1188c 100644 --- a/src/ui/components/ChangeableText.tsx +++ b/src/ui/components/ChangeableText.tsx @@ -1,5 +1,6 @@ import { h } from "preact"; import { useState, useRef, useEffect, Ref } from "preact/hooks"; +import t from "src/l10n"; interface Props { value: string; @@ -34,7 +35,7 @@ export default function ChangeableText({ value, handleChange }: Props): h.JSX.El ref={el} /> ) : ( - setShowInput(true)} aria-label="Double click to rename"> + setShowInput(true)} aria-label={t("Double click to rename")}> {value} ) diff --git a/src/ui/components/commandComponent.tsx b/src/ui/components/commandComponent.tsx index 5376f9a..0487621 100644 --- a/src/ui/components/commandComponent.tsx +++ b/src/ui/components/commandComponent.tsx @@ -3,6 +3,7 @@ import { CommandIconPair } from "src/types"; import { getCommandFromId } from "src/util"; import ChangeableText from "./ChangeableText"; import { ObsidianIcon } from "src/util"; +import t from "src/l10n"; interface CommandViewerProps { pair: CommandIconPair; @@ -28,25 +29,25 @@ export default function CommandComponent({ pair, handleRemove, handleDown, handl const isChecked = cmd.hasOwnProperty("checkCallback") || cmd.hasOwnProperty("editorCheckCallback"); const modeIcon = getModeIcon(pair.mode); - const modeName = pair.mode.match(/desktop|mobile|any/) ? pair.mode[0].toUpperCase() + pair.mode.substring(1) : `This device`; + const modeName = pair.mode.match(/desktop|mobile|any/) ? pair.mode[0].toUpperCase() + pair.mode.substring(1) : t("This device"); return (
- +
{/* @ts-ignore */} handleRename(target?.value)} value={pair.name} /> {pair.name !== cmd.name && ({cmd.name})}
-
Added by {isInternal ? "Obsidian" : owningPlugin.name}. {isChecked ? "Warning: This is a checked Command, meaning it might not run under every circumstance." : ""}
+
{t("Added by {{plugin_name}}.".replace("{{plugin_name}}", isInternal ? "Obsidian" : owningPlugin.name))} {isChecked ? t("Warning: This is a checked Command, meaning it might not run under every circumstance.") : ""}
- - - -
diff --git a/src/ui/components/commandViewerComponent.tsx b/src/ui/components/commandViewerComponent.tsx index ba9f4e6..1884f82 100644 --- a/src/ui/components/commandViewerComponent.tsx +++ b/src/ui/components/commandViewerComponent.tsx @@ -7,7 +7,7 @@ import { chooseNewCommand, isModeActive } from "src/util"; import { arrayMoveMutable } from "array-move"; import ChooseIconModal from "../chooseIconModal"; import ConfirmDeleteModal from "../confirmDeleteModal"; -import { CommandIconPair } from "src/types"; +import t from "src/l10n"; // eslint-disable-next-line @typescript-eslint/no-non-null-assertion export const ManagerContext = createContext(null!); @@ -56,12 +56,12 @@ export default function CommandViewer({ manager, plugin }: CommandViewerProps): />; } })} - {!manager.pairs.some((pre) => isModeActive(pre.mode)) &&
+ {!manager.pairs.some((pre) => isModeActive(pre.mode) || pre.mode.match(/mobile|desktop/)) &&
{/* This isn't really dangerous, as the svg is inserted at build time and no other data can be passed to it */}
-

No commands here!

- Would you like to add one now? +

{t("No commands here!")}

+ {t("Would you like to add one now?")}
}
@@ -70,10 +70,11 @@ export default function CommandViewer({ manager, plugin }: CommandViewerProps): onClick={async (): Promise => { const pair = await chooseNewCommand(plugin); await manager.addCommand(pair); + manager.reorder(); this.forceUpdate(); }} > - Add command + {t("Add command")}
diff --git a/src/ui/components/confirmDeleteComponent.tsx b/src/ui/components/confirmDeleteComponent.tsx index 4496b8f..ad75ee5 100644 --- a/src/ui/components/confirmDeleteComponent.tsx +++ b/src/ui/components/confirmDeleteComponent.tsx @@ -1,10 +1,11 @@ import { Fragment, h } from "preact"; +import t from "src/l10n"; import ConfirmDeleteModal from "../confirmDeleteModal"; export function confirmDeleteComponent({ modal }: { modal: ConfirmDeleteModal; }): h.JSX.Element { return ( -

Are you sure you want to delete the Command?

+

{t("Are you sure you want to delete the Command?")}

diff --git a/src/ui/components/settingTabComponent.tsx b/src/ui/components/settingTabComponent.tsx index f01f525..c5cbb27 100644 --- a/src/ui/components/settingTabComponent.tsx +++ b/src/ui/components/settingTabComponent.tsx @@ -1,15 +1,15 @@ -import { setIcon } from "obsidian"; +import confetti from "canvas-confetti"; +import { Notice } from "obsidian"; import { Fragment, h } from "preact"; -import { useEffect, useRef, useState } from "preact/hooks"; +import { useEffect, useState } from "preact/hooks"; +import t from "src/l10n"; +import { ObsidianIcon } from "src/util"; import CommanderPlugin from "../../main"; import CommandViewer from "./commandViewerComponent"; import { ToggleComponent } from "./settingComponent"; -import confetti from "canvas-confetti"; export default function settingTabComponent({ plugin, mobileMode }: { plugin: CommanderPlugin; mobileMode: boolean; }): h.JSX.Element { const [activeTab, setActiveTab] = useState(0); - const coffeeIcon = useRef(null); - const tabToNextTab = ({ key, shiftKey }: KeyboardEvent): void => { if (shiftKey && key === "Tab") { @@ -28,18 +28,13 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co return () => removeEventListener("keydown", tabToNextTab); }); - useEffect(() => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - setIcon(coffeeIcon.current!, "coffee", 24); - }, []); - const tabs = [ { - name: "General", + name: t("General"), tab: => { plugin.settings.confirmDeletion = !value; @@ -47,16 +42,29 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co }} /> => { plugin.settings.showAddCommand = !value; + + if (!plugin.settings.showAddCommand) { + const elements = document.getElementsByClassName("cmdr-adder"); + const x: Element[] = []; + for (let i = 0; i < elements.length; i++) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + x.push(elements.item(i)!); + } + x.forEach((pre) => pre.remove()); + } else { + new Notice(t("Please restart Obsidian for these changes to take effect.")); + } + await plugin.saveSettings(); }} /> => { plugin.settings.debug = !value; await plugin.saveSettings(); @@ -64,31 +72,31 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co }, { - name: "Editor Menu", + name: t("Editor Menu"), tab: }, { - name: "File Menu", + name: t("File Menu"), tab: }, { - name: "Left Ribbon", + name: t("Left Ribbon"), tab: }, { - name: "Right Ribbon", + name: t("Right Ribbon"), tab: }, { - name: "Titlebar", + name: t("Titlebar"), tab: }, { - name: "Statusbar", + name: t("Statusbar"), tab: }, { - name: "Page Header", + name: t("Page Header"), tab: } ]; @@ -97,13 +105,14 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co

{plugin.manifest.name}

-
=> { + onClick={async ({ target }): Promise => { const myCanvas = document.createElement('canvas'); document.body.appendChild(myCanvas); myCanvas.style.position = "fixed"; @@ -120,10 +129,9 @@ export default function settingTabComponent({ plugin, mobileMode }: { plugin: Co resize: true, useWorker: true }); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const pos = coffeeIcon.current!.getBoundingClientRect(); + const pos = (target as HTMLDivElement).getBoundingClientRect(); - setTimeout(() => location.replace("https://buymeacoffee.com/phibr0"), 800); + setTimeout(() => location.replace("https://buymeacoffee.com/phibr0"), Math.random() * 800 + 500); await myConfetti({ particleCount: 150, diff --git a/src/ui/confirmDeleteModal.ts b/src/ui/confirmDeleteModal.ts index 414e1b4..429be84 100644 --- a/src/ui/confirmDeleteModal.ts +++ b/src/ui/confirmDeleteModal.ts @@ -1,5 +1,6 @@ import { Modal } from "obsidian"; import { h, render, VNode } from "preact"; +import t from "src/l10n"; import CommanderPlugin from "src/main"; import { confirmDeleteComponent } from "./components/confirmDeleteComponent"; @@ -13,7 +14,7 @@ export default class ConfirmDeleteModal extends Modal { } public async onOpen(): Promise { - this.titleEl.innerText = "Remove Command"; + this.titleEl.innerText = t("Remove Command"); this.containerEl.style.zIndex = "99"; this.reactComponent = h(confirmDeleteComponent, { modal: this }); render(this.reactComponent, this.contentEl); diff --git a/src/util.tsx b/src/util.tsx index f56c81f..3f644b5 100644 --- a/src/util.tsx +++ b/src/util.tsx @@ -5,7 +5,7 @@ import ChooseIconModal from './ui/chooseIconModal'; import { Command, setIcon } from 'obsidian'; import ChooseCustomNameModal from './ui/chooseCustomNameModal'; import { ComponentProps, h } from 'preact'; -import { useRef, useEffect } from 'preact/hooks'; +import { useRef, useLayoutEffect } from 'preact/hooks'; /** * It creates a modal, waits for the user to select a command, and then creates another modal to wait @@ -45,7 +45,7 @@ interface ObsidianIconProps extends ComponentProps<"div"> { export function ObsidianIcon({ icon, size, ...props }: ObsidianIconProps): h.JSX.Element { const iconEl = useRef(null); - useEffect(() => { + useLayoutEffect(() => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion setIcon(iconEl.current!, icon, size); }, [icon, size]); diff --git a/tsconfig.json b/tsconfig.json index 2d9174e..fb2faa6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,8 @@ "jsx": "preserve", "jsxFactory": "h", "jsxFragmentFactory": "Fragment", - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true }, "include": ["**/*.ts", "**/*.tsx"] }