Files
DemonGatanjieu-Anomalous_Mo…/web/modules/locales.js
T

690 lines
44 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export const i18n = {
zh: {
title: '📦 Anomalous 模型浏览器',
scan: '🔄 扫描目录并同步 C 站数据',
scanTitle: '扫描目录',
scanConfirm: '注意:\n扫描过程将会自动比对 Civitai 并重命名本地模型,同时清理损坏文件。\n确定要开始扫描吗?',
scanning: '扫描中...',
scanBg: '🚀 扫描后台启动!',
scanDone: '完成',
scanCompleteMsg: '✅ 扫描完成!\n\n⚠️ 提示:由于部分模型已被重命名或去重,请点击 ComfyUI 的 [Refresh] 按钮以同步最新的模型列表。',
eco: '🔋 视频悬浮播放 (节能模式)',
autoPlay: '🎬 自动播放视频封面 (高能耗)',
togglePlayTitle: '切换播放模式',
clean: '🧹 清理无效的 .info 残留文件',
cleanTitle: '清理重复 Info',
cleanConfirm: '将扫描并删除所有无用的 .civitai.info 残留文件。是否继续?',
cleaning: '清理中',
cleanDone: '✅ 清理完毕!删除了',
files: '个文件。',
cleanFail: '❌ 清理失败: ',
cleanErr: '❌ 清理出错: ',
folders: '📂 文件夹',
collapseAll: '➖ 收起全部',
expandAll: '➕ 展开全部',
noModels: '此文件夹中没有找到模型。',
noPreview: '暂无预览图',
clickScan: '点击扫描',
back: '⬅️ 返回',
delModel: '🗑️ 删除',
delConfirm: '确定彻底删除',
delConfirm2: '及其所有关联配置、预览图和缓存文件吗?此操作不可逆!',
delSuccess: '✅ 删除成功!\n',
delNote: '\n\n⚠️ 提示:请重启 ComfyUI,否则由于缓存继续使用会报错',
delFail: '❌ 删除失败: ',
copyAll: '📋 复制全部',
copied: '✅ 已复制!',
clickToCopy: '点击复制: ',
compatibleModels: '🔗 兼容模型',
loadingCompatible: '加载中...',
backToPrev: '🔙 返回上一层',
applyToCanvas: '➕ 插入节点',
applySuccess: '✅ 已添加至工作流',
help: '帮助',
helpTitle: '📖 使用手册',
helpContent: `
<div style="line-height: 1.6; font-size: 0.95em; color: #eee; padding: 10px;">
<h3 style="color:#00ffcc; margin-top:0;">📖 标准操作说明</h3>
<p><strong>1. 🔄 前置准备 (扫描向导)</strong><br>具体位置:界面左侧底部的 <strong>扫描向导 (🔄)</strong>。<br>这是最重要的前置操作!请先打开扫描向导执行扫描。切记保持网络畅通。部分 C站限制级模型信息需要在设置中填入 API-KEY。扫描完成后,插件的各项功能基本激活。</p>
<p><strong>2. 🩺 拯救爆红 (模型医生)</strong><br>具体位置:左侧底部第二个 <strong>听诊器 (🩺)</strong> 按钮。<br>当导入别人使用该插件输出的工作流或者图片时,若模型路径爆红,点击模型医生就能智能识别当前所有节点实现正确路径的替换。</p>
<p><strong>3. 🤖 选中交互 (节点助手)</strong><br>具体位置:左侧第三个 <strong>机器人 (🤖)</strong> 按钮。<br>打开后在画布上选择模型节点。新版操作卡可以替换当前模型,也可在兼容的 MODEL + CLIP 链前方或后方插入 LoRA。模型卡会标注类别与基础模型类型;选择 LoRA 时会优先按已连接主模型的类型自动筛选,也可切回全部 LoRA。文件夹、完整路径搜索、排序和多分支安全保护仍然保留。</p>
<p><strong>4. ⚙️ 个性化配置 (设置面板)</strong><br>具体位置:左侧底部的 <strong>齿轮 (⚙️)</strong> 按钮。<br>可以调节语言、主页面字体大小;进入“模型设置”可选择视频封面始终播放或悬停播放,以及卡片使用流畅缩略图或原始封面。详情页始终保留原图画质。</p>
<p><strong>5. 📑 顶部导航与笔记本功能</strong><br>具体位置:右侧顶部的按钮分别为 <strong>模型 (📦)</strong>、<strong>图库 (🖼️)</strong>、<strong>笔记本 (📑)</strong>、<strong>停靠侧边栏 (◧)</strong>。<br>点击笔记本,点击新建 <strong>➕</strong> 号。确认后选择基础模型(如SD1.5),接着选择主模型和对应的 lora。点击下方的 <strong>📝纯文本/粘贴</strong> 填入提示词,选择左上角的语言即可实现双语对照。确认后自动分块标签,支持查找替换和直接修改单个标签。最后点击 <strong>🚀 发送到画布</strong> 即可一键连线!</p>
<p><strong>6. 📁 文件夹管理 (Folder Manager)</strong><br>具体位置:设置 (⚙️) 面板内的 <strong>📁 文件夹管理</strong>。<br>可以用来隐藏不需要的内置文件夹。隐藏后的文件夹不仅从侧边栏消失,后端的静默扫描和本地读取也会完全跳过,实现真正的“零性能损耗”。并且可以在这里拖拽调整文件夹在侧边栏显示的顺序。</p>
<p><strong>7. 📥 工作流导出与导入 (分享码)</strong><br>具体位置:设置 (⚙️) 按钮左侧的 <strong>导入/导出 (📥)</strong> 按钮。<br>该功能可以将当前的工作流一键编码导出为一段专属分享码,方便发到社交平台。别人只需复制这串分享码,在此界面粘贴即可直接还原导入完整的工作流,并且在导入前系统会自动校验模型是否在本地存在。</p>
<p><strong>8. 💬 提交反馈 / 报告问题</strong><br>具体位置:设置 (⚙️) 面板内的 <strong>💬 提交反馈 / 报告问题</strong>。<br>当你遇到插件报错或有新功能建议时,点击该按钮可一键直达 GitHub Issues 页面提交反馈。</p>
</div>`,
notebooks: '笔记本',
notebookTitle: '笔记本管理',
workspace: '创作工作台',
workspaceTitle: '创作工作台',
promptNotes: '提示词笔记',
createNotebook: '新建',
saveNotebook: '💾 保存',
deleteNotebook: '🗑️ 删除',
renameNotebook: '✏️ 重命名',
baseModel: 'Base Model (基础模型)',
mainModel: 'Main Model (主模型)',
sendToCanvas: '🚀 发送到画布',
translate: '翻译',
newNotebookName: '新笔记本名称',
noBaseModel: '请先选择 Base Model',
dialogOk: '确定',
dialogCancel: '取消',
closeHelp: '关闭说明',
delSure: '⚠️ 确定吗?',
dockTitle: '侧边停靠',
replaceAll: '全部替换',
editRaw: '📝 纯文本/粘贴',
findPlaceholder: '查找...',
replacePlaceholder: '替换为...',
models: '模型',
gallery: '图库',
apiKeyConfig: '🔑 Civitai API 密钥配置 (用于下载封面)',
apiKeyPrompt: '请输入你的 Civitai API Key:',
settingsBtn: '设置',
closeSettings: '✖ 关闭设置面板',
doctorBtn: '节点助手',
importBtn: '📥 导入 / 导出工作流 (分享码)',
recipeTitle: '工作流配方',
recipeClose: '关闭工作流配方',
recipeSaveCurrent: '保存当前工作流',
recipeSaveTitle: '保存为工作流配方',
recipeName: '名称',
recipeDefaultName: '新工作流配方',
recipeNameRequired: '请填写配方名称。',
recipeTags: '标签',
recipeTagsHint: '例如:人像, SDXL, 放大',
recipeNotes: '备注',
recipeNotesHint: '记录这个版本为什么好用……',
recipeThumbnail: '工作流缩略图',
recipeCancel: '取消',
recipeSave: '保存',
recipeSaving: '正在保存…',
recipeSaveReceipt: '已保存:{nodes} 个节点,{links} 条连线,{groups} 个分组。',
recipeSaveReceiptMismatch: '已保存,但完整性回执与当前画布不一致;请重新打开配方核对。',
recipeEmpty: '还没有工作流配方。保存一个已经跑通的工作流吧。',
recipeLoadError: '无法加载工作流配方。',
recipeUntitled: '未命名配方',
recipeSearchPlaceholder: '搜索名称、笔记或标签…',
recipeClearFilters: '清除筛选',
recipeNoTags: '暂无标签',
recipeNoMatches: '没有匹配的配方。请清除搜索或标签筛选。',
recipeFilterByTag: '按此标签筛选',
recipeImport: '导入配方包',
recipeExport: '导出配方包',
recipeExportError: '导出工作流配方包失败。',
recipeImportError: '导入工作流配方包失败。',
recipeExportSnapshotsConfirm: '导出时包含模型预览快照吗?\n\n快照是展示数据,不包含模型文件;视频封面只保留轻量静态快照,不会打包原视频。',
recipeExportHistoryConfirm: '导出时包含历史版本吗?\n\n历史可能包含旧提示词和备注。',
recipeExportRedactIdentityConfirm: '是否移除模型 SHA-256、大小和来源信息?\n\n点击“确定”将移除这些身份信息。',
recipeImportSummary: '配方包检查完成。确认导入以下内容吗?',
recipeImportAssets: '预览资产',
recipeImportHistory: '历史版本',
recipeImportRenamePrompt: '配方名称已存在,请输入导入后的名称:',
recipeModel: '模型',
recipeLoras: 'LoRA',
recipePrompt: '正向提示词',
recipeSteps: '步数',
recipeRestore: '恢复版本',
recipeAppendCanvas: '追加到画布',
recipeAppendError: '无法追加此配方到当前画布。',
recipeDelete: '删除',
recipeDeleteConfirm: '确定删除这个工作流配方吗?',
recipeDeleteError: '删除工作流配方失败。',
recipeSaveError: '保存工作流配方失败。',
recipeNodeParams: '节点参数',
recipeUnknownNode: '未知节点',
recipeCopyParameter: '复制参数值',
recipeCopied: '已复制',
recipeCopyFailed: '复制失败',
recipeAdvancedInfo: '高级信息',
recipeInlineEditName: '点击修改名称',
recipeInlineEditNotes: '点击修改备注',
recipeInlineEditTags: '编辑标签',
recipeInlineSave: '保存',
recipeInlineCancel: '取消',
recipeInlineSaving: '保存中…',
recipeInlineError: '保存失败,请重试。',
recipeInlineNameRequired: '名称不能为空。',
recipeSomeParamsInWorkflow: '其余复杂或敏感参数仍保存在完整工作流中。',
recipeMoreNodesInWorkflow: '其余节点仍保存在完整工作流中。',
recipeMissingNodes: '当前缺少以下节点类型,恢复后可能无法运行',
recipeBindImage: '绑定封面图片',
recipeNoImage: '不绑定图片',
recipeCanvasPreview: '当前画布',
recipeLoadingRecentImages: '正在读取最近生成结果…',
recipeRecentImages: '最近生成结果',
recipeRecentImagesUnavailable: '暂时无法读取最近生成结果。',
recipeChoosePinnedParams: '选择关键参数',
recipePinnedParams: '关键参数',
recipeKeepImage: '保留当前封面',
recipeEdit: '编辑',
recipeEditTitle: '编辑工作流配方',
recipeEditNodeParams: '编辑节点参数',
recipeComplexParam: '复杂值仅展示;完整值仍安全保存在工作流中。',
recipeHistory: '版本历史',
recipeHistoryEmpty: '还没有历史版本。更新配方后会自动保留旧版本。',
recipeUnknownVersion: '未知时间',
recipeRestoreVersion: '恢复此版本',
recipeRestoreVersionConfirm: '恢复此版本会覆盖当前配方,但当前内容会先自动存入历史。继续吗?',
recipeEditCanvas: '载入画布编辑',
recipeEditCanvasConfirm: '载入会替换当前画布。完成结构编辑后,点击“更新当前配方”即可保存为新版本。继续吗?',
recipeUpdate: '保存更新',
recipeUpdateCurrent: '更新当前配方',
recipeUpdateError: '更新工作流配方失败。',
recipeViewDetails: '查看详情',
recipeDetailBack: '返回配方列表',
recipeDetailOverview: '概览',
recipeGallery: '图库',
recipeGalleryLoading: '正在查找匹配的历史出图…',
recipeGalleryEmpty: '未在最近 200 张含工作流数据的 PNG 中找到与此配方结构匹配的出图。',
recipeGalleryRefresh: '刷新匹配结果',
recipeGallerySetCover: '设为配方封面',
recipeGalleryCoverSaved: '已设为配方封面',
recipeGalleryCoverError: '无法设置配方封面。',
recipeGalleryLoadError: '无法读取配方图库。',
recipeGalleryScanHint: '已检查最近 {count} 张含工作流数据的 PNG。',
recipeGalleryOpenImage: '查看原图',
recipeGalleryCompare: '参数对比',
recipeGalleryComparison: '配方与出图参数',
recipeGalleryComparisonLoading: '正在读取这张图片的参数…',
recipeGalleryComparisonError: '无法读取这张图片的参数。',
recipeGalleryNoDifferences: '没有发现可显示的参数差异。',
recipeGalleryDifferenceHint: '以下是节点参数的差异;图库匹配本身只关注节点类型。',
recipeGalleryRecipeValue: '配方',
recipeGalleryImageValue: '图片',
recipeDetailModels: '模型与复现',
recipeDetailParameters: '参数笔记本',
recipeDetailParametersHint: '这里展示配方保存的完整参数;长文本可展开并复制。参数图库只匹配相同参数,不会因为本地路径不同而失效。',
recipeParameterSnapshots: '参数快照',
recipeParameterSnapshotsHint: '每次保存配方都会留下一个只读版本。',
recipeParameterRefresh: '刷新快照',
recipeParameterLoading: '正在读取参数快照…',
recipeParameterLoadError: '无法读取参数快照。',
recipeParameterNoSnapshots: '这个配方还没有参数快照。',
recipeParameterUntitled: '未命名参数快照',
recipeParameterNew: '新建参数笔记',
recipeParameterReadCurrent: '读取当前并新建',
recipeParameterReadCurrentSaving: '正在读取并保存…',
recipeParameterReadCurrentError: '无法读取当前画布参数。',
recipeParameterSkeletonMismatch: '当前画布缺少配方骨架节点,未执行任何修改。',
recipeParameterApply: '应用到当前工作流',
recipeParameterApplying: '正在检查骨架并应用…',
recipeParameterApplied: '已应用 {count} 项参数',
recipeParameterApplyError: '应用参数失败,当前画布未完成修改。',
recipeParameterNewHint: '基于当前配方骨架编辑节点参数;种子等运行时变化值会被忽略。保存后会生成新的只读快照,不会覆盖历史记录。',
recipeParameterName: '笔记名称',
recipeParameterSave: '保存参数笔记',
recipeParameterCancel: '取消编辑',
recipeParameterSaveError: '参数笔记保存失败。',
recipeParameterSensitiveHidden: '敏感控件已隐藏',
recipeDetailParameterSummary: '常用参数',
recipeDetailNodeParameters: '节点参数',
recipeDetailUnknownNode: '未命名节点',
recipeDetailWidget: '控件',
recipeDetailScheduler: '调度器',
recipeDetailSteps: '步数',
recipeDetailCFG: 'CFG',
recipeDetailDenoise: '降噪',
recipeDetailSeed: '种子',
recipeParameterGallery: '相同参数的出图',
recipeParameterGalleryLoading: '正在查找相同参数的历史出图…',
recipeParameterGalleryEmpty: '没有找到参数完全一致的历史出图。',
recipeParameterGalleryError: '无法读取参数图库。',
recipeDetailNoSavedParameters: '此配方没有可展示的参数。',
recipeDetailVersions: '版本',
recipeDetailSummary: '摘要',
recipeDetailModelComposition: '模型组成',
recipeDetailBaseModel: '主模型',
recipeDetailIdentity: '已验证身份',
recipeDetailUnverified: '未验证模型',
recipeDetailMissingNodes: '缺失节点类型',
recipeDetailFingerprint: '工作流指纹',
recipeDetailNotIndexed: '尚未索引',
recipeDetailLoraSummary: 'LoRA',
recipeDetailSampler: '采样器',
recipeDetailResolution: '分辨率',
recipeDetailUnavailable: '不可用',
recipeDetailEditOrigin: '✏️ 编辑来源',
recipeOriginDialogTitle: '编辑模型来源信息',
recipeOriginOfficialName: '官方模型名称',
recipeOriginModelUrl: '官方网址 (Model URL)',
recipeOriginFetchHash: '🌍 通过 Hash 自动获取',
recipeOriginFetching: '获取中...',
recipeOriginFetchFailed: '未找到或网络异常',
recipeOriginFetchSuccess: '已成功获取!',
recipeDetailNoNotes: '没有备注。',
recipeDetailUpdated: '更新时间',
recipeDetailCopyPrompt: '复制提示词',
recipeDetailCopyFingerprint: '复制工作流指纹',
recipeDetailCopyHash: '复制完整哈希',
recipeDetailPrompts: '提示词',
recipeDetailPositivePrompt: '正向提示词',
recipeDetailNegativePrompt: '负面提示词',
recipeDetailNoPrompts: '此配方没有可安全展示的提示词摘要。',
recipeDetailVolatileIgnored: '运行时变化,已忽略',
recipeDetailExpandValue: '展开完整内容',
recipeDetailCollapseValue: '收起内容',
recipeIdentityVerified: '身份已核验',
recipeIdentityUnverified: '本地可用,未核验',
recipeIdentityUnavailable: '本机未找到',
recipeIdentityHelpDesc: '核验的是物理文件是否一致,不代表判断模型画质或可用性。',
recipeDetailRefreshAvailability: '检查本机可用性',
recipeDetailRefreshOrigin: '刷新来源信息',
recipeDetailRefreshOriginDesc: '刷新当前配方中的所有模型来源信息(支持补充旧配方数据)',
recipeDetailRefreshing: '检查中…',
recipeDetailRefreshError: '检查本机可用性失败',
recipeDetailAvailable: '本机可用',
recipeDetailMissing: '本机缺失',
recipeDetailAvailabilityNotChecked: '尚未检查本机',
recipeDetailNoModelReferences: '没有识别到受支持的模型加载器。其他自定义控件保留在参数和完整工作流中。',
recipeDetailModel: '模型',
recipeModelPath: '模型路径',
recipeOpenLocalModel: '打开本地模型详情',
recipeMatchLocalModel: '匹配本地模型',
recipeMatchingLocalModel: '正在匹配本地模型…',
recipeMatchRecipeModels: '匹配配方模型',
recipeMatchRecipeModelsDesc: '根据模型哈希、文件大小和模型类别,在本地模型目录中查找对应文件;不会使用原作者路径。',
recipeMatchingRecipeModels: '正在匹配配方模型…',
recipeRecipeMatchSummary: '已找到 {found}/{total} 个本地匹配',
recipeAllModelsMatched: '配方中的模型都已匹配或无需匹配',
recipeApplyLocalMatch: '应用此匹配',
recipeApplyLocalMatchDesc: '将匹配到的本地模型路径写入配方工作流',
recipeApplyingLocalMatch: '正在应用匹配…',
recipeApplyLocalMatchSuccess: '已应用本地模型匹配',
recipeApplyLocalMatchError: '无法应用此模型匹配',
recipeLocalModelNotFound: '暂未找到匹配的本地模型。',
recipeLocalModelAmbiguous: '找到多个候选,请先补充模型身份信息。',
recipeLocalModelMatchError: '匹配失败,请稍后重试。',
recipeDetailSearchParameters: '按节点、类型或控件名称搜索…',
recipeDetailWidget: '控件',
recipeDetailNoParameters: '没有匹配的安全参数。',
recipeDetailCurrentVersion: '当前版本',
recipeCompareVersion: '对比此版本',
recipeDiffLoading: '正在比较…',
recipeDiffSummary: '变更摘要',
recipeDiffBefore: '之前',
recipeDiffAfter: '之后',
recipeDiffNoChanges: '两个版本没有检测到有意义的变更。',
recipeDiffError: '无法读取此历史版本。',
recipeDiffPinned: '钉选参数',
recipeDiffPrompts: '提示词',
recipeDiffModels: '模型引用',
recipeDiffParameters: '参数摘要',
recipeDiffWorkflow: '工作流结构',
recipeDiffPresentation: '展示信息',
recipeDiffOther: '其他',
recipeDetailUnknownTime: '未知时间',
recipeDetailLoadingPreviews: '正在加载本机模型预览…',
recipeDetailCurrentPreview: '当前本机预览',
recipeDetailNoPreview: '暂无预览',
recipeSaveModelPreviewSnapshots: '打包模型封面图 (内置到配方中)',
recipeSaveModelPreviewSnapshotsHint: '将当前模型的小尺寸封面图直接打包进配方文件中。当你将配方分享给他人时,对方即使没有该模型也能看到精美的封面图。(为节省体积,仅保存静态图,不包含视频)',
recipeDetailSavedSnapshot: '已保存快照',
},
en: {
title: '📦 Anomalous Model Browser',
scan: '🔄 Scan folder and sync Civitai data',
scanTitle: 'Scan Folder',
scanConfirm: 'Notice:\nThe scan process will automatically compare with Civitai and rename your local files.\nStart scan?',
scanning: 'Scanning...',
scanBg: '🚀 Scan started in background!',
scanDone: 'Done',
scanCompleteMsg: '✅ Scan Complete!\n\n⚠️ Note: Please click [Refresh] to sync the model list since files were renamed.',
eco: '🔋 Eco Mode (Play video on hover)',
autoPlay: '🎬 AutoPlay Videos (High perf cost)',
togglePlayTitle: 'Toggle Play Mode',
clean: '🧹 Clean orphaned .info files',
cleanTitle: 'Clean Duplicate Info',
cleanConfirm: 'This will globally scan and delete all redundant .civitai.info files. Continue?',
cleaning: 'Cleaning',
cleanDone: '✅ Clean Complete! Deleted',
files: 'files.',
cleanFail: '❌ Failed: ',
cleanErr: '❌ Error: ',
folders: '📂 Folders',
collapseAll: '➖ Collapse All',
expandAll: '➕ Expand All',
noModels: 'No models found in this folder.',
noPreview: 'No preview available',
clickScan: 'Click Scan',
back: '⬅️ Back',
delModel: '🗑️ Delete',
delConfirm: 'Are you sure you want to permanently delete',
delConfirm2: ' and all its associated configs, previews, and cache files? This action is irreversible!',
delSuccess: '✅ Delete Complete!\n',
delNote: '\n\n⚠️ Note: Please restart ComfyUI, otherwise continuing to use it due to cache will cause errors.',
delFail: '❌ Delete Failed: ',
copyAll: '📋 Copy All',
copied: '✅ Copied!',
clickToCopy: 'Click to copy: ',
compatibleModels: '🔗 Compatible Models',
loadingCompatible: 'Loading...',
backToPrev: '🔙 Back to prev',
applyToCanvas: '➕ Add Node',
applySuccess: '✅ Added to workflow',
help: 'Help',
helpTitle: '📖 User Manual',
helpContent: `
<div style="line-height: 1.6; font-size: 0.95em; color: #eee; padding: 10px;">
<h3 style="color:#00ffcc; margin-top:0;">📖 Step-by-Step Guide</h3>
<p><strong>1. 🔄 Prerequisites (Scan Wizard)</strong><br>Location: The <strong>Scan (🔄)</strong> icon at the bottom left.<br>This is the most crucial step! Open the Scan Wizard and execute a scan. Keep your network connected. (API-KEY may be needed in Settings for NSFW Civitai models). Scanning activates all core features.</p>
<p><strong>2. 🩺 Fix Broken Nodes (Model Doctor)</strong><br>Location: The 2nd icon <strong>(Stethoscope 🩺)</strong> from the bottom left.<br>When importing a workflow/image exported by this plugin and nodes turn red, open the Model Doctor to intelligently identify and replace them with correct local paths.</p>
<p><strong>3. 🤖 Visual Info (Node Assistant)</strong><br>Location: The 3rd icon <strong>(Robot 🤖)</strong> from the bottom left.<br>The redesigned action card can replace the current model or insert a LoRA before/after a compatible MODEL + CLIP chain. Picker cards show category and base-model badges. LoRA choices default to the connected main model's type when metadata is available, with an option to show all LoRAs. Folder browsing, full-path search, sorting, and ambiguous-branch protection remain available.</p>
<p><strong>4. ⚙️ Settings Panel</strong><br>Location: The <strong>Gear (⚙️)</strong> icon at the bottom left.<br>Adjust language and UI scale. Open “Model Settings” to choose always-play or hover-play video covers and optimized thumbnails or original covers. Detail pages always retain original image quality.</p>
<p><strong>5. 📑 Top Navigation & Notebook</strong><br>Location: Top right tabs <strong>Models (📦)</strong>, <strong>Gallery (🖼️)</strong>, <strong>Notebook (📑)</strong>, <strong>Dock (◧)</strong>.<br>Click Notebook -> click <strong>➕</strong> -> select Base Model (e.g. SD1.5) -> pick Main Model & LoRA. Click <strong>📝 Edit Raw/Paste</strong> to input prompts, select language on top-left for bilingual translation. Confirm to auto-chunk tags (supports find/replace & direct edit). Finally, click <strong>🚀 Send to Canvas</strong>!</p>
<p><strong>6. 📁 Folder Manager</strong><br>Location: Inside the Settings (⚙️) panel, click <strong>📁 Manage Folders</strong>.<br>Use this to hide unneeded built-in folders. Hidden folders will be completely skipped by background scans and I/O reads, achieving true "zero performance cost". You can also drag and drop to reorder how folders appear in the sidebar.</p>
<p><strong>7. 📥 Workflow Export & Import (Share Code)</strong><br>Location: The <strong>Import/Export (📥)</strong> icon to the left of the Settings gear.<br>You can encode your current workflow into a single share code for easy sharing on social platforms. Others can simply copy this code and paste it here to instantly import the workflow. The system will also automatically pre-check if the required models exist locally.</p>
<p><strong>8. 💬 Submit Feedback / Report Bug</strong><br>Location: Inside the Settings (⚙️) panel, click <strong>💬 Submit Feedback / Report Bug</strong>.<br>If you encounter bugs or have feature requests, click this to go directly to our GitHub Issues page.</p>
</div>`,
notebooks: 'Notebooks',
notebookTitle: 'Notebook Manager',
workspace: 'Workspace',
workspaceTitle: 'Creative Workspace',
promptNotes: 'Prompt Notes',
createNotebook: 'New',
saveNotebook: '💾 Save',
deleteNotebook: '🗑️ Delete',
renameNotebook: '✏️ Rename',
baseModel: 'Base Model',
mainModel: 'Main Model',
sendToCanvas: '🚀 Send to Canvas',
translate: 'Translate',
newNotebookName: 'New Notebook Name',
noBaseModel: 'Select a Base Model first',
dialogOk: 'OK',
dialogCancel: 'Cancel',
closeHelp: 'Close Manual',
delSure: '⚠️ Sure?',
dockTitle: 'Dock to Left',
replaceAll: 'Replace All',
editRaw: '📝 Edit Raw / Paste',
findPlaceholder: 'Find...',
replacePlaceholder: 'Replace with...',
models: 'Models',
gallery: 'Gallery',
apiKeyConfig: '🔑 Civitai API Key Config (For downloading previews)',
apiKeyPrompt: 'Enter your Civitai API Key:',
settingsBtn: 'Settings',
closeSettings: '✖ Close Settings',
doctorBtn: 'Node Assistant',
importBtn: '📥 Import / Export Workflow (Share Code)',
recipeTitle: 'Workflow Recipes',
recipeClose: 'Close Workflow Recipes',
recipeSaveCurrent: 'Save Current Workflow',
recipeSaveTitle: 'Save Workflow Recipe',
recipeName: 'Name',
recipeDefaultName: 'New Workflow Recipe',
recipeNameRequired: 'Enter a recipe name.',
recipeTags: 'Tags',
recipeTagsHint: 'For example: portrait, SDXL, upscale',
recipeNotes: 'Notes',
recipeNotesHint: 'Why this version works well…',
recipeThumbnail: 'Workflow thumbnail',
recipeCancel: 'Cancel',
recipeSave: 'Save',
recipeSaving: 'Saving…',
recipeSaveReceipt: 'Saved: {nodes} nodes, {links} links, {groups} groups.',
recipeSaveReceiptMismatch: 'Saved, but the integrity receipt differs from the current canvas. Reopen the recipe to verify it.',
recipeEmpty: 'No Workflow Recipes yet. Save a workflow that is working well.',
recipeLoadError: 'Could not load Workflow Recipes.',
recipeUntitled: 'Untitled Recipe',
recipeSearchPlaceholder: 'Search names, notes, or tags…',
recipeClearFilters: 'Clear filters',
recipeNoTags: 'No tags yet',
recipeNoMatches: 'No recipes match. Clear the search or tag filters.',
recipeFilterByTag: 'Filter by this tag',
recipeImport: 'Import package',
recipeExport: 'Export package',
recipeExportError: 'Could not export the Workflow Recipe package.',
recipeImportError: 'Could not import the Workflow Recipe package.',
recipeExportSnapshotsConfirm: 'Include model preview snapshots in the export?\n\nSnapshots are presentation data; video covers are reduced to lightweight stills and original videos are never packed.',
recipeExportHistoryConfirm: 'Include historical versions in the export?\n\nHistory may contain older prompts and notes.',
recipeExportRedactIdentityConfirm: 'Remove model SHA-256, size, and provenance information?\n\nChoose OK to remove those identity fields.',
recipeDialogNo: 'No',
recipeImportSummary: 'The recipe package passed inspection. Import these contents?',
recipeImportAssets: 'Preview assets',
recipeImportHistory: 'Historical versions',
recipeImportRenamePrompt: 'This recipe name already exists. Enter the imported name:',
recipeModel: 'Model',
recipeLoras: 'LoRAs',
recipePrompt: 'Positive prompt',
recipeSteps: 'Steps',
recipeRestore: 'Restore version',
recipeAppendCanvas: 'Append to Canvas',
recipeAppendError: 'Could not append this recipe to the current canvas.',
recipeDelete: 'Delete',
recipeDeleteConfirm: 'Delete this Workflow Recipe?',
recipeDeleteError: 'Could not delete this Workflow Recipe.',
recipeSaveError: 'Could not save this Workflow Recipe.',
recipeNodeParams: 'Node parameters',
recipeUnknownNode: 'Unknown node',
recipeCopyParameter: 'Copy parameter value',
recipeCopied: 'Copied',
recipeCopyFailed: 'Copy failed',
recipeAdvancedInfo: 'Advanced information',
recipeInlineEditName: 'Click to edit the name',
recipeInlineEditNotes: 'Click to edit notes',
recipeInlineEditTags: 'Edit tags',
recipeInlineSave: 'Save',
recipeInlineCancel: 'Cancel',
recipeInlineSaving: 'Saving…',
recipeInlineError: 'Could not save. Try again.',
recipeInlineNameRequired: 'Name cannot be empty.',
recipeSomeParamsInWorkflow: 'Other complex or sensitive parameters remain in the full workflow.',
recipeMoreNodesInWorkflow: 'Other nodes remain in the full workflow.',
recipeMissingNodes: 'These node types are currently missing; the restored workflow may not run',
recipeBindImage: 'Bind cover image',
recipeNoImage: 'No image',
recipeCanvasPreview: 'Current canvas',
recipeLoadingRecentImages: 'Loading recent outputs…',
recipeRecentImages: 'Recent outputs',
recipeRecentImagesUnavailable: 'Recent outputs are currently unavailable.',
recipeChoosePinnedParams: 'Choose key parameters',
recipePinnedParams: 'Key parameters',
recipeKeepImage: 'Keep current cover',
recipeEdit: 'Edit',
recipeEditTitle: 'Edit Workflow Recipe',
recipeEditNodeParams: 'Edit node parameters',
recipeComplexParam: 'Complex values are shown only; the full value remains safely stored in the workflow.',
recipeHistory: 'Version history',
recipeHistoryEmpty: 'No prior version yet. The previous version is retained automatically on update.',
recipeUnknownVersion: 'Unknown time',
recipeRestoreVersion: 'Restore this version',
recipeRestoreVersionConfirm: 'Restore this version? The current recipe will first be retained in history.',
recipeEditCanvas: 'Edit on canvas',
recipeEditCanvasConfirm: 'Loading replaces the current canvas. After structural edits, use Update Current Recipe to save a new version. Continue?',
recipeUpdate: 'Save updates',
recipeUpdateCurrent: 'Update Current Recipe',
recipeUpdateError: 'Could not update this Workflow Recipe.',
recipeViewDetails: 'View details',
recipeDetailBack: 'Back to recipes',
recipeDetailOverview: 'Overview',
recipeGallery: 'Gallery',
recipeGalleryLoading: 'Finding matching history images…',
recipeGalleryEmpty: 'No matching result was found in the latest 200 PNGs with workflow metadata.',
recipeGalleryRefresh: 'Refresh matches',
recipeGallerySetCover: 'Set as recipe cover',
recipeGalleryCoverSaved: 'Recipe cover set',
recipeGalleryCoverError: 'Could not set the recipe cover.',
recipeGalleryLoadError: 'Could not load the recipe gallery.',
recipeGalleryScanHint: 'Checked the latest {count} PNGs with workflow metadata.',
recipeGalleryOpenImage: 'View full image',
recipeGalleryCompare: 'Compare parameters',
recipeGalleryComparison: 'Recipe vs image parameters',
recipeGalleryComparisonLoading: 'Reading this image parameters…',
recipeGalleryComparisonError: 'Could not read this image parameters.',
recipeGalleryNoDifferences: 'No displayable parameter differences were found.',
recipeGalleryDifferenceHint: 'These are node-parameter differences; gallery matching only uses node types.',
recipeGalleryRecipeValue: 'Recipe',
recipeGalleryImageValue: 'Image',
recipeDetailModels: 'Models & reproducibility',
recipeDetailParameters: 'Parameter Notebook',
recipeDetailParametersHint: 'This view contains the saved parameters. Long values can be expanded and copied. The parameter gallery matches values, not local paths.',
recipeParameterSnapshots: 'Parameter snapshots',
recipeParameterSnapshotsHint: 'Each recipe save creates one read-only snapshot.',
recipeParameterRefresh: 'Refresh snapshots',
recipeParameterLoading: 'Loading parameter snapshots…',
recipeParameterLoadError: 'Could not load parameter snapshots.',
recipeParameterNoSnapshots: 'This recipe has no parameter snapshots yet.',
recipeParameterUntitled: 'Untitled parameter snapshot',
recipeParameterNew: 'New parameter note',
recipeParameterReadCurrent: 'Read current and create',
recipeParameterReadCurrentSaving: 'Reading and saving…',
recipeParameterReadCurrentError: 'Could not read parameters from the current canvas.',
recipeParameterSkeletonMismatch: 'The current canvas is missing recipe skeleton nodes; nothing was changed.',
recipeParameterApply: 'Apply to current workflow',
recipeParameterApplying: 'Checking the skeleton and applying…',
recipeParameterApplied: 'Applied {count} parameters',
recipeParameterApplyError: 'Could not apply parameters; the current canvas was not fully changed.',
recipeParameterNewHint: 'Edit node parameters from the current recipe skeleton. Runtime-changing values such as seeds are ignored. Saving creates a new read-only snapshot and never overwrites history.',
recipeParameterName: 'Note name',
recipeParameterSave: 'Save parameter note',
recipeParameterCancel: 'Cancel editing',
recipeParameterSaveError: 'Could not save the parameter note.',
recipeParameterSensitiveHidden: 'Sensitive widget hidden',
recipeDetailParameterSummary: 'Common parameters',
recipeDetailNodeParameters: 'Node parameters',
recipeDetailUnknownNode: 'Unnamed node',
recipeDetailWidget: 'Widget',
recipeDetailScheduler: 'Scheduler',
recipeDetailSteps: 'Steps',
recipeDetailCFG: 'CFG',
recipeDetailDenoise: 'Denoise',
recipeDetailSeed: 'Seed',
recipeParameterGallery: 'Outputs with the same parameters',
recipeParameterGalleryLoading: 'Finding historical outputs with the same parameters…',
recipeParameterGalleryEmpty: 'No historical output with identical parameters was found.',
recipeParameterGalleryError: 'Could not load the parameter gallery.',
recipeDetailNoSavedParameters: 'This recipe has no displayable parameters.',
recipeDetailVersions: 'Versions',
recipeDetailSummary: 'Summary',
recipeDetailModelComposition: 'Model composition',
recipeDetailBaseModel: 'Base model',
recipeDetailIdentity: 'Verified identities',
recipeDetailUnverified: 'Unverified models',
recipeDetailMissingNodes: 'Missing node types',
recipeDetailFingerprint: 'Workflow fingerprint',
recipeDetailNotIndexed: 'Not indexed yet',
recipeDetailLoraSummary: 'LoRA',
recipeDetailSampler: 'Sampler',
recipeDetailResolution: 'Resolution',
recipeDetailUnavailable: 'Unavailable',
recipeDetailEditOrigin: '✏️ Edit Origin',
recipeOriginDialogTitle: 'Edit Model Origin',
recipeOriginOfficialName: 'Official Model Name',
recipeOriginModelUrl: 'Official Model URL',
recipeOriginFetchHash: '🌍 Auto-fetch via Hash',
recipeOriginFetching: 'Fetching...',
recipeOriginFetchFailed: 'Not found or network error',
recipeOriginFetchSuccess: 'Successfully fetched!',
recipeDetailNoNotes: 'No notes.',
recipeDetailUpdated: 'Updated',
recipeDetailCopyPrompt: 'Copy prompt',
recipeDetailCopyFingerprint: 'Copy workflow fingerprint',
recipeDetailCopyHash: 'Copy full hash',
recipeDetailPrompts: 'Prompts',
recipeDetailPositivePrompt: 'Positive prompt',
recipeDetailNegativePrompt: 'Negative prompt',
recipeDetailNoPrompts: 'This recipe has no safe prompt summary to show.',
recipeDetailVolatileIgnored: 'Runtime-changing value ignored',
recipeDetailExpandValue: 'Show full value',
recipeDetailCollapseValue: 'Collapse value',
recipeIdentityVerified: 'Identity verified',
recipeIdentityUnverified: 'Local available, unverified',
recipeIdentityUnavailable: 'Not found locally',
recipeIdentityHelpDesc: 'Verification checks if the physical file matches the saved hash, it does not judge model quality.',
recipeDetailRefreshAvailability: 'Check local availability',
recipeDetailRefreshOrigin: 'Refresh Origin Info',
recipeDetailRefreshOriginDesc: 'Refresh all model origin information in this recipe (supports backfilling old recipes)',
recipeDetailRefreshing: 'Checking…',
recipeDetailRefreshError: 'Could not check local availability.',
recipeDetailAvailable: 'Available locally',
recipeDetailMissing: 'Missing locally',
recipeDetailAvailabilityNotChecked: 'Not checked locally',
recipeDetailNoModelReferences: 'No supported model loaders were detected. Other custom widgets remain in Parameters and the full workflow.',
recipeDetailModel: 'Model',
recipeModelPath: 'Model path',
recipeOpenLocalModel: 'Open local model details',
recipeMatchLocalModel: 'Match local model',
recipeMatchingLocalModel: 'Matching local model…',
recipeMatchRecipeModels: 'Match recipe models',
recipeMatchRecipeModelsDesc: 'Find local files by model hash, file size, and model category; the author’s path is not used.',
recipeMatchingRecipeModels: 'Matching recipe models…',
recipeRecipeMatchSummary: 'Found {found}/{total} local matches',
recipeAllModelsMatched: 'All recipe models are already matched or need no match',
recipeApplyLocalMatch: 'Apply match',
recipeApplyLocalMatchDesc: 'Write the matched local model path into the recipe workflow',
recipeApplyingLocalMatch: 'Applying match…',
recipeApplyLocalMatchSuccess: 'Local model match applied',
recipeApplyLocalMatchError: 'Could not apply this model match',
recipeLocalModelNotFound: 'No matching local model was found.',
recipeLocalModelAmbiguous: 'Multiple candidates found; add model identity information first.',
recipeLocalModelMatchError: 'Matching failed. Try again later.',
recipeDetailSearchParameters: 'Search node, type, or widget name…',
recipeDetailWidget: 'Widget',
recipeDetailNoParameters: 'No safe parameters match the search.',
recipeDetailCurrentVersion: 'Current version',
recipeCompareVersion: 'Compare version',
recipeDiffLoading: 'Comparing…',
recipeDiffSummary: 'Change summary',
recipeDiffBefore: 'Before',
recipeDiffAfter: 'After',
recipeDiffNoChanges: 'No meaningful changes were detected between these versions.',
recipeDiffError: 'Could not read this historical version.',
recipeDiffPinned: 'Pinned parameters',
recipeDiffPrompts: 'Prompts',
recipeDiffModels: 'Model references',
recipeDiffParameters: 'Parameter summary',
recipeDiffWorkflow: 'Workflow structure',
recipeDiffPresentation: 'Presentation',
recipeDiffOther: 'Other',
recipeDetailUnknownTime: 'Unknown time',
recipeDetailLoadingPreviews: 'Loading local model previews…',
recipeDetailCurrentPreview: 'Current local preview',
recipeDetailNoPreview: 'No preview available',
recipeSaveModelPreviewSnapshots: 'Embed Model Thumbnails',
recipeSaveModelPreviewSnapshotsHint: 'Embed small static thumbnails of the models directly into the recipe file. When you share this recipe, others will be able to see the model covers even if they don\'t have the models locally. (Videos are excluded to save space)',
recipeDetailSavedSnapshot: 'Saved snapshot',
}
};
const DEFAULT_LOCALE = 'zh';
const FALLBACK_LOCALE = 'en';
const hasOwn = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
export const supportedLocales = Object.freeze(Object.keys(i18n));
export function normalizeLocale(value) {
const raw = String(value ?? '').trim().toLowerCase().replace(/_/g, '-');
if (!raw) return '';
const base = raw.split('-')[0];
return hasOwn(i18n, base) ? base : '';
}
export function resolveLocale(value = globalThis.anomalous_browser_lang) {
return normalizeLocale(value) || DEFAULT_LOCALE;
}
export function formatTranslation(template, params = {}) {
if (typeof template !== 'string') return template;
return template.replace(/\{([A-Za-z0-9_.-]+)\}/g, (token, key) => (
hasOwn(params, key) ? String(params[key]) : token
));
}
export function translate(key, params = {}, locale = resolveLocale()) {
const activeLocale = resolveLocale(locale);
const template = i18n[activeLocale]?.[key]
?? i18n[FALLBACK_LOCALE]?.[key]
?? i18n[DEFAULT_LOCALE]?.[key]
?? key;
return formatTranslation(template, params);
}
export function createTranslator(locale) {
return (key, params = {}) => translate(key, params, locale);
}