"use strict";
var TabLocalFiles;
(function (TabLocalFiles) {
function formatShortcut(spec) {
if (shortcutPlatform() === "mac") {
return `${spec.alt ? "⌥" : ""}${spec.shift ? "⇧" : ""}${spec.mod ? "⌘" : ""}${spec.key}`;
}
const parts = [];
if (spec.mod) {
parts.push("Ctrl");
}
if (spec.alt) {
parts.push("Alt");
}
if (spec.shift) {
parts.push("Shift");
}
parts.push(spec.key);
return parts.join("+");
}
TabLocalFiles.formatShortcut = formatShortcut;
function shortcutPlatform() {
const navigatorInfo = globalThis.navigator;
const platform = (navigatorInfo?.userAgentData?.platform || navigatorInfo?.platform || "").toLowerCase();
if (platform.includes("mac")) {
return "mac";
}
if (platform.includes("win")) {
return "windows";
}
return "other";
}
TabLocalFiles.shortcutPlatform = shortcutPlatform;
})(TabLocalFiles || (TabLocalFiles = {}));
var TabLocalFiles;
(function (TabLocalFiles) {
TabLocalFiles.RUNTIME_VERSION = "0.1.7";
})(TabLocalFiles || (TabLocalFiles = {}));
var TabLocalFiles;
(function (TabLocalFiles) {
const DEFAULT_LOCALE = "zh-CN";
const I18N_MESSAGES = {
"zh-CN": {
"app.description": "本地文件渲染",
"viewer.openingTitle": "正在打开文件",
"viewer.openingDescription": "Previewer 正在准备文件预览。",
"common.fileName": "文件名",
"common.fileSize": "大小",
"common.fileCreated": "创建时间",
"common.fileModified": "修改时间",
"common.today": "今天",
"common.yesterday": "昨天",
"common.filePath": "文件路径",
"common.pathEllipsis": "...",
"common.showCollapsedPath": "显示折叠的中间路径",
"common.collapsedPathSegments": "折叠的中间路径",
"common.fileActions": "文件操作",
"common.fileInfo": "文件信息",
"common.moreActions": "更多操作",
"common.renameFile": "重命名文件",
"common.expandExplorer": "展开资源管理器",
"common.collapseExplorer": "收起资源管理器",
"common.expandHeader": "展开文件头",
"common.collapseHeader": "收起文件头",
"common.rawFile": "原始文件",
"common.openInNewTab": "在新标签页打开",
"common.save": "保存",
"common.saveAs": "另存为……",
"common.downloadRemoteFile": "下载到本地",
"common.print": "打印",
"print.preparing": "正在准备打印内容…",
"print.failed": "无法准备打印内容",
"print.notReady": "内容尚未加载完成,请稍后再试",
"print.pageAlt": "打印第 {page} 页",
"print.namedPageAlt": "{fileName} 第 {page} 页",
"print.preparingPage": "正在准备第 {page}/{total} 页…",
"print.preparingSlide": "正在准备第 {slide}/{total} 张幻灯片…",
"print.namedSlideAlt": "{fileName} 第 {slide} 张幻灯片",
"common.edit": "编辑",
"common.preview": "预览",
"common.copy": "复制",
"common.copyAllText": "复制全部",
"common.export": "导出",
"common.revealInFileManager": "在文件管理器中显示",
"common.revealInFinder": "在 Finder 中显示",
"common.revealInExplorer": "在文件资源管理器中显示",
"common.revealUnavailableRemote": "在线页面无法显示",
"common.editUnavailableRemote": "在线页面无法编辑",
"common.fileUnavailable": "该文件可能已被移至别处、修改或删除。",
"common.unknown": "未知",
"common.unknownError": "未知错误",
"common.untitled": "Untitled",
"common.localFile": "Local file",
"common.loading": "正在加载...",
"common.notModified": "未修改",
"common.unsavedChanges": "有未保存的修改",
"common.unexportedChanges": "有未导出的修改",
"common.copiedToClipboard": "已复制到剪贴板",
"common.copiedSelectedText": "已复制选中文本",
"common.copyFailed": "复制失败",
"common.saving": "正在保存...",
"common.exporting": "正在导出...",
"common.savingAs": "正在另存为...",
"common.downloadingRemoteFile": "正在下载...",
"common.savedToOriginal": "已保存到原文件",
"common.saved": "已保存",
"common.savedAs": "已另存为",
"common.downloadedRemoteFile": "已下载到本地",
"common.exportedToDownloads": "已导出到下载文件夹",
"common.cancelledExport": "已取消导出",
"common.cancelledSaveAs": "已取消另存为",
"common.cancelledDownload": "已取消下载",
"common.cancel": "取消",
"common.saveFailedWorkspace": "保存失败:无法写入当前工作区文件",
"common.exportFailed": "导出失败",
"common.saveAsFailed": "另存失败",
"common.downloadRemoteFailed": "下载失败:无法读取在线文件",
"common.downloadUnavailable": "当前文件无法下载",
"common.fileContent": "文件内容",
"common.textFile": "Text file",
"common.filePickerLocalFile": "Local file",
"editor.clean": "已同步",
"editor.external": "外部更新中",
"editor.externalHint": "其他程序正在修改此文件,改动已自动同步到这里",
"changes.unreadAbove": "上方 {count} 处未读改动",
"changes.unreadBelow": "下方 {count} 处未读改动",
"changes.markAllRead": "全部标为已读",
"changes.jump": "跳到这处改动",
"changes.added": "外部新增",
"changes.modified": "外部修改",
"changes.deleted": "外部删除了这里的内容",
"editor.readonly": "只读",
"editor.dirty": "未保存",
"editor.saving": "保存中",
"editor.saved": "已保存",
"editor.autoSavePending": "待保存",
"editor.autoSaved": "已自动保存",
"editor.savedAsUtf8": "文件原为 {encoding} 编码,内容无法用该编码表示,已改为 UTF-8 保存",
"editor.error": "保存失败",
"editor.conflict": "文件冲突",
"editor.draftRestored": "已恢复未保存草稿",
"editor.draftOutOfSpace": "浏览器存储空间不足,本文档的未保存草稿无法留存。文字一个字也没被删减,建议尽快保存到文件。",
"editor.unsavedTitle": "保存修改?",
"editor.unsavedDescription": "“{fileName}”有未保存的修改。",
"editor.saveBeforeLeave": "离开前保存“{fileName}”的修改?",
"editor.discardBeforeLeave": "放弃“{fileName}”的未保存修改?",
"editor.discard": "放弃修改",
"editor.beforeUnload": "当前文件有未保存的修改。",
"editor.revertTitle": "还原到打开文件时的内容?",
"editor.revertDescription": "将丢弃“{fileName}”自本次打开以来的全部修改,包括已经自动保存到磁盘的部分。",
"editor.revertConfirm": "还原",
"editor.conflictTitle": "文件已在其他位置修改",
"editor.conflictDescription": "“{fileName}”的磁盘内容已变化。为避免覆盖他人的修改,只有明确确认后才会继续保存。也可以取消并使用“另存为”。",
"editor.overwrite": "仍然覆盖",
"markdown.bold": "粗体",
"markdown.italic": "斜体",
"markdown.insertLink": "插入链接",
"markdown.insertImage": "插入图片",
"markdown.widthDecrease": "减小正文宽度",
"markdown.contentWidth": "正文宽度",
"markdown.widthIncrease": "增加正文宽度",
"markdown.taskToggle": "切换任务状态",
"markdown.taskReadonlyRemote": "在线 Markdown 只读,请下载到本地后编辑",
"large.previewTitle": "大文件安全预览",
"large.previewDescription": "已先加载前 {previewSize},滚动到底部继续按需加载;编辑和保存已禁用。",
"large.previewAria": "{kind} 大文件预览片段",
"large.previewMeta": "{kind} · 大文件预览 · {size}",
"large.blockedTitle": "文件过大,已停止自动预览",
"large.blockedDescription": "{kind} 文件大小 {size}。为避免浏览器崩溃,Previewer 没有读取完整内容。可以打开原始文件或在文件管理器中定位。",
"large.blockedMeta": "{kind} · 文件过大 · {size}",
"large.emptyPreview": "无法读取安全预览片段。",
"large.virtualStatus": "正在显示 {start} - {end} / {total}",
"large.virtualLoading": "正在加载下一段...",
"large.virtualError": "加载失败,滚动后将重试。",
"large.directoryLimited": "仅显示前 {count} 项,文件夹过大时不会一次渲染全部内容。",
"toolbar.reveal": "在文件管理器中显示",
"theme.followingBrowser": "跟随浏览器{theme}主题,点击可临时固定{nextTheme}",
"theme.fixed": "已固定{theme}主题,点击恢复跟随浏览器",
"theme.dark": "深色",
"theme.light": "浅色",
"rename.inProgress": "正在重命名...",
"rename.success": "已重命名",
"rename.failed": "重命名失败:{error}",
"rename.invalidName": "文件名包含非法字符",
"rename.duplicateName": "当前文件夹已存在同名文件",
"rename.extensionNone": "无扩展名",
"rename.extensionChangeTitle": "确认变更扩展名",
"rename.extensionChangeDescription": "「{fileName}」的扩展名即将变更为「{extension}」,这会改变文件的打开方式。确认重命名吗?",
"rename.extensionChangeConfirm": "确认重命名",
"common.panelMode": "预览 / 编辑模式",
"common.previewModeHint": "预览模式(⌘E 切换)",
"common.editModeHint": "编辑模式(⌘E 切换)",
"common.editUnsupportedType": "该格式不支持编辑",
"common.copyAbsolutePath": "复制绝对路径",
"common.copiedPath": "已复制绝对路径",
"common.duplicateFile": "创建副本",
"common.reloadFromDisk": "从磁盘刷新",
"common.resizePanes": "拖动调整两栏宽度(双击恢复默认)",
"common.reloadedFromDisk": "已从磁盘重新加载",
"common.reloadFailed": "读取文件失败",
"common.revert": "还原",
"common.revertToOpened": "还原到打开文件时的内容",
"common.revertUnavailable": "当前内容与打开文件时一致",
"common.reverted": "已还原到打开文件时的内容",
"common.saveNothingToSave": "没有需要保存的修改",
"common.saveHandledByAutoSave": "自动保存已接管,无需手动保存",
"common.moreTools": "更多工具",
"common.undo": "撤销",
"common.quoteFileToChat": "引用文件到 Chat",
"common.undoChatEdit": "撤销 AI 修改",
"common.chatEditConflict": "内容已被修改,无法安全撤销。",
"common.redo": "重做",
"common.fit": "适应",
"common.zoomPercent": "缩放比例,可输入百分比",
"duplicate.readFailed": "读取文件内容失败,无法创建副本",
"duplicate.failed": "创建副本失败:{error}",
"duplicate.success": "已创建副本 {fileName}",
"duplicate.namePattern": "{name}(副本)",
"duplicate.namePatternIndexed": "{name}(副本 {index})",
"document.translate": "翻译文档并保存为新文件或覆盖原文件",
"document.translateShort": "译文…",
"document.translateTitle": "导出译文",
"document.translateModeLabel": "输出内容",
"document.translateModeTranslationFirst": "双语(译文在上)",
"document.translateModeOriginalFirst": "双语(译文在下)",
"document.translateModeReplace": "仅译文",
"document.translateLanguageLabel": "目标语言",
"document.translateOutputLabel": "保存方式",
"document.translateOutputNew": "导出为新文件",
"document.translateOutputOverwrite": "覆盖当前文件",
"document.translateSummaryExport": "将翻译 {count} 个段落,结果导出为 {fileName},保存到下载目录。代码块、表格、链接地址保持原样。翻译会消耗账户用量。",
"document.translateSummaryOverwrite": "将翻译 {count} 个段落并覆盖当前文件。代码块、表格、链接地址保持原样。翻译会消耗账户用量。",
"document.translateNothing": "没有需要翻译的正文段落",
"document.translateUnavailable": "翻译服务不可用,请确认翻译扩展已启用",
"document.translateStart": "开始翻译",
"document.translateCancel": "取消",
"document.translateRunning": "正在翻译 {completed}/{total}",
"document.translateCancelled": "已取消翻译",
"document.translateFailed": "翻译失败:{error}",
"document.translateSourceChanged": "文档在翻译期间被修改,已放弃覆盖保存",
"document.translateDoneOverwrite": "已翻译 {count} 个段落并保存",
"document.translateDoneExported": "已翻译 {count} 个段落,已导出 {fileName} 到下载目录",
"document.translateKeptOriginal": ";{count} 个段落未能翻译,保留原文",
"document.translateAllRejected": "译文会破坏文档格式,未写入任何内容",
"markdown.toc": "目录",
"markdown.tocResizeAria": "调整目录宽度",
"markdown.tocResizeTitle": "拖拽调整目录宽度(双击恢复默认)",
"markdown.readingWidth": "阅读宽度",
"markdown.widthFixed": "默认",
"markdown.widthFull": "全宽",
"markdown.fontSize": "字号",
"markdown.fontDecrease": "减小字号",
"markdown.fontIncrease": "增大字号",
"markdown.fontMedium": "中",
"markdown.fontLarge": "大",
"markdown.fontXLarge": "超大",
"markdown.heading1": "一级标题",
"markdown.heading2": "二级标题",
"markdown.heading3": "三级标题",
"markdown.heading4": "四级标题",
"markdown.heading5": "五级标题",
"markdown.strikethrough": "删除线",
"markdown.inlineCode": "行内代码",
"markdown.unorderedList": "无序列表",
"markdown.orderedList": "有序列表",
"markdown.taskList": "任务列表",
"markdown.blockquote": "引用",
"markdown.codeBlock": "代码块",
"markdown.insertTable": "插入表格",
"markdown.horizontalRule": "分割线",
"markdown.clearFormat": "清除格式",
"common.shortcutHint": "{label}({shortcut})",
"markdown.tableHeader": "列",
"markdown.tableCell": "内容",
"markdown.editModeSwitch": "编辑方式",
"markdown.editSource": "源码",
"markdown.editSplit": "分屏",
"markdown.editInline": "即时编辑",
"markdown.inlineLoading": "正在加载即时编辑器...",
"markdown.codeCopied": "已复制",
"markdown.statLines": "行数",
"markdown.statWords": "词数",
"markdown.exportHtml": "HTML",
"markdown.exportHtmlDone": "已导出 HTML",
"markdown.exportHtmlFailed": "导出 HTML 失败",
"markdown.exportPdf": "PDF",
"markdown.exportPdfWorking": "正在生成 PDF…",
"markdown.exportPdfDone": "已导出 PDF",
"markdown.exportPdfFailed": "导出 PDF 失败",
"markdown.exportImage": "长图 (PNG)",
"markdown.exportImageWorking": "正在生成长图…",
"markdown.exportImageDone": "已导出长图",
"markdown.exportImageFailed": "导出长图失败",
"markdown.exportImageTooTall": "文档太长,无法生成单张长图",
"markdown.exportUnavailable": "当前环境不支持此导出方式",
"markdown.inlineLoadFailed": "即时编辑器加载失败,已切回源码视图",
"inline.placeholder": "开始输入…",
"inline.codeSearchLanguage": "搜索语言",
"inline.codeNoResult": "无结果",
"inline.codePreview": "预览",
"inline.codePreviewLoading": "正在渲染图表...",
"inline.codeHideCode": "隐藏代码",
"inline.linkPlaceholder": "粘贴链接...",
"inline.imageUrlPlaceholder": "粘贴图片链接...",
"markdown.searchPlaceholder": "在文档中搜索",
"markdown.searchPrev": "上一个匹配",
"markdown.searchNext": "下一个匹配",
"markdown.searchClose": "关闭搜索",
"markdown.imagePasteFailed": "图片保存失败",
"markdown.formatTables": "格式化表格",
"markdown.frontmatter": "文档属性",
"markdown.frontmatterKey": "属性名",
"markdown.frontmatterValue": "属性值",
"markdown.frontmatterEmptyValue": "没有值",
"markdown.frontmatterAdd": "添加文档属性",
"markdown.frontmatterRemove": "移除该属性",
"markdown.frontmatterNewKey": "新属性",
"markdown.largeSourceOnly": "大文件仅支持源码编辑",
"markdown.splitTooNarrow": "窗口太窄,放不下分屏的两栏",
"markdown.footnotes": "脚注",
"markdown.footnoteBackref": "返回引用处",
"markdown.alertNote": "说明",
"markdown.alertTip": "提示",
"markdown.alertImportant": "重要",
"markdown.alertWarning": "警告",
"markdown.alertCaution": "危险",
"markdown.alertAbstract": "摘要",
"markdown.alertInfo": "信息",
"markdown.alertTodo": "待办",
"markdown.alertSuccess": "成功",
"markdown.alertQuestion": "问题",
"markdown.alertFailure": "失败",
"markdown.alertDanger": "危险",
"markdown.alertBug": "缺陷",
"markdown.alertExample": "示例",
"markdown.alertQuote": "引用",
"markdown.searchToggleReplace": "显示替换",
"markdown.searchCaseSensitive": "区分大小写",
"markdown.searchReplacePlaceholder": "替换为",
"markdown.searchReplaceOne": "替换",
"markdown.searchReplaceAll": "全部替换",
"svg.sourceEditorAria": "SVG 源码编辑器",
"code.lineNumbers": "行号",
"code.wordWrap": "自动换行",
"code.highlightLanguage": "语法高亮",
"code.jsonRawStyle": "JSON 显示方式",
"code.jsonStyleOriginal": "原始",
"code.jsonStylePretty": "格式化",
"code.jsonStyleTree": "树形",
"code.dataViewMode": "数据视图",
"code.dataTreeLoading": "解析中…",
"code.dataTreeParseError": "解析失败",
"code.jsonStyleCompact": "压缩",
"code.jsonFormatPretty2": "格式化(2 空格)",
"code.jsonFormatPretty4": "格式化(4 空格)",
"code.jsonFormatCompact": "压缩",
"code.invalidJson": "JSON 无效,无法执行该操作",
"code.compactApplied": "已压缩",
"code.jsonValid": "JSON 有效",
"code.jsonInvalid": "JSON 无效",
"code.jsonExpandNode": "展开",
"code.jsonCollapseNode": "折叠",
"code.jsonTreeRoot": "根节点",
"code.jsonTreeAria": "JSON 结构树",
"code.jsonNodeKeys": "{count} 个键",
"code.jsonNodeItems": "{count} 项",
"code.jsonFoldLimited": "结构超过 {lines} 行,已关闭折叠",
"code.lineNumbersUnavailable": "当前显示方式没有行号",
"code.csvViewMode": "表格显示方式",
"code.csvViewTable": "表格",
"code.csvViewRaw": "原始文本",
"code.csvDimensions": "{rows} 行 × {columns} 列",
"code.jsonlViewMode": "JSON Lines 显示方式",
"code.jsonlRecords": "{count} 条记录",
"code.jsonlValid": "每一行都是有效 JSON",
"code.jsonlInvalidSummary": "{count} 行不是有效 JSON,首个在第 {line} 行",
"code.jsonlInvalidLine": "第 {line} 行不是有效 JSON:{text}",
"code.jsonlInvalid": "不是有效 JSON",
"code.jsonlLineLabel": "第 {line} 行",
"code.jsonlLineColumn": "行",
"code.jsonlValueColumn": "值",
"code.jsonlTreeLimited": "仅显示前 {count} 行;编辑态保留完整原始文本。",
"code.errorLinesOnly": "仅显示错误行",
"code.errorLinesMatched": "仅显示错误行:{count} 行命中",
"code.noErrorLines": "(无匹配的错误行)",
"office.richPreviewReadOnly": "当前排版预览暂不支持编辑",
"directory.sortBy": "排序方式",
"directory.sortByName": "名称",
"directory.sortByKind": "类型",
"directory.sortDirection": "排序方向",
"directory.sortAscending": "升序",
"directory.sortDescending": "降序",
"directory.viewMode": "视图",
"directory.viewList": "列表",
"directory.viewGrid": "网格",
"directory.kindFolder": "文件夹",
"create.inProgress": "正在新建 {fileName}...",
"create.success": "已新建",
"create.failed": "新建失败:{error}",
"create.missingDirectory": "无法确定当前文件夹,不能新建文件。",
"create.workspaceUnavailable": "当前环境未开放 chrome.tabLocalWorkspace,无法新建文件。",
"create.directoryNotWritable": "当前文件夹未授权写入,无法新建文件。",
"create.new": "新建",
"create.newFileType": "新建文件类型",
"outline.empty": "没有可展示的目录",
"outline.aria": "文档大纲",
"outline.title": "文档大纲",
"outline.collapseAll": "全部折叠",
"outline.expandAll": "全部展开",
"outline.toggleAria": "折叠或展开子标题",
"directory.aria": "文件夹树",
"directory.backToRoot": "回到根目录",
"directory.backToParent": ".. 上级目录",
"directory.empty": "空文件夹",
"directory.loading": "正在加载...",
"directory.expandFailed": "无法展开文件夹",
"directory.readFailed": "无法读取文件夹",
"directory.previewDescription": "文件夹内的文件和子文件夹如下所示,也会同步显示在左侧目录树中。",
"directory.previewItemCount": "包含条目",
"directory.previewPath": "路径",
"directory.resizeAria": "调整侧栏宽度",
"directory.resizeTitle": "拖拽调整侧栏宽度",
"directory.settings": "文件夹选项",
"directory.showHiddenFiles": "显示隐藏项目",
"directory.foldersFirst": "文件夹优先",
"directory.rememberSidebarWidth": "记住侧栏宽度",
"directory.openSettingsPage": "设置项",
"directory.newFolder": "新建文件夹",
"directory.newFolderName": "未命名文件夹",
"directory.newFolderFailed": "新建文件夹失败:{error}",
"directory.rename": "重命名",
"directory.renameAria": "新名称",
"directory.moved": "已移动到「{folder}」",
"directory.moveFailed": "移动失败:{error}",
"directory.moveExists": "「{folder}」中已有同名项目",
"directory.extensionLocked": "这类文件不能修改扩展名",
"directory.newFolderItem": "文件夹",
"directory.favoritesMenu": "收藏的文件夹",
"directory.favoritesEmpty": "还没有收藏的文件夹。在文件夹的「⋯」菜单里,或点文件头的星标即可收藏。",
"trash.placeTrash": "废纸篓",
"trash.placeRecycleBin": "回收站",
"trash.action": "移到{place}",
"trash.confirmTitle": "移到{place}?",
"trash.confirmFile": "「{name}」将被移到{place},之后可以从{place}中恢复。",
"trash.confirmFolder": "文件夹「{name}」及其中的全部内容将被移到{place},之后可以从{place}中恢复。",
"trash.done": "已移到{place}",
"trash.failed": "移到{place}失败:{error}",
"favorites.add": "收藏",
"favorites.remove": "取消收藏",
"favorites.added": "已收藏",
"favorites.removed": "已取消收藏",
"popup.settings": "设置",
"popup.favorites": "收藏",
"popup.recents": "最近打开",
"popup.favoritesEmpty": "在文件头点击星标,即可把文件或文件夹收藏到这里。",
"popup.recentsEmpty": "最近打开的文件和文件夹会显示在这里。",
"settings.title": "Previewer 设置",
"settings.general": "通用",
"settings.showHiddenFilesDescription": "在文件夹树与文件夹概览中显示以点开头的隐藏文件。",
"settings.rememberSidebarWidthDescription": "下次打开文件夹时恢复上次调整的侧栏宽度。",
"settings.documentTitle": "用文档标题命名标签页",
"settings.documentTitleDescription": "预览 Markdown、MDX、HTML 时,用文档自己的标题(frontmatter 标题、一级标题、
)命名标签页;文档没有标题时仍用文件名。",
"settings.lineNumbers": "显示行号",
"settings.lineNumbersDescription": "在代码与文本文件的预览和编辑器中显示行号。",
"settings.wordWrap": "自动换行",
"settings.wordWrapDescription": "超出宽度的长行自动折行显示,关闭后横向滚动查看。",
"settings.syntax": "支持的 Markdown 语法",
"settings.syntaxDescription": "Previewer 能识别的 Markdown 写法。基础部分遵循 GitHub Flavored Markdown,另外支持若干常见方言与两种图表围栏。",
"settings.syntaxGroupBasic": "基础",
"settings.syntaxGroupBlocks": "块级",
"settings.syntaxGroupExtended": "扩展",
"settings.syntaxHeading": "一到六级标题,自动生成大纲",
"settings.syntaxEmphasis": "行内强调与代码",
"settings.syntaxLinkImage": "链接与图片,相对路径按文档位置解析",
"settings.syntaxList": "无序、有序与可勾选的任务列表",
"settings.syntaxQuote": "引用块,可嵌套",
"settings.syntaxRule": "水平分隔线",
"settings.syntaxCodeFence": "围栏代码块,按语言高亮",
"settings.syntaxTable": "表格,支持对齐冒号",
"settings.syntaxDefinitionList": "定义列表",
"settings.syntaxFootnote": "脚注引用与文末脚注区",
"settings.syntaxAlert": "GFM 提示块(NOTE/TIP/IMPORTANT/WARNING/CAUTION)与 Obsidian Callout([!tip] 标题、+/- 折叠)",
"settings.syntaxFrontmatter": "YAML frontmatter,可在顶部折叠面板中查看与编辑",
"settings.syntaxHighlight": "高亮与插入标记",
"settings.syntaxSubSup": "下标与上标",
"settings.syntaxMath": "KaTeX 数学公式,也支持 \\( \\) 与 \\[ \\] 分隔符",
"settings.syntaxMermaid": "Mermaid 图表;mindmap 语法渲染为脑图",
"settings.syntaxSvg": "SVG,经白名单消毒后渲染",
"settings.syntaxHtml": "静态展示类标签;脚本、事件属性与危险协议会被移除",
"settings.shortcuts": "快捷键",
"settings.shortcutsDescription": "编辑 Markdown 时可用的快捷键。按键随平台显示,macOS 上 Ctrl 显示为 ⌘。",
"settings.shortcutGroupFormat": "行内格式",
"settings.shortcutGroupBlocks": "块级格式",
"settings.shortcutGroupDocument": "文档操作",
"settings.fileTypes": "文件关联",
"settings.fileTypesDescription": "Previewer 支持的文件类型。可查看每个类型当前的系统打开方式,将 Tabbit 设为系统默认,或选择在浏览器内使用 Previewer 还是浏览器自带方式打开。",
"settings.currentHandler": "当前系统默认应用",
"settings.currentHandlerSelf": "Tabbit(当前浏览器)",
"settings.currentHandlerUnknown": "未检测到默认应用",
"settings.detecting": "检测中...",
"settings.detectUnavailable": "无法检测",
"settings.systemDefault": "设为系统默认",
"settings.systemDefaultActive": "已是系统默认打开方式",
"settings.setAsDefault": "设为默认",
"settings.setAllAsDefault": "全部设为默认",
"settings.setAllNothingPending": "该分类目前没有可批量设为默认的项",
"settings.unsetDefaultHint": "如需取消默认,请在系统设置中修改",
"settings.openWith": "Tabbit 内打开方式",
"settings.openWithPreviewer": "Tabbit Previewer",
"settings.openWithNative": "浏览器自带",
"settings.openWithNativeUnavailable": "该格式无法用浏览器自带方式正常显示",
"settings.setDefaultRequested": "已请求将 Tabbit 设为 {extension} 的默认打开方式",
"settings.openedSystemSettings": "已打开系统设置,请选择 Tabbit 作为 {extension} 的默认应用",
"settings.setDefaultUnsupported": "当前系统暂不支持设置 {extension} 的默认应用",
"settings.setDefaultFailed": "设置 {extension} 默认打开方式失败",
"settings.type.markdown": "Markdown",
"settings.type.svg": "SVG",
"settings.type.image": "图片",
"settings.type.media": "音频与视频",
"settings.type.pdf": "PDF",
"settings.type.office": "Office 文档",
"settings.type.html": "HTML",
"settings.type.codeText": "代码与文本",
"settings.type.subtitle": "字幕",
"settings.type.archive": "压缩包",
"editor.sourceLabel": "文件内容",
"markdown.contentLabel": "Markdown 内容",
"code.contentLabel": "代码内容",
"code.delimitedContentLabel": "表格原始文本",
"code.tablePreviewAria": "{fileName} 表格预览",
"code.unnamedColumn": "列 {index}",
"code.tablePreviewLimited": "仅预览前 {rows} 行、前 {columns} 列;编辑态保留完整原始文本。",
"code.noFormattingNeeded": "当前内容无需格式化",
"code.formatApplied": "已应用格式化",
"code.sourceReloaded": "{fileName} 源文件已重新读取",
"code.formatJson": "格式化 JSON",
"code.expandCode": "展开代码",
"code.subtitleViewMode": "字幕视图",
"code.subtitleTimeline": "时间轴",
"code.subtitleSource": "源码",
"code.subtitleInfoFormat": "格式",
"code.subtitleInfoCues": "条数",
"code.subtitleInfoDuration": "时长",
"code.subtitleInfoLanguage": "语言",
"code.subtitleInfoEncoding": "编码",
"code.subtitleTimelineTruncated": "字幕过多,时间轴仅显示前 {shown} 条(共 {total} 条),完整内容请切换到源码视图",
"code.subtitleSearchPlaceholder": "搜索台词,或输入 12:30 跳转",
"code.subtitleCopyCue": "复制这条字幕",
"code.subtitleTextView": "纯文本",
"code.subtitleTextTruncated": "字幕过多,纯文本视图仅显示前 {shown} 条(共 {total} 条);「复制全文」仍包含全部内容",
"code.subtitleBilingual": "双语",
"code.subtitleEncodingTooltip": "检测到的文件编码",
"code.subtitleTranscode": "转存为 UTF-8",
"code.subtitleTranscoded": "已转存为 UTF-8,旧播放器不再乱码",
"code.subtitleTranscodeFailed": "转存失败,请重试",
"code.subtitleBinaryNotice": "这是二进制的位图字幕文件(VobSub 图形字幕),无法作为文本预览或编辑。请将它与同名 .idx 文件放在一起,在视频播放器中加载使用。",
"code.subtitleExportMenu": "导出",
"code.subtitleExportSrt": "SRT",
"code.subtitleExportVtt": "VTT",
"code.subtitleExportTxt": "纯文本 (TXT)",
"code.subtitleExportUnparseable": "无法解析字幕内容,未导出",
"code.subtitleExported": "已导出 {fileName}",
"code.subtitleExportFailed": "导出失败,请重试",
"code.searchPlaceholder": "查找",
"code.searchPrev": "上一个",
"code.searchNext": "下一个",
"code.searchClose": "关闭",
"code.replacePlaceholder": "替换为",
"code.replaceOne": "替换",
"code.replaceAll": "全部替换",
"code.replacedCount": "已替换 {count} 处",
"code.subtitleShiftMenu": "时轴平移",
"code.subtitleShiftLabel": "偏移量(毫秒)",
"code.subtitleShiftHint": "正值延后、负值提前,应用后直接保存。仅修正整体偏移,无法修复帧率漂移。",
"code.subtitleShiftApply": "应用并保存",
"code.subtitleShiftInvalid": "请输入非零的毫秒偏移量",
"code.subtitleShifted": "已平移 {count} 条时间轴并保存",
"code.subtitleShiftedClamped": "已平移并保存,部分时间被截止到 00:00",
"code.subtitleShiftFailed": "平移保存失败,请重试",
"code.subtitleShiftExported": "该格式不支持原位平移,已导出平移后的 {fileName}",
"code.subtitleCleanMenu": "清理",
"code.subtitleCleanTags": "去除样式标签",
"code.subtitleCleanAnnotations": "去除括注说明(SDH)",
"code.subtitleCleanMusic": "去除音乐符号行",
"code.subtitleCleanDuplicates": "合并重复与空白条目",
"code.subtitleCleaned": "已清理 {count} 处并保存",
"code.subtitleCleanNothing": "没有需要清理的内容",
"code.subtitleCleanFailed": "清理失败,请重试",
"code.subtitleCleanExported": "该格式不支持原位清理,已导出清理后的 {fileName}",
"code.subtitleTranslate": "翻译字幕并保存为新文件",
"code.subtitleTranslateTitle": "翻译字幕",
"code.subtitleTranslateModeLabel": "输出内容",
"code.subtitleTranslateModeBilingual": "双语(译文在上)",
"code.subtitleTranslateModeReplace": "仅译文",
"code.subtitleTranslateLanguageLabel": "目标语言",
"code.subtitleTranslateOutputLabel": "保存方式",
"code.subtitleTranslateOutputNew": "另存为新文件",
"code.subtitleTranslateOutputOverwrite": "覆盖当前文件",
"code.subtitleTranslateOverwriteUnavailable": "仅本地 SRT 文件支持覆盖保存,当前文件将另存为新文件",
"code.subtitleTranslateSummary": "将翻译 {count} 条字幕(约 {characters} 字符),已包含目标语言的条目会自动跳过。翻译会消耗账户用量。",
"code.subtitleTranslateNothing": "没有需要翻译的条目(可能已包含目标语言)",
"code.subtitleTranslateStart": "开始翻译",
"code.subtitleTranslateCancel": "取消",
"code.subtitleTranslateRunning": "正在翻译 {completed}/{total} 条…",
"code.subtitleTranslateCancelled": "已取消,未修改文件",
"code.subtitleTranslateUnavailable": "翻译服务不可用,请确认浏览器版本",
"code.subtitleTranslateSourceChanged": "字幕内容已变化,请重新开始翻译",
"code.subtitleTranslateFailed": "翻译失败:{error}",
"code.subtitleTranslateDoneOverwrite": "已翻译 {count} 条并保存到当前文件",
"code.subtitleTranslateDoneExported": "已翻译 {count} 条,导出为 {fileName}",
"code.subtitleLangChinese": "中文",
"code.subtitleLangJapanese": "日文",
"code.subtitleLangKorean": "韩文",
"code.subtitleLangLatin": "英文",
"code.subtitleLangCyrillic": "西里尔文",
"code.subtitleLangArabic": "阿拉伯文",
"subtitle.binaryUnknown": "二进制 SUB",
"subtitle.vobsubDescription": "检测到 MPEG Program Stream / DVD subpicture 数据;不会按文本解码或写回。",
"subtitle.binaryDescription": "该 SUB 文件包含二进制数据,已停止文本解码以避免乱码或误写。",
"subtitle.vobsubCompanionHint": "VobSub 画面、语言和时间索引通常由同名 .idx 文件描述;请同时打开配套 IDX 查看时间戳。",
"subtitle.scannedBytes": "已检查头部",
"subtitle.packHeaders": "MPEG pack 头",
"subtitle.privateStreams": "字幕私有流包",
"html.sourceLoading": "正在读取源码",
"html.sourceEditorAria": "HTML source editor",
"html.previewAria": "HTML preview",
"html.previewFrameTitle": "{fileName} preview",
"html.printFrameTitle": "{fileName} 打印预览",
"html.preparing": "正在准备源码与预览",
"html.viewMode": "HTML view mode",
"html.modeSource": "源码",
"html.modeSplit": "分屏",
"html.modePreview": "预览",
"html.reload": "重新读取",
"html.sourceReloaded": "已重新读取源码",
"html.sourceRead": "已读取 HTML 源码",
"html.readFailed": "读取失败:无法读取 HTML 源文件",
"html.readRequiresWorkspace": "读取失败:需要本地写回服务读取 HTML 源码",
"html.previewUnavailable": "该文件可能已被移至别处、修改或删除。",
"html.previewUnavailableInArchive": "压缩包内的 HTML 暂不支持预览。可在左侧查看源码,解压后打开即可正常预览。",
"html.previewUnavailableInArchiveStatus": "暂不支持预览",
"image.stageAria": "Image preview stage",
"image.loadingTitle": "正在加载图片",
"image.loadingMeta": "{extension} · 正在读取图片",
"image.readyStatus": "可缩放、拖动、旋转和翻转",
"image.zoomOut": "缩小",
"image.zoomIn": "放大",
"image.fit": "适应窗口",
"image.actualSize": "100% 原始尺寸",
"image.rotateLeft": "左转",
"image.rotateRight": "右转",
"image.flipHorizontal": "水平翻转",
"image.flipVertical": "垂直翻转",
"image.reset": "重置",
"image.exportPng": "PNG",
"image.loadFailedTitle": "图片加载失败",
"image.loadFailedMeta": "{extension} · 加载失败",
"image.loadFailedStatus": "无法读取当前图片,请检查链接是否仍然有效",
"image.zoomedOut": "已缩小视图",
"image.zoomedIn": "已放大视图,可拖动查看细节",
"image.fitApplied": "已适应窗口",
"image.actualSizeApplied": "已切换到 100% 原始尺寸",
"image.resetApplied": "已重置变换并适应窗口",
"image.wheelZoomed": "滚轮缩放视图,可拖动查看细节",
"image.transformed": "有图片变换",
"image.panned": "已移动视图",
"image.notLoaded": "图片尚未加载完成",
"image.exportedPng": "已导出 PNG",
"image.exportFailed": "导出失败,浏览器可能限制了当前本地图片的画布读取",
"media.kind.audio": "音频",
"media.kind.video": "视频",
"media.loading": "正在读取媒体信息",
"media.playbackRate": "播放速度",
"media.playbackRateValue": "播放速度:{rate}",
"media.pictureInPicture": "画中画",
"media.pictureInPictureActive": "已进入画中画模式",
"media.pictureInPictureFailed": "无法进入画中画模式",
"media.fullscreen": "全屏",
"media.fullscreenActive": "已进入全屏模式",
"media.fullscreenFailed": "无法进入全屏模式",
"media.loadFailed": "媒体加载失败",
"media.loadFailedDetail": "无法播放此媒体;容器或内部编码可能不受支持",
"svg.stageAria": "SVG 预览区域,放大后可使用方向键移动视图",
"pdf.loadingMeta": "PDF · 正在读取文件",
"pdf.initialStatus": "使用 PDF.js 渲染,原始文件可作为浏览器兜底",
"pdf.toggleNavigation": "显示或隐藏 PDF 导航",
"pdf.navLabel": "导航",
"pdf.hideNavigation": "隐藏 PDF 导航",
"pdf.showNavigation": "显示 PDF 导航",
"pdf.previousPage": "上一页",
"pdf.nextPage": "下一页",
"pdf.pageJumpTitle": "跳转到指定页码",
"pdf.currentPage": "当前页码",
"pdf.pageLabelTitle": "第 {page} 页 · 页码标签 {label}",
"pdf.searchTitle": "搜索 PDF 文本",
"pdf.searchPlaceholder": "搜索 PDF",
"pdf.previousSearchResult": "上一个搜索结果",
"pdf.nextSearchResult": "下一个搜索结果",
"pdf.fitWidth": "适应宽度",
"pdf.fitPage": "适应整页",
"pdf.handTool": "拖拽平移",
"pdf.handToolOn": "已开启拖拽平移:按住鼠标左键拖动页面",
"pdf.handToolOff": "已关闭拖拽平移:拖动可选择文本",
"pdf.rotateRight": "右转",
"pdf.viewMode": "PDF 视图模式",
"pdf.viewContinuous": "连续",
"pdf.viewSingle": "单页",
"pdf.viewTwoPage": "双页",
"pdf.readAloud": "朗读当前页或所选文本",
"pdf.readAloudLabel": "朗读",
"pdf.rerender": "重新渲染",
"pdf.navAria": "PDF 导航",
"pdf.navTabsAria": "PDF 导航面板",
"pdf.navTitle": "阅读导航",
"pdf.tabPages": "页面",
"pdf.tabOutline": "目录",
"pdf.tabNotes": "备注",
"pdf.infoLoading": "正在读取文档信息",
"pdf.infoEmpty": "这个 PDF 没有可读取的文档信息",
"pdf.propTitle": "标题",
"pdf.propAuthor": "作者",
"pdf.propSubject": "主题",
"pdf.propKeywords": "关键词",
"pdf.propCreator": "创建工具",
"pdf.propProducer": "PDF 生成器",
"pdf.propCreated": "创建时间",
"pdf.propVersion": "PDF 版本",
"pdf.infoAttachments": "附件",
"pdf.attachmentSave": "另存附件 {name}",
"pdf.attachmentSaving": "正在保存附件 {name}",
"pdf.attachmentSaved": "已保存附件 {name}",
"pdf.attachmentSaveFailed": "无法保存附件 {name}",
"pdf.infoLayers": "图层",
"pdf.layerUntitled": "未命名图层",
"pdf.layerShown": "已显示图层「{name}」",
"pdf.layerHidden": "已隐藏图层「{name}」",
"pdf.infoSignature": "数字签名",
"pdf.infoSignatureN": "数字签名 {index}",
"pdf.metaSigned": "已签名",
"pdf.signatureSigner": "签名人",
"pdf.signatureTime": "签名时间",
"pdf.signatureReason": "原因",
"pdf.signatureLocation": "地点",
"pdf.signatureContact": "联系方式",
"pdf.signatureField": "签名域",
"pdf.permission.print": "打印",
"pdf.permission.copy": "复制文本",
"pdf.permission.modify": "修改内容",
"pdf.permission.annotate": "添加批注",
"pdf.permission.forms": "填写表单",
"pdf.permissionAllowed": "允许",
"pdf.permissionRestricted": "作者已限制",
"pdf.printRestricted": "这个 PDF 的作者限制了打印,打印结果可能受限",
"pdf.copyRestricted": "这个 PDF 的作者限制了复制文本",
"pdf.navLoading": "正在准备导航",
"pdf.notePlaceholder": "为当前页记录备注",
"pdf.noteHint": "备注只保存在这台设备,不会写入 PDF 原文件。",
"pdf.noteAria": "当前 PDF 页面备注",
"pdf.stageAria": "{fileName} PDF preview",
"pdf.loadingTitle": "正在加载 PDF",
"pdf.loadingDescription": "解析文件并准备页面渲染。",
"pdf.zoomedOut": "已缩小视图",
"pdf.zoomedIn": "已放大视图",
"pdf.fitWidthApplied": "已适应宽度",
"pdf.fitPageApplied": "已适应整页",
"pdf.actualSizeApplied": "已切换到 100% 原始尺寸",
"pdf.rotatedRight": "已右转 PDF 视图",
"pdf.viewModeApplied": "已切换到 {mode} 视图",
"pdf.rerenderingVisible": "正在重新渲染可见页面",
"pdf.wheelZoomed": "滚轮缩放 PDF 视图",
"pdf.readFailed": "无法读取 PDF 文件。可以尝试打开原始文件。",
"pdf.parsing": "正在解析 PDF",
"pdf.renderedPages": "PDF.js 渲染 · 共 {pages}",
"pdf.pageAria": "第 {page} 页",
"pdf.thumbnailTitle": "跳转到第 {page} 页",
"pdf.pageHasNote": "这一页有备注",
"pdf.waitingRender": "等待渲染",
"pdf.rendering": "正在渲染",
"pdf.renderFailed": "渲染失败",
"pdf.noTranslatableText": "此页未检测到可翻译文本;扫描件需要 OCR 文字层。",
"pdf.translationPageAria": "第 {page} 页翻译",
"pdf.translatingPage": "正在翻译第 {page} 页…",
"pdf.translationProgress": "已完成 {completed}/{total} 段",
"pdf.translationFailed": "此页翻译失败",
"pdf.translationRetry": "翻译失败,点击重试",
"pdf.translationBudgetExceeded": "此页文字过多,已超过翻译上限(64 段或 48K 字符)。",
"pdf.ocrTextTooLarge": "此页识别文字超过 64KiB,无法安全翻译。",
"pdf.readingProgress": "正在读取 PDF · {percent}%",
"pdf.searching": "正在搜索 PDF 文本",
"pdf.searchFound": "找到 {count} 个匹配项",
"pdf.searchNoResults": "没有找到匹配项",
"pdf.searchCleared": "已清除搜索",
"pdf.notePage": "第 {page} 页备注",
"pdf.noteUnsaved": "备注未保存",
"pdf.noteSaved": "备注已保存到本机",
"pdf.marksTitle": "本页标注",
"pdf.marksHint": "选中正文后可高亮或下划线。标注只保存在本机,不写入 PDF。",
"pdf.marksEmpty": "这一页还没有标注",
"pdf.markHighlight": "高亮",
"pdf.markUnderline": "下划线",
"pdf.markCopy": "复制",
"pdf.toolHighlight": "高亮",
"pdf.toolInk": "画笔",
"pdf.toolFreeText": "文字",
"pdf.toolStamp": "图片",
"pdf.editUnavailable": "当前 PDF.js 版本不支持标注编辑",
"pdf.editRestricted": "文档作者已限制添加批注",
"pdf.exportAnnotated": "导出一份带标注的副本,原文件不变",
"pdf.exportAnnotatedLabel": "带标注的 PDF 副本",
"pdf.exportAnnotatedNeedsEdit": "进入编辑模式并添加标注后,可导出带标注的副本",
"pdf.exportAnnotatedDone": "已导出 {name}",
"pdf.exportAnnotatedFailed": "导出带标注副本失败",
"pdf.annotatedCopySuffix": "标注",
"pdf.saveAnnotations": "把标注写入原 PDF 文件",
"pdf.saveAnnotationsDone": "标注已写入原文件",
"pdf.saveAnnotationsFailed": "标注写入原文件失败",
"pdf.saveAnnotationsConfirmTitle": "写入原 PDF 文件?",
"pdf.saveAnnotationsConfirmDescription": "将把本次编辑的标注写入「{fileName}」本体,覆盖磁盘上的原文件。预览模式的高亮与下划线只存在本机,不会一起写入。",
"pdf.saveAnnotationsConfirm": "写入原文件",
"pdf.annotationsEmpty": "还没有可保存的标注",
"pdf.markAdded": "已添加{kind},只保存在本机",
"pdf.markRemoved": "已删除标注",
"pdf.markDelete": "删除标注",
"pdf.markJump": "定位到这条{kind}",
"pdf.copied": "已复制所选文本",
"pdf.copyFailed": "复制失败",
"pdf.selectionToolbarAria": "所选文本操作",
"pdf.outlineLoading": "正在读取目录",
"pdf.outlineUnavailable": "当前 PDF 没有可读取目录",
"pdf.outlineEmpty": "这个 PDF 没有目录",
"pdf.outlineUntitled": "未命名目录项",
"pdf.outlineGoTo": "跳转到第 {page} 页",
"pdf.outlineExternal": "打开外部链接",
"pdf.linkInternal": "跳转到文档内的链接目标",
"pdf.linkUnresolved": "这个链接的目标页面无法定位",
"pdf.annotationAria": "批注:{summary}",
"pdf.readAloudStopped": "已停止朗读",
"pdf.readAloudNoText": "当前页没有可朗读文本",
"pdf.readAloudFinished": "朗读结束",
"pdf.readAloudFailed": "朗读失败",
"pdf.readAloudSelection": "正在朗读所选文本",
"pdf.readAloudPage": "正在朗读第 {page} 页",
"pdf.previewFailedTitle": "PDF 预览失败",
"pdf.passwordRequired": "这个 PDF 需要密码,当前预览暂不处理加密 PDF。",
"pdf.renderErrorDetail": "PDF.js 无法渲染此文件:{detail}",
"pdf.renderError": "PDF.js 无法渲染此文件。",
"pdf.canvasUnavailable": "当前浏览器无法创建 PDF canvas。",
"office.loadingTitle": "正在读取文件",
"office.loadingDescription": "会尽量提取可预览的内容。",
"office.kindStatus": "{kind} 文档",
"office.parsing": "正在解析文档内容",
"office.readFailed": "无法读取当前本地文件。",
"office.unsupportedExtension": "暂不支持该 Office 扩展名。",
"office.parseFailed": "文档解析失败,可能是加密文件、损坏文件或浏览器不支持 ZIP 解压。",
"office.noDocxBody": "没有找到 DOCX 正文内容。",
"office.docxMeta": "DOCX · {paragraphs} · 只读文本预览,复杂样式以原文件为准",
"office.docxBodyLabel": "DOCX 正文",
"office.docxReady": "已读取 DOCX,当前为只读文本预览",
"office.docxRendering": "正在渲染 DOCX 预览",
"office.docxRendered": "已渲染 DOCX 预览",
"office.docxFitWidth": "适应宽度",
"office.docxZoomedOut": "已缩小 DOCX 预览",
"office.docxZoomedIn": "已放大 DOCX 预览",
"office.docxFitWidthApplied": "已适应 DOCX 页面宽度",
"office.docxActualSizeApplied": "已切换到 DOCX 100% 原始尺寸",
"office.noXlsxSheets": "没有找到 XLSX 工作表。",
"office.sheet": "工作表",
"office.sheetCount": "共 {count}",
"office.currentSheetTsv": "当前工作表 TSV",
"office.sheetSwitched": "已切换工作表",
"office.noPptxSlides": "没有找到 PPTX 幻灯片。",
"office.pptxMissingViewer": "PptxViewJS 未加载,已切换到文本大纲预览",
"office.pptxRendering": "正在使用 PptxViewJS 渲染 PPTX",
"office.pptxReady": "已读取 PPTX,当前为只读文本大纲预览",
"office.pptxTextLabel": "PPTX 幻灯片文本",
"office.pptxOutlineTitle": "文本大纲",
"office.pptxOutlineDescription": "查看幻灯片文本",
"office.pptxBackToSlides": "返回幻灯片预览",
"office.pptxViewerLoading": "正在加载 {count}",
"office.pptxPreviousPage": "上一页",
"office.pptxNextPage": "下一页",
"office.pptxZoomOut": "缩小",
"office.pptxZoomIn": "放大",
"office.pptxFit": "适应",
"office.pptxViewerMountFailed": "PPTX 预览器挂载失败,已切换到文本大纲预览",
"office.pptxRenderingPage": "正在渲染第 {page} 页",
"office.pptxViewerReady": "PptxViewJS 预览",
"office.pptxViewerReadyStatus": "已使用 PptxViewJS 渲染 PPTX",
"office.pptxRenderFailed": "PptxViewJS 渲染失败,已切换到文本大纲预览",
"office.legacyUnsupportedStatus": "旧版 Office 二进制格式暂不支持浏览器内解析",
"office.legacyUnsupportedTitle": "{extension} 暂不支持预览",
"office.legacyUnsupportedDescription": "轻量方案先支持 .docx / .xlsx / .pptx。旧版格式建议另存为新版 OOXML 后再打开。",
"office.parseErrorTitle": "无法解析文档",
"office.emptyDocxTitle": "没有提取到正文",
"office.emptyDocxDescription": "该文档可能主要由图片、图表或受保护内容组成。",
"office.emptyXlsxTitle": "没有可展示的表格内容",
"office.emptyXlsxDescription": "可以切换到编辑态填写 TSV 内容后保存。",
"office.chart": "图表",
"office.chartSeries": "系列 {index}",
"office.chartUnresolved": "图表结构已识别,但引用的数据范围暂时无法解析。",
"office.embeddedChart": "嵌入图表",
"office.emptyPptxTitle": "没有提取到幻灯片文本",
"office.emptyPptxDescription": "该演示文稿可能主要由图片或图形组成。",
"office.blankSlide": "空白幻灯片",
"office.xlsxMeta": "XLSX · {sheetName} · {sheetCount} · 保存当前显示值,复杂公式/样式以轻量兼容为准",
"office.pptxMeta": "PPTX · {slides} · {images} · 轻量编辑会保存文本,图片/版式保留原文件结构",
"unsupported.displayName": "不支持的文件",
"unsupported.description": "当前文件类型无法直接预览,可以在文件管理器中定位。",
"unsupported.type": "类型",
"unsupported.path": "路径",
"unsupported.size": "大小",
"unsupported.created": "创建时间",
"unsupported.modified": "修改时间",
"unsupported.reading": "正在读取...",
"unsupported.revealRequested": "已请求文件管理器定位",
"unsupported.revealFailed": "无法定位文件",
"unsupported.unreadable": "无法读取",
"zip.displayName": "压缩包",
"zip.kicker": "Archive",
"zip.folderKicker": "Archive folder",
"zip.entryKicker": "Archive entry",
"zip.loading": "正在读取压缩包...",
"zip.ready": "已读取压缩包索引",
"zip.refresh": "从磁盘重新读取",
"zip.description": "在左侧目录树中展开即可浏览压缩包内的文件,无需解压。",
"zip.emptyArchive": "这个压缩包里没有文件。",
"zip.entries": "文件条目",
"zip.childEntries": "当前层级",
"zip.uncompressedSize": "原始大小",
"zip.compressedSize": "压缩后大小",
"zip.ratio": "压缩率",
"zip.archiveSize": "压缩包大小",
"zip.archive": "所属压缩包",
"zip.entryPath": "包内路径",
"zip.readOnly": "压缩包内的文件是只读的,无法修改或重命名。",
"zip.readFailed": "无法读取这个压缩包。",
"zip.tooLarge": "压缩包超过 {size} 的预览上限,未读取内容。",
"zip.corrupt": "文件已损坏,或者不是有效的 ZIP 压缩包。",
"zip.skippedUnsafe": "已跳过 {count} 个路径越界的条目。",
"zip.truncated": "条目过多,仅索引前 {count} 项。",
"zip.encryptedEntries": "其中 {count} 个条目已加密,无法预览。",
"zip.entryEncrypted": "这个条目已加密,需要密码才能解压,无法预览。",
"zip.entryUnsupportedMethod": "这个条目使用了浏览器不支持的压缩算法,无法预览。",
"zip.entryTooLarge": "这个条目解压后超过单条目预览上限,未展开。",
"zip.entryRatio": "这个条目的压缩比异常,出于安全考虑没有解压。",
"zip.entryCorrupt": "这个条目已损坏,无法解压。",
"zip.entryNotFound": "压缩包中找不到这个条目。",
"fileType.directory": "文件夹",
"fileType.markdown": "Markdown",
"fileType.svg": "SVG",
"fileType.image": "图片",
"fileType.pdf": "PDF",
"fileType.office": "Office",
"fileType.html": "HTML",
"fileType.code-text": "代码 / 文本",
"fileType.unsupported": "不支持的文件"
},
en: {
"app.description": "Local file rendering",
"viewer.openingTitle": "Opening file",
"viewer.openingDescription": "Previewer is preparing the file preview.",
"common.fileName": "File Name",
"common.fileSize": "Size",
"common.fileCreated": "Created",
"common.fileModified": "Modified",
"common.today": "Today",
"common.yesterday": "Yesterday",
"common.filePath": "File Path",
"common.pathEllipsis": "...",
"common.showCollapsedPath": "Show collapsed middle path",
"common.collapsedPathSegments": "Collapsed middle path",
"common.fileActions": "File Actions",
"common.fileInfo": "File Info",
"common.moreActions": "More Actions",
"common.renameFile": "Rename File",
"common.expandExplorer": "Expand Explorer",
"common.collapseExplorer": "Collapse Explorer",
"common.expandHeader": "Expand File Header",
"common.collapseHeader": "Collapse File Header",
"common.rawFile": "Raw File",
"common.openInNewTab": "Open in New Tab",
"common.save": "Save",
"common.saveAs": "Save As...",
"common.downloadRemoteFile": "Download to Local Device",
"common.print": "Print",
"print.preparing": "Preparing content for printing…",
"print.failed": "Unable to prepare content for printing",
"print.notReady": "The content is not ready yet. Please try again shortly.",
"print.pageAlt": "Print page {page}",
"print.namedPageAlt": "{fileName}, page {page}",
"print.preparingPage": "Preparing page {page} of {total}…",
"print.preparingSlide": "Preparing slide {slide} of {total}…",
"print.namedSlideAlt": "{fileName}, slide {slide}",
"common.edit": "Edit",
"common.preview": "Preview",
"common.copy": "Copy",
"common.copyAllText": "Copy All",
"common.export": "Export",
"common.revealInFileManager": "Show in File Manager",
"common.revealInFinder": "Show in Finder",
"common.revealInExplorer": "Show in Explorer",
"common.revealUnavailableRemote": "Online pages cannot be shown",
"common.editUnavailableRemote": "Online pages cannot be edited",
"common.fileUnavailable": "This file may have been moved, changed, or deleted.",
"common.unknown": "Unknown",
"common.unknownError": "Unknown error",
"common.untitled": "Untitled",
"common.localFile": "Local file",
"common.loading": "Loading...",
"common.notModified": "Not modified",
"common.unsavedChanges": "Unsaved changes",
"common.unexportedChanges": "Unexported changes",
"common.copiedToClipboard": "Copied to clipboard",
"common.copiedSelectedText": "Copied selected text",
"common.copyFailed": "Copy failed",
"common.saving": "Saving...",
"common.exporting": "Exporting...",
"common.savingAs": "Saving as...",
"common.downloadingRemoteFile": "Downloading...",
"common.savedToOriginal": "Saved to original file",
"common.saved": "Saved",
"common.savedAs": "Saved as",
"common.downloadedRemoteFile": "Downloaded to local device",
"common.exportedToDownloads": "Exported to Downloads",
"common.cancelledExport": "Export canceled",
"common.cancelledSaveAs": "Save as canceled",
"common.cancelledDownload": "Download canceled",
"common.cancel": "Cancel",
"common.saveFailedWorkspace": "Save failed: unable to write the current workspace file",
"common.exportFailed": "Export failed",
"common.saveAsFailed": "Save as failed",
"common.downloadRemoteFailed": "Download failed: unable to read the online file",
"common.downloadUnavailable": "This file cannot be downloaded",
"common.fileContent": "File content",
"common.textFile": "Text file",
"common.filePickerLocalFile": "Local file",
"editor.clean": "Synced",
"editor.external": "External edit",
"editor.externalHint": "Another program is editing this file; its changes are synced here automatically",
"changes.unreadAbove": "{count} unread above",
"changes.unreadBelow": "{count} unread below",
"changes.markAllRead": "Mark all as read",
"changes.jump": "Jump to this change",
"changes.added": "Added externally",
"changes.modified": "Modified externally",
"changes.deleted": "Lines removed externally",
"editor.readonly": "Read only",
"editor.dirty": "Unsaved",
"editor.saving": "Saving",
"editor.saved": "Saved",
"editor.autoSavePending": "Autosaving",
"editor.autoSaved": "Autosaved",
"editor.savedAsUtf8": "The file was {encoding}-encoded and cannot hold this content; it was saved as UTF-8",
"editor.error": "Save failed",
"editor.conflict": "File conflict",
"editor.draftRestored": "Recovered unsaved draft",
"editor.draftOutOfSpace": "Browser storage is full, so this document has no recovery draft. Nothing was cut from your text — save it to the file soon.",
"editor.unsavedTitle": "Save changes?",
"editor.unsavedDescription": "“{fileName}” has unsaved changes.",
"editor.saveBeforeLeave": "Save changes to “{fileName}” before leaving?",
"editor.discardBeforeLeave": "Discard unsaved changes to “{fileName}”?",
"editor.discard": "Discard changes",
"editor.beforeUnload": "The current file has unsaved changes.",
"editor.revertTitle": "Revert to the opened content?",
"editor.revertDescription": "This discards every change made to “{fileName}” since it was opened, including changes already autosaved to disk.",
"editor.revertConfirm": "Revert",
"editor.conflictTitle": "File changed elsewhere",
"editor.conflictDescription": "The copy of “{fileName}” on disk has changed. To avoid silently overwriting someone else's work, saving can continue only after explicit confirmation. You can also cancel and use Save As.",
"editor.overwrite": "Overwrite anyway",
"markdown.bold": "Bold",
"markdown.italic": "Italic",
"markdown.insertLink": "Insert Link",
"markdown.insertImage": "Insert Image",
"markdown.widthDecrease": "Decrease Content Width",
"markdown.contentWidth": "Content Width",
"markdown.widthIncrease": "Increase Content Width",
"markdown.taskToggle": "Toggle task status",
"markdown.taskReadonlyRemote": "Online Markdown is read-only. Download it locally to edit tasks.",
"large.previewTitle": "Large-file safety preview",
"large.previewDescription": "Loaded the first {previewSize}. More content loads on demand as you scroll; editing and saving are disabled.",
"large.previewAria": "{kind} large-file preview fragment",
"large.previewMeta": "{kind} · large-file preview · {size}",
"large.blockedTitle": "File too large for automatic preview",
"large.blockedDescription": "This {kind} file is {size}. Previewer did not read the full content to avoid crashing the browser. Open the raw file or reveal it in the file manager instead.",
"large.blockedMeta": "{kind} · file too large · {size}",
"large.emptyPreview": "Unable to read a safe preview fragment.",
"large.virtualStatus": "Showing {start} - {end} / {total}",
"large.virtualLoading": "Loading the next chunk...",
"large.virtualError": "Loading failed. Scroll again to retry.",
"large.directoryLimited": "Showing only the first {count} items. Very large folders are not rendered all at once.",
"toolbar.reveal": "Show in file manager",
"theme.followingBrowser": "Following browser {theme} theme. Click to temporarily pin {nextTheme}.",
"theme.fixed": "{theme} theme pinned. Click to follow the browser again.",
"theme.dark": "dark",
"theme.light": "light",
"rename.inProgress": "Renaming...",
"rename.success": "Renamed",
"rename.failed": "Rename failed: {error}",
"rename.invalidName": "File name contains invalid characters",
"rename.duplicateName": "A file with this name already exists in the current folder",
"rename.extensionNone": "no extension",
"rename.extensionChangeTitle": "Confirm extension change",
"rename.extensionChangeDescription": "The extension of \"{fileName}\" is about to change to \"{extension}\". This changes how the file opens. Rename anyway?",
"rename.extensionChangeConfirm": "Rename",
"common.panelMode": "Preview / edit mode",
"common.previewModeHint": "Preview mode (⌘E to toggle)",
"common.editModeHint": "Edit mode (⌘E to toggle)",
"common.editUnsupportedType": "This format does not support editing",
"common.copyAbsolutePath": "Copy Absolute Path",
"common.copiedPath": "Absolute path copied",
"common.duplicateFile": "Create a Copy",
"common.reloadFromDisk": "Reload from Disk",
"common.resizePanes": "Drag to resize the panes (double-click to reset)",
"common.reloadedFromDisk": "Reloaded from disk",
"common.reloadFailed": "Failed to read the file",
"common.revert": "Revert",
"common.revertToOpened": "Revert to the content the file was opened with",
"common.revertUnavailable": "Already matches the content the file was opened with",
"common.reverted": "Reverted to the content the file was opened with",
"common.saveNothingToSave": "No changes to save",
"common.saveHandledByAutoSave": "Autosave is handling this file",
"common.moreTools": "More Tools",
"common.undo": "Undo",
"common.quoteFileToChat": "Reference file in Chat",
"common.undoChatEdit": "Undo AI edit",
"common.chatEditConflict": "The content has changed; this edit cannot be safely undone.",
"common.redo": "Redo",
"common.fit": "Fit",
"common.zoomPercent": "Zoom level, type a percentage",
"duplicate.readFailed": "Failed to read the file; cannot create a copy",
"duplicate.failed": "Failed to create a copy: {error}",
"duplicate.success": "Created copy {fileName}",
"duplicate.namePattern": "{name} (copy)",
"duplicate.namePatternIndexed": "{name} (copy {index})",
"document.translate": "Translate this document into a new file or over the original",
"document.translateShort": "Translation…",
"document.translateTitle": "Export Translation",
"document.translateModeLabel": "Output",
"document.translateModeTranslationFirst": "Bilingual (translation first)",
"document.translateModeOriginalFirst": "Bilingual (original first)",
"document.translateModeReplace": "Translation only",
"document.translateLanguageLabel": "Target language",
"document.translateOutputLabel": "Save as",
"document.translateOutputNew": "Export a new file",
"document.translateOutputOverwrite": "Overwrite this file",
"document.translateSummaryExport": "Translates {count} blocks and exports {fileName} to your downloads. Code blocks, tables and link targets stay as they are. Translation uses your account quota.",
"document.translateSummaryOverwrite": "Translates {count} blocks and overwrites this file. Code blocks, tables and link targets stay as they are. Translation uses your account quota.",
"document.translateNothing": "There is no prose to translate",
"document.translateUnavailable": "Translation is unavailable; check that the translation extension is enabled",
"document.translateStart": "Translate",
"document.translateCancel": "Cancel",
"document.translateRunning": "Translating {completed}/{total}",
"document.translateCancelled": "Translation cancelled",
"document.translateFailed": "Translation failed: {error}",
"document.translateSourceChanged": "The document changed while translating; the overwrite was abandoned",
"document.translateDoneOverwrite": "Translated {count} blocks and saved",
"document.translateDoneExported": "Translated {count} blocks and exported {fileName} to your downloads",
"document.translateKeptOriginal": "; {count} blocks could not be translated and keep their original text",
"document.translateAllRejected": "the translation would have broken the document's syntax, so nothing was written",
"markdown.toc": "TOC",
"markdown.tocResizeAria": "Resize table of contents width",
"markdown.tocResizeTitle": "Drag to resize the table of contents (double-click to reset)",
"markdown.readingWidth": "Reading Width",
"markdown.widthFixed": "Fixed Width",
"markdown.widthFull": "Full Width",
"markdown.fontSize": "Font Size",
"markdown.fontDecrease": "Decrease Font Size",
"markdown.fontIncrease": "Increase Font Size",
"markdown.fontMedium": "M",
"markdown.fontLarge": "L",
"markdown.fontXLarge": "XL",
"markdown.heading1": "Heading 1",
"markdown.heading2": "Heading 2",
"markdown.heading3": "Heading 3",
"markdown.heading4": "Heading 4",
"markdown.heading5": "Heading 5",
"markdown.strikethrough": "Strikethrough",
"markdown.inlineCode": "Inline Code",
"markdown.unorderedList": "Bulleted List",
"markdown.orderedList": "Numbered List",
"markdown.taskList": "Task List",
"markdown.blockquote": "Blockquote",
"markdown.codeBlock": "Code Block",
"markdown.insertTable": "Insert Table",
"markdown.horizontalRule": "Horizontal Rule",
"markdown.clearFormat": "Clear Formatting",
"common.shortcutHint": "{label} ({shortcut})",
"markdown.tableHeader": "Column",
"markdown.tableCell": "Cell",
"markdown.editModeSwitch": "Editing Mode",
"markdown.editSource": "Source",
"markdown.editSplit": "Split",
"markdown.editInline": "Inline",
"markdown.inlineLoading": "Loading the inline editor...",
"markdown.codeCopied": "Copied",
"markdown.statLines": "Lines",
"markdown.statWords": "Words",
"markdown.exportHtml": "HTML",
"markdown.exportHtmlDone": "Exported HTML",
"markdown.exportHtmlFailed": "HTML export failed",
"markdown.exportPdf": "PDF",
"markdown.exportPdfWorking": "Generating PDF…",
"markdown.exportPdfDone": "Exported PDF",
"markdown.exportPdfFailed": "PDF export failed",
"markdown.exportImage": "Long image (PNG)",
"markdown.exportImageWorking": "Generating long image…",
"markdown.exportImageDone": "Exported long image",
"markdown.exportImageFailed": "Long image export failed",
"markdown.exportImageTooTall": "The document is too long for a single image",
"markdown.exportUnavailable": "This export is not available in the current environment",
"markdown.inlineLoadFailed": "Failed to load the inline editor; switched back to the source view",
"inline.placeholder": "Start writing...",
"inline.codeSearchLanguage": "Search language",
"inline.codeNoResult": "No result",
"inline.codePreview": "Preview",
"inline.codePreviewLoading": "Rendering diagram...",
"inline.codeHideCode": "Hide code",
"inline.linkPlaceholder": "Paste link...",
"inline.imageUrlPlaceholder": "Paste image URL...",
"markdown.searchPlaceholder": "Search in document",
"markdown.searchPrev": "Previous match",
"markdown.searchNext": "Next match",
"markdown.searchClose": "Close search",
"markdown.imagePasteFailed": "Failed to Save Image",
"markdown.formatTables": "Format Tables",
"markdown.frontmatter": "Frontmatter",
"markdown.frontmatterKey": "Property name",
"markdown.frontmatterValue": "Value",
"markdown.frontmatterEmptyValue": "No value",
"markdown.frontmatterAdd": "Add a property",
"markdown.frontmatterRemove": "Remove this property",
"markdown.frontmatterNewKey": "new-property",
"markdown.largeSourceOnly": "Large File: Source Editing Only",
"markdown.splitTooNarrow": "Not enough room for two panes",
"markdown.footnotes": "Footnotes",
"markdown.footnoteBackref": "Back to Reference",
"markdown.alertNote": "Note",
"markdown.alertTip": "Tip",
"markdown.alertImportant": "Important",
"markdown.alertWarning": "Warning",
"markdown.alertCaution": "Caution",
"markdown.alertAbstract": "Abstract",
"markdown.alertInfo": "Info",
"markdown.alertTodo": "Todo",
"markdown.alertSuccess": "Success",
"markdown.alertQuestion": "Question",
"markdown.alertFailure": "Failure",
"markdown.alertDanger": "Danger",
"markdown.alertBug": "Bug",
"markdown.alertExample": "Example",
"markdown.alertQuote": "Quote",
"markdown.searchToggleReplace": "Toggle Replace",
"markdown.searchCaseSensitive": "Match Case",
"markdown.searchReplacePlaceholder": "Replace with",
"markdown.searchReplaceOne": "Replace",
"markdown.searchReplaceAll": "Replace All",
"svg.sourceEditorAria": "SVG source editor",
"code.lineNumbers": "Line Numbers",
"code.wordWrap": "Word Wrap",
"code.highlightLanguage": "Syntax Highlighting",
"code.jsonRawStyle": "JSON display style",
"code.jsonStyleOriginal": "Original",
"code.jsonStylePretty": "Pretty",
"code.jsonStyleTree": "Tree",
"code.dataViewMode": "Data View",
"code.dataTreeLoading": "Parsing…",
"code.dataTreeParseError": "Parse Failed",
"code.jsonStyleCompact": "Compact",
"code.jsonFormatPretty2": "Pretty Format (2 Spaces)",
"code.jsonFormatPretty4": "Pretty Format (4 Spaces)",
"code.jsonFormatCompact": "Compact Format",
"code.invalidJson": "Invalid JSON; cannot run this action",
"code.compactApplied": "Compacted",
"code.jsonValid": "Valid JSON",
"code.jsonInvalid": "Invalid JSON",
"code.jsonExpandNode": "Expand",
"code.jsonCollapseNode": "Collapse",
"code.jsonTreeRoot": "root",
"code.jsonTreeAria": "JSON structure tree",
"code.jsonNodeKeys": "{count} keys",
"code.jsonNodeItems": "{count} items",
"code.jsonFoldLimited": "Folding is off above {lines} lines",
"code.lineNumbersUnavailable": "This display style has no line numbers",
"code.csvViewMode": "Table display mode",
"code.csvViewTable": "Table",
"code.csvViewRaw": "Raw Text",
"code.csvDimensions": "{rows} rows × {columns} columns",
"code.jsonlViewMode": "JSON Lines display mode",
"code.jsonlRecords": "{count} records",
"code.jsonlValid": "Every line is valid JSON",
"code.jsonlInvalidSummary": "Lines that are not valid JSON: {count}, first on line {line}",
"code.jsonlInvalidLine": "Line {line} is not valid JSON: {text}",
"code.jsonlInvalid": "not valid JSON",
"code.jsonlLineLabel": "Line {line}",
"code.jsonlLineColumn": "Line",
"code.jsonlValueColumn": "Value",
"code.jsonlTreeLimited": "Showing only the first {count} lines; edit mode keeps the complete source text.",
"code.errorLinesOnly": "Error Lines Only",
"code.errorLinesMatched": "Error lines only: {count} matched",
"code.noErrorLines": "(no matching error lines)",
"office.richPreviewReadOnly": "The rich preview does not support editing yet",
"directory.sortBy": "Sort By",
"directory.sortByName": "Name",
"directory.sortByKind": "Type",
"directory.sortDirection": "Sort Direction",
"directory.sortAscending": "Ascending",
"directory.sortDescending": "Descending",
"directory.viewMode": "View",
"directory.viewList": "List",
"directory.viewGrid": "Grid",
"directory.kindFolder": "Folder",
"create.inProgress": "Creating {fileName}...",
"create.success": "Created",
"create.failed": "Create failed: {error}",
"create.missingDirectory": "Cannot determine the current folder, so a file cannot be created.",
"create.workspaceUnavailable": "chrome.tabLocalWorkspace is not available, so a file cannot be created.",
"create.directoryNotWritable": "The current folder is not writable, so a file cannot be created.",
"create.new": "New",
"create.newFileType": "New File Type",
"outline.empty": "No TOC available",
"outline.aria": "Table of Contents",
"outline.title": "Table of Contents",
"outline.collapseAll": "Collapse all",
"outline.expandAll": "Expand all",
"outline.toggleAria": "Collapse or expand subsections",
"directory.aria": "Folder tree",
"directory.backToRoot": "Back to root folder",
"directory.backToParent": ".. Parent directory",
"directory.empty": "Empty folder",
"directory.loading": "Loading...",
"directory.expandFailed": "Unable to expand folder",
"directory.readFailed": "Unable to read folder",
"directory.previewDescription": "Files and subfolders are listed below and mirrored in the sidebar tree.",
"directory.previewItemCount": "Items",
"directory.previewPath": "Path",
"directory.resizeAria": "Resize sidebar width",
"directory.resizeTitle": "Drag to resize sidebar width",
"directory.settings": "Folder Options",
"directory.showHiddenFiles": "Show Hidden Items",
"directory.foldersFirst": "Folders First",
"directory.rememberSidebarWidth": "Remember Sidebar Width",
"directory.openSettingsPage": "Settings",
"directory.newFolder": "New Folder",
"directory.newFolderName": "untitled folder",
"directory.newFolderFailed": "Couldn't create the folder: {error}",
"directory.rename": "Rename",
"directory.renameAria": "New name",
"directory.moved": "Moved to “{folder}”",
"directory.moveFailed": "Couldn't move: {error}",
"directory.moveExists": "“{folder}” already has an item with this name",
"directory.extensionLocked": "This kind of file can't change its extension",
"directory.newFolderItem": "Folder",
"directory.favoritesMenu": "Favorite Folders",
"directory.favoritesEmpty": "No favorite folders yet. Use a folder's ⋯ menu, or the star in the file header, to add one.",
"trash.placeTrash": "Trash",
"trash.placeRecycleBin": "Recycle Bin",
"trash.action": "Move to {place}",
"trash.confirmTitle": "Move to {place}?",
"trash.confirmFile": "“{name}” will be moved to the {place}. You can restore it from there.",
"trash.confirmFolder": "The folder “{name}” and everything in it will be moved to the {place}. You can restore it from there.",
"trash.done": "Moved to the {place}",
"trash.failed": "Couldn't move to the {place}: {error}",
"favorites.add": "Add to Favorites",
"favorites.remove": "Remove from Favorites",
"favorites.added": "Added to Favorites",
"favorites.removed": "Removed from Favorites",
"popup.settings": "Settings",
"popup.favorites": "Favorites",
"popup.recents": "Recent",
"popup.favoritesEmpty": "Star a file or folder from its header to keep it here.",
"popup.recentsEmpty": "Files and folders you open will show up here.",
"settings.title": "Previewer Settings",
"settings.general": "General",
"settings.showHiddenFilesDescription": "Show dot-prefixed hidden files in the folder tree and folder overview.",
"settings.rememberSidebarWidthDescription": "Restore the last sidebar width the next time a folder opens.",
"settings.documentTitle": "Name tabs after the document's own title",
"settings.documentTitleDescription": "Title tabs from a Markdown, MDX or HTML document's own title (frontmatter title, first heading, ), falling back to the file name when it has none.",
"settings.lineNumbers": "Show line numbers",
"settings.lineNumbersDescription": "Show the line-number gutter in code and text previews and editors.",
"settings.wordWrap": "Word wrap",
"settings.wordWrapDescription": "Wrap long lines to the viewport; when off, scroll horizontally instead.",
"settings.syntax": "Supported Markdown",
"settings.syntaxDescription": "The Markdown this build understands. The basics follow GitHub Flavored Markdown, plus a few common dialects and two diagram fences.",
"settings.syntaxGroupBasic": "Basics",
"settings.syntaxGroupBlocks": "Blocks",
"settings.syntaxGroupExtended": "Extended",
"settings.syntaxHeading": "Headings one through six; the outline is built from them",
"settings.syntaxEmphasis": "Inline emphasis and code",
"settings.syntaxLinkImage": "Links and images; relative paths resolve against the document",
"settings.syntaxList": "Bulleted, numbered and checkable task lists",
"settings.syntaxQuote": "Blockquotes, nestable",
"settings.syntaxRule": "Horizontal rule",
"settings.syntaxCodeFence": "Fenced code blocks, highlighted by language",
"settings.syntaxTable": "Tables, including alignment colons",
"settings.syntaxDefinitionList": "Definition lists",
"settings.syntaxFootnote": "Footnote references and a footnote section",
"settings.syntaxAlert": "GFM alerts (NOTE/TIP/IMPORTANT/WARNING/CAUTION) and Obsidian callouts ([!tip] Title, +/- folding)",
"settings.syntaxFrontmatter": "YAML front matter, viewable in a panel at the top",
"settings.syntaxHighlight": "Highlight and insert marks",
"settings.syntaxSubSup": "Subscript and superscript",
"settings.syntaxMath": "KaTeX math; \\( \\) and \\[ \\] delimiters also work",
"settings.syntaxMermaid": "Mermaid diagrams; mindmap syntax renders as a mind map",
"settings.syntaxSvg": "SVG, rendered after whitelist sanitising",
"settings.syntaxHtml": "Static display tags; scripts, event attributes and unsafe protocols are removed",
"settings.shortcuts": "Shortcuts",
"settings.shortcutsDescription": "Keyboard shortcuts available while editing Markdown. Keys follow your platform; Ctrl appears as ⌘ on macOS.",
"settings.shortcutGroupFormat": "Inline formatting",
"settings.shortcutGroupBlocks": "Block formatting",
"settings.shortcutGroupDocument": "Document actions",
"settings.fileTypes": "File Associations",
"settings.fileTypesDescription": "File types supported by Previewer. Check each type's current system handler, make Tabbit the system default, or choose whether the browser opens it with Previewer or its built-in viewer.",
"settings.currentHandler": "Current System Default App",
"settings.currentHandlerSelf": "Tabbit (this browser)",
"settings.currentHandlerUnknown": "No default app detected",
"settings.detecting": "Detecting...",
"settings.detectUnavailable": "Unavailable",
"settings.systemDefault": "Set as System Default",
"settings.systemDefaultActive": "Currently the system default",
"settings.setAsDefault": "Set as default",
"settings.setAllAsDefault": "Set all as default",
"settings.setAllNothingPending": "Nothing in this section can be set as default right now",
"settings.unsetDefaultHint": "To remove the default, change it in system settings",
"settings.openWith": "Open in Tabbit with",
"settings.openWithPreviewer": "Tabbit Previewer",
"settings.openWithNative": "Browser built‑in",
"settings.openWithNativeUnavailable": "This format can't be shown usefully by the browser's built-in viewer",
"settings.setDefaultRequested": "Requested to make Tabbit the default app for {extension}",
"settings.openedSystemSettings": "System settings opened. Choose Tabbit as the default app for {extension}",
"settings.setDefaultUnsupported": "Setting the default app for {extension} is not supported on this system",
"settings.setDefaultFailed": "Failed to set the default app for {extension}",
"settings.type.markdown": "Markdown",
"settings.type.svg": "SVG",
"settings.type.image": "Images",
"settings.type.media": "Audio & Video",
"settings.type.pdf": "PDF",
"settings.type.office": "Office Documents",
"settings.type.html": "HTML",
"settings.type.codeText": "Code & Text",
"settings.type.subtitle": "Subtitles",
"settings.type.archive": "Archives",
"editor.sourceLabel": "File content",
"markdown.contentLabel": "Markdown content",
"code.contentLabel": "Code content",
"code.delimitedContentLabel": "Table source text",
"code.tablePreviewAria": "{fileName} table preview",
"code.unnamedColumn": "Column {index}",
"code.tablePreviewLimited": "Previewing only the first {rows} rows and first {columns} columns; edit mode keeps the complete source text.",
"code.noFormattingNeeded": "Current content does not need formatting",
"code.formatApplied": "Formatting applied",
"code.sourceReloaded": "{fileName} source file reloaded",
"code.formatJson": "Format JSON",
"code.expandCode": "Expand Code",
"code.subtitleViewMode": "Subtitle view",
"code.subtitleTimeline": "Timeline",
"code.subtitleSource": "Source",
"code.subtitleInfoFormat": "Format",
"code.subtitleInfoCues": "Cues",
"code.subtitleInfoDuration": "Duration",
"code.subtitleInfoLanguage": "Language",
"code.subtitleInfoEncoding": "Encoding",
"code.subtitleTimelineTruncated": "Too many cues: the timeline shows the first {shown} of {total}. Switch to the source view for the full text.",
"code.subtitleSearchPlaceholder": "Search dialogue, or a time like 12:30",
"code.subtitleCopyCue": "Copy this cue",
"code.subtitleTextView": "Plain text",
"code.subtitleTextTruncated": "Too many cues: the plain-text view shows the first {shown} of {total}. \"Copy all\" still includes everything.",
"code.subtitleBilingual": "Bilingual",
"code.subtitleEncodingTooltip": "Detected file encoding",
"code.subtitleTranscode": "Re-save as UTF-8",
"code.subtitleTranscoded": "Saved as UTF-8",
"code.subtitleTranscodeFailed": "Re-save failed, please try again",
"code.subtitleBinaryNotice": "This is a binary bitmap subtitle file (VobSub graphic subtitles). It cannot be previewed or edited as text. Keep it next to its matching .idx file and load it in a video player.",
"code.subtitleExportMenu": "Export",
"code.subtitleExportSrt": "SRT",
"code.subtitleExportVtt": "VTT",
"code.subtitleExportTxt": "Plain text (TXT)",
"code.subtitleExportUnparseable": "Could not parse the subtitles; nothing was exported",
"code.subtitleExported": "Exported {fileName}",
"code.subtitleExportFailed": "Export failed, please try again",
"code.searchPlaceholder": "Find",
"code.searchPrev": "Previous",
"code.searchNext": "Next",
"code.searchClose": "Close",
"code.replacePlaceholder": "Replace with",
"code.replaceOne": "Replace",
"code.replaceAll": "Replace all",
"code.replacedCount": "Replaced {count} occurrences",
"code.subtitleShiftMenu": "Shift timing",
"code.subtitleShiftLabel": "Offset (ms)",
"code.subtitleShiftHint": "Positive delays, negative advances; saves immediately. Fixes a constant offset only, not frame-rate drift.",
"code.subtitleShiftApply": "Apply and save",
"code.subtitleShiftInvalid": "Enter a non-zero offset in milliseconds",
"code.subtitleShifted": "Shifted {count} cue timings and saved",
"code.subtitleShiftedClamped": "Shifted and saved; some timings were clamped to 00:00",
"code.subtitleShiftFailed": "Shift failed, please try again",
"code.subtitleShiftExported": "This format cannot be shifted in place; exported the shifted {fileName}",
"code.subtitleCleanMenu": "Clean up",
"code.subtitleCleanTags": "Remove styling tags",
"code.subtitleCleanAnnotations": "Remove bracketed captions (SDH)",
"code.subtitleCleanMusic": "Remove music lines",
"code.subtitleCleanDuplicates": "Merge duplicate and empty cues",
"code.subtitleCleaned": "Cleaned {count} items and saved",
"code.subtitleCleanNothing": "Nothing to clean",
"code.subtitleCleanFailed": "Clean up failed, please try again",
"code.subtitleCleanExported": "This format cannot be cleaned in place; exported the cleaned {fileName}",
"code.subtitleTranslate": "Translate the subtitles into a new file",
"code.subtitleTranslateTitle": "Translate subtitles",
"code.subtitleTranslateModeLabel": "Output",
"code.subtitleTranslateModeBilingual": "Bilingual (translation above)",
"code.subtitleTranslateModeReplace": "Translation only",
"code.subtitleTranslateLanguageLabel": "Target language",
"code.subtitleTranslateOutputLabel": "Save as",
"code.subtitleTranslateOutputNew": "New file",
"code.subtitleTranslateOutputOverwrite": "Overwrite this file",
"code.subtitleTranslateOverwriteUnavailable": "Only a writable local SRT can be overwritten; this file will be saved as a new file",
"code.subtitleTranslateSummary": "Will translate {count} cues (~{characters} characters); cues already in the target language are skipped. Translation consumes your account quota.",
"code.subtitleTranslateNothing": "Nothing to translate (the target language may already be present)",
"code.subtitleTranslateStart": "Start translating",
"code.subtitleTranslateCancel": "Cancel",
"code.subtitleTranslateRunning": "Translating {completed}/{total}…",
"code.subtitleTranslateCancelled": "Cancelled; the file was not changed",
"code.subtitleTranslateUnavailable": "Translation service unavailable; please make sure the browser is up to date",
"code.subtitleTranslateSourceChanged": "Subtitle content changed; please restart translation",
"code.subtitleTranslateFailed": "Translation failed: {error}",
"code.subtitleTranslateDoneOverwrite": "Translated {count} cues and saved to this file",
"code.subtitleTranslateDoneExported": "Translated {count} cues; exported {fileName}",
"code.subtitleLangChinese": "Chinese",
"code.subtitleLangJapanese": "Japanese",
"code.subtitleLangKorean": "Korean",
"code.subtitleLangLatin": "English/Latin",
"code.subtitleLangCyrillic": "Cyrillic",
"code.subtitleLangArabic": "Arabic",
"subtitle.binaryUnknown": "Binary SUB",
"subtitle.vobsubDescription": "MPEG Program Stream / DVD subpicture data detected; it will not be decoded or written as text.",
"subtitle.binaryDescription": "This SUB file contains binary data. Text decoding was stopped to prevent garbled output or accidental writes.",
"subtitle.vobsubCompanionHint": "VobSub images, languages, and timing are normally described by a same-name .idx file. Open the companion IDX to inspect timestamps.",
"subtitle.scannedBytes": "Header scanned",
"subtitle.packHeaders": "MPEG pack headers",
"subtitle.privateStreams": "Subtitle private-stream packets",
"html.sourceLoading": "Reading source",
"html.sourceEditorAria": "HTML source editor",
"html.previewAria": "HTML preview",
"html.previewFrameTitle": "{fileName} preview",
"html.printFrameTitle": "{fileName} print preview",
"html.preparing": "Preparing source and preview",
"html.viewMode": "HTML view mode",
"html.modeSource": "Source",
"html.modeSplit": "Split",
"html.modePreview": "Preview",
"html.reload": "Reload",
"html.sourceReloaded": "Source reloaded",
"html.sourceRead": "HTML source loaded",
"html.readFailed": "Read failed: unable to read the HTML source file",
"html.readRequiresWorkspace": "Read failed: local workspace access is required to read HTML source",
"html.previewUnavailable": "This file may have been moved, changed, or deleted.",
"html.previewUnavailableInArchive": "HTML inside an archive is not supported for preview yet. The source is available on the left; extract the archive to preview it.",
"html.previewUnavailableInArchiveStatus": "Preview not supported",
"image.stageAria": "Image preview stage",
"image.loadingTitle": "Loading image",
"image.loadingMeta": "{extension} · Reading image",
"image.readyStatus": "Zoom, pan, rotate, and flip",
"image.zoomOut": "Zoom Out",
"image.zoomIn": "Zoom In",
"image.fit": "Fit to Window",
"image.actualSize": "100% Actual Size",
"image.rotateLeft": "Rotate Left",
"image.rotateRight": "Rotate Right",
"image.flipHorizontal": "Flip Horizontal",
"image.flipVertical": "Flip Vertical",
"image.reset": "Reset",
"image.exportPng": "PNG",
"image.loadFailedTitle": "Image failed to load",
"image.loadFailedMeta": "{extension} · Load failed",
"image.loadFailedStatus": "Unable to read this image. Check whether the link is still valid.",
"image.zoomedOut": "Zoomed out",
"image.zoomedIn": "Zoomed in. Drag to inspect details.",
"image.fitApplied": "Fit to window",
"image.actualSizeApplied": "Switched to 100% actual size",
"image.resetApplied": "Reset transforms and fit to window",
"image.wheelZoomed": "Wheel zoomed. Drag to inspect details.",
"image.transformed": "Image transformed",
"image.panned": "View moved",
"image.notLoaded": "Image has not finished loading",
"image.exportedPng": "PNG exported",
"image.exportFailed": "Export failed. The browser may have restricted canvas access for this local image.",
"media.kind.audio": "Audio",
"media.kind.video": "Video",
"media.loading": "Reading media information",
"media.playbackRate": "Playback Speed",
"media.playbackRateValue": "Playback speed: {rate}",
"media.pictureInPicture": "Picture in Picture",
"media.pictureInPictureActive": "Picture in Picture active",
"media.pictureInPictureFailed": "Unable to enter Picture in Picture",
"media.fullscreen": "Full Screen",
"media.fullscreenActive": "Full screen active",
"media.fullscreenFailed": "Unable to enter full screen",
"media.loadFailed": "Media failed to load",
"media.loadFailedDetail": "Unable to play this media; its container or codec may not be supported",
"svg.stageAria": "SVG preview region. Use the arrow keys to move the zoomed view.",
"pdf.loadingMeta": "PDF · Reading file",
"pdf.initialStatus": "Rendered with PDF.js. The raw file is available as a browser fallback.",
"pdf.toggleNavigation": "Show or hide PDF navigation",
"pdf.navLabel": "Navigation",
"pdf.hideNavigation": "Hide PDF navigation",
"pdf.showNavigation": "Show PDF navigation",
"pdf.previousPage": "Previous Page",
"pdf.nextPage": "Next Page",
"pdf.pageJumpTitle": "Jump to page",
"pdf.currentPage": "Current page",
"pdf.pageLabelTitle": "Page {page} · label {label}",
"pdf.searchTitle": "Search PDF text",
"pdf.searchPlaceholder": "Search PDF",
"pdf.previousSearchResult": "Previous search result",
"pdf.nextSearchResult": "Next search result",
"pdf.fitWidth": "Fit Width",
"pdf.fitPage": "Fit Page",
"pdf.handTool": "Hand tool",
"pdf.handToolOn": "Hand tool on: drag with the left button to pan",
"pdf.handToolOff": "Hand tool off: drag to select text",
"pdf.rotateRight": "Rotate Right",
"pdf.viewMode": "PDF view mode",
"pdf.viewContinuous": "Continuous",
"pdf.viewSingle": "Single",
"pdf.viewTwoPage": "Two-Page",
"pdf.readAloud": "Read current page or selected text aloud",
"pdf.readAloudLabel": "Read Aloud",
"pdf.rerender": "Render Again",
"pdf.navAria": "PDF navigation",
"pdf.navTabsAria": "PDF navigation panels",
"pdf.navTitle": "Reading navigation",
"pdf.tabPages": "Pages",
"pdf.tabOutline": "Outline",
"pdf.tabNotes": "Notes",
"pdf.infoLoading": "Reading document info",
"pdf.infoEmpty": "This PDF carries no readable document info",
"pdf.propTitle": "Title",
"pdf.propAuthor": "Author",
"pdf.propSubject": "Subject",
"pdf.propKeywords": "Keywords",
"pdf.propCreator": "Application",
"pdf.propProducer": "PDF producer",
"pdf.propCreated": "Created",
"pdf.propVersion": "PDF version",
"pdf.infoAttachments": "Attachment(s)",
"pdf.attachmentSave": "Save attachment {name}",
"pdf.attachmentSaving": "Saving attachment {name}",
"pdf.attachmentSaved": "Saved attachment {name}",
"pdf.attachmentSaveFailed": "Could not save attachment {name}",
"pdf.infoLayers": "Layer(s)",
"pdf.layerUntitled": "Untitled layer",
"pdf.layerShown": "Layer \u201c{name}\u201d shown",
"pdf.layerHidden": "Layer \u201c{name}\u201d hidden",
"pdf.infoSignature": "Digital signature(s)",
"pdf.infoSignatureN": "Digital signature {index}",
"pdf.metaSigned": "Signed",
"pdf.signatureSigner": "Signer",
"pdf.signatureTime": "Signed at",
"pdf.signatureReason": "Reason",
"pdf.signatureLocation": "Location",
"pdf.signatureContact": "Contact",
"pdf.signatureField": "Signature field",
"pdf.permission.print": "Print",
"pdf.permission.copy": "Copy text",
"pdf.permission.modify": "Modify content",
"pdf.permission.annotate": "Add annotations",
"pdf.permission.forms": "Fill forms",
"pdf.permissionAllowed": "Allowed",
"pdf.permissionRestricted": "Restricted by author",
"pdf.printRestricted": "The author of this PDF restricted printing; the printout may be limited",
"pdf.copyRestricted": "The author of this PDF restricted copying text",
"pdf.navLoading": "Preparing navigation",
"pdf.notePlaceholder": "Write a note for the current page",
"pdf.noteHint": "Notes stay on this device and do not modify the PDF file.",
"pdf.noteAria": "Current PDF page note",
"pdf.stageAria": "{fileName} PDF preview",
"pdf.loadingTitle": "Loading PDF",
"pdf.loadingDescription": "Parsing the file and preparing page rendering.",
"pdf.zoomedOut": "Zoomed out",
"pdf.zoomedIn": "Zoomed in",
"pdf.fitWidthApplied": "Fit to width",
"pdf.fitPageApplied": "Fit to page",
"pdf.actualSizeApplied": "Switched to 100% actual size",
"pdf.rotatedRight": "Rotated PDF view right",
"pdf.viewModeApplied": "Switched to {mode} view",
"pdf.rerenderingVisible": "Rendering visible pages again",
"pdf.wheelZoomed": "Wheel zoomed PDF view",
"pdf.readFailed": "Unable to read the PDF file. Try opening the raw file.",
"pdf.parsing": "Parsing PDF",
"pdf.renderedPages": "PDF.js rendered · {pages}",
"pdf.pageAria": "Page {page}",
"pdf.thumbnailTitle": "Jump to page {page}",
"pdf.pageHasNote": "This page has a note",
"pdf.waitingRender": "Waiting to render",
"pdf.rendering": "Rendering",
"pdf.renderFailed": "Render failed",
"pdf.noTranslatableText": "No translatable text was detected on this page. Scanned pages require an OCR text layer.",
"pdf.translationPageAria": "Translation for page {page}",
"pdf.translatingPage": "Translating page {page}…",
"pdf.translationProgress": "Translated {completed}/{total} blocks",
"pdf.translationFailed": "Translation failed for this page",
"pdf.translationRetry": "Translation failed. Click to retry",
"pdf.translationBudgetExceeded": "This page exceeds the translation limit of 64 blocks or 48K characters.",
"pdf.ocrTextTooLarge": "Recognized text on this page exceeds the 64KiB safety limit.",
"pdf.readingProgress": "Reading PDF · {percent}%",
"pdf.searching": "Searching PDF text",
"pdf.searchFound": "Found {count} matches",
"pdf.searchNoResults": "No matches found",
"pdf.searchCleared": "Search cleared",
"pdf.notePage": "Page {page} note",
"pdf.noteUnsaved": "Note not saved",
"pdf.noteSaved": "Note saved on this device",
"pdf.marksTitle": "Marks on this page",
"pdf.marksHint": "Select text to highlight or underline it. Marks stay on this device and are never written into the PDF.",
"pdf.marksEmpty": "No marks on this page yet",
"pdf.markHighlight": "Highlight",
"pdf.markUnderline": "Underline",
"pdf.markCopy": "Copy",
"pdf.toolHighlight": "Highlight",
"pdf.toolInk": "Draw",
"pdf.toolFreeText": "Text",
"pdf.toolStamp": "Image",
"pdf.editUnavailable": "This PDF.js build does not support annotation editing",
"pdf.editRestricted": "The document's author restricted adding annotations",
"pdf.exportAnnotated": "Export a copy with the annotations baked in, leaving the original alone",
"pdf.exportAnnotatedLabel": "PDF copy with annotations",
"pdf.exportAnnotatedNeedsEdit": "Enter edit mode and add annotations to export a copy",
"pdf.exportAnnotatedDone": "Exported {name}",
"pdf.exportAnnotatedFailed": "Could not export the annotated copy",
"pdf.annotatedCopySuffix": "annotated",
"pdf.saveAnnotations": "Write the annotations into the original PDF",
"pdf.saveAnnotationsDone": "Annotations written into the original file",
"pdf.saveAnnotationsFailed": "Could not write the annotations into the original file",
"pdf.saveAnnotationsConfirmTitle": "Write into the original PDF?",
"pdf.saveAnnotationsConfirmDescription": "This writes the annotations from this editing session into “{fileName}” itself, overwriting the file on disk. Preview-mode highlights and underlines stay on this device and are not included.",
"pdf.saveAnnotationsConfirm": "Write into original",
"pdf.annotationsEmpty": "No annotations to save yet",
"pdf.markAdded": "{kind} added; kept on this device only",
"pdf.markRemoved": "Mark removed",
"pdf.markDelete": "Delete mark",
"pdf.markJump": "Scroll to this {kind}",
"pdf.copied": "Copied the selected text",
"pdf.copyFailed": "Copy failed",
"pdf.selectionToolbarAria": "Selected text actions",
"pdf.outlineLoading": "Reading outline",
"pdf.outlineUnavailable": "This PDF has no readable outline",
"pdf.outlineEmpty": "This PDF has no outline",
"pdf.outlineUntitled": "Untitled outline item",
"pdf.outlineGoTo": "Jump to page {page}",
"pdf.outlineExternal": "Open external link",
"pdf.linkInternal": "Jump to the link target in this document",
"pdf.linkUnresolved": "The target page of this link could not be located",
"pdf.annotationAria": "Annotation: {summary}",
"pdf.readAloudStopped": "Read aloud stopped",
"pdf.readAloudNoText": "No readable text on this page",
"pdf.readAloudFinished": "Read aloud finished",
"pdf.readAloudFailed": "Read aloud failed",
"pdf.readAloudSelection": "Reading selected text",
"pdf.readAloudPage": "Reading page {page}",
"pdf.previewFailedTitle": "PDF preview failed",
"pdf.passwordRequired": "This PDF requires a password. Encrypted PDFs are not handled in the current preview.",
"pdf.renderErrorDetail": "PDF.js could not render this file: {detail}",
"pdf.renderError": "PDF.js could not render this file.",
"pdf.canvasUnavailable": "This browser cannot create a PDF canvas.",
"office.loadingTitle": "Reading file",
"office.loadingDescription": "Previewer will try to extract previewable content.",
"office.kindStatus": "{kind} document",
"office.parsing": "Parsing document content",
"office.readFailed": "Unable to read the current local file.",
"office.unsupportedExtension": "This Office extension is not supported yet.",
"office.parseFailed": "Document parsing failed. The file may be encrypted, damaged, or ZIP decompression may be unavailable in this browser.",
"office.noDocxBody": "No DOCX body content was found.",
"office.docxMeta": "DOCX · {paragraphs} · Read-only text preview; complex styling follows the original file",
"office.docxBodyLabel": "DOCX body",
"office.docxReady": "DOCX loaded in read-only text preview.",
"office.docxRendering": "Rendering DOCX preview",
"office.docxRendered": "DOCX preview rendered",
"office.docxFitWidth": "Fit Width",
"office.docxZoomedOut": "DOCX preview zoomed out",
"office.docxZoomedIn": "DOCX preview zoomed in",
"office.docxFitWidthApplied": "Fit DOCX page to width",
"office.docxActualSizeApplied": "Switched DOCX preview to 100% actual size",
"office.noXlsxSheets": "No XLSX worksheets were found.",
"office.sheet": "Sheet",
"office.sheetCount": "{count}",
"office.currentSheetTsv": "Current sheet TSV",
"office.sheetSwitched": "Sheet switched.",
"office.noPptxSlides": "No PPTX slides were found.",
"office.pptxMissingViewer": "PptxViewJS is not loaded. Switched to text outline preview.",
"office.pptxRendering": "Rendering PPTX with PptxViewJS",
"office.pptxReady": "PPTX loaded in read-only text outline preview.",
"office.pptxTextLabel": "PPTX slide text",
"office.pptxOutlineTitle": "Text Outline",
"office.pptxOutlineDescription": "View slide text",
"office.pptxBackToSlides": "Back to Slide Preview",
"office.pptxViewerLoading": "Loading {count}",
"office.pptxPreviousPage": "Previous Page",
"office.pptxNextPage": "Next Page",
"office.pptxZoomOut": "Zoom Out",
"office.pptxZoomIn": "Zoom In",
"office.pptxFit": "Fit",
"office.pptxViewerMountFailed": "PPTX preview mount failed. Switched to text outline preview.",
"office.pptxRenderingPage": "Rendering page {page}",
"office.pptxViewerReady": "PptxViewJS preview",
"office.pptxViewerReadyStatus": "PPTX rendered with PptxViewJS.",
"office.pptxRenderFailed": "PptxViewJS rendering failed. Switched to text outline preview.",
"office.legacyUnsupportedStatus": "Legacy Office binary formats cannot be parsed in the browser yet.",
"office.legacyUnsupportedTitle": "{extension} preview is not supported yet",
"office.legacyUnsupportedDescription": "The lightweight path currently supports .docx, .xlsx, and .pptx. Save legacy formats as modern OOXML and open them again.",
"office.parseErrorTitle": "Unable to parse document",
"office.emptyDocxTitle": "No body text extracted",
"office.emptyDocxDescription": "This document may mainly contain images, charts, or protected content.",
"office.emptyXlsxTitle": "No table content to show",
"office.emptyXlsxDescription": "Switch to edit mode to fill TSV content, then save.",
"office.chart": "Chart",
"office.chartSeries": "Series {index}",
"office.chartUnresolved": "The chart structure was recognized, but the referenced data range cannot be resolved yet.",
"office.embeddedChart": "Embedded chart",
"office.emptyPptxTitle": "No slide text extracted",
"office.emptyPptxDescription": "This presentation may mainly contain images or shapes.",
"office.blankSlide": "Blank slide",
"office.xlsxMeta": "XLSX · {sheetName} · {sheetCount} · Saves current displayed values; complex formulas and styles use lightweight compatibility",
"office.pptxMeta": "PPTX · {slides} · {images} · Light editing saves text while images/layout keep the original structure",
"unsupported.displayName": "Unsupported file",
"unsupported.description": "This file type cannot be previewed directly. You can locate it in the file manager.",
"unsupported.type": "Type",
"unsupported.path": "Path",
"unsupported.size": "Size",
"unsupported.created": "Created",
"unsupported.modified": "Modified",
"unsupported.reading": "Reading...",
"unsupported.revealRequested": "File manager reveal requested",
"unsupported.revealFailed": "Unable to locate file",
"unsupported.unreadable": "Unable to read",
"zip.displayName": "Archive",
"zip.kicker": "Archive",
"zip.folderKicker": "Archive folder",
"zip.entryKicker": "Archive entry",
"zip.loading": "Reading archive...",
"zip.ready": "Archive index loaded",
"zip.refresh": "Reload from disk",
"zip.description": "Expand the archive in the sidebar to browse its files without extracting it.",
"zip.emptyArchive": "This archive contains no files.",
"zip.entries": "File entries",
"zip.childEntries": "In this folder",
"zip.uncompressedSize": "Original size",
"zip.compressedSize": "Compressed size",
"zip.ratio": "Compression ratio",
"zip.archiveSize": "Archive size",
"zip.archive": "Archive",
"zip.entryPath": "Path in archive",
"zip.readOnly": "Files inside an archive are read-only and cannot be edited or renamed.",
"zip.readFailed": "This archive could not be read.",
"zip.tooLarge": "The archive is larger than the {size} preview budget and was not read.",
"zip.corrupt": "This file is damaged or is not a valid ZIP archive.",
"zip.skippedUnsafe": "Skipped {count} entries whose paths escape the archive root.",
"zip.truncated": "Too many entries; only the first {count} were indexed.",
"zip.encryptedEntries": "{count} entries are encrypted and cannot be previewed.",
"zip.entryEncrypted": "This entry is encrypted and needs a password, so it cannot be previewed.",
"zip.entryUnsupportedMethod": "This entry uses a compression method the browser cannot decode.",
"zip.entryTooLarge": "This entry expands beyond the per-entry preview budget and was not opened.",
"zip.entryRatio": "This entry has an abnormal compression ratio and was not expanded, as a safety measure.",
"zip.entryCorrupt": "This entry is damaged and cannot be expanded.",
"zip.entryNotFound": "This entry is not present in the archive.",
"fileType.directory": "Folder",
"fileType.markdown": "Markdown",
"fileType.svg": "SVG",
"fileType.image": "Image",
"fileType.pdf": "PDF",
"fileType.office": "Office",
"fileType.html": "HTML",
"fileType.code-text": "Code / Text",
"fileType.unsupported": "Unsupported file"
}
};
const COUNT_UNITS = {
"zh-CN": {
line: { one: "行", other: "行" },
page: { one: "页", other: "页" },
sheet: { one: "个工作表", other: "个工作表" },
paragraph: { one: "段正文", other: "段正文" },
image: { one: "张图片", other: "张图片" },
slide: { one: "页幻灯片", other: "页幻灯片" },
entry: { one: "项", other: "项" }
},
en: {
line: { one: "line", other: "lines" },
page: { one: "page", other: "pages" },
sheet: { one: "sheet", other: "sheets" },
paragraph: { one: "paragraph", other: "paragraphs" },
image: { one: "image", other: "images" },
slide: { one: "slide", other: "slides" },
entry: { one: "item", other: "items" }
}
};
function currentLocale() {
const language = browserUiLanguage();
if (!language) {
return DEFAULT_LOCALE;
}
return normalizeLocale(language);
}
TabLocalFiles.currentLocale = currentLocale;
function t(key, values = {}) {
return messageTemplate(key).replace(/\{(\w+)\}/g, (_match, name) => String(values[name] ?? ""));
}
TabLocalFiles.t = t;
function messageTemplate(key) {
const locale = currentLocale();
return I18N_MESSAGES[locale][key] || I18N_MESSAGES[DEFAULT_LOCALE][key] || key;
}
TabLocalFiles.messageTemplate = messageTemplate;
function formatCount(count, unit) {
const locale = currentLocale();
const unitMessages = COUNT_UNITS[locale][unit];
const label = count === 1 ? unitMessages.one : unitMessages.other;
return locale === "zh-CN" ? `${count} ${label}` : `${count} ${label}`;
}
TabLocalFiles.formatCount = formatCount;
function fileTypeDisplayName(definition) {
return t(`fileType.${definition.id}`) || definition.displayName;
}
TabLocalFiles.fileTypeDisplayName = fileTypeDisplayName;
function applyDocumentLocale() {
if (typeof document === "undefined") {
return;
}
document.documentElement.lang = currentLocale();
document.documentElement.dir = "ltr";
}
TabLocalFiles.applyDocumentLocale = applyDocumentLocale;
function localizeDocument(root) {
const target = root || safeDocument();
if (!target) {
return;
}
applyDocumentLocale();
target.querySelectorAll("[data-tlf-i18n]").forEach((element) => {
const key = element.dataset.tlfI18n;
if (key) {
element.textContent = t(key);
}
});
target.querySelectorAll("[data-tlf-i18n-title]").forEach((element) => {
const key = element.dataset.tlfI18nTitle;
if (key) {
element.setAttribute("title", t(key));
}
});
target.querySelectorAll("[data-tlf-i18n-aria-label]").forEach((element) => {
const key = element.dataset.tlfI18nAriaLabel;
if (key) {
element.setAttribute("aria-label", t(key));
}
});
target.querySelectorAll("[data-tlf-i18n-placeholder]").forEach((element) => {
const key = element.dataset.tlfI18nPlaceholder;
if (key) {
element.setAttribute("placeholder", t(key));
}
});
}
TabLocalFiles.localizeDocument = localizeDocument;
function browserUiLanguage() {
const chromeI18n = globalThis.chrome?.i18n;
try {
const language = chromeI18n?.getUILanguage?.();
if (language) {
return language;
}
}
catch {
}
const nav = globalThis.navigator;
return nav?.languages?.[0] || nav?.language;
}
function safeDocument() {
return typeof document === "undefined" ? undefined : document;
}
function normalizeLocale(language) {
const normalized = language.toLowerCase().replace("_", "-");
return normalized === "zh" || normalized.startsWith("zh-") ? "zh-CN" : "en";
}
})(TabLocalFiles || (TabLocalFiles = {}));
var TabLocalFiles;
(function (TabLocalFiles) {
TabLocalFiles.RENDERER_CONTENT_SCRIPT_ID = "tab-local-files-renderer";
TabLocalFiles.PREFERENCES_STORAGE_KEY = "tab-local-files:preferences";
})(TabLocalFiles || (TabLocalFiles = {}));
var TabLocalFiles;
(function (TabLocalFiles) {
var Preferences;
(function (Preferences) {
const LOCAL_CACHE_KEY = "tab-local-files:preferences-cache";
let cache;
let hydration;
let mutationRevision = 0;
const changeListeners = [];
function read() {
if (!cache) {
cache = parsePreferences(safeLocalStorageGet(LOCAL_CACHE_KEY)) || {};
}
return cache;
}
Preferences.read = read;
function readOpenModes() {
return { ...(read().openModes || {}) };
}
Preferences.readOpenModes = readOpenModes;
function useDocumentTitle() {
return (read().preview || {}).documentTitle !== false;
}
Preferences.useDocumentTitle = useDocumentTitle;
function showLineNumbers() {
return (read().preview || {}).lineNumbers !== false;
}
Preferences.showLineNumbers = showLineNumbers;
function useWordWrap() {
return (read().preview || {}).wordWrap !== false;
}
Preferences.useWordWrap = useWordWrap;
const MARKDOWN_READING_WIDTHS = ["fixed", "full"];
const MARKDOWN_FONT_SIZES = ["medium", "large", "xlarge"];
function markdownReadingWidth() {
return oneOf((read().preview || {}).markdownWidth, MARKDOWN_READING_WIDTHS, "fixed");
}
Preferences.markdownReadingWidth = markdownReadingWidth;
function markdownFontSize() {
return oneOf((read().preview || {}).markdownFontSize, MARKDOWN_FONT_SIZES, "medium");
}
Preferences.markdownFontSize = markdownFontSize;
function oneOf(value, allowed, fallback) {
return typeof value === "string" && allowed.includes(value)
? value
: fallback;
}
function update(patch) {
const current = read();
const next = {
...current,
...(patch.directory ? { directory: { ...(current.directory || {}), ...patch.directory } } : {}),
...(patch.openModes ? { openModes: { ...(current.openModes || {}), ...patch.openModes } } : {}),
...(patch.preview ? { preview: { ...(current.preview || {}), ...patch.preview } } : {})
};
commit(next);
return next;
}
Preferences.update = update;
function writeOpenMode(extension, mode) {
const normalized = extension.toLowerCase();
const openModes = readOpenModes();
if (mode) {
openModes[normalized] = mode;
}
else {
delete openModes[normalized];
}
commit({ ...read(), openModes });
}
Preferences.writeOpenMode = writeOpenMode;
function init() {
if (hydration) {
return hydration;
}
subscribeToExternalChanges();
const hydrationRevision = mutationRevision;
hydration = new Promise((resolve) => {
const storage = chromeStorageApi()?.local;
const get = storage?.get;
if (!get) {
resolve();
return;
}
try {
get.call(storage, TabLocalFiles.PREFERENCES_STORAGE_KEY, (result) => {
if (mutationRevision === hydrationRevision) {
applyExternalValue(result?.[TabLocalFiles.PREFERENCES_STORAGE_KEY]);
}
resolve();
});
}
catch {
resolve();
}
});
return hydration;
}
Preferences.init = init;
function onChange(listener) {
changeListeners.push(listener);
}
Preferences.onChange = onChange;
function commit(next) {
mutationRevision += 1;
cache = next;
const serialized = JSON.stringify(next);
safeLocalStorageSet(LOCAL_CACHE_KEY, serialized);
const storage = chromeStorageApi()?.local;
const set = storage?.set;
if (!set) {
return;
}
try {
set.call(storage, { [TabLocalFiles.PREFERENCES_STORAGE_KEY]: next });
}
catch {
}
}
function subscribeToExternalChanges() {
const changedEvent = chromeStorageApi()?.onChanged;
const addListener = changedEvent?.addListener;
if (!addListener) {
return;
}
try {
addListener.call(changedEvent, (changes, areaName) => {
if (areaName !== "local" || !(TabLocalFiles.PREFERENCES_STORAGE_KEY in changes)) {
return;
}
mutationRevision += 1;
applyExternalValue(changes[TabLocalFiles.PREFERENCES_STORAGE_KEY]?.newValue);
});
}
catch {
}
}
function applyExternalValue(value) {
const parsed = normalizePreferences(value);
if (!parsed || JSON.stringify(parsed) === JSON.stringify(read())) {
return;
}
cache = parsed;
safeLocalStorageSet(LOCAL_CACHE_KEY, JSON.stringify(parsed));
changeListeners.forEach((listener) => {
try {
listener();
}
catch {
}
});
}
function parsePreferences(raw) {
if (!raw) {
return undefined;
}
try {
return normalizePreferences(JSON.parse(raw));
}
catch {
return undefined;
}
}
function normalizePreferences(value) {
if (!value || typeof value !== "object") {
return undefined;
}
const record = value;
const preferences = {};
if (record.directory && typeof record.directory === "object") {
preferences.directory = record.directory;
}
if (record.preview && typeof record.preview === "object") {
preferences.preview = record.preview;
}
if (record.openModes && typeof record.openModes === "object") {
const openModes = {};
for (const [extension, mode] of Object.entries(record.openModes)) {
if (mode === "native" || mode === "previewer") {
openModes[extension.toLowerCase()] = mode;
}
}
preferences.openModes = openModes;
}
return preferences;
}
function chromeStorageApi() {
return globalThis.chrome?.storage;
}
function safeLocalStorageGet(key) {
try {
return globalThis.localStorage?.getItem(key) ?? null;
}
catch {
return null;
}
}
function safeLocalStorageSet(key, value) {
try {
globalThis.localStorage?.setItem(key, value);
}
catch {
}
}
})(Preferences = TabLocalFiles.Preferences || (TabLocalFiles.Preferences = {}));
})(TabLocalFiles || (TabLocalFiles = {}));
var TabLocalFiles;
(function (TabLocalFiles) {
var Theme;
(function (Theme) {
const LEGACY_MODE_STORAGE_KEY = "tab-local-files:theme";
const MODE_STORAGE_KEY = "tab-local-files:theme-mode";
const MEDIA_QUERY = "(prefers-color-scheme: dark)";
const PORT_NAME = "tlf-theme";
const PORT_RECONNECT_DELAY_MS = 1000;
const CHROMIUM_UNSET_USER_COLOR = -6645094;
const TABBIT_DEFAULT_ORANGE = -810932;
let activeGeneration = 0;
let bindingCleanup;
let lastBrowserColors;
let lastAppliedTheme;
let lastAppliedAccent;
let lastAppliedMode;
const changeHandlers = new Set();
function start() {
stop();
clearLegacyPreference();
const generation = ++activeGeneration;
const isActive = () => generation === activeGeneration;
applyColors();
void readBrowserThemeColors().then((colors) => {
if (isActive() && colors) {
lastBrowserColors = colors;
applyColors(colors);
}
});
const mediaQuery = window.matchMedia?.(MEDIA_QUERY);
const onSystemThemeChange = () => {
if (isActive()) {
applyColors();
}
};
mediaQuery?.addEventListener("change", onSystemThemeChange);
const api = tabThemeColorApi();
const onTabThemeChange = (colors) => {
if (!isActive()) {
return;
}
const normalized = normalizeColors(colors);
if (typeof normalized?.is_dark_mode === "boolean") {
lastBrowserColors = {
...lastBrowserColors,
is_dark_mode: normalized.is_dark_mode
};
}
applyColors(lastBrowserColors);
void readBrowserThemeColors().then((refreshed) => {
if (isActive() && refreshed) {
lastBrowserColors = refreshed;
applyColors(refreshed);
}
});
};
api?.onChanged?.addListener?.(onTabThemeChange);
const onUserColorChange = (colors) => {
if (!isActive()) {
return;
}
const normalized = normalizeColors(colors);
if (!normalized?.user_color) {
return;
}
lastBrowserColors = {
...lastBrowserColors,
user_color: normalized.user_color,
is_dark_mode: normalized.is_dark_mode ?? lastBrowserColors?.is_dark_mode
};
applyColors(lastBrowserColors);
};
api?.onUserColorChanged?.addListener?.(onUserColorChange);
let port;
let reconnectTimer;
const connectBackgroundPort = () => {
port = connectThemePort((colors) => {
if (!isActive()) {
return;
}
lastBrowserColors = colors || undefined;
applyColors(lastBrowserColors);
}, () => {
port = undefined;
if (!isActive() || reconnectTimer !== undefined) {
return;
}
reconnectTimer = window.setTimeout(() => {
reconnectTimer = undefined;
if (isActive()) {
connectBackgroundPort();
}
}, PORT_RECONNECT_DELAY_MS);
});
};
connectBackgroundPort();
bindingCleanup = () => {
if (reconnectTimer !== undefined) {
window.clearTimeout(reconnectTimer);
reconnectTimer = undefined;
}
mediaQuery?.removeEventListener("change", onSystemThemeChange);
api?.onChanged?.removeListener?.(onTabThemeChange);
api?.onUserColorChanged?.removeListener?.(onUserColorChange);
port?.disconnect?.();
};
}
Theme.start = start;
function stop() {
activeGeneration += 1;
bindingCleanup?.();
bindingCleanup = undefined;
}
Theme.stop = stop;
function onChange(handler) {
changeHandlers.add(handler);
return () => {
changeHandlers.delete(handler);
};
}
Theme.onChange = onChange;
function currentState() {
const theme = lastAppliedTheme ?? resolveTheme(lastBrowserColors);
return {
theme,
mode: currentMode(),
source: browserAccentValue(lastBrowserColors) !== undefined ? "browser" : "fallback"
};
}
Theme.currentState = currentState;
function currentMode() {
const storedMode = readStorage(MODE_STORAGE_KEY);
return storedMode === "dark" || storedMode === "light" ? storedMode : "browser";
}
Theme.currentMode = currentMode;
function toggleMode() {
const mode = currentMode();
if (mode === "browser") {
setMode(resolveTheme(lastBrowserColors) === "light" ? "dark" : "light");
}
else {
setMode("browser");
}
applyColors();
const generation = activeGeneration;
void readBrowserThemeColors().then((colors) => {
if (generation === activeGeneration && colors) {
lastBrowserColors = colors;
applyColors(colors);
}
});
}
Theme.toggleMode = toggleMode;
function applyColors(colors = lastBrowserColors) {
applyResolvedTheme(resolveTheme(colors), colors);
}
function clearLegacyPreference() {
if (readStorage(MODE_STORAGE_KEY)) {
return;
}
removeStorage(LEGACY_MODE_STORAGE_KEY);
}
function setMode(mode) {
if (mode === "browser") {
removeStorage(MODE_STORAGE_KEY);
return;
}
writeStorage(MODE_STORAGE_KEY, mode);
}
function resolveTheme(colors) {
const mode = currentMode();
if (mode === "dark" || mode === "light") {
return mode;
}
if (typeof colors?.is_dark_mode === "boolean") {
return colors.is_dark_mode ? "dark" : "light";
}
return systemTheme();
}
function systemTheme() {
return window.matchMedia?.(MEDIA_QUERY).matches ? "dark" : "light";
}
function applyResolvedTheme(theme, colors) {
const seed = browserAccentValue(colors);
const mode = currentMode();
const changed = lastAppliedTheme !== theme || lastAppliedAccent !== seed || lastAppliedMode !== mode;
lastAppliedTheme = theme;
lastAppliedAccent = seed;
lastAppliedMode = mode;
const root = document.documentElement;
root.dataset.tlfTheme = theme;
root.dataset.tlfThemeMode = mode;
root.dataset.tlfThemeSource = seed !== undefined ? "browser" : "fallback";
root.style.colorScheme = theme;
applySeedColor(seed);
if (changed) {
const state = {
theme,
mode,
source: seed !== undefined ? "browser" : "fallback"
};
changeHandlers.forEach((handler) => {
try {
handler(state);
}
catch (error) {
console.warn("[Previewer] Theme change handler failed", error);
}
});
}
}
function applySeedColor(seed) {
const style = document.documentElement.style;
if (!style?.setProperty || !style.removeProperty) {
return;
}
if (seed === undefined) {
style.removeProperty("--primary");
return;
}
const { r, g, b } = skColorToRgb(seed);
style.setProperty("--primary", `rgb(${r}, ${g}, ${b})`);
}
function browserAccentValue(colors) {
return [colors?.user_color, colors?.accent_color, colors?.primary_color, colors?.background_color]
.map(seedColorValue)
.find((value) => value !== undefined);
}
function seedColorValue(color) {
if (typeof color?.value !== "number" || ((color.value >>> 24) & 255) === 0) {
return undefined;
}
const value = normalizeColorValue(color.value);
return isUsableSeed(value) ? value : undefined;
}
function isUsableSeed(value) {
const { r, g, b } = skColorToRgb(value);
const brightest = Math.max(r, g, b);
const chroma = brightest - Math.min(r, g, b);
return chroma > 12 || (brightest > 32 && brightest < 224);
}
function skColorToRgb(value) {
const unsignedValue = value >>> 0;
return {
r: (unsignedValue >> 16) & 255,
g: (unsignedValue >> 8) & 255,
b: unsignedValue & 255
};
}
async function readBrowserThemeColors() {
const directColors = await (readBrowserThemeColorsDirectly() || Promise.resolve(undefined));
if (directColors) {
return directColors;
}
console.info("[Previewer] chrome.tabThemeColor is unavailable or empty in this page context; requesting background theme colors.");
return readBrowserThemeColorsFromBackground();
}
function readBrowserThemeColorsDirectly() {
const api = tabThemeColorApi();
if (!api?.getColors && !api?.getUserColor) {
return undefined;
}
return (async () => {
const userColors = api.getUserColor ? await readColorsFromApi(api.getUserColor.bind(api)) : undefined;
if (userColors && hasUsableColor(userColors)) {
return userColors;
}
return api.getColors ? readColorsFromApi(api.getColors.bind(api)) : userColors;
})();
}
function readColorsFromApi(reader) {
return new Promise((resolve) => {
let settled = false;
const finish = (colors) => {
if (settled) {
return;
}
settled = true;
resolve(normalizeColors(colors) || undefined);
};
try {
reader(finish);
}
catch {
finish(undefined);
}
});
}
function readBrowserThemeColorsFromBackground() {
const runtime = chromeRuntimeApi();
if (!runtime?.sendMessage) {
console.warn("[Previewer] chrome.runtime.sendMessage is unavailable; falling back to default orange theme.");
return Promise.resolve(undefined);
}
const sendMessage = runtime.sendMessage.bind(runtime);
return new Promise((resolve) => {
sendMessage({ type: "tlf-get-tab-theme-colors" }, (response) => {
if (runtime.lastError?.message) {
console.warn("[Previewer] Failed to request background theme colors; falling back to default orange theme.", runtime.lastError.message);
resolve(undefined);
return;
}
if (!response?.ok) {
console.warn("[Previewer] Background theme color request failed; falling back to default orange theme.", response);
resolve(undefined);
return;
}
const colors = normalizeColors(response.themeColors) || undefined;
if (!colors) {
console.warn("[Previewer] Background returned no theme colors; falling back to default orange theme.");
}
resolve(colors);
});
});
}
function connectThemePort(onColors, onDisconnect) {
const runtime = chromeRuntimeApi();
if (!runtime?.connect) {
return undefined;
}
try {
const port = runtime.connect({ name: PORT_NAME });
const onMessage = (message) => {
if (message?.type !== "tlf-tab-theme-colors") {
return;
}
const colors = normalizeColors(message.colors) || undefined;
if (!colors) {
console.warn("[Previewer] Background theme port returned no colors; falling back to default orange theme.");
}
onColors(colors);
};
port.onMessage?.addListener(onMessage);
const handleDisconnect = () => {
port.onMessage?.removeListener?.(onMessage);
port.onDisconnect?.removeListener?.(handleDisconnect);
onDisconnect();
};
port.onDisconnect?.addListener(handleDisconnect);
return {
onMessage: port.onMessage,
disconnect: () => {
port.onMessage?.removeListener?.(onMessage);
port.onDisconnect?.removeListener?.(handleDisconnect);
port.disconnect?.();
}
};
}
catch (error) {
console.warn("[Previewer] Failed to connect background theme port; falling back to one-shot theme lookup.", error);
return undefined;
}
}
function normalizeColors(colors) {
if (!colors) {
return undefined;
}
return {
...colors,
user_color: normalizeColor(colors.user_color),
primary_color: normalizeColor(colors.primary_color),
accent_color: normalizeColor(colors.accent_color),
background_color: normalizeColor(colors.background_color),
text_color: normalizeColor(colors.text_color)
};
}
function normalizeColor(color) {
if (!color) {
return undefined;
}
return { value: normalizeColorValue(color.value) };
}
function hasUsableColor(colors) {
return browserAccentValue(colors) !== undefined;
}
function normalizeColorValue(value) {
return value === CHROMIUM_UNSET_USER_COLOR ? TABBIT_DEFAULT_ORANGE : value;
}
function tabThemeColorApi() {
return globalThis.chrome?.tabThemeColor;
}
function chromeRuntimeApi() {
return globalThis.chrome?.runtime;
}
function readStorage(key) {
try {
return window.localStorage.getItem(key);
}
catch {
return null;
}
}
function writeStorage(key, value) {
try {
window.localStorage.setItem(key, value);
}
catch {
return;
}
}
function removeStorage(key) {
try {
window.localStorage.removeItem(key);
}
catch {
return;
}
}
})(Theme = TabLocalFiles.Theme || (TabLocalFiles.Theme = {}));
})(TabLocalFiles || (TabLocalFiles = {}));
var TabLocalFiles;
(function (TabLocalFiles) {
const FALLBACK_FILE_TYPE_CATALOG = [
{
id: "markdown",
labelKey: "settings.type.markdown",
extensions: [".md", ".markdown"],
defaultOpenMode: "previewer",
chromeNativeRenderable: true,
osAssociation: "associate"
},
{
id: "svg",
labelKey: "settings.type.svg",
extensions: [".svg"],
defaultOpenMode: "previewer",
chromeNativeRenderable: true,
osAssociation: "associate"
},
{
id: "pdf",
labelKey: "settings.type.pdf",
extensions: [".pdf"],
defaultOpenMode: "native",
chromeNativeRenderable: true,
osAssociation: "associate"
},
{
id: "office",
labelKey: "settings.type.office",
extensions: [".doc", ".docx", ".ppt", ".pptx", ".xls", ".xlsx"],
defaultOpenMode: "previewer",
chromeNativeRenderable: false,
osAssociation: "none"
},
{
id: "html",
labelKey: "settings.type.html",
extensions: [".html", ".htm", ".xhtml", ".xht", ".xhtm"],
defaultOpenMode: "native",
chromeNativeRenderable: true,
osAssociation: "associate",
osAssociationOverrides: {
".xhtml": "none",
".xht": "none",
".xhtm": "none"
}
},
{
id: "subtitle",
labelKey: "settings.type.subtitle",
extensions: [".srt", ".vtt", ".ass", ".ssa", ".ttml", ".dfxp", ".smi", ".sbv", ".sub", ".mpl", ".lrc", ".idx"],
defaultOpenMode: "previewer",
chromeNativeRenderable: true,
chromeNativeRenderableOverrides: {
".sub": false
},
osAssociation: "none"
},
{
id: "code-text",
labelKey: "settings.type.codeText",
extensions: [
".txt",
".text",
".csv",
".tsv",
".rtf",
".tex",
".bib",
".mdx",
".js",
".cjs",
".mjs",
".ts",
".jsx",
".tsx",
".vue",
".py",
".rb",
".java",
".swift",
".go",
".rs",
".cpp",
".cc",
".cxx",
".c",
".h",
".hh",
".hpp",
".hxx",
".css",
".less",
".scss",
".json",
".jsonc",
".jsonl",
".ndjson",
".xml",
".yaml",
".yml",
".toml",
".ini",
".sh",
".sql",
".log"
],
defaultOpenMode: "previewer",
chromeNativeRenderable: true,
osAssociation: "associate",
osAssociationOverrides: {
".text": "none",
".rtf": "none",
".mdx": "none",
".cjs": "none",
".mjs": "none",
".vue": "none",
".rb": "none",
".swift": "none",
".cc": "none",
".cxx": "none",
".hh": "none",
".hxx": "none",
".less": "none",
".scss": "none",
".jsonc": "none",
".jsonl": "none",
".ndjson": "none",
".toml": "none",
".ini": "none"
}
},
{
id: "zip",
labelKey: "settings.type.archive",
extensions: [
".zip",
".jar",
".apk",
".crx",
".epub",
".skill",
".xpi",
".vsix",
".whl",
".nupkg",
".odt",
".ods",
".odp"
],
defaultOpenMode: "previewer",
chromeNativeRenderable: false,
osAssociation: "none"
},
{
id: "image",
labelKey: "settings.type.image",
extensions: [".png", ".jpg", ".jpeg", ".webp", ".gif", ".bmp", ".avif", ".ico", ".apng"],
defaultOpenMode: "previewer",
chromeNativeRenderable: true,
osAssociation: "associate",
osAssociationOverrides: {
".avif": "none",
".ico": "none",
".apng": "none"
}
},
{
id: "media",
labelKey: "settings.type.media",
extensions: [
".webm",
".mp4",
".m4v",
".mkv",
".ogv",
".ogm",
".mp3",
".wav",
".flac",
".ogg",
".oga",
".opus",
".weba",
".m4a",
".mka"
],
defaultOpenMode: "native",
chromeNativeRenderable: true,
osAssociation: "none"
}
];
function manifestFileTypeCatalog() {
return globalThis.chrome?.runtime?.getManifest?.()?.tab_local_file_preview?.fileTypeCatalog;
}
TabLocalFiles.FILE_TYPE_CATALOG = manifestFileTypeCatalog() ?? FALLBACK_FILE_TYPE_CATALOG;
function extensionsForId(id) {
return TabLocalFiles.FILE_TYPE_CATALOG.find((entry) => entry.id === id)?.extensions ?? [];
}
TabLocalFiles.MARKDOWN_EXTENSIONS = extensionsForId("markdown");
TabLocalFiles.IMAGE_EXTENSIONS = [...extensionsForId("image"), ...extensionsForId("svg")];
TabLocalFiles.MEDIA_EXTENSIONS = extensionsForId("media");
TabLocalFiles.HTML_EXTENSIONS = [...extensionsForId("html"), ".text_html"];
TabLocalFiles.OFFICE_EXTENSIONS = extensionsForId("office");
TabLocalFiles.SUBTITLE_EXTENSIONS = extensionsForId("subtitle");
TabLocalFiles.CODE_TEXT_EXTENSIONS = extensionsForId("code-text");
TabLocalFiles.ARCHIVE_CATALOG_EXTENSIONS = extensionsForId("zip");
TabLocalFiles.SIDEBAR_ONLY_EXTENSIONS = TabLocalFiles.ARCHIVE_CATALOG_EXTENSIONS.filter((extension) => extension !== ".zip" && extension !== ".skill");
function catalogEntryForExtension(extension) {
const normalized = extension.toLowerCase();
return TabLocalFiles.FILE_TYPE_CATALOG.find((entry) => entry.extensions.includes(normalized));
}
TabLocalFiles.catalogEntryForExtension = catalogEntryForExtension;
function catalogDefaultOpenMode(extension) {
return catalogEntryForExtension(extension)?.defaultOpenMode;
}
TabLocalFiles.catalogDefaultOpenMode = catalogDefaultOpenMode;
function catalogChromeNativeRenderable(extension) {
const normalized = extension.toLowerCase();
const entry = catalogEntryForExtension(normalized);
return entry?.chromeNativeRenderableOverrides?.[normalized] ?? entry?.chromeNativeRenderable;
}
TabLocalFiles.catalogChromeNativeRenderable = catalogChromeNativeRenderable;
function catalogOsAssociation(extension) {
const normalized = extension.toLowerCase();
const entry = catalogEntryForExtension(normalized);
if (!entry) {
return "none";
}
return entry.osAssociationOverrides?.[normalized] ?? entry.osAssociation;
}
TabLocalFiles.catalogOsAssociation = catalogOsAssociation;
function effectiveOpenMode(extension) {
const normalized = extension.toLowerCase();
return TabLocalFiles.Preferences.readOpenModes()[normalized] || catalogDefaultOpenMode(normalized);
}
TabLocalFiles.effectiveOpenMode = effectiveOpenMode;
})(TabLocalFiles || (TabLocalFiles = {}));
var TabLocalFiles;
(function (TabLocalFiles) {
var SettingsPage;
(function (SettingsPage) {
const RE_DETECT_DELAYS_MS = [1500, 8000];
const systemOpenInfoByExtension = {};
function start() {
TabLocalFiles.Theme.start();
TabLocalFiles.localizeDocument();
document.title = TabLocalFiles.t("settings.title");
bindNavigation();
renderFileTypeList();
renderShortcutReference();
renderSyntaxReference();
bindGeneralSettings();
syncOpenModeControls();
void TabLocalFiles.Preferences.init().then(() => {
syncGeneralSettings();
syncOpenModeControls();
});
TabLocalFiles.Preferences.onChange(() => {
syncGeneralSettings();
syncOpenModeControls();
});
void detectSystemOpenInfo(allCatalogExtensions());
}
SettingsPage.start = start;
function bindNavigation() {
window.addEventListener("hashchange", showPageFromHash);
showPageFromHash();
}
function showPageFromHash() {
const pages = Array.from(document.querySelectorAll("[data-tlf-settings-page]"));
const requested = window.location.hash.slice(1);
const active = pages.find((page) => page.dataset.tlfSettingsPage === requested) || pages[0];
if (!active) {
return;
}
pages.forEach((page) => {
page.hidden = page !== active;
});
const activeId = active.dataset.tlfSettingsPage;
document.querySelectorAll("[data-tlf-settings-nav]").forEach((item) => {
const current = item.dataset.tlfSettingsNav === activeId;
if (current) {
item.setAttribute("aria-current", "page");
const title = document.querySelector("[data-tlf-settings-page-title]");
if (title) {
title.textContent = item.textContent?.trim() || "";
}
}
else {
item.removeAttribute("aria-current");
}
});
const scroller = document.querySelector("[data-tlf-settings-scroll]");
if (scroller) {
scroller.scrollTop = 0;
}
}
const SHORTCUT_GROUPS = [
{
titleKey: "settings.shortcutGroupFormat",
items: [
{ labelKey: "markdown.bold", spec: { mod: true, key: "B" } },
{ labelKey: "markdown.italic", spec: { mod: true, key: "I" } },
{ labelKey: "markdown.strikethrough", spec: { mod: true, shift: true, key: "X" } },
{ labelKey: "markdown.insertLink", spec: { mod: true, key: "K" } },
{ labelKey: "markdown.inlineCode", spec: { mod: true, shift: true, key: "C" } },
{ labelKey: "markdown.codeBlock", spec: { mod: true, shift: true, key: "K" } }
]
},
{
titleKey: "settings.shortcutGroupBlocks",
items: [
{ labelKey: "markdown.heading1", spec: { mod: true, alt: true, key: "1" } },
{ labelKey: "markdown.heading2", spec: { mod: true, alt: true, key: "2" } },
{ labelKey: "markdown.heading3", spec: { mod: true, alt: true, key: "3" } },
{ labelKey: "markdown.orderedList", spec: { mod: true, shift: true, key: "7" } },
{ labelKey: "markdown.unorderedList", spec: { mod: true, shift: true, key: "8" } },
{ labelKey: "markdown.blockquote", spec: { mod: true, shift: true, key: "9" } }
]
},
{
titleKey: "settings.shortcutGroupDocument",
items: [
{ labelKey: "common.save", spec: { mod: true, key: "S" } },
{ labelKey: "markdown.searchPlaceholder", spec: { mod: true, key: "F" } },
{ labelKey: "markdown.searchNext", spec: { mod: true, key: "G" } },
{ labelKey: "markdown.searchPrev", spec: { mod: true, shift: true, key: "G" } }
]
}
];
function renderShortcutReference() {
const container = document.querySelector("[data-tlf-settings-shortcuts]");
if (!container) {
return;
}
container.innerHTML = SHORTCUT_GROUPS.map((group) => `
${escapeHtml(TabLocalFiles.t(group.titleKey))}
${group.items
.map((item) => `
- ${escapeHtml(TabLocalFiles.t(item.labelKey))}
- ${escapeHtml(TabLocalFiles.formatShortcut(item.spec))}
`)
.join("")}
`).join("");
}
const SYNTAX_GROUPS = [
{
titleKey: "settings.syntaxGroupBasic",
rows: [
["# 一级标题 … ###### 六级标题", "settings.syntaxHeading"],
["**粗体** *斜体* ~~删除线~~ `行内代码`", "settings.syntaxEmphasis"],
["[文字](地址) ", "settings.syntaxLinkImage"],
["- 无序项 / 1. 有序项 / - [ ] 任务", "settings.syntaxList"],
["> 引用块", "settings.syntaxQuote"],
["--- 分隔线", "settings.syntaxRule"]
]
},
{
titleKey: "settings.syntaxGroupBlocks",
rows: [
["```语言 … ```", "settings.syntaxCodeFence"],
["| 表头 | 表头 |", "settings.syntaxTable"],
["术语 换行 : 定义", "settings.syntaxDefinitionList"],
["[^1] 与 [^1]: 脚注内容", "settings.syntaxFootnote"],
["> [!NOTE] / [!TIP] / [!WARNING]", "settings.syntaxAlert"],
["--- YAML --- 置于文首", "settings.syntaxFrontmatter"]
]
},
{
titleKey: "settings.syntaxGroupExtended",
rows: [
["==高亮== ++插入++", "settings.syntaxHighlight"],
["H~2~O x^2^", "settings.syntaxSubSup"],
["$行内公式$ $$块级公式$$", "settings.syntaxMath"],
["```mermaid … ```", "settings.syntaxMermaid"],
["```svg … ``` 或内联