Add a Dictionary
This guide explains how to add a new dictionary or translation module to ClueLens. All source modules live under components/dicts/.
Core concepts
Each dictionary module consists of some of the following files:
| File | Purpose | Required |
|---|---|---|
search.ts | Runs the search and returns result data | Yes |
view.tsx | React component for rendering results | Yes |
types.ts | Type definitions for structured results | Required for structured dictionaries |
configView.tsx | Configuration UI | Required when configuration exists |
settingBackup.ts | Backup and restore handling | Required when configuration participates in backup |
icon.png | Source icon | Yes |
Two module patterns
Simple translators
Use this for services that return translated text, such as Google Translate, Caiyun, or DeepLx.
search.tsreturnsstring[]view.tsxcan reuse the sharedCommonViewcomponent- Reference implementations:
google/,caiyun/,deeplx/
Structured dictionaries
Use this for sources that return structured data, such as Bing Dictionary, Jisho, or Urban Dictionary.
search.tsreturns an array of custom typestypes.tsdefines those typesview.tsxis a custom renderer- Reference implementations:
bing/,jisho/,urban/,wiktionary/
Five steps
Step 1: Register DictID
Add a new enum value to components/dicts/types.ts:
export enum DictID {
// existing values
YourDict = 'yourDict',
}Step 2: Create the module folder
components/dicts/yourDict/
├── icon.png
├── search.ts
├── view.tsx
├── types.ts
├── configView.tsx
└── settingBackup.tsStep 3: Implement search.ts
The module must export a search function that returns an array.
Simple translator example:
import { SearchOptions } from '../types';
export async function search(
text: string,
options?: SearchOptions
): Promise<string[]> {
const query = text.trim();
if (!query) return [];
const translatedText = await callYourAPI(query, options?.targetLang);
return translatedText ? [translatedText] : [];
}Structured dictionary example:
import { YourDictResult } from './types';
export async function search(text: string): Promise<YourDictResult[]> {
const query = text.trim();
if (!query) return [];
const results = await fetchResults(query);
return results;
}Key points
- Always call
trim()on user input - Return
[]for empty input - Translator modules can use
options?.targetLang - Keep network logic inside
search.ts
Step 4: Implement the renderer
Simple translator using CommonView:
import TranslateView from '../shared/CommonView';
export function ResultsView({ data }: { data: unknown[] }) {
return <TranslateView result={data as string[]} />;
}Structured dictionary with a custom view:
import { YourDictResult } from './types';
export function ResultsView({ data }: { data: unknown[] }) {
const results = data as YourDictResult[];
return (
<div>
{results.map((item, i) => (
<div key={i}>
<h3>{item.title}</h3>
<p>{item.definition}</p>
</div>
))}
</div>
);
}Important
view.tsx must export a named component called ResultsView. Do not use a default export.
Step 5: Register metadata
In components/dicts/index.tsx:
- Import the icon:
import yourDictIcon from './yourDict/icon.png';- Add an entry to
dictMetaMap:
[DictID.YourDict]: {
id: DictID.YourDict,
displayName: 'Your Dictionary',
displayNameKey: 'dict.yourDict',
icon: yourDictIcon,
language: { type: 'all' },
type: ModuleType.Dict,
},Meaning of language:
| Type | Meaning | Example |
|---|---|---|
{ type: 'all' } | Supports every language | Google Translate |
{ type: 'monolingual', languages: ['en'] } | Supports specific languages only | DictionaryAPI |
{ type: 'pairs', pairs: [['en', 'zh'], ['zh', 'en']] } | Supports language pairs | Bing Dictionary |
Meaning of type:
| Type | Meaning | Effect |
|---|---|---|
ModuleType.Dict | Dictionary | Does not receive targetLang |
ModuleType.Translator | Translator | Receives targetLang automatically |
ModuleType.Other | Other, such as AI | Does not receive targetLang |
Search modules and result views are discovered automatically through file naming conventions with import.meta.glob, so no extra loader wiring is needed.
Add configuration options
If the module needs an API key or custom settings:
- Define the config type and defaults in
yourDict/types.ts - Add a storage entry in
utils/storage.ts - Create
yourDict/configView.tsx - If the config must participate in backup and restore, create
yourDict/settingBackup.tsand exportsettingsBackupHandler
Add localization
If the module name or configuration copy needs translation, add entries to each locale file under i18n/locales/:
{
"dict.yourDict": "Your Dictionary"
}Good references
| Use case | Reference module |
|---|---|
| Simple translator | google/ |
| Translator with configuration | caiyun/, deeplx/ |
| Structured dictionary | urban/, jisho/ |
| Custom HTML view | bing/ |
| Dictionary with settings UI | wiktionary/ |
| AI output | openai/ |