diff --git a/main.js b/main.js
index f2d9a18..7b0c17d 100644
--- a/main.js
+++ b/main.js
@@ -12,15 +12,135 @@
* 7. 设置快捷键后即时检测冲突,冲突时显示警告 + 跳转入口
*
* 替代 Templater 的 codepython.md 模板,无需 Templater 依赖。
+ *
+ * 双语 UI(中文 / 英文),可在设置面板顶部切换界面语言。
*/
const { Plugin, Notice, PluginSettingTab, Setting, Modal } = require("obsidian");
const PLUGIN_ID = "quick-codeblock";
+// ================================================================
+// i18n (Bilingual support) 中英双语
+// ================================================================
+
+const I18N = {
+ zh: {
+ // Commands
+ cmd_insert_default: "插入代码块({lang})",
+ cmd_insert_pick: "插入代码块(选择语言)",
+ cmd_insert_lang: "插入代码块({lang})",
+ // Modal
+ modal_pick_title: "选择代码块语言",
+ // Settings - title
+ setting_title: "代码块快捷插入",
+ // Settings - language switcher
+ setting_language: "界面语言",
+ setting_language_desc: "选择设置面板的显示语言",
+ lang_zh: "中文",
+ lang_en: "English",
+ // Settings - basic
+ setting_default_lang: "默认语言",
+ setting_default_lang_desc: "主命令「插入代码块」使用的语言",
+ setting_lang_list: "语言列表",
+ setting_lang_list_desc: "每行一个语言,会为每个语言注册独立命令。修改后重新打开设置面板可刷新下方选项。",
+ setting_keep_indent: "保留选中内容缩进",
+ setting_keep_indent_desc: "选中文本包裹成代码块时,是否保留原有缩进",
+ // Settings - hotkeys section
+ sec_hotkeys: "快捷键设置",
+ hotkeys_desc: "为需要的语言配置快捷键。点击输入框后按下组合键即可设置,按 Backspace 或 Esc 清除。设置后自动检测冲突。",
+ btn_add_hotkey: "+ 添加快捷键配置",
+ hotkey_placeholder: "点击设置…",
+ // Settings - more hotkeys
+ setting_more_hotkeys: "更多快捷键设置",
+ setting_more_hotkeys_desc: "打开 Obsidian 系统的快捷键设置页面,可查看 / 修改所有命令的快捷键",
+ btn_open_hotkeys: "打开 Obsidian 快捷键设置",
+ notice_hotkeys_opened: "已打开快捷键设置,可在搜索框输入命令名查找",
+ notice_hotkeys_failed: "无法自动打开,请手动进入:设置 → 快捷键",
+ // Settings - tips
+ tip_title: "使用方法",
+ tip_1: "1. Ctrl+P 打开命令面板,搜索「插入代码块」",
+ tip_2: "2. 无选中文本时:插入空代码块,光标自动定位到块内",
+ tip_3: "3. 有选中文本时:用 ```lang 包裹选中的内容",
+ tip_4: "4. 在上方「快捷键设置」区域,点击「+ 添加」为需要的语言配置快捷键",
+ tip_5: "5. 修改语言列表后,关闭再打开设置面板即可刷新选项",
+ // Hotkey config item
+ conflict_label: "⚠️ 冲突:",
+ conflict_link: "前往修改 ›",
+ no_conflict: "✓ 无冲突",
+ btn_delete_config: "删除此配置",
+ notice_cleared: "已清除:{lang} 快捷键",
+ notice_set_failed: "设置失败:{msg}",
+ notice_conflict: "⚠️ 「{hotkey}」与「{name}」冲突,点击警告中的「前往修改」处理",
+ notice_set: "已设置:{lang} → {hotkey}",
+ notice_search_conflict: "请在快捷键设置中搜索「{name}」查看并修改",
+ // Settings - reset
+ setting_reset: "恢复默认设置",
+ setting_reset_desc: "将所有设置恢复为默认值(界面语言选择会被保留)",
+ btn_reset: "重置",
+ notice_reset: "设置已恢复为默认值",
+ },
+ en: {
+ // Commands
+ cmd_insert_default: "Insert code block ({lang})",
+ cmd_insert_pick: "Insert code block (pick language)",
+ cmd_insert_lang: "Insert code block ({lang})",
+ // Modal
+ modal_pick_title: "Choose code block language",
+ // Settings - title
+ setting_title: "Quick CodeBlock",
+ // Settings - language switcher
+ setting_language: "UI Language",
+ setting_language_desc: "Select the display language for settings panel",
+ lang_zh: "中文",
+ lang_en: "English",
+ // Settings - basic
+ setting_default_lang: "Default language",
+ setting_default_lang_desc: "Language used by the main \"Insert code block\" command",
+ setting_lang_list: "Language list",
+ setting_lang_list_desc: "One language per line. An independent command is registered for each. Reopen the settings panel after editing to refresh options below.",
+ setting_keep_indent: "Keep selection indentation",
+ setting_keep_indent_desc: "Whether to preserve original indentation when wrapping selected text into a code block",
+ // Settings - hotkeys section
+ sec_hotkeys: "Hotkey Settings",
+ hotkeys_desc: "Configure hotkeys for the languages you need. Click the input box then press a key combo to set, press Backspace or Esc to clear. Conflicts are detected automatically.",
+ btn_add_hotkey: "+ Add hotkey config",
+ hotkey_placeholder: "Click to set…",
+ // Settings - more hotkeys
+ setting_more_hotkeys: "More hotkey settings",
+ setting_more_hotkeys_desc: "Open Obsidian's built-in hotkey settings to view / modify hotkeys for all commands",
+ btn_open_hotkeys: "Open Obsidian hotkey settings",
+ notice_hotkeys_opened: "Hotkey settings opened. Type a command name in the search box to find it.",
+ notice_hotkeys_failed: "Unable to open automatically. Please go to: Settings → Hotkeys",
+ // Settings - tips
+ tip_title: "Usage",
+ tip_1: "1. Press Ctrl+P to open the command palette and search for \"Insert code block\"",
+ tip_2: "2. With no selection: inserts an empty code block and places the cursor inside",
+ tip_3: "3. With a selection: wraps the selected text with ```lang",
+ tip_4: "4. In the \"Hotkey Settings\" area above, click \"+ Add\" to configure hotkeys for languages you need",
+ tip_5: "5. After editing the language list, close and reopen the settings panel to refresh options",
+ // Hotkey config item
+ conflict_label: "⚠️ Conflict: ",
+ conflict_link: "Fix ›",
+ no_conflict: "✓ No conflict",
+ btn_delete_config: "Delete this config",
+ notice_cleared: "Cleared: {lang} hotkey",
+ notice_set_failed: "Failed to set: {msg}",
+ notice_conflict: "⚠️ \"{hotkey}\" conflicts with \"{name}\". Click \"Fix\" in the warning to resolve.",
+ notice_set: "Set: {lang} → {hotkey}",
+ notice_search_conflict: 'Search "{name}" in hotkey settings to view and modify it',
+ // Settings - reset
+ setting_reset: "Reset to defaults",
+ setting_reset_desc: "Restore all settings to default values (UI language choice is preserved)",
+ btn_reset: "Reset",
+ notice_reset: "Settings reset to defaults",
+ },
+};
+
const DEFAULT_SETTINGS = {
defaultLanguage: "python",
languages: "python\njavascript\nbash\nshell\nsql\njson\nyaml\ngo\nrust\njava\nhtml\ncss",
keepIndent: true,
+ language: "zh", // "zh" or "en"
// 快捷键配置列表:用户主动添加,默认只有一项(默认语言)
// 每项: { lang: "python", hotkey: { modifiers, key } | null }
hotkeyConfigs: [{ lang: "python", hotkey: null }],
@@ -105,6 +225,19 @@ function openHotkeysSettings(app) {
// 插件主类
// ================================================================
class QuickCodeBlockPlugin extends Plugin {
+ // i18n helper —— 支持可选的 {placeholder} 参数替换
+ t(key, params) {
+ const lang = this.settings ? this.settings.language : "zh";
+ const dict = I18N[lang] || I18N.zh;
+ let text = dict[key] || key;
+ if (params) {
+ for (const k of Object.keys(params)) {
+ text = text.replace(new RegExp("\\{" + k + "\\}", "g"), params[k]);
+ }
+ }
+ return text;
+ }
+
async onload() {
await this.loadSettings();
this.registerCommands();
@@ -127,14 +260,14 @@ class QuickCodeBlockPlugin extends Plugin {
// 1. 主命令
this.addCommand({
id: "insert-codeblock-default",
- name: `插入代码块(${def})`,
+ name: this.t("cmd_insert_default", { lang: def }),
editorCallback: (editor) => this.insertCodeBlock(editor, def),
});
// 2. 选择语言命令
this.addCommand({
id: "insert-codeblock-pick",
- name: "插入代码块(选择语言)",
+ name: this.t("cmd_insert_pick"),
editorCallback: (editor) => {
const langs = this.getLanguages();
new LanguagePickerModal(this.app, langs, (lang) => {
@@ -147,7 +280,7 @@ class QuickCodeBlockPlugin extends Plugin {
for (const lang of this.getLanguages()) {
this.addCommand({
id: `insert-codeblock-${lang}`,
- name: `插入代码块(${lang})`,
+ name: this.t("cmd_insert_lang", { lang: lang }),
editorCallback: (editor) => this.insertCodeBlock(editor, lang),
});
}
@@ -235,7 +368,7 @@ class LanguagePickerModal extends Modal {
const { contentEl } = this;
contentEl.empty();
contentEl.addClass("qcb-picker");
- contentEl.createEl("h2", { text: "选择代码块语言" });
+ contentEl.createEl("h2", { text: this.app.plugins.plugins[PLUGIN_ID].t("modal_pick_title") });
const grid = contentEl.createEl("div", { cls: "qcb-lang-grid" });
for (const lang of this.languages) {
@@ -256,16 +389,42 @@ class LanguagePickerModal extends Modal {
// 设置面板
// ================================================================
class CodeBlockSettingTab extends PluginSettingTab {
+ // i18n helper —— 委托给 plugin
+ t(key, params) {
+ return this.plugin.t(key, params);
+ }
+
display() {
const { containerEl } = this;
containerEl.empty();
- containerEl.createEl("h2", { text: "代码块快捷插入" });
+ containerEl.createEl("h2", { text: this.t("setting_title") });
+
+ // ---- 界面语言切换器(顶部)----
+ new Setting(containerEl)
+ .setName(this.t("setting_language"))
+ .setDesc(this.t("setting_language_desc"))
+ .addDropdown((dropdown) =>
+ dropdown
+ .addOption("zh", this.t("lang_zh"))
+ .addOption("en", this.t("lang_en"))
+ .setValue(this.plugin.settings.language)
+ .onChange(async (value) => {
+ this.plugin.settings.language = value;
+ await this.plugin.saveSettings();
+ // 重新注册命令(使命令名跟随语言)
+ this.plugin.registerCommands();
+ // 重新渲染设置面板
+ this.display();
+ })
+ );
+
+ containerEl.createEl("hr", { cls: "qcb-divider" });
// ---- 基础设置 ----
new Setting(containerEl)
- .setName("默认语言")
- .setDesc("主命令「插入代码块」使用的语言")
+ .setName(this.t("setting_default_lang"))
+ .setDesc(this.t("setting_default_lang_desc"))
.addText((text) =>
text
.setPlaceholder("python")
@@ -277,8 +436,8 @@ class CodeBlockSettingTab extends PluginSettingTab {
);
new Setting(containerEl)
- .setName("语言列表")
- .setDesc("每行一个语言,会为每个语言注册独立命令。修改后重新打开设置面板可刷新下方选项。")
+ .setName(this.t("setting_lang_list"))
+ .setDesc(this.t("setting_lang_list_desc"))
.addTextArea((text) => {
text
.setPlaceholder("python\njavascript\nbash\n...")
@@ -292,8 +451,8 @@ class CodeBlockSettingTab extends PluginSettingTab {
});
new Setting(containerEl)
- .setName("保留选中内容缩进")
- .setDesc("选中文本包裹成代码块时,是否保留原有缩进")
+ .setName(this.t("setting_keep_indent"))
+ .setDesc(this.t("setting_keep_indent_desc"))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.settings.keepIndent)
@@ -305,12 +464,10 @@ class CodeBlockSettingTab extends PluginSettingTab {
// ---- 快捷键设置区域 ----
containerEl.createEl("hr", { cls: "qcb-divider" });
- containerEl.createEl("h3", { text: "快捷键设置" });
+ containerEl.createEl("h3", { text: this.t("sec_hotkeys") });
const desc = containerEl.createEl("p", { cls: "qcb-desc" });
- desc.innerHTML =
- "为需要的语言配置快捷键。点击输入框后按下组合键即可设置," +
- "按 Backspace 或 Esc 清除。设置后自动检测冲突。";
+ desc.innerHTML = this.t("hotkeys_desc");
// 配置列表
const configs = this.plugin.settings.hotkeyConfigs;
@@ -321,7 +478,7 @@ class CodeBlockSettingTab extends PluginSettingTab {
// 添加按钮
new Setting(containerEl).addButton((btn) =>
btn
- .setButtonText("+ 添加快捷键配置")
+ .setButtonText(this.t("btn_add_hotkey"))
.setCta()
.onClick(async () => {
this.plugin.settings.hotkeyConfigs.push({
@@ -337,17 +494,17 @@ class CodeBlockSettingTab extends PluginSettingTab {
containerEl.createEl("hr", { cls: "qcb-divider" });
new Setting(containerEl)
- .setName("更多快捷键设置")
- .setDesc("打开 Obsidian 系统的快捷键设置页面,可查看 / 修改所有命令的快捷键")
+ .setName(this.t("setting_more_hotkeys"))
+ .setDesc(this.t("setting_more_hotkeys_desc"))
.addButton((btn) =>
btn
- .setButtonText("打开 Obsidian 快捷键设置")
+ .setButtonText(this.t("btn_open_hotkeys"))
.onClick(() => {
const ok = openHotkeysSettings(this.app);
if (ok) {
- new Notice("已打开快捷键设置,可在搜索框输入命令名查找", 6000);
+ new Notice(this.t("notice_hotkeys_opened"), 6000);
} else {
- new Notice("无法自动打开,请手动进入:设置 → 快捷键", 6000);
+ new Notice(this.t("notice_hotkeys_failed"), 6000);
}
})
);
@@ -355,12 +512,34 @@ class CodeBlockSettingTab extends PluginSettingTab {
// ---- 使用说明 ----
const tip = containerEl.createEl("div", { cls: "qcb-tip" });
tip.innerHTML =
- "使用方法
" +
- "1. Ctrl+P 打开命令面板,搜索「插入代码块」
" +
- "2. 无选中文本时:插入空代码块,光标自动定位到块内
" +
- "3. 有选中文本时:用 ```lang 包裹选中的内容
" +
- "4. 在上方「快捷键设置」区域,点击「+ 添加」为需要的语言配置快捷键
" +
- "5. 修改语言列表后,关闭再打开设置面板即可刷新选项";
+ "" + this.t("tip_title") + "
" +
+ this.t("tip_1") + "
" +
+ this.t("tip_2") + "
" +
+ this.t("tip_3") + "
" +
+ this.t("tip_4") + "
" +
+ this.t("tip_5");
+
+ // ---- 重置(保留语言选择)----
+ containerEl.createEl("hr", { cls: "qcb-divider" });
+
+ new Setting(containerEl)
+ .setName(this.t("setting_reset"))
+ .setDesc(this.t("setting_reset_desc"))
+ .addButton((btn) =>
+ btn
+ .setButtonText(this.t("btn_reset"))
+ .setWarning()
+ .onClick(async () => {
+ const savedLang = this.plugin.settings.language;
+ this.plugin.settings = Object.assign({}, DEFAULT_SETTINGS);
+ this.plugin.settings.language = savedLang;
+ await this.plugin.saveSettings();
+ // 重新注册命令(命令名跟随语言)
+ this.plugin.registerCommands();
+ this.display();
+ new Notice(this.t("notice_reset"), 2000);
+ })
+ );
}
// 创建单个快捷键配置项:语言选择 + 快捷键输入 + 冲突检测 + 删除
@@ -385,39 +564,40 @@ class CodeBlockSettingTab extends PluginSettingTab {
const inputEl = setting.controlEl.createEl("input", {
type: "text",
cls: "qcb-hotkey-input",
- attr: { readonly: true, placeholder: "点击设置…" },
+ attr: { readonly: true, placeholder: this.t("hotkey_placeholder") },
});
inputEl.value = formatHotkey(config.hotkey);
// 冲突提示
const warningEl = setting.descEl.createEl("div", { cls: "qcb-warning" });
- const updateWarning = (hotkey) => {
+ const updateWarning = (hotkey, lang) => {
warningEl.empty();
warningEl.removeClass("has-conflict");
if (!hotkey) return;
- const conflict = findConflict(this.app, fullId, hotkey);
+ const currentFullId = `${PLUGIN_ID}:insert-codeblock-${lang}`;
+ const conflict = findConflict(this.app, currentFullId, hotkey);
if (conflict) {
warningEl.addClass("has-conflict");
- warningEl.createEl("span", { text: "⚠️ 冲突:", cls: "qcb-conflict-label" });
+ warningEl.createEl("span", { text: this.t("conflict_label"), cls: "qcb-conflict-label" });
warningEl.createEl("span", { text: conflict.commandName, cls: "qcb-conflict-name" });
warningEl.createEl("span", { text: " " });
const link = warningEl.createEl("a", {
- text: "前往修改 ›",
+ text: this.t("conflict_link"),
cls: "qcb-conflict-link",
attr: { href: "#" },
});
link.addEventListener("click", (ev) => {
ev.preventDefault();
openHotkeysSettings(this.app);
- new Notice(`请在快捷键设置中搜索「${conflict.commandName}」查看并修改`, 8000);
+ new Notice(this.t("notice_search_conflict", { name: conflict.commandName }), 8000);
});
} else {
- warningEl.createEl("span", { text: "✓ 无冲突", cls: "qcb-ok" });
+ warningEl.createEl("span", { text: this.t("no_conflict"), cls: "qcb-ok" });
}
};
- updateWarning(config.hotkey);
+ updateWarning(config.hotkey, config.lang);
// 语言变更:清除旧绑定,绑定到新语言
select.addEventListener("change", async () => {
@@ -436,20 +616,8 @@ class CodeBlockSettingTab extends PluginSettingTab {
} catch (e) {}
}
await plugin.saveSettings();
- // 更新 fullId 和冲突检测
- fullId; // 注意:fullId 是 const,这里用闭包里的 config.lang 重新检测
- const currentFullId = `${PLUGIN_ID}:insert-codeblock-${config.lang}`;
- warningEl.empty();
- if (config.hotkey) {
- const conflict = findConflict(this.app, currentFullId, config.hotkey);
- if (conflict) {
- warningEl.addClass("has-conflict");
- warningEl.createEl("span", { text: "⚠️ 冲突:", cls: "qcb-conflict-label" });
- warningEl.createEl("span", { text: conflict.commandName, cls: "qcb-conflict-name" });
- } else {
- warningEl.createEl("span", { text: "✓ 无冲突", cls: "qcb-ok" });
- }
- }
+ // 更新冲突检测
+ updateWarning(config.hotkey, config.lang);
});
// 录制状态
@@ -472,8 +640,8 @@ class CodeBlockSettingTab extends PluginSettingTab {
config.hotkey = null;
inputEl.value = "";
await plugin.saveSettings();
- updateWarning(null);
- new Notice(`已清除:${config.lang} 快捷键`, 2000);
+ updateWarning(null, config.lang);
+ new Notice(this.t("notice_cleared", { lang: config.lang }), 2000);
return;
}
@@ -498,21 +666,21 @@ class CodeBlockSettingTab extends PluginSettingTab {
this.app.hotkeyManager.setHotkeys(bindId, [hotkey]);
} catch (e) {
console.error(`[quick-codeblock] 设置 ${config.lang} 快捷键失败:`, e);
- new Notice(`设置失败:${e.message}`, 5000);
+ new Notice(this.t("notice_set_failed", { msg: e.message }), 5000);
return;
}
await plugin.saveSettings();
- updateWarning(hotkey);
+ updateWarning(hotkey, config.lang);
const conflict = findConflict(this.app, bindId, hotkey);
if (conflict) {
new Notice(
- `⚠️ 「${formatHotkey(hotkey)}」与「${conflict.commandName}」冲突,点击警告中的「前往修改」处理`,
+ this.t("notice_conflict", { hotkey: formatHotkey(hotkey), name: conflict.commandName }),
8000
);
} else {
- new Notice(`已设置:${config.lang} → ${formatHotkey(hotkey)}`, 2000);
+ new Notice(this.t("notice_set", { lang: config.lang, hotkey: formatHotkey(hotkey) }), 2000);
}
});
@@ -520,7 +688,7 @@ class CodeBlockSettingTab extends PluginSettingTab {
setting.addExtraButton((btn) =>
btn
.setIcon("trash")
- .setTooltip("删除此配置")
+ .setTooltip(this.t("btn_delete_config"))
.onClick(async () => {
if (config.hotkey) {
try {
diff --git a/main.ts b/main.ts
index b431bb1..0358789 100644
--- a/main.ts
+++ b/main.ts
@@ -7,6 +7,8 @@
* esbuild main.ts --bundle --external:obsidian --format=cjs --outfile=main.js
*
* 已提供编译好的 main.js,通常无需自行编译。
+ *
+ * 双语 UI(中文 / 英文),可在设置面板顶部切换界面语言。
*/
import { App, Editor, Modal, Notice, Plugin, PluginSettingTab, Setting } from "obsidian";
@@ -29,15 +31,134 @@ interface PluginSettings {
defaultLanguage: string;
languages: string;
keepIndent: boolean;
+ language: "zh" | "en";
hotkeyConfigs: HotkeyConfig[];
}
const PLUGIN_ID = "quick-codeblock";
+// ================================================================
+// i18n (Bilingual support) 中英双语
+// ================================================================
+
+const I18N: Record> = {
+ zh: {
+ // Commands
+ cmd_insert_default: "插入代码块({lang})",
+ cmd_insert_pick: "插入代码块(选择语言)",
+ cmd_insert_lang: "插入代码块({lang})",
+ // Modal
+ modal_pick_title: "选择代码块语言",
+ // Settings - title
+ setting_title: "代码块快捷插入",
+ // Settings - language switcher
+ setting_language: "界面语言",
+ setting_language_desc: "选择设置面板的显示语言",
+ lang_zh: "中文",
+ lang_en: "English",
+ // Settings - basic
+ setting_default_lang: "默认语言",
+ setting_default_lang_desc: "主命令「插入代码块」使用的语言",
+ setting_lang_list: "语言列表",
+ setting_lang_list_desc: "每行一个语言,会为每个语言注册独立命令。修改后重新打开设置面板可刷新下方选项。",
+ setting_keep_indent: "保留选中内容缩进",
+ setting_keep_indent_desc: "选中文本包裹成代码块时,是否保留原有缩进",
+ // Settings - hotkeys section
+ sec_hotkeys: "快捷键设置",
+ hotkeys_desc: "为需要的语言配置快捷键。点击输入框后按下组合键即可设置,按 Backspace 或 Esc 清除。设置后自动检测冲突。",
+ btn_add_hotkey: "+ 添加快捷键配置",
+ hotkey_placeholder: "点击设置…",
+ // Settings - more hotkeys
+ setting_more_hotkeys: "更多快捷键设置",
+ setting_more_hotkeys_desc: "打开 Obsidian 系统的快捷键设置页面,可查看 / 修改所有命令的快捷键",
+ btn_open_hotkeys: "打开 Obsidian 快捷键设置",
+ notice_hotkeys_opened: "已打开快捷键设置,可在搜索框输入命令名查找",
+ notice_hotkeys_failed: "无法自动打开,请手动进入:设置 → 快捷键",
+ // Settings - tips
+ tip_title: "使用方法",
+ tip_1: "1. Ctrl+P 打开命令面板,搜索「插入代码块」",
+ tip_2: "2. 无选中文本时:插入空代码块,光标自动定位到块内",
+ tip_3: "3. 有选中文本时:用 ```lang 包裹选中的内容",
+ tip_4: "4. 在上方「快捷键设置」区域,点击「+ 添加」为需要的语言配置快捷键",
+ tip_5: "5. 修改语言列表后,关闭再打开设置面板即可刷新选项",
+ // Hotkey config item
+ conflict_label: "⚠️ 冲突:",
+ conflict_link: "前往修改 ›",
+ no_conflict: "✓ 无冲突",
+ btn_delete_config: "删除此配置",
+ notice_cleared: "已清除:{lang} 快捷键",
+ notice_set_failed: "设置失败:{msg}",
+ notice_conflict: "⚠️ 「{hotkey}」与「{name}」冲突,点击警告中的「前往修改」处理",
+ notice_set: "已设置:{lang} → {hotkey}",
+ notice_search_conflict: "请在快捷键设置中搜索「{name}」查看并修改",
+ // Settings - reset
+ setting_reset: "恢复默认设置",
+ setting_reset_desc: "将所有设置恢复为默认值(界面语言选择会被保留)",
+ btn_reset: "重置",
+ notice_reset: "设置已恢复为默认值",
+ },
+ en: {
+ // Commands
+ cmd_insert_default: "Insert code block ({lang})",
+ cmd_insert_pick: "Insert code block (pick language)",
+ cmd_insert_lang: "Insert code block ({lang})",
+ // Modal
+ modal_pick_title: "Choose code block language",
+ // Settings - title
+ setting_title: "Quick CodeBlock",
+ // Settings - language switcher
+ setting_language: "UI Language",
+ setting_language_desc: "Select the display language for settings panel",
+ lang_zh: "中文",
+ lang_en: "English",
+ // Settings - basic
+ setting_default_lang: "Default language",
+ setting_default_lang_desc: "Language used by the main \"Insert code block\" command",
+ setting_lang_list: "Language list",
+ setting_lang_list_desc: "One language per line. An independent command is registered for each. Reopen the settings panel after editing to refresh options below.",
+ setting_keep_indent: "Keep selection indentation",
+ setting_keep_indent_desc: "Whether to preserve original indentation when wrapping selected text into a code block",
+ // Settings - hotkeys section
+ sec_hotkeys: "Hotkey Settings",
+ hotkeys_desc: "Configure hotkeys for the languages you need. Click the input box then press a key combo to set, press Backspace or Esc to clear. Conflicts are detected automatically.",
+ btn_add_hotkey: "+ Add hotkey config",
+ hotkey_placeholder: "Click to set…",
+ // Settings - more hotkeys
+ setting_more_hotkeys: "More hotkey settings",
+ setting_more_hotkeys_desc: "Open Obsidian's built-in hotkey settings to view / modify hotkeys for all commands",
+ btn_open_hotkeys: "Open Obsidian hotkey settings",
+ notice_hotkeys_opened: "Hotkey settings opened. Type a command name in the search box to find it.",
+ notice_hotkeys_failed: "Unable to open automatically. Please go to: Settings → Hotkeys",
+ // Settings - tips
+ tip_title: "Usage",
+ tip_1: "1. Press Ctrl+P to open the command palette and search for \"Insert code block\"",
+ tip_2: "2. With no selection: inserts an empty code block and places the cursor inside",
+ tip_3: "3. With a selection: wraps the selected text with ```lang",
+ tip_4: "4. In the \"Hotkey Settings\" area above, click \"+ Add\" to configure hotkeys for languages you need",
+ tip_5: "5. After editing the language list, close and reopen the settings panel to refresh options",
+ // Hotkey config item
+ conflict_label: "⚠️ Conflict: ",
+ conflict_link: "Fix ›",
+ no_conflict: "✓ No conflict",
+ btn_delete_config: "Delete this config",
+ notice_cleared: "Cleared: {lang} hotkey",
+ notice_set_failed: "Failed to set: {msg}",
+ notice_conflict: "⚠️ \"{hotkey}\" conflicts with \"{name}\". Click \"Fix\" in the warning to resolve.",
+ notice_set: "Set: {lang} → {hotkey}",
+ notice_search_conflict: 'Search "{name}" in hotkey settings to view and modify it',
+ // Settings - reset
+ setting_reset: "Reset to defaults",
+ setting_reset_desc: "Restore all settings to default values (UI language choice is preserved)",
+ btn_reset: "Reset",
+ notice_reset: "Settings reset to defaults",
+ },
+};
+
const DEFAULT_SETTINGS: PluginSettings = {
defaultLanguage: "python",
languages: "python\njavascript\nbash\nshell\nsql\njson\nyaml\ngo\nrust\njava\nhtml\ncss",
keepIndent: true,
+ language: "zh",
hotkeyConfigs: [{ lang: "python", hotkey: null }],
};
@@ -115,6 +236,19 @@ function openHotkeysSettings(app: App): boolean {
export default class QuickCodeBlockPlugin extends Plugin {
settings!: PluginSettings;
+ // i18n helper —— 支持可选的 {placeholder} 参数替换
+ t(key: string, params?: Record): string {
+ const lang = this.settings ? this.settings.language : "zh";
+ const dict = I18N[lang] || I18N.zh;
+ let text = dict[key] || key;
+ if (params) {
+ for (const k of Object.keys(params)) {
+ text = text.replace(new RegExp("\\{" + k + "\\}", "g"), params[k]);
+ }
+ }
+ return text;
+ }
+
async onload(): Promise {
await this.loadSettings();
this.registerCommands();
@@ -134,13 +268,13 @@ export default class QuickCodeBlockPlugin extends Plugin {
const def = this.settings.defaultLanguage;
this.addCommand({
id: "insert-codeblock-default",
- name: `插入代码块(${def})`,
+ name: this.t("cmd_insert_default", { lang: def }),
editorCallback: (editor: Editor) => this.insertCodeBlock(editor, def),
});
this.addCommand({
id: "insert-codeblock-pick",
- name: "插入代码块(选择语言)",
+ name: this.t("cmd_insert_pick"),
editorCallback: (editor: Editor) => {
const langs = this.getLanguages();
new LanguagePickerModal(this.app, langs, (lang: string) => {
@@ -152,7 +286,7 @@ export default class QuickCodeBlockPlugin extends Plugin {
for (const lang of this.getLanguages()) {
this.addCommand({
id: `insert-codeblock-${lang}`,
- name: `插入代码块(${lang})`,
+ name: this.t("cmd_insert_lang", { lang }),
editorCallback: (editor: Editor) => this.insertCodeBlock(editor, lang),
});
}
@@ -233,7 +367,8 @@ class LanguagePickerModal extends Modal {
const { contentEl } = this;
contentEl.empty();
contentEl.addClass("qcb-picker");
- contentEl.createEl("h2", { text: "选择代码块语言" });
+ const plugin = (this.app as any).plugins.plugins[PLUGIN_ID] as QuickCodeBlockPlugin;
+ contentEl.createEl("h2", { text: plugin.t("modal_pick_title") });
const grid = contentEl.createEl("div", { cls: "qcb-lang-grid" });
for (const lang of this.languages) {
const item = grid.createEl("div", { cls: "qcb-lang-item", text: lang });
@@ -257,14 +392,41 @@ class CodeBlockSettingTab extends PluginSettingTab {
this.plugin = plugin;
}
+ // i18n helper —— 委托给 plugin
+ t(key: string, params?: Record): string {
+ return this.plugin.t(key, params);
+ }
+
display(): void {
const { containerEl } = this;
containerEl.empty();
- containerEl.createEl("h2", { text: "代码块快捷插入" });
+ containerEl.createEl("h2", { text: this.t("setting_title") });
+ // ---- 界面语言切换器(顶部)----
new Setting(containerEl)
- .setName("默认语言")
- .setDesc("主命令「插入代码块」使用的语言")
+ .setName(this.t("setting_language"))
+ .setDesc(this.t("setting_language_desc"))
+ .addDropdown((dropdown) =>
+ dropdown
+ .addOption("zh", this.t("lang_zh"))
+ .addOption("en", this.t("lang_en"))
+ .setValue(this.plugin.settings.language)
+ .onChange(async (value) => {
+ this.plugin.settings.language = value as "zh" | "en";
+ await this.plugin.saveSettings();
+ // 重新注册命令(使命令名跟随语言)
+ (this.plugin as any).registerCommands();
+ // 重新渲染设置面板
+ this.display();
+ })
+ );
+
+ containerEl.createEl("hr", { cls: "qcb-divider" });
+
+ // ---- 基础设置 ----
+ new Setting(containerEl)
+ .setName(this.t("setting_default_lang"))
+ .setDesc(this.t("setting_default_lang_desc"))
.addText((text) =>
text
.setPlaceholder("python")
@@ -276,8 +438,8 @@ class CodeBlockSettingTab extends PluginSettingTab {
);
new Setting(containerEl)
- .setName("语言列表")
- .setDesc("每行一个语言,会为每个语言注册独立命令。修改后重新打开设置面板可刷新下方选项。")
+ .setName(this.t("setting_lang_list"))
+ .setDesc(this.t("setting_lang_list_desc"))
.addTextArea((text) => {
text
.setPlaceholder("python\njavascript\nbash\n...")
@@ -291,8 +453,8 @@ class CodeBlockSettingTab extends PluginSettingTab {
});
new Setting(containerEl)
- .setName("保留选中内容缩进")
- .setDesc("选中文本包裹成代码块时,是否保留原有缩进")
+ .setName(this.t("setting_keep_indent"))
+ .setDesc(this.t("setting_keep_indent_desc"))
.addToggle((toggle) =>
toggle
.setValue(this.plugin.settings.keepIndent)
@@ -302,13 +464,12 @@ class CodeBlockSettingTab extends PluginSettingTab {
})
);
+ // ---- 快捷键设置区域 ----
containerEl.createEl("hr", { cls: "qcb-divider" });
- containerEl.createEl("h3", { text: "快捷键设置" });
+ containerEl.createEl("h3", { text: this.t("sec_hotkeys") });
const desc = containerEl.createEl("p", { cls: "qcb-desc" });
- desc.innerHTML =
- "为需要的语言配置快捷键。点击输入框后按下组合键即可设置," +
- "按 Backspace 或 Esc 清除。设置后自动检测冲突。";
+ desc.innerHTML = this.t("hotkeys_desc");
const configs = this.plugin.settings.hotkeyConfigs;
for (let i = 0; i < configs.length; i++) {
@@ -317,7 +478,7 @@ class CodeBlockSettingTab extends PluginSettingTab {
new Setting(containerEl).addButton((btn) =>
btn
- .setButtonText("+ 添加快捷键配置")
+ .setButtonText(this.t("btn_add_hotkey"))
.setCta()
.onClick(async () => {
this.plugin.settings.hotkeyConfigs.push({
@@ -332,29 +493,51 @@ class CodeBlockSettingTab extends PluginSettingTab {
containerEl.createEl("hr", { cls: "qcb-divider" });
new Setting(containerEl)
- .setName("更多快捷键设置")
- .setDesc("打开 Obsidian 系统的快捷键设置页面,可查看 / 修改所有命令的快捷键")
+ .setName(this.t("setting_more_hotkeys"))
+ .setDesc(this.t("setting_more_hotkeys_desc"))
.addButton((btn) =>
btn
- .setButtonText("打开 Obsidian 快捷键设置")
+ .setButtonText(this.t("btn_open_hotkeys"))
.onClick(() => {
const ok = openHotkeysSettings(this.app);
if (ok) {
- new Notice("已打开快捷键设置,可在搜索框输入命令名查找", 6000);
+ new Notice(this.t("notice_hotkeys_opened"), 6000);
} else {
- new Notice("无法自动打开,请手动进入:设置 → 快捷键", 6000);
+ new Notice(this.t("notice_hotkeys_failed"), 6000);
}
})
);
const tip = containerEl.createEl("div", { cls: "qcb-tip" });
tip.innerHTML =
- "使用方法
" +
- "1. Ctrl+P 打开命令面板,搜索「插入代码块」
" +
- "2. 无选中文本时:插入空代码块,光标自动定位到块内
" +
- "3. 有选中文本时:用 ```lang 包裹选中的内容
" +
- "4. 在上方「快捷键设置」区域,点击「+ 添加」为需要的语言配置快捷键
" +
- "5. 修改语言列表后,关闭再打开设置面板即可刷新选项";
+ "" + this.t("tip_title") + "
" +
+ this.t("tip_1") + "
" +
+ this.t("tip_2") + "
" +
+ this.t("tip_3") + "
" +
+ this.t("tip_4") + "
" +
+ this.t("tip_5");
+
+ // ---- 重置(保留语言选择)----
+ containerEl.createEl("hr", { cls: "qcb-divider" });
+
+ new Setting(containerEl)
+ .setName(this.t("setting_reset"))
+ .setDesc(this.t("setting_reset_desc"))
+ .addButton((btn) =>
+ btn
+ .setButtonText(this.t("btn_reset"))
+ .setWarning()
+ .onClick(async () => {
+ const savedLang = this.plugin.settings.language;
+ this.plugin.settings = Object.assign({}, DEFAULT_SETTINGS);
+ this.plugin.settings.language = savedLang;
+ await this.plugin.saveSettings();
+ // 重新注册命令(命令名跟随语言)
+ (this.plugin as any).registerCommands();
+ this.display();
+ new Notice(this.t("notice_reset"), 2000);
+ })
+ );
}
private createHotkeyConfigItem(index: number): void {
@@ -374,7 +557,7 @@ class CodeBlockSettingTab extends PluginSettingTab {
const inputEl = setting.controlEl.createEl("input", {
type: "text",
cls: "qcb-hotkey-input",
- attr: { readonly: true, placeholder: "点击设置…" },
+ attr: { readonly: true, placeholder: this.t("hotkey_placeholder") },
});
inputEl.value = formatHotkey(config.hotkey);
@@ -388,21 +571,21 @@ class CodeBlockSettingTab extends PluginSettingTab {
const conflict = findConflict(this.app, currentFullId, hotkey);
if (conflict) {
warningEl.addClass("has-conflict");
- warningEl.createEl("span", { text: "⚠️ 冲突:", cls: "qcb-conflict-label" });
+ warningEl.createEl("span", { text: this.t("conflict_label"), cls: "qcb-conflict-label" });
warningEl.createEl("span", { text: conflict.commandName, cls: "qcb-conflict-name" });
warningEl.createEl("span", { text: " " });
const link = warningEl.createEl("a", {
- text: "前往修改 ›",
+ text: this.t("conflict_link"),
cls: "qcb-conflict-link",
attr: { href: "#" },
});
link.addEventListener("click", (ev: MouseEvent) => {
ev.preventDefault();
openHotkeysSettings(this.app);
- new Notice(`请在快捷键设置中搜索「${conflict.commandName}」查看并修改`, 8000);
+ new Notice(this.t("notice_search_conflict", { name: conflict.commandName }), 8000);
});
} else {
- warningEl.createEl("span", { text: "✓ 无冲突", cls: "qcb-ok" });
+ warningEl.createEl("span", { text: this.t("no_conflict"), cls: "qcb-ok" });
}
};
@@ -443,7 +626,7 @@ class CodeBlockSettingTab extends PluginSettingTab {
inputEl.value = "";
await plugin.saveSettings();
updateWarning(null, config.lang);
- new Notice(`已清除:${config.lang} 快捷键`, 2000);
+ new Notice(this.t("notice_cleared", { lang: config.lang }), 2000);
return;
}
@@ -467,7 +650,7 @@ class CodeBlockSettingTab extends PluginSettingTab {
(this.app as any).hotkeyManager.setHotkeys(bindId, [hotkey]);
} catch (e: any) {
console.error(`[quick-codeblock] 设置 ${config.lang} 快捷键失败:`, e);
- new Notice(`设置失败:${e.message}`, 5000);
+ new Notice(this.t("notice_set_failed", { msg: e.message }), 5000);
return;
}
@@ -477,18 +660,18 @@ class CodeBlockSettingTab extends PluginSettingTab {
const conflict = findConflict(this.app, bindId, hotkey);
if (conflict) {
new Notice(
- `⚠️ 「${formatHotkey(hotkey)}」与「${conflict.commandName}」冲突,点击警告中的「前往修改」处理`,
+ this.t("notice_conflict", { hotkey: formatHotkey(hotkey), name: conflict.commandName }),
8000
);
} else {
- new Notice(`已设置:${config.lang} → ${formatHotkey(hotkey)}`, 2000);
+ new Notice(this.t("notice_set", { lang: config.lang, hotkey: formatHotkey(hotkey) }), 2000);
}
});
setting.addExtraButton((btn) =>
btn
.setIcon("trash")
- .setTooltip("删除此配置")
+ .setTooltip(this.t("btn_delete_config"))
.onClick(async () => {
if (config.hotkey) {
try {
diff --git a/manifest.json b/manifest.json
index 849584f..a2b8f82 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,7 +1,7 @@
{
"id": "quick-codeblock",
"name": "XU Quick CodeBlock",
- "version": "1.1.1",
+ "version": "1.1.2",
"minAppVersion": "1.4.0",
"description": "快捷插入代码块并自动定位光标。支持自定义语言、选中文本包裹、快捷键配置与冲突检测.",
"author": "旭说云原生",