diff --git a/src/content/components/config-panel.ts b/src/content/components/config-panel.ts index e2b189d..7d921ee 100644 --- a/src/content/components/config-panel.ts +++ b/src/content/components/config-panel.ts @@ -208,7 +208,7 @@ export class ConfigPanel extends LitElement { ${!showExecutionView && hasConflicts ? html`
- ⚠️ 检测到 ${this.conflictCount} 个冲突 + ⚠️ ${I18nService.t('conflicts_detected', [String(this.conflictCount)])}
` : ''} diff --git a/src/content/components/file-selector-panel.ts b/src/content/components/file-selector-panel.ts index 9e87a5a..1a95472 100644 --- a/src/content/components/file-selector-panel.ts +++ b/src/content/components/file-selector-panel.ts @@ -446,7 +446,7 @@ export class FileSelectorPanel extends LitElement { // Confirm if there are conflicts if (this.conflictIds.size > 0) { - const conflictMessage = `检测到 ${this.conflictIds.size} 个冲突,是否继续?`; + const conflictMessage = I18nService.t('conflicts_detected_confirm', [String(this.conflictIds.size)]); const confirmed = confirm(conflictMessage); if (!confirmed) { diff --git a/src/content/components/preview-panel.ts b/src/content/components/preview-panel.ts index 863e750..e77b07b 100644 --- a/src/content/components/preview-panel.ts +++ b/src/content/components/preview-panel.ts @@ -60,9 +60,7 @@ export class PreviewPanel extends LitElement { - - 检测到 ${this.conflictCount} 个冲突 - + ${I18nService.t('conflicts_detected', [String(this.conflictCount)])} ` : ''} @@ -70,7 +68,7 @@ export class PreviewPanel extends LitElement {
- 预览项: + ${I18nService.t('preview_items')} ${this.items.length}
${this.showStatus @@ -92,7 +90,7 @@ export class PreviewPanel extends LitElement { ${hasConflicts ? html`
- 冲突: + ${I18nService.t('preview_summary_conflict')} ${this.conflictCount}
` @@ -104,7 +102,7 @@ export class PreviewPanel extends LitElement { ? html`
-

正在生成预览...

+

${I18nService.t('preview_loading')}

` : html` diff --git a/src/content/components/toolbar.ts b/src/content/components/toolbar.ts index 905a23d..cd1ca79 100644 --- a/src/content/components/toolbar.ts +++ b/src/content/components/toolbar.ts @@ -152,7 +152,7 @@ export class Toolbar extends LitElement {
- 已选择 ${this.selectedCount} / ${this.totalCount} 个文件 + ${I18nService.t('selected_files_count', [String(this.selectedCount), String(this.totalCount)])}
diff --git a/src/content/components/virtual-file-list.ts b/src/content/components/virtual-file-list.ts index 3fc77b9..1055274 100644 --- a/src/content/components/virtual-file-list.ts +++ b/src/content/components/virtual-file-list.ts @@ -2,6 +2,7 @@ import { LitElement, html, css, type PropertyValues } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { virtualize, virtualizerRef } from '@lit-labs/virtualizer/virtualize.js'; import { FileItem } from '../../types/platform'; +import { I18nService } from '../../utils/i18n'; /** * Virtual File List Component @@ -201,7 +202,7 @@ export class VirtualFileList extends LitElement { -

没有找到文件

+

${I18nService.t('no_files_found')}

`; } diff --git a/src/content/components/virtual-preview-list.ts b/src/content/components/virtual-preview-list.ts index 2065038..5c88ec9 100644 --- a/src/content/components/virtual-preview-list.ts +++ b/src/content/components/virtual-preview-list.ts @@ -153,7 +153,7 @@ export class VirtualPreviewList extends LitElement { -

选择文件并配置规则以查看预览

+

${I18nService.t('preview_empty_hint')}

`; } diff --git a/src/content/index.ts b/src/content/index.ts index 36d99ef..07ee4fa 100644 --- a/src/content/index.ts +++ b/src/content/index.ts @@ -169,36 +169,60 @@ function cleanupOldInstances(): void { * @param platform - 平台名称 (aliyun/baidu/quark) */ async function injectPageScriptToMainWorld(platform: 'aliyun' | 'baidu' | 'quark'): Promise { + // ✅ 引用编译后的 .js 文件(Vite 会将 TypeScript 编译为 JavaScript) + const scriptPath = `src/adapters/${platform}/page-script.js`; + const scriptURL = chrome.runtime.getURL(scriptPath); + let script: HTMLScriptElement | null = null; + try { - // ✅ 引用编译后的 .js 文件(Vite 会将 TypeScript 编译为 JavaScript) - const scriptPath = `src/adapters/${platform}/page-script.js`; - const scriptURL = chrome.runtime.getURL(scriptPath); - // 创建 script 标签并注入到页面 (MAIN world) - const script = document.createElement('script'); - script.src = scriptURL; - script.type = 'module'; // 支持 ES6 模块 + const scriptEl = document.createElement('script'); + script = scriptEl; + scriptEl.src = scriptURL; + scriptEl.type = 'module'; // 支持 ES6 模块 - // 等待脚本加载完成 + // 等待脚本加载完成(加超时保护,避免 CSP/站点脚本拦截导致 onload/onerror 永不触发,从而阻塞整个悬浮按钮注入) + const timeoutMs = 1500; await new Promise((resolve, reject) => { - script.onload = () => { + const cleanup = () => { + scriptEl.onload = null; + scriptEl.onerror = null; + }; + + const timer = window.setTimeout(() => { + cleanup(); + reject(new Error(`Timeout loading page-script for ${platform}`)); + }, timeoutMs); + + scriptEl.onload = () => { + window.clearTimeout(timer); + cleanup(); resolve(); }; - script.onerror = () => { + scriptEl.onerror = () => { + window.clearTimeout(timer); + cleanup(); reject(new Error(`Failed to load page-script for ${platform}`)); }; // 注入到页面 - (document.head || document.documentElement).appendChild(script); + (document.head || document.documentElement).appendChild(scriptEl); }); // 脚本加载后可以移除标签 (代码已执行) - script.remove(); + scriptEl.remove(); logger.info(`${platform} page-script injected to MAIN world successfully`); } catch (error) { - logger.error(`Failed to inject ${platform} page-script:`, error instanceof Error ? error : new Error(String(error))); - throw error; + // 不要阻塞悬浮按钮注入:即使 page-script 注入失败,也应该让 UI 先显示出来 + // 相关平台的 API 调用可能会退化/失败,但用户至少能看到按钮和面板,且能在控制台看到诊断信息 + logger.warn( + `[DIAG] Failed to inject ${platform} page-script (continue without it):`, + error instanceof Error ? error : new Error(String(error)) + ); + } finally { + // Best-effort cleanup: 避免遗留无用的