- 新增Yandex和DuckDuckGo搜索引擎适配器配置 - 更新manifest.json添加新搜索引擎权限 - 优化URL工具类支持更多搜索引擎参数解析 - 移除调试日志输出 - 修复百度搜索输入框选择器兼容性问题 - 添加文档归档和历史需求规范 版本升级至1.8.6
45 KiB
Technical Specification - Search Engine Adapters Expansion
Project: SearchSyntax Pro v1.8.1 Feature: 新增 7 个搜索引擎适配器支持 Document Version: 1.0 Created: 2025-11-26 Status: Ready for Implementation
1. Problem Statement
Business Issue
SearchSyntax Pro 当前仅支持 10 个搜索引擎,缺乏对多个主流搜索引擎的支持,限制了用户在特定市场和隐私友好搜索场景下的选择。
Current State
- 已支持引擎: Baidu, Google, Bing, DuckDuckGo, Brave, Yandex, Twitter, Reddit, GitHub, Stack Overflow
- 缺失引擎: Yahoo, Startpage, Ecosia, Qwant, Naver, Sogou, 360搜索
- 用户无法使用这些搜索引擎的高级语法功能
Expected Outcome
添加 7 个新搜索引擎适配器,所有语法支持与官方搜索引擎能力保持一致,提供完整的中英文国际化支持。
2. Solution Overview
Approach
采用现有适配器模式,通过复用 Google/Bing/Baidu 适配器逻辑,实现 7 个新搜索引擎的适配器。分三个阶段实施,优先兼容性引擎,再处理区域市场引擎。
Core Changes
- 适配器实现: 创建 7 个新的适配器类文件
- 类型定义: 扩展
SearchEngine类型 - 工厂注册: 在 factory.ts 注册新适配器
- 国际化: 添加引擎名称和验证消息翻译
- 测试: 为核心逻辑编写单元测试
Success Criteria
- 所有 7 个引擎可正常构建查询 URL
- 语法支持与官方文档一致
- 多关键词 OR 组合在支持的引擎中正常工作
- 语法降级正确处理不支持的语法
- 所有用户可见文本有中英文翻译
- 核心逻辑单元测试通过
3. Technical Implementation
3.1 Database Changes
无数据库变更 - 仅使用 Chrome Storage API
3.2 Code Changes
Phase 1: 兼容性引擎 (3个)
3.2.1 Yahoo Search Adapter
文件路径: /Users/lhly/chromeex/ssp/src/services/adapters/yahoo.ts
实现规格:
/**
* Yahoo 搜索引擎适配器
* 基于 Bing 语法兼容性实现
*/
export class YahooAdapter implements SearchEngineAdapter {
getName(): string {
return '雅虎' // 将通过 i18n 翻译
}
getBaseUrl(): string {
return 'https://search.yahoo.com/search'
}
// 查询参数格式: ?p={query}
buildQuery(params: SearchParams): string {
const baseUrl = this.getBaseUrl()
const query = this.buildSearchQuery(params)
return `${baseUrl}?p=${encodeURIComponent(query)}`
}
// 支持的语法 (与 Bing 相同)
getSupportedSyntax(): SyntaxType[] {
return [
'site',
'filetype',
'exact',
'date_range',
'intitle',
'inurl',
'exclude',
'or',
'intext', // Yahoo 使用 inbody:
'number_range',
'wildcard',
'allintitle', // 降级为多个 intitle
'related'
// 不支持 'cache'
]
}
// 多关键词支持 (与 Bing 一致)
// - sites: 支持 OR 组合
// - fileTypes: 支持 OR 组合
// - exactMatches: 原生并列支持
// 语法降级
degradeSyntax(params: SearchParams): SearchParams {
const degradedParams = { ...params }
if (params.cacheSite) {
console.warn('Yahoo不支持cache语法,该参数将被忽略')
degradedParams.cacheSite = undefined
}
return degradedParams
}
// UI 功能特性
getSupportedFeatures(): UIFeatureType[] {
return [
'site', 'filetype', 'intitle', 'inurl', 'intext',
'exact_match', 'exclude', 'or_keywords',
'date_range', 'related'
]
}
getFeatureGroups(): EngineFeatureGroups {
return {
location: ['site', 'filetype', 'intitle', 'inurl', 'intext'],
precision: ['exact_match'],
logic: ['exclude', 'or_keywords'],
range: ['date_range'],
special: ['related']
}
}
}
关键实现细节:
- baseUrl:
https://search.yahoo.com/search - 查询参数:
?p=(区别于 Google 的?q=) - 语法处理: 完全复用 BingAdapter 的 buildSearchQuery 逻辑
- intext 映射: 使用
inbody:(与 Bing 一致) - allintitle 降级: 转换为多个
intitle:(与 Bing 一致) - cache 降级: 设为 undefined 并记录警告
3.2.2 Startpage Adapter
文件路径: /Users/lhly/chromeex/ssp/src/services/adapters/startpage.ts
实现规格:
/**
* Startpage 搜索引擎适配器
* 基于 Google 语法兼容性实现 (隐私友好)
*/
export class StartpageAdapter implements SearchEngineAdapter {
getName(): string {
return 'Startpage'
}
getBaseUrl(): string {
return 'https://www.startpage.com/sp/search'
}
// 查询参数格式: ?query={query}
buildQuery(params: SearchParams): string {
const baseUrl = this.getBaseUrl()
const query = this.buildSearchQuery(params)
return `${baseUrl}?query=${encodeURIComponent(query)}`
}
// 支持的语法 (Google 子集)
getSupportedSyntax(): SyntaxType[] {
return [
'site',
'filetype',
'exact',
'date_range', // before:/after:
'intitle',
'exclude',
'or'
// 不支持: inurl, intext, wildcard, allintitle, related, cache, number_range
]
}
// 多关键词支持 (与 Google 一致)
// - sites: 支持 OR 组合
// - fileTypes: 支持 OR 组合
// - exactMatches: 原生并列支持
// 语法降级
degradeSyntax(params: SearchParams): SearchParams {
const degradedParams = { ...params }
const warnings: string[] = []
// Startpage 不支持的语法直接忽略
if (params.inUrl) {
degradedParams.inUrl = undefined
warnings.push('Startpage不支持inurl语法')
}
if (params.inText) {
degradedParams.inText = undefined
warnings.push('Startpage不支持intext语法')
}
if (params.wildcardQuery) {
degradedParams.wildcardQuery = undefined
warnings.push('Startpage不支持通配符语法')
}
if (params.allInTitle) {
degradedParams.allInTitle = undefined
warnings.push('Startpage不支持allintitle语法')
}
if (params.relatedSite) {
degradedParams.relatedSite = undefined
warnings.push('Startpage不支持related语法')
}
if (params.cacheSite) {
degradedParams.cacheSite = undefined
warnings.push('Startpage不支持cache语法')
}
if (params.numberRange) {
degradedParams.numberRange = undefined
warnings.push('Startpage不支持数字范围语法')
}
if (warnings.length > 0) {
console.warn(`[Startpage] 语法降级:`, warnings.join('; '))
}
return degradedParams
}
// 日期格式: before:YYYY-MM-DD after:YYYY-MM-DD (与 Google 一致)
private buildDateFilter(dateRange: { from: string; to: string }): string {
const { from, to } = dateRange
if (from && to) {
return `after:${this.formatDate(from)} before:${this.formatDate(to)}`
} else if (from) {
return `after:${this.formatDate(from)}`
} else if (to) {
return `before:${this.formatDate(to)}`
}
return ''
}
getSupportedFeatures(): UIFeatureType[] {
return [
'site', 'filetype', 'intitle',
'exact_match', 'exclude', 'or_keywords',
'date_range'
]
}
getFeatureGroups(): EngineFeatureGroups {
return {
location: ['site', 'filetype', 'intitle'],
precision: ['exact_match'],
logic: ['exclude', 'or_keywords'],
range: ['date_range']
}
}
}
关键实现细节:
- baseUrl:
https://www.startpage.com/sp/search - 查询参数:
?query=(注意不是?q=) - 语法处理: 复用 GoogleAdapter 核心逻辑,但过滤不支持的语法
- 日期格式:
before:/after:(与 Google 一致) - 语法降级: 大量不支持语法需要降级处理
3.2.3 Ecosia Adapter
文件路径: /Users/lhly/chromeex/ssp/src/services/adapters/ecosia.ts
实现规格:
/**
* Ecosia 搜索引擎适配器
* 基于 Google/Bing 混合语法实现 (环保搜索)
*/
export class EcosiaAdapter implements SearchEngineAdapter {
getName(): string {
return 'Ecosia'
}
getBaseUrl(): string {
return 'https://www.ecosia.org/search'
}
// 查询参数格式: ?q={query}
buildQuery(params: SearchParams): string {
const baseUrl = this.getBaseUrl()
const query = this.buildSearchQuery(params)
return `${baseUrl}?q=${encodeURIComponent(query)}`
}
// 支持的语法 (Google/Bing 基础子集)
getSupportedSyntax(): SyntaxType[] {
return [
'site',
'filetype',
'exact',
'exclude',
'or'
// 官方文档仅明确支持这些基础操作符
// 不支持: date_range, intitle, inurl, intext 等高级语法
]
}
// 多关键词支持 (与 Google/Bing 一致)
// - sites: 支持 OR 组合
// - fileTypes: 支持 OR 组合
// - exactMatches: 原生并列支持
// 语法降级
degradeSyntax(params: SearchParams): SearchParams {
const degradedParams = { ...params }
const warnings: string[] = []
// Ecosia 仅支持基础语法
const unsupportedFields = [
'dateRange', 'inTitle', 'inUrl', 'inText', 'allInTitle',
'numberRange', 'wildcardQuery', 'relatedSite', 'cacheSite'
]
unsupportedFields.forEach(field => {
if (params[field as keyof SearchParams]) {
(degradedParams as any)[field] = undefined
warnings.push(`Ecosia不支持${field}语法`)
}
})
if (warnings.length > 0) {
console.warn(`[Ecosia] 语法降级:`, warnings.join('; '))
}
return degradedParams
}
getSupportedFeatures(): UIFeatureType[] {
return [
'site', 'filetype',
'exact_match', 'exclude', 'or_keywords'
]
}
getFeatureGroups(): EngineFeatureGroups {
return {
location: ['site', 'filetype'],
precision: ['exact_match'],
logic: ['exclude', 'or_keywords']
}
}
}
关键实现细节:
- baseUrl:
https://www.ecosia.org/search - 查询参数:
?q= - 语法处理: 仅实现基础语法 (site, filetype, exact, exclude, OR)
- 语法降级: 大量高级语法不支持,需要全部降级
Phase 2: 区域市场引擎 (3个)
3.2.4 Naver Adapter
文件路径: /Users/lhly/chromeex/ssp/src/services/adapters/naver.ts
实现规格:
/**
* Naver 搜索引擎适配器
* 韩国市场第一大搜索引擎
*/
export class NaverAdapter implements SearchEngineAdapter {
getName(): string {
return 'Naver' // 不翻译为韩语,仅中英文
}
getBaseUrl(): string {
return 'https://search.naver.com/search.naver'
}
// 查询参数格式: ?query={query}
buildQuery(params: SearchParams): string {
const baseUrl = this.getBaseUrl()
const query = this.buildSearchQuery(params)
return `${baseUrl}?query=${encodeURIComponent(query)}`
}
// 支持的语法 (基础子集)
getSupportedSyntax(): SyntaxType[] {
return [
'site',
'filetype',
'exact',
'exclude'
// Naver 官方文档支持有限,不支持 OR, intitle, inurl 等高级语法
]
}
// 多关键词支持 (有限)
// - sites: 不支持 OR 组合 (单个 site: 仅)
// - fileTypes: 支持基础文件类型 (pdf, doc, xls, ppt, hwp)
// - exactMatches: 原生并列支持
// 语法降级
degradeSyntax(params: SearchParams): SearchParams {
const degradedParams = { ...params }
const warnings: string[] = []
// Naver 不支持多站点 OR 组合
if (params.sites && params.sites.length > 1) {
degradedParams.sites = [params.sites[0]] // 仅保留第一个
warnings.push('Naver不支持多站点OR组合,仅使用第一个站点')
}
// Naver 不支持多文件类型 OR 组合
if (params.fileTypes && params.fileTypes.length > 1) {
degradedParams.fileTypes = [params.fileTypes[0]]
warnings.push('Naver不支持多文件类型OR组合,仅使用第一个类型')
}
// 不支持的高级语法
const unsupportedFields = [
'orKeywords', 'dateRange', 'inTitle', 'inUrl', 'inText',
'allInTitle', 'numberRange', 'wildcardQuery', 'relatedSite', 'cacheSite'
]
unsupportedFields.forEach(field => {
if (params[field as keyof SearchParams]) {
(degradedParams as any)[field] = undefined
warnings.push(`Naver不支持${field}语法`)
}
})
if (warnings.length > 0) {
console.warn(`[Naver] 语法降级:`, warnings.join('; '))
}
return degradedParams
}
// 文件类型支持: pdf, doc, xls, ppt, hwp (韩国 Hancom 文档格式)
private getSupportedFileTypes(): string[] {
return ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'hwp']
}
getSupportedFeatures(): UIFeatureType[] {
return [
'site', 'filetype',
'exact_match', 'exclude'
]
}
getFeatureGroups(): EngineFeatureGroups {
return {
location: ['site', 'filetype'],
precision: ['exact_match'],
logic: ['exclude']
}
}
}
关键实现细节:
- baseUrl:
https://search.naver.com/search.naver - 查询参数:
?query= - 语法处理: 仅基础语法,不支持 OR 组合
- 特殊文件类型: 支持韩国 HWP 格式 (Hancom Office)
- 多关键词限制: 不支持 OR 组合,降级为单个
3.2.5 Sogou Adapter
文件路径: /Users/lhly/chromeex/ssp/src/services/adapters/sogou.ts
实现规格:
/**
* Sogou 搜索引擎适配器
* 中国第二大搜索引擎
*/
export class SogouAdapter implements SearchEngineAdapter {
getName(): string {
return '搜狗'
}
getBaseUrl(): string {
return 'https://www.sogou.com/web'
}
// 查询参数格式: ?query={query}
buildQuery(params: SearchParams): string {
const baseUrl = this.getBaseUrl()
const query = this.buildSearchQuery(params)
return `${baseUrl}?query=${encodeURIComponent(query)}`
}
// 支持的语法 (参考 Baidu,部分支持)
getSupportedSyntax(): SyntaxType[] {
return [
'site',
'filetype',
'exact',
'intitle',
'inurl',
'exclude',
'or'
// 不支持: date_range, intext, allintitle, number_range, wildcard, related, cache
]
}
// 多关键词支持 (部分支持)
// - sites: 支持 OR 组合
// - fileTypes: 支持 OR 组合 (pdf, doc, xls, ppt, txt)
// - exactMatches: 原生并列支持
// 语法降级
degradeSyntax(params: SearchParams): SearchParams {
const degradedParams = { ...params }
const warnings: string[] = []
// Sogou 不支持的语法
const unsupportedFields = [
'dateRange', 'inText', 'allInTitle', 'numberRange',
'wildcardQuery', 'relatedSite', 'cacheSite'
]
unsupportedFields.forEach(field => {
if (params[field as keyof SearchParams]) {
(degradedParams as any)[field] = undefined
warnings.push(`Sogou不支持${field}语法`)
}
})
if (warnings.length > 0) {
console.warn(`[Sogou] 语法降级:`, warnings.join('; '))
}
return degradedParams
}
// 文件类型支持: pdf, doc, docx, xls, xlsx, ppt, pptx, txt
private getSupportedFileTypes(): string[] {
return ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt']
}
getSupportedFeatures(): UIFeatureType[] {
return [
'site', 'filetype', 'intitle', 'inurl',
'exact_match', 'exclude', 'or_keywords'
]
}
getFeatureGroups(): EngineFeatureGroups {
return {
location: ['site', 'filetype', 'intitle', 'inurl'],
precision: ['exact_match'],
logic: ['exclude', 'or_keywords']
}
}
}
关键实现细节:
- baseUrl:
https://www.sogou.com/web - 查询参数:
?query= - 语法处理: 参考 BaiduAdapter,支持中等复杂度语法
- 中文优化: 支持中文分词和拼音搜索 (引擎内部处理)
- 多关键词支持: 支持 OR 组合
3.2.6 360 Search Adapter
文件路径: /Users/lhly/chromeex/ssp/src/services/adapters/so360.ts
实现规格:
/**
* 360搜索引擎适配器
* 中国市场第三大搜索引擎
*/
export class So360Adapter implements SearchEngineAdapter {
getName(): string {
return '360搜索'
}
getBaseUrl(): string {
return 'https://www.so.com/s'
}
// 查询参数格式: ?q={query}
buildQuery(params: SearchParams): string {
const baseUrl = this.getBaseUrl()
const query = this.buildSearchQuery(params)
return `${baseUrl}?q=${encodeURIComponent(query)}`
}
// 支持的语法 (基础子集)
getSupportedSyntax(): SyntaxType[] {
return [
'site',
'filetype',
'exact',
'intitle',
'exclude'
// 不支持: OR, inurl, intext, date_range 等高级语法
]
}
// 多关键词支持 (有限)
// - sites: 不支持 OR 组合
// - fileTypes: 不支持 OR 组合
// - exactMatches: 原生并列支持
// 语法降级
degradeSyntax(params: SearchParams): SearchParams {
const degradedParams = { ...params }
const warnings: string[] = []
// 360搜索 不支持多站点 OR 组合
if (params.sites && params.sites.length > 1) {
degradedParams.sites = [params.sites[0]]
warnings.push('360搜索不支持多站点OR组合,仅使用第一个站点')
}
// 360搜索 不支持多文件类型 OR 组合
if (params.fileTypes && params.fileTypes.length > 1) {
degradedParams.fileTypes = [params.fileTypes[0]]
warnings.push('360搜索不支持多文件类型OR组合,仅使用第一个类型')
}
// 不支持的高级语法
const unsupportedFields = [
'orKeywords', 'dateRange', 'inUrl', 'inText', 'allInTitle',
'numberRange', 'wildcardQuery', 'relatedSite', 'cacheSite'
]
unsupportedFields.forEach(field => {
if (params[field as keyof SearchParams]) {
(degradedParams as any)[field] = undefined
warnings.push(`360搜索不支持${field}语法`)
}
})
if (warnings.length > 0) {
console.warn(`[360搜索] 语法降级:`, warnings.join('; '))
}
return degradedParams
}
getSupportedFeatures(): UIFeatureType[] {
return [
'site', 'filetype', 'intitle',
'exact_match', 'exclude'
]
}
getFeatureGroups(): EngineFeatureGroups {
return {
location: ['site', 'filetype', 'intitle'],
precision: ['exact_match'],
logic: ['exclude']
}
}
}
关键实现细节:
- baseUrl:
https://www.so.com/s - 查询参数:
?q= - 语法处理: 基础语法支持,类似 Naver
- 多关键词限制: 不支持 OR 组合,降级为单个
- 中文优化: 支持中文内容优化 (引擎内部处理)
Phase 3: 欧洲市场引擎 (1个)
3.2.7 Qwant Adapter
文件路径: /Users/lhly/chromeex/ssp/src/services/adapters/qwant.ts
实现规格:
/**
* Qwant 搜索引擎适配器
* 法国隐私友好搜索引擎
*/
export class QwantAdapter implements SearchEngineAdapter {
getName(): string {
return 'Qwant'
}
getBaseUrl(): string {
return 'https://www.qwant.com/'
}
// 查询参数格式: ?q={query}
buildQuery(params: SearchParams): string {
const baseUrl = this.getBaseUrl()
const query = this.buildSearchQuery(params)
return `${baseUrl}?q=${encodeURIComponent(query)}`
}
// 支持的语法 (基础子集)
getSupportedSyntax(): SyntaxType[] {
return [
'site',
'filetype',
'exact'
// Qwant 官方文档显示支持极其有限
// 不支持: exclude, OR 及所有高级语法
]
}
// 多关键词支持 (不支持)
// - sites: 不支持 OR 组合
// - fileTypes: 不支持 OR 组合
// - exactMatches: 原生并列支持
// 语法降级
degradeSyntax(params: SearchParams): SearchParams {
const degradedParams = { ...params }
const warnings: string[] = []
// Qwant 不支持多站点 OR 组合
if (params.sites && params.sites.length > 1) {
degradedParams.sites = [params.sites[0]]
warnings.push('Qwant不支持多站点OR组合,仅使用第一个站点')
}
// Qwant 不支持多文件类型 OR 组合
if (params.fileTypes && params.fileTypes.length > 1) {
degradedParams.fileTypes = [params.fileTypes[0]]
warnings.push('Qwant不支持多文件类型OR组合,仅使用第一个类型')
}
// 不支持的所有高级语法
const unsupportedFields = [
'excludeWords', 'orKeywords', 'dateRange', 'inTitle', 'inUrl',
'inText', 'allInTitle', 'numberRange', 'wildcardQuery',
'relatedSite', 'cacheSite'
]
unsupportedFields.forEach(field => {
if (params[field as keyof SearchParams]) {
(degradedParams as any)[field] = undefined
warnings.push(`Qwant不支持${field}语法`)
}
})
if (warnings.length > 0) {
console.warn(`[Qwant] 语法降级:`, warnings.join('; '))
}
return degradedParams
}
getSupportedFeatures(): UIFeatureType[] {
return [
'site', 'filetype',
'exact_match'
]
}
getFeatureGroups(): EngineFeatureGroups {
return {
location: ['site', 'filetype'],
precision: ['exact_match']
}
}
}
关键实现细节:
- baseUrl:
https://www.qwant.com/ - 查询参数:
?q= - 语法处理: 最小语法支持 (仅 site, filetype, exact)
- 多关键词限制: 不支持 OR 组合
- Qwick 快捷方式: 可选实现 (如 !w Wikipedia),暂不实现
3.3 Type Definitions
文件路径: /Users/lhly/chromeex/ssp/src/types/index.ts
修改内容:
// 第 2 行,修改 SearchEngine 类型定义
export type SearchEngine =
| 'baidu'
| 'google'
| 'bing'
| 'twitter'
| 'duckduckgo'
| 'brave'
| 'yandex'
| 'reddit'
| 'github'
| 'stackoverflow'
// 🔥 新增 7 个搜索引擎
| 'yahoo'
| 'startpage'
| 'ecosia'
| 'qwant'
| 'naver'
| 'sogou'
| 'so360';
3.4 Factory Registration
文件路径: /Users/lhly/chromeex/ssp/src/services/adapters/factory.ts
修改内容:
- Import 语句 (第 1-11 行后新增):
import { YahooAdapter } from './yahoo'
import { StartpageAdapter } from './startpage'
import { EcosiaAdapter } from './ecosia'
import { QwantAdapter } from './qwant'
import { NaverAdapter } from './naver'
import { SogouAdapter } from './sogou'
import { So360Adapter } from './so360'
- createAdapter 方法 (第 39-63 行,switch case 新增):
private static createAdapter(engine: SearchEngine): SearchEngineAdapter {
switch (engine) {
// 现有引擎 ...
case 'stackoverflow':
return new StackOverflowAdapter()
// 🔥 新增 7 个引擎适配器
case 'yahoo':
return new YahooAdapter()
case 'startpage':
return new StartpageAdapter()
case 'ecosia':
return new EcosiaAdapter()
case 'qwant':
return new QwantAdapter()
case 'naver':
return new NaverAdapter()
case 'sogou':
return new SogouAdapter()
case 'so360':
return new So360Adapter()
default:
throw new Error(`不支持的搜索引擎: ${engine}`)
}
}
- getSupportedEngines 方法 (第 69-71 行,数组新增):
static getSupportedEngines(): SearchEngine[] {
return [
'baidu', 'google', 'bing', 'twitter', 'duckduckgo',
'brave', 'yandex', 'reddit', 'github', 'stackoverflow',
// 🔥 新增 7 个引擎
'yahoo', 'startpage', 'ecosia', 'qwant',
'naver', 'sogou', 'so360'
]
}
3.5 Internationalization (i18n)
文件路径: /Users/lhly/chromeex/ssp/src/i18n/translations.ts
修改内容 (在第 16 行后新增):
3.5.1 引擎名称翻译
const translations: Record<Language, Record<string, string>> = {
'zh-CN': {
// 现有引擎 ...
'common.searchEngines.stackoverflow': 'Stack Overflow',
// 🔥 新增 7 个引擎名称 (中文)
'common.searchEngines.yahoo': 'Yahoo搜索',
'common.searchEngines.startpage': 'Startpage',
'common.searchEngines.ecosia': 'Ecosia',
'common.searchEngines.qwant': 'Qwant',
'common.searchEngines.naver': 'Naver',
'common.searchEngines.sogou': '搜狗',
'common.searchEngines.so360': '360搜索',
// 其余翻译 ...
},
'en-US': {
// 现有引擎 ...
'common.searchEngines.stackoverflow': 'Stack Overflow',
// 🔥 新增 7 个引擎名称 (英文)
'common.searchEngines.yahoo': 'Yahoo Search',
'common.searchEngines.startpage': 'Startpage',
'common.searchEngines.ecosia': 'Ecosia',
'common.searchEngines.qwant': 'Qwant',
'common.searchEngines.naver': 'Naver',
'common.searchEngines.sogou': 'Sogou',
'common.searchEngines.so360': '360 Search',
// 其余翻译 ...
}
}
3.5.2 验证消息翻译
新增翻译键 (在适当位置添加):
'zh-CN': {
// ... 现有翻译 ...
// 🔥 新增适配器验证消息
'adapter.validation.unsupportedSyntax': '{engine}不支持{syntax}语法,该参数将被忽略',
'adapter.validation.unsupportedMultiKeyword': '{engine}不支持多关键词OR组合,仅使用第一个',
'adapter.validation.syntaxDegraded': '{engine}不支持部分高级语法,已自动降级',
'adapter.validation.queryLengthExceeded': '查询长度超过{engine}的限制({max}字符)',
// ... 其余翻译 ...
},
'en-US': {
// ... 现有翻译 ...
// 🔥 新增适配器验证消息
'adapter.validation.unsupportedSyntax': '{engine} does not support {syntax} syntax, parameter ignored',
'adapter.validation.unsupportedMultiKeyword': '{engine} does not support multi-keyword OR combination, using first one only',
'adapter.validation.syntaxDegraded': '{engine} does not support some advanced syntax, automatically degraded',
'adapter.validation.queryLengthExceeded': 'Query length exceeds {engine} limit ({max} characters)',
// ... 其余翻译 ...
}
3.6 Configuration Changes
无需配置文件修改 - 所有配置通过代码硬编码
3.7 Query Length Limits
统一查询长度限制 (在各适配器的 validateParams 方法中):
// 所有引擎统一使用 180 字符限制 (最保守策略)
const MAX_QUERY_LENGTH = 180
async validateParams(params: SearchParams): Promise<ValidationResult> {
const warnings: string[] = []
const language = await getCurrentLanguage()
const t = (key: string, vars?) => translate(language, key, vars)
const fullQuery = this.buildSearchQuery(params)
if (fullQuery.length > MAX_QUERY_LENGTH) {
warnings.push(
t('adapter.validation.queryLengthExceeded', {
engine: this.getName(),
max: MAX_QUERY_LENGTH.toString()
})
)
}
return { isValid: true, warnings }
}
4. Implementation Sequence
Phase 1: 兼容性引擎 (预计 2-3 小时)
Step 1.1: Yahoo Adapter 实现
- 创建
/src/services/adapters/yahoo.ts - 复用 BingAdapter 核心逻辑
- 修改 baseUrl 为
https://search.yahoo.com/search - 修改查询参数为
?p= - 实现 degradeSyntax (处理 cache)
- 创建
/src/services/adapters/yahoo.test.ts - 编写核心逻辑单元测试
Step 1.2: Startpage Adapter 实现
- 创建
/src/services/adapters/startpage.ts - 复用 GoogleAdapter 核心逻辑
- 修改 baseUrl 为
https://www.startpage.com/sp/search - 修改查询参数为
?query= - 实现 degradeSyntax (处理多个不支持语法)
- 创建
/src/services/adapters/startpage.test.ts - 编写核心逻辑单元测试
Step 1.3: Ecosia Adapter 实现
- 创建
/src/services/adapters/ecosia.ts - 实现基础语法支持 (site, filetype, exact, exclude, OR)
- 修改 baseUrl 为
https://www.ecosia.org/search - 实现 degradeSyntax (处理所有高级语法)
- 创建
/src/services/adapters/ecosia.test.ts - 编写核心逻辑单元测试
Step 1.4: Phase 1 集成
- 更新
src/types/index.ts(添加 yahoo, startpage, ecosia) - 更新
src/services/adapters/factory.ts(注册 3 个适配器) - 更新
src/i18n/translations.ts(添加引擎名称翻译) - 手动测试 3 个引擎的搜索功能
- 验证语法降级警告正确显示
Phase 2: 区域市场引擎 (预计 3-4 小时)
Step 2.1: Naver Adapter 实现
- 创建
/src/services/adapters/naver.ts - 实现基础语法 (site, filetype, exact, exclude)
- 修改 baseUrl 为
https://search.naver.com/search.naver - 实现 degradeSyntax (禁用 OR 组合,处理高级语法)
- 添加 HWP 文件类型支持
- 创建
/src/services/adapters/naver.test.ts - 编写核心逻辑单元测试
Step 2.2: Sogou Adapter 实现
- 创建
/src/services/adapters/sogou.ts - 参考 BaiduAdapter,实现中等复杂度语法
- 修改 baseUrl 为
https://www.sogou.com/web - 修改查询参数为
?query= - 实现 degradeSyntax (处理不支持的高级语法)
- 创建
/src/services/adapters/sogou.test.ts - 编写核心逻辑单元测试
Step 2.3: 360 Search Adapter 实现
- 创建
/src/services/adapters/so360.ts - 实现基础语法 (site, filetype, exact, intitle, exclude)
- 修改 baseUrl 为
https://www.so.com/s - 实现 degradeSyntax (禁用 OR 组合,处理高级语法)
- 创建
/src/services/adapters/so360.test.ts - 编写核心逻辑单元测试
Step 2.4: Phase 2 集成
- 更新
src/types/index.ts(添加 naver, sogou, so360) - 更新
src/services/adapters/factory.ts(注册 3 个适配器) - 更新
src/i18n/translations.ts(添加引擎名称翻译) - 手动测试 3 个引擎的搜索功能
- 验证中文内容搜索正常工作
Phase 3: 欧洲市场引擎 (预计 1-2 小时)
Step 3.1: Qwant Adapter 实现
- 创建
/src/services/adapters/qwant.ts - 实现最小语法支持 (site, filetype, exact)
- 修改 baseUrl 为
https://www.qwant.com/ - 实现 degradeSyntax (处理所有高级语法)
- 创建
/src/services/adapters/qwant.test.ts - 编写核心逻辑单元测试
Step 3.2: Phase 3 集成
- 更新
src/types/index.ts(添加 qwant) - 更新
src/services/adapters/factory.ts(注册 qwant) - 更新
src/i18n/translations.ts(添加引擎名称翻译) - 手动测试 Qwant 搜索功能
Final Integration (预计 1 小时)
Step 4.1: 完整性验证
- 运行所有单元测试 (
npm run test) - 运行类型检查 (
npm run type-check) - 运行 ESLint (
npm run lint) - 手动测试所有 17 个引擎 (10 + 7)
Step 4.2: 国际化验证
- 切换到中文,验证所有引擎名称正确显示
- 切换到英文,验证所有引擎名称正确显示
- 验证语法降级警告消息的中英文显示
Step 4.3: 功能验证
- 测试多关键词 OR 组合 (在支持的引擎中)
- 测试语法降级 (在不支持的引擎中)
- 测试查询长度警告
- 测试引擎切换功能
Step 4.4: 文档更新
- 更新
README.md(如果需要) - 更新版本号至 1.9.0
- 生成 CHANGELOG
5. Test Specification
5.1 Unit Test Structure
测试文件命名: {adapter-name}.test.ts
测试框架: Jest + @testing-library
5.2 Core Test Cases
5.2.1 Yahoo Adapter Tests
文件: /src/services/adapters/yahoo.test.ts
import { YahooAdapter } from './yahoo'
import type { SearchParams } from '@/types'
describe('YahooAdapter', () => {
let adapter: YahooAdapter
beforeEach(() => {
adapter = new YahooAdapter()
})
describe('基础功能', () => {
test('应返回正确的引擎名称', () => {
expect(adapter.getName()).toBe('雅虎')
})
test('应返回正确的基础URL', () => {
expect(adapter.getBaseUrl()).toBe('https://search.yahoo.com/search')
})
})
describe('URL构建', () => {
test('应构建基础搜索URL', () => {
const params: SearchParams = {
keyword: 'test query',
engine: 'yahoo'
}
const url = adapter.buildQuery(params)
expect(url).toContain('search.yahoo.com/search')
expect(url).toContain('?p=')
expect(url).toContain('test%20query')
})
test('应支持site语法', () => {
const params: SearchParams = {
keyword: 'test',
engine: 'yahoo',
site: 'example.com'
}
const url = adapter.buildQuery(params)
expect(url).toContain('site%3Aexample.com')
})
test('应支持多站点OR组合', () => {
const params: SearchParams = {
keyword: 'test',
engine: 'yahoo',
sites: ['example.com', 'test.com']
}
const url = adapter.buildQuery(params)
expect(url).toContain('site%3Aexample.com')
expect(url).toContain('OR')
expect(url).toContain('site%3Atest.com')
})
test('应支持filetype语法', () => {
const params: SearchParams = {
keyword: 'test',
engine: 'yahoo',
fileType: 'pdf'
}
const url = adapter.buildQuery(params)
expect(url).toContain('filetype%3Apdf')
})
test('应支持多文件类型OR组合', () => {
const params: SearchParams = {
keyword: 'test',
engine: 'yahoo',
fileTypes: ['pdf', 'doc']
}
const url = adapter.buildQuery(params)
expect(url).toContain('filetype%3Apdf')
expect(url).toContain('OR')
expect(url).toContain('filetype%3Adoc')
})
})
describe('语法支持', () => {
test('应支持Bing兼容语法', () => {
const supportedSyntax = adapter.getSupportedSyntax()
expect(supportedSyntax).toContain('site')
expect(supportedSyntax).toContain('filetype')
expect(supportedSyntax).toContain('intitle')
expect(supportedSyntax).toContain('inurl')
expect(supportedSyntax).toContain('related')
})
test('不应支持cache语法', () => {
const supportedSyntax = adapter.getSupportedSyntax()
expect(supportedSyntax).not.toContain('cache')
})
})
describe('语法降级', () => {
test('应降级cache语法', () => {
const params: SearchParams = {
keyword: 'test',
engine: 'yahoo',
cacheSite: 'example.com'
}
const degraded = adapter.degradeSyntax(params)
expect(degraded.cacheSite).toBeUndefined()
})
test('应保留支持的语法', () => {
const params: SearchParams = {
keyword: 'test',
engine: 'yahoo',
site: 'example.com',
fileType: 'pdf'
}
const degraded = adapter.degradeSyntax(params)
expect(degraded.site).toBe('example.com')
expect(degraded.fileType).toBe('pdf')
})
})
})
5.2.2 Startpage Adapter Tests
文件: /src/services/adapters/startpage.test.ts
import { StartpageAdapter } from './startpage'
describe('StartpageAdapter', () => {
let adapter: StartpageAdapter
beforeEach(() => {
adapter = new StartpageAdapter()
})
test('应使用query参数而不是q', () => {
const params = {
keyword: 'test',
engine: 'startpage' as const
}
const url = adapter.buildQuery(params)
expect(url).toContain('?query=')
expect(url).not.toContain('?q=')
})
test('应降级不支持的inurl语法', () => {
const params = {
keyword: 'test',
engine: 'startpage' as const,
inUrl: 'blog'
}
const degraded = adapter.degradeSyntax(params)
expect(degraded.inUrl).toBeUndefined()
})
test('应支持date_range语法', () => {
const supportedSyntax = adapter.getSupportedSyntax()
expect(supportedSyntax).toContain('date_range')
expect(supportedSyntax).not.toContain('inurl')
})
})
5.2.3 Naver Adapter Tests
文件: /src/services/adapters/naver.test.ts
import { NaverAdapter } from './naver'
describe('NaverAdapter', () => {
let adapter: NaverAdapter
beforeEach(() => {
adapter = new NaverAdapter()
})
test('应降级多站点OR组合为单个站点', () => {
const params = {
keyword: 'test',
engine: 'naver' as const,
sites: ['site1.com', 'site2.com', 'site3.com']
}
const degraded = adapter.degradeSyntax(params)
expect(degraded.sites).toHaveLength(1)
expect(degraded.sites![0]).toBe('site1.com')
})
test('应降级多文件类型OR组合为单个类型', () => {
const params = {
keyword: 'test',
engine: 'naver' as const,
fileTypes: ['pdf', 'doc', 'xls']
}
const degraded = adapter.degradeSyntax(params)
expect(degraded.fileTypes).toHaveLength(1)
expect(degraded.fileTypes![0]).toBe('pdf')
})
test('应降级OR关键词语法', () => {
const params = {
keyword: 'test',
engine: 'naver' as const,
orKeywords: ['keyword1', 'keyword2']
}
const degraded = adapter.degradeSyntax(params)
expect(degraded.orKeywords).toBeUndefined()
})
})
5.3 Test Coverage Requirements
必须测试的核心逻辑 (每个适配器):
- ✅ URL 构建正确性 (baseUrl + 查询参数格式)
- ✅ 单个语法支持 (site, filetype, exact)
- ✅ 多关键词 OR 组合 (如果引擎支持)
- ✅ 语法降级处理 (不支持的语法应设为 undefined)
- ✅ getSupportedSyntax 返回正确列表
不需要测试:
- ❌ UI 集成测试
- ❌ E2E 测试
- ❌ 性能测试
- ❌ 国际化翻译内容测试 (手动验证即可)
6. Validation Plan
6.1 Unit Tests
运行命令: npm run test
测试内容:
- 所有适配器的 URL 构建逻辑
- 语法支持列表正确性
- 多关键词 OR 组合正确性
- 语法降级处理正确性
6.2 Integration Tests
手动测试流程:
-
引擎切换测试
- 打开扩展弹窗
- 依次切换到 17 个搜索引擎
- 验证引擎名称正确显示 (中英文)
-
搜索功能测试
- 每个引擎执行基础关键词搜索
- 验证跳转到正确的搜索引擎页面
- 验证 URL 参数格式正确
-
语法支持测试
- 在支持 OR 的引擎中测试多站点/多文件类型
- 在不支持 OR 的引擎中验证降级警告
- 测试高级语法在各引擎中的行为
-
国际化测试
- 切换语言到中文,验证所有引擎名称
- 切换语言到英文,验证所有引擎名称
- 验证警告消息的中英文显示
6.3 Business Logic Verification
验收测试场景:
| 场景 | 引擎 | 操作 | 预期结果 |
|---|---|---|---|
| 多站点搜索 | Yahoo | 输入 2 个站点 | URL 包含 (site:a.com OR site:b.com) |
| 多站点降级 | Naver | 输入 2 个站点 | 仅使用第一个站点,显示警告 |
| cache 降级 | Yahoo | 输入 cache 站点 | cache 参数被忽略,显示警告 |
| 日期范围 | Startpage | 输入日期范围 | URL 包含 before: 和 after: |
| 基础语法 | Qwant | 输入 site + filetype | URL 正确构建 |
| 高级语法降级 | Qwant | 输入 intitle | intitle 被忽略,显示警告 |
| 中文搜索 | Sogou | 输入中文关键词 | 正确处理中文 URL 编码 |
7. Implementation Constraints
7.1 MUST Requirements
- Direct Implementability: 每个适配器必须可直接编码实现,无需额外架构设计
- Syntax Consistency: 语法支持必须与官方搜索引擎一致
- Degradation Handling: 不支持的语法必须正确降级并发出警告
- i18n Completeness: 所有用户可见文本必须有中英文翻译
- Test Coverage: 核心逻辑必须有单元测试覆盖
7.2 MUST NOT Requirements
- No Over-Engineering: 不引入复杂设计模式 (直接复用现有适配器逻辑)
- No Additional Languages: 不添加中英文以外的语言支持
- No UI Changes: 不修改现有 UI 组件 (使用现有下拉选择器)
- No Backend Services: 不引入服务器端依赖
- No Breaking Changes: 保持向后兼容,不破坏现有功能
7.3 Code Quality Standards
- TypeScript: 严格类型检查,无 any 类型
- ESLint: 无 linting 错误
- Code Style: 与现有适配器保持一致
- Comments: 关键逻辑添加中文注释
- Naming: 遵循现有命名约定
8. Risk Mitigation
8.1 Identified Risks
| 风险 | 可能性 | 影响 | 缓解措施 |
|---|---|---|---|
| 官方 URL 格式变化 | 中 | 高 | 使用 try-catch 包裹,允许降级处理 |
| 语法支持文档不准确 | 高 | 中 | 通过实际测试验证,保守策略 |
| 多关键词支持不确定 | 中 | 中 | 默认禁用,测试验证后启用 |
| 查询长度限制未知 | 低 | 低 | 统一使用 180 字符保守限制 |
| 国际化翻译遗漏 | 低 | 中 | 使用 checklist 逐项验证 |
8.2 Fallback Strategies
- URL 构建失败: 返回基础 URL + 关键词,允许用户手动搜索
- 语法不支持: 降级处理,发出警告,允许搜索继续
- 查询过长: 仅警告,不阻止搜索
- 验证失败: 宽松验证策略,仅警告不阻止
9. Acceptance Criteria
9.1 Functional Acceptance
- 所有 7 个新引擎可正常搜索
- 多站点 OR 组合在 Yahoo, Startpage, Ecosia, Sogou 中工作
- 多文件类型 OR 组合在支持的引擎中工作
- 语法降级在 Naver, 360搜索, Qwant 中正确处理
- cache 语法在 Yahoo 中正确降级
- 查询长度超限时显示警告
9.2 i18n Acceptance
- 所有 7 个引擎名称有中文翻译
- 所有 7 个引擎名称有英文翻译
- 语法降级警告有中英文翻译
- 切换语言时所有文本正确更新
- 不包含中英文以外的语言
9.3 Code Quality Acceptance
- 所有单元测试通过 (
npm run test) - TypeScript 类型检查通过 (
npm run type-check) - ESLint 检查通过 (
npm run lint) - 代码风格与现有适配器一致
- 关键逻辑有中文注释
9.4 User Experience Acceptance
- 引擎选择器包含所有 17 个引擎
- 引擎切换流畅无卡顿
- 搜索结果在正确的引擎中打开
- 警告消息清晰易懂
- 不支持的语法不阻止搜索
10. Post-Implementation
10.1 Documentation Updates
- 更新
README.md支持的引擎列表 - 生成
CHANGELOG.md版本 1.9.0 - 更新
manifest.json版本号
10.2 Version Release
新版本号: 1.9.0
发布说明:
## v1.9.0 - 2025-11-26
### 新增功能
- ✨ 新增 7 个搜索引擎支持
- Yahoo Search (雅虎搜索)
- Startpage (隐私友好搜索)
- Ecosia (环保搜索引擎)
- Qwant (欧洲隐私搜索)
- Naver (韩国搜索引擎)
- Sogou (搜狗搜索)
- 360搜索
### 改进
- 🌐 完整的中英文国际化支持
- ⚙️ 智能语法降级处理
- ✅ 完整的单元测试覆盖
### 技术细节
- 所有语法支持与官方搜索引擎保持一致
- 多关键词 OR 组合在支持的引擎中正常工作
- 不支持的语法自动降级并发出友好警告
10.3 Future Enhancements
可选后续改进 (不在本次实施范围):
- 添加 Perplexity AI 和 You.com 支持
- 实现 Qwant Qwick 快捷方式
- 优化中文搜索引擎的分词处理
- 添加引擎特定的搜索建议
11. Reference Materials
11.1 Official Documentation
- Yahoo: Bing 语法兼容性参考
- Startpage: 官方 Help Center
- Ecosia: 官方 FAQ
- Qwant: 官方帮助页面
- Naver: Naver Search API 文档
- Sogou: 搜狗帮助中心
- 360搜索: 360 帮助页面
11.2 Existing Code References
- Google Adapter:
/src/services/adapters/google.ts(最完整语法支持) - Bing Adapter:
/src/services/adapters/bing.ts(Yahoo 参考) - Baidu Adapter:
/src/services/adapters/baidu.ts(中文引擎参考) - Factory Pattern:
/src/services/adapters/factory.ts - Type Definitions:
/src/types/index.ts - i18n System:
/src/i18n/translations.ts
11.3 Test Examples
- Twitter Tests:
/src/services/adapters/twitter.test.ts(现有测试参考)
Appendix A: Complete Syntax Support Matrix
| 搜索引擎 | site | filetype | exact | intitle | inurl | intext | OR | exclude | date_range | cache | related | |---------|------|----------|-------|---------|-------|--------|----|---------|-----------|----- --|---------| | Yahoo | ✅ | ✅ | ✅ | ✅ | ✅ | ✅* | ✅ | ✅ | ✅ | ❌ | ✅ | | Startpage | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | | Ecosia | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | | Qwant | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | | Naver | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | | Sogou | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | | 360搜索 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
注释:
*Yahoo 使用inbody:而不是intext:- ✅ = 完整支持
- ❌ = 不支持,需要降级处理
Appendix B: Multi-Keyword OR Support Matrix
| 搜索引擎 | sites OR | fileTypes OR | exactMatches 并列 |
|---|---|---|---|
| Yahoo | ✅ | ✅ | ✅ |
| Startpage | ✅ | ✅ | ✅ |
| Ecosia | ✅ | ✅ | ✅ |
| Qwant | ❌ | ❌ | ✅ |
| Naver | ❌ | ❌ | ✅ |
| Sogou | ✅ | ✅ | ✅ |
| 360搜索 | ❌ | ❌ | ✅ |
Document Status: ✅ Ready for Implementation Estimated Implementation Time: 7-10 hours Last Updated: 2025-11-26