@llm-translate/cli 1.0.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +51 -0
- package/.env.example +33 -0
- package/.github/workflows/docs-pages.yml +57 -0
- package/.github/workflows/release.yml +49 -0
- package/.translaterc.json +44 -0
- package/CLAUDE.md +243 -0
- package/Dockerfile +55 -0
- package/README.md +371 -0
- package/RFC.md +1595 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +4494 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +1152 -0
- package/dist/index.js +3841 -0
- package/dist/index.js.map +1 -0
- package/docker-compose.yml +56 -0
- package/docs/.vitepress/config.ts +161 -0
- package/docs/api/agent.md +262 -0
- package/docs/api/engine.md +274 -0
- package/docs/api/index.md +171 -0
- package/docs/api/providers.md +304 -0
- package/docs/changelog.md +64 -0
- package/docs/cli/dir.md +243 -0
- package/docs/cli/file.md +213 -0
- package/docs/cli/glossary.md +273 -0
- package/docs/cli/index.md +129 -0
- package/docs/cli/init.md +158 -0
- package/docs/cli/serve.md +211 -0
- package/docs/glossary.json +235 -0
- package/docs/guide/chunking.md +272 -0
- package/docs/guide/configuration.md +139 -0
- package/docs/guide/cost-optimization.md +237 -0
- package/docs/guide/docker.md +371 -0
- package/docs/guide/getting-started.md +150 -0
- package/docs/guide/glossary.md +241 -0
- package/docs/guide/index.md +86 -0
- package/docs/guide/ollama.md +515 -0
- package/docs/guide/prompt-caching.md +221 -0
- package/docs/guide/providers.md +232 -0
- package/docs/guide/quality-control.md +206 -0
- package/docs/guide/vitepress-integration.md +265 -0
- package/docs/index.md +63 -0
- package/docs/ja/api/agent.md +262 -0
- package/docs/ja/api/engine.md +274 -0
- package/docs/ja/api/index.md +171 -0
- package/docs/ja/api/providers.md +304 -0
- package/docs/ja/changelog.md +64 -0
- package/docs/ja/cli/dir.md +243 -0
- package/docs/ja/cli/file.md +213 -0
- package/docs/ja/cli/glossary.md +273 -0
- package/docs/ja/cli/index.md +111 -0
- package/docs/ja/cli/init.md +158 -0
- package/docs/ja/guide/chunking.md +271 -0
- package/docs/ja/guide/configuration.md +139 -0
- package/docs/ja/guide/cost-optimization.md +30 -0
- package/docs/ja/guide/getting-started.md +150 -0
- package/docs/ja/guide/glossary.md +214 -0
- package/docs/ja/guide/index.md +32 -0
- package/docs/ja/guide/ollama.md +410 -0
- package/docs/ja/guide/prompt-caching.md +221 -0
- package/docs/ja/guide/providers.md +232 -0
- package/docs/ja/guide/quality-control.md +137 -0
- package/docs/ja/guide/vitepress-integration.md +265 -0
- package/docs/ja/index.md +58 -0
- package/docs/ko/api/agent.md +262 -0
- package/docs/ko/api/engine.md +274 -0
- package/docs/ko/api/index.md +171 -0
- package/docs/ko/api/providers.md +304 -0
- package/docs/ko/changelog.md +64 -0
- package/docs/ko/cli/dir.md +243 -0
- package/docs/ko/cli/file.md +213 -0
- package/docs/ko/cli/glossary.md +273 -0
- package/docs/ko/cli/index.md +111 -0
- package/docs/ko/cli/init.md +158 -0
- package/docs/ko/guide/chunking.md +271 -0
- package/docs/ko/guide/configuration.md +139 -0
- package/docs/ko/guide/cost-optimization.md +30 -0
- package/docs/ko/guide/getting-started.md +150 -0
- package/docs/ko/guide/glossary.md +214 -0
- package/docs/ko/guide/index.md +32 -0
- package/docs/ko/guide/ollama.md +410 -0
- package/docs/ko/guide/prompt-caching.md +221 -0
- package/docs/ko/guide/providers.md +232 -0
- package/docs/ko/guide/quality-control.md +137 -0
- package/docs/ko/guide/vitepress-integration.md +265 -0
- package/docs/ko/index.md +58 -0
- package/docs/zh/api/agent.md +262 -0
- package/docs/zh/api/engine.md +274 -0
- package/docs/zh/api/index.md +171 -0
- package/docs/zh/api/providers.md +304 -0
- package/docs/zh/changelog.md +64 -0
- package/docs/zh/cli/dir.md +243 -0
- package/docs/zh/cli/file.md +213 -0
- package/docs/zh/cli/glossary.md +273 -0
- package/docs/zh/cli/index.md +111 -0
- package/docs/zh/cli/init.md +158 -0
- package/docs/zh/guide/chunking.md +271 -0
- package/docs/zh/guide/configuration.md +139 -0
- package/docs/zh/guide/cost-optimization.md +30 -0
- package/docs/zh/guide/getting-started.md +150 -0
- package/docs/zh/guide/glossary.md +214 -0
- package/docs/zh/guide/index.md +32 -0
- package/docs/zh/guide/ollama.md +410 -0
- package/docs/zh/guide/prompt-caching.md +221 -0
- package/docs/zh/guide/providers.md +232 -0
- package/docs/zh/guide/quality-control.md +137 -0
- package/docs/zh/guide/vitepress-integration.md +265 -0
- package/docs/zh/index.md +58 -0
- package/package.json +91 -0
- package/release.config.mjs +15 -0
- package/schemas/glossary.schema.json +110 -0
- package/src/cli/commands/dir.ts +469 -0
- package/src/cli/commands/file.ts +291 -0
- package/src/cli/commands/glossary.ts +221 -0
- package/src/cli/commands/init.ts +68 -0
- package/src/cli/commands/serve.ts +60 -0
- package/src/cli/index.ts +64 -0
- package/src/cli/options.ts +59 -0
- package/src/core/agent.ts +1119 -0
- package/src/core/chunker.ts +391 -0
- package/src/core/engine.ts +634 -0
- package/src/errors.ts +188 -0
- package/src/index.ts +147 -0
- package/src/integrations/vitepress.ts +549 -0
- package/src/parsers/markdown.ts +383 -0
- package/src/providers/claude.ts +259 -0
- package/src/providers/interface.ts +109 -0
- package/src/providers/ollama.ts +379 -0
- package/src/providers/openai.ts +308 -0
- package/src/providers/registry.ts +153 -0
- package/src/server/index.ts +152 -0
- package/src/server/middleware/auth.ts +93 -0
- package/src/server/middleware/logger.ts +90 -0
- package/src/server/routes/health.ts +84 -0
- package/src/server/routes/translate.ts +210 -0
- package/src/server/types.ts +138 -0
- package/src/services/cache.ts +899 -0
- package/src/services/config.ts +217 -0
- package/src/services/glossary.ts +247 -0
- package/src/types/analysis.ts +164 -0
- package/src/types/index.ts +265 -0
- package/src/types/modes.ts +121 -0
- package/src/types/mqm.ts +157 -0
- package/src/utils/logger.ts +141 -0
- package/src/utils/tokens.ts +116 -0
- package/tests/fixtures/glossaries/ml-glossary.json +53 -0
- package/tests/fixtures/input/lynq-installation.ko.md +350 -0
- package/tests/fixtures/input/lynq-installation.md +350 -0
- package/tests/fixtures/input/simple.ko.md +27 -0
- package/tests/fixtures/input/simple.md +27 -0
- package/tests/unit/chunker.test.ts +229 -0
- package/tests/unit/glossary.test.ts +146 -0
- package/tests/unit/markdown.test.ts +205 -0
- package/tests/unit/tokens.test.ts +81 -0
- package/tsconfig.json +28 -0
- package/tsup.config.ts +34 -0
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# TranslationAgent
|
|
2
|
+
|
|
3
|
+
::: info 翻译说明
|
|
4
|
+
所有非英文文档均使用 Claude Sonnet 4 自动翻译。
|
|
5
|
+
:::
|
|
6
|
+
|
|
7
|
+
实现 Self-Refine 算法的底层翻译代理。
|
|
8
|
+
|
|
9
|
+
## 构造函数
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { TranslationAgent } from '@llm-translate/cli';
|
|
13
|
+
|
|
14
|
+
const agent = new TranslationAgent(options: TranslationAgentOptions);
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 选项
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
interface TranslationAgentOptions {
|
|
21
|
+
provider: LLMProvider;
|
|
22
|
+
qualityThreshold?: number; // Default: 85
|
|
23
|
+
maxIterations?: number; // Default: 4
|
|
24
|
+
verbose?: boolean; // Default: false
|
|
25
|
+
strictQuality?: boolean; // Default: false
|
|
26
|
+
enableCaching?: boolean; // Default: true for Claude
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 方法
|
|
31
|
+
|
|
32
|
+
### translate
|
|
33
|
+
|
|
34
|
+
使用 Self-Refine 循环翻译内容。
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
const result = await agent.translate(request: TranslationRequest);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### 请求
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
interface TranslationRequest {
|
|
44
|
+
content: string; // Source text to translate
|
|
45
|
+
sourceLang: string; // Source language code
|
|
46
|
+
targetLang: string; // Target language code
|
|
47
|
+
glossary?: ResolvedGlossary; // Resolved glossary for target language
|
|
48
|
+
context?: {
|
|
49
|
+
documentPurpose?: string;
|
|
50
|
+
previousChunks?: string[];
|
|
51
|
+
documentSummary?: string;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### 结果
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
interface TranslationResult {
|
|
60
|
+
content: string; // Translated text
|
|
61
|
+
metadata: {
|
|
62
|
+
qualityScore: number;
|
|
63
|
+
qualityThreshold: number;
|
|
64
|
+
thresholdMet: boolean;
|
|
65
|
+
iterations: number;
|
|
66
|
+
tokensUsed: {
|
|
67
|
+
input: number;
|
|
68
|
+
output: number;
|
|
69
|
+
cacheRead?: number;
|
|
70
|
+
cacheWrite?: number;
|
|
71
|
+
};
|
|
72
|
+
duration: number;
|
|
73
|
+
provider: string;
|
|
74
|
+
model: string;
|
|
75
|
+
};
|
|
76
|
+
glossaryCompliance?: {
|
|
77
|
+
applied: string[]; // Terms successfully applied
|
|
78
|
+
missed: string[]; // Terms not found in translation
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Self-Refine 算法
|
|
84
|
+
|
|
85
|
+
代理实现了这个迭代优化过程:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// Pseudocode
|
|
89
|
+
async translate(request) {
|
|
90
|
+
// 1. Initial translation with glossary
|
|
91
|
+
let translation = await generateInitialTranslation(request);
|
|
92
|
+
let iterations = 1;
|
|
93
|
+
|
|
94
|
+
while (iterations < maxIterations) {
|
|
95
|
+
// 2. Evaluate quality
|
|
96
|
+
const evaluation = await evaluateQuality(translation);
|
|
97
|
+
|
|
98
|
+
if (evaluation.score >= qualityThreshold) {
|
|
99
|
+
break; // Quality met
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 3. Generate improvement suggestions
|
|
103
|
+
const suggestions = await generateReflection(translation);
|
|
104
|
+
|
|
105
|
+
// 4. Apply improvements
|
|
106
|
+
translation = await improveTranslation(translation, suggestions);
|
|
107
|
+
iterations++;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return { content: translation, metadata: { ... } };
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## 使用示例
|
|
115
|
+
|
|
116
|
+
### 基础翻译
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { TranslationAgent, createClaudeProvider } from '@llm-translate/cli';
|
|
120
|
+
|
|
121
|
+
const provider = createClaudeProvider();
|
|
122
|
+
const agent = new TranslationAgent({
|
|
123
|
+
provider,
|
|
124
|
+
qualityThreshold: 85,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const result = await agent.translate({
|
|
128
|
+
content: 'Hello, world!',
|
|
129
|
+
sourceLang: 'en',
|
|
130
|
+
targetLang: 'ko',
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
console.log(result.content); // 안녕하세요, 세계!
|
|
134
|
+
console.log(result.metadata.qualityScore); // 92
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 使用术语表
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { loadGlossary, resolveGlossary } from '@llm-translate/cli';
|
|
141
|
+
|
|
142
|
+
const glossary = await loadGlossary('./glossary.json');
|
|
143
|
+
const resolved = resolveGlossary(glossary, 'ko');
|
|
144
|
+
|
|
145
|
+
const result = await agent.translate({
|
|
146
|
+
content: 'The component renders a prop.',
|
|
147
|
+
sourceLang: 'en',
|
|
148
|
+
targetLang: 'ko',
|
|
149
|
+
glossary: resolved,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
console.log(result.glossaryCompliance);
|
|
153
|
+
// { applied: ['component', 'prop'], missed: [] }
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 使用上下文
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
const result = await agent.translate({
|
|
160
|
+
content: 'Click the button to continue.',
|
|
161
|
+
sourceLang: 'en',
|
|
162
|
+
targetLang: 'ko',
|
|
163
|
+
context: {
|
|
164
|
+
documentPurpose: 'User interface instructions',
|
|
165
|
+
previousChunks: [
|
|
166
|
+
'이전 단계에서 설정을 완료했습니다.', // Previous translation
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 严格质量模式
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { TranslationError, ErrorCode } from '@llm-translate/cli';
|
|
176
|
+
|
|
177
|
+
const agent = new TranslationAgent({
|
|
178
|
+
provider,
|
|
179
|
+
qualityThreshold: 95,
|
|
180
|
+
strictQuality: true, // Throw if threshold not met
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
try {
|
|
184
|
+
const result = await agent.translate(request);
|
|
185
|
+
} catch (error) {
|
|
186
|
+
if (error instanceof TranslationError &&
|
|
187
|
+
error.code === ErrorCode.QUALITY_THRESHOLD_NOT_MET) {
|
|
188
|
+
console.log(`Quality: ${error.details.score}/${error.details.threshold}`);
|
|
189
|
+
console.log(`Issues: ${error.details.issues.join(', ')}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## 质量评估
|
|
195
|
+
|
|
196
|
+
代理根据四个标准评估翻译:
|
|
197
|
+
|
|
198
|
+
| 标准 | 权重 | 描述 |
|
|
199
|
+
|-----------|--------|-------------|
|
|
200
|
+
| 语义准确性 | 40% | 意义保持 |
|
|
201
|
+
| 流畅性 | 25% | 自然语言流 |
|
|
202
|
+
| 术语表合规性 | 20% | 术语一致性 |
|
|
203
|
+
| 格式保持 | 15% | 结构维护 |
|
|
204
|
+
|
|
205
|
+
### 评估结果
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
interface QualityEvaluation {
|
|
209
|
+
score: number; // 0-100
|
|
210
|
+
breakdown: {
|
|
211
|
+
accuracy: number; // 0-40
|
|
212
|
+
fluency: number; // 0-25
|
|
213
|
+
glossary: number; // 0-20
|
|
214
|
+
format: number; // 0-15
|
|
215
|
+
};
|
|
216
|
+
issues: string[]; // Specific problems identified
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## 提示缓存
|
|
221
|
+
|
|
222
|
+
当 `enableCaching` 为 true(Claude 的默认值)时,代理会为缓存构建提示:
|
|
223
|
+
|
|
224
|
+
```
|
|
225
|
+
┌─────────────────────────────────┐
|
|
226
|
+
│ System Instructions (CACHED) │ ← Reused across chunks
|
|
227
|
+
├─────────────────────────────────┤
|
|
228
|
+
│ Glossary (CACHED) │ ← Reused across chunks
|
|
229
|
+
├─────────────────────────────────┤
|
|
230
|
+
│ Source Text (NOT cached) │ ← Changes per chunk
|
|
231
|
+
└─────────────────────────────────┘
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
这可以为多分块文档减少 40-50% 的成本。
|
|
235
|
+
|
|
236
|
+
## 高级:自定义评估
|
|
237
|
+
|
|
238
|
+
覆盖默认评估逻辑:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
class CustomAgent extends TranslationAgent {
|
|
242
|
+
protected async evaluateQuality(
|
|
243
|
+
source: string,
|
|
244
|
+
translation: string,
|
|
245
|
+
sourceLang: string,
|
|
246
|
+
targetLang: string
|
|
247
|
+
): Promise<QualityEvaluation> {
|
|
248
|
+
// Custom evaluation logic
|
|
249
|
+
const baseEval = await super.evaluateQuality(
|
|
250
|
+
source, translation, sourceLang, targetLang
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
// Add custom checks
|
|
254
|
+
if (translation.length < source.length * 0.5) {
|
|
255
|
+
baseEval.score -= 10;
|
|
256
|
+
baseEval.issues.push('Translation suspiciously short');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return baseEval;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
```
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# TranslationEngine
|
|
2
|
+
|
|
3
|
+
::: info 翻译说明
|
|
4
|
+
所有非英文文档均使用 Claude Sonnet 4 自动翻译。
|
|
5
|
+
:::
|
|
6
|
+
|
|
7
|
+
翻译操作的主要入口点。
|
|
8
|
+
|
|
9
|
+
## 构造函数
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { TranslationEngine } from '@llm-translate/cli';
|
|
13
|
+
|
|
14
|
+
const engine = new TranslationEngine(options: TranslationEngineOptions);
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 选项
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
interface TranslationEngineOptions {
|
|
21
|
+
provider: LLMProvider;
|
|
22
|
+
qualityThreshold?: number; // Default: 85
|
|
23
|
+
maxIterations?: number; // Default: 4
|
|
24
|
+
chunkingConfig?: ChunkingConfig;
|
|
25
|
+
verbose?: boolean; // Default: false
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 方法
|
|
30
|
+
|
|
31
|
+
### translateFile
|
|
32
|
+
|
|
33
|
+
翻译单个文件。
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
const result = await engine.translateFile(options: TranslateFileOptions);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
#### 选项
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
interface TranslateFileOptions {
|
|
43
|
+
input: string; // Input file path
|
|
44
|
+
output?: string; // Output file path (optional)
|
|
45
|
+
sourceLang?: string; // Source language (auto-detect if omitted)
|
|
46
|
+
targetLang: string; // Target language (required)
|
|
47
|
+
glossary?: string | Glossary; // Glossary path or object
|
|
48
|
+
context?: {
|
|
49
|
+
documentPurpose?: string;
|
|
50
|
+
preserveFormatting?: boolean;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
#### 返回值
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
interface TranslateFileResult {
|
|
59
|
+
content: string;
|
|
60
|
+
outputPath?: string;
|
|
61
|
+
metadata: {
|
|
62
|
+
qualityScore: number;
|
|
63
|
+
qualityThreshold: number;
|
|
64
|
+
thresholdMet: boolean;
|
|
65
|
+
iterations: number;
|
|
66
|
+
tokensUsed: {
|
|
67
|
+
input: number;
|
|
68
|
+
output: number;
|
|
69
|
+
cacheRead?: number;
|
|
70
|
+
cacheWrite?: number;
|
|
71
|
+
};
|
|
72
|
+
duration: number;
|
|
73
|
+
chunks: number;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### 示例
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const result = await engine.translateFile({
|
|
82
|
+
input: 'docs/guide.md',
|
|
83
|
+
output: 'docs/guide.ko.md',
|
|
84
|
+
targetLang: 'ko',
|
|
85
|
+
glossary: './glossary.json',
|
|
86
|
+
context: {
|
|
87
|
+
documentPurpose: 'Technical documentation for developers',
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
console.log(`Quality: ${result.metadata.qualityScore}`);
|
|
92
|
+
console.log(`Output: ${result.outputPath}`);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### translateContent
|
|
96
|
+
|
|
97
|
+
直接翻译内容(无需文件 I/O)。
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const result = await engine.translateContent(
|
|
101
|
+
content: string,
|
|
102
|
+
options: TranslateContentOptions
|
|
103
|
+
);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### 选项
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
interface TranslateContentOptions {
|
|
110
|
+
sourceLang?: string;
|
|
111
|
+
targetLang: string;
|
|
112
|
+
glossary?: ResolvedGlossary;
|
|
113
|
+
format?: 'markdown' | 'html' | 'text';
|
|
114
|
+
context?: {
|
|
115
|
+
documentPurpose?: string;
|
|
116
|
+
previousChunks?: string[];
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### 示例
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const content = `
|
|
125
|
+
# Hello World
|
|
126
|
+
|
|
127
|
+
This is a **markdown** document.
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
const result = await engine.translateContent(content, {
|
|
131
|
+
targetLang: 'ko',
|
|
132
|
+
format: 'markdown',
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
console.log(result.content);
|
|
136
|
+
// # 안녕하세요
|
|
137
|
+
//
|
|
138
|
+
// 이것은 **마크다운** 문서입니다.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### translateDirectory
|
|
142
|
+
|
|
143
|
+
翻译目录中的所有文件。
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const results = await engine.translateDirectory(options: TranslateDirectoryOptions);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### 选项
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
interface TranslateDirectoryOptions {
|
|
153
|
+
input: string; // Input directory
|
|
154
|
+
output: string; // Output directory
|
|
155
|
+
targetLang: string;
|
|
156
|
+
glossary?: string | Glossary;
|
|
157
|
+
pattern?: string; // Glob pattern (default: '**/*.md')
|
|
158
|
+
exclude?: string[]; // Patterns to exclude
|
|
159
|
+
concurrency?: number; // Parallel processing (default: 3)
|
|
160
|
+
continueOnError?: boolean;
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### 返回值
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
interface TranslateDirectoryResult {
|
|
168
|
+
successful: TranslateFileResult[];
|
|
169
|
+
failed: Array<{
|
|
170
|
+
file: string;
|
|
171
|
+
error: Error;
|
|
172
|
+
}>;
|
|
173
|
+
summary: {
|
|
174
|
+
total: number;
|
|
175
|
+
successful: number;
|
|
176
|
+
failed: number;
|
|
177
|
+
totalDuration: number;
|
|
178
|
+
averageQuality: number;
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### 示例
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
const results = await engine.translateDirectory({
|
|
187
|
+
input: './docs',
|
|
188
|
+
output: './docs-ko',
|
|
189
|
+
targetLang: 'ko',
|
|
190
|
+
glossary: './glossary.json',
|
|
191
|
+
concurrency: 5,
|
|
192
|
+
continueOnError: true,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
console.log(`Translated: ${results.summary.successful}/${results.summary.total}`);
|
|
196
|
+
console.log(`Average quality: ${results.summary.averageQuality}`);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## 事件
|
|
200
|
+
|
|
201
|
+
TranslationEngine 继承自 EventEmitter:
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
engine.on('chunk:start', (data) => {
|
|
205
|
+
console.log(`Starting chunk ${data.index}/${data.total}`);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
engine.on('chunk:complete', (data) => {
|
|
209
|
+
console.log(`Chunk ${data.index}: quality ${data.quality}`);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
engine.on('file:start', (data) => {
|
|
213
|
+
console.log(`Translating: ${data.file}`);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
engine.on('file:complete', (data) => {
|
|
217
|
+
console.log(`Completed: ${data.file} (${data.quality})`);
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## 完整示例
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
import {
|
|
225
|
+
TranslationEngine,
|
|
226
|
+
createClaudeProvider,
|
|
227
|
+
loadGlossary,
|
|
228
|
+
resolveGlossary,
|
|
229
|
+
} from '@llm-translate/cli';
|
|
230
|
+
|
|
231
|
+
async function translateDocs() {
|
|
232
|
+
// Setup provider
|
|
233
|
+
const provider = createClaudeProvider({
|
|
234
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
235
|
+
defaultModel: 'claude-sonnet-4-5-20250929',
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Load and resolve glossary
|
|
239
|
+
const glossary = await loadGlossary('./glossary.json');
|
|
240
|
+
|
|
241
|
+
// Create engine
|
|
242
|
+
const engine = new TranslationEngine({
|
|
243
|
+
provider,
|
|
244
|
+
qualityThreshold: 90,
|
|
245
|
+
maxIterations: 5,
|
|
246
|
+
verbose: true,
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Track progress
|
|
250
|
+
engine.on('chunk:complete', ({ index, total, quality }) => {
|
|
251
|
+
console.log(`Progress: ${index}/${total} (quality: ${quality})`);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Translate
|
|
255
|
+
try {
|
|
256
|
+
const result = await engine.translateFile({
|
|
257
|
+
input: 'README.md',
|
|
258
|
+
output: 'README.ko.md',
|
|
259
|
+
targetLang: 'ko',
|
|
260
|
+
glossary,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
console.log('Translation complete!');
|
|
264
|
+
console.log(`Quality: ${result.metadata.qualityScore}`);
|
|
265
|
+
console.log(`Tokens: ${result.metadata.tokensUsed.input} in / ${result.metadata.tokensUsed.output} out`);
|
|
266
|
+
|
|
267
|
+
if (result.metadata.tokensUsed.cacheRead) {
|
|
268
|
+
console.log(`Cache hit: ${result.metadata.tokensUsed.cacheRead} tokens`);
|
|
269
|
+
}
|
|
270
|
+
} catch (error) {
|
|
271
|
+
console.error('Translation failed:', error.message);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
```
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# API 参考
|
|
2
|
+
|
|
3
|
+
::: info 翻译说明
|
|
4
|
+
所有非英文文档均使用 Claude Sonnet 4 自动翻译。
|
|
5
|
+
:::
|
|
6
|
+
|
|
7
|
+
llm-translate 可以在您的 Node.js 应用程序中以编程方式使用。
|
|
8
|
+
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @llm-translate/cli
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 快速开始
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { TranslationEngine, createClaudeProvider } from '@llm-translate/cli';
|
|
19
|
+
|
|
20
|
+
// Create provider
|
|
21
|
+
const provider = createClaudeProvider({
|
|
22
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Create engine
|
|
26
|
+
const engine = new TranslationEngine({
|
|
27
|
+
provider,
|
|
28
|
+
qualityThreshold: 85,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Translate
|
|
32
|
+
const result = await engine.translateFile({
|
|
33
|
+
input: 'README.md',
|
|
34
|
+
output: 'README.ko.md',
|
|
35
|
+
sourceLang: 'en',
|
|
36
|
+
targetLang: 'ko',
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
console.log(result.metadata);
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 核心类
|
|
43
|
+
|
|
44
|
+
### [TranslationEngine](./engine)
|
|
45
|
+
|
|
46
|
+
翻译操作的主要入口点。
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
const engine = new TranslationEngine(options);
|
|
50
|
+
await engine.translateFile({ input, output, targetLang });
|
|
51
|
+
await engine.translateContent(content, options);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### [TranslationAgent](./agent)
|
|
55
|
+
|
|
56
|
+
带有 Self-Refine 循环的低级翻译代理。
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const agent = new TranslationAgent({ provider, qualityThreshold });
|
|
60
|
+
const result = await agent.translate(request);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### [Providers](./providers)
|
|
64
|
+
|
|
65
|
+
LLM 提供商实现。
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import {
|
|
69
|
+
createClaudeProvider,
|
|
70
|
+
createOpenAIProvider,
|
|
71
|
+
createOllamaProvider,
|
|
72
|
+
} from '@llm-translate/cli';
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 类型导出
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import type {
|
|
79
|
+
// Configuration
|
|
80
|
+
TranslationConfig,
|
|
81
|
+
ProviderConfig,
|
|
82
|
+
|
|
83
|
+
// Requests/Results
|
|
84
|
+
TranslationRequest,
|
|
85
|
+
TranslationResult,
|
|
86
|
+
|
|
87
|
+
// Glossary
|
|
88
|
+
Glossary,
|
|
89
|
+
GlossaryTerm,
|
|
90
|
+
ResolvedGlossary,
|
|
91
|
+
|
|
92
|
+
// Quality
|
|
93
|
+
QualityEvaluation,
|
|
94
|
+
|
|
95
|
+
// Provider
|
|
96
|
+
LLMProvider,
|
|
97
|
+
ChatMessage,
|
|
98
|
+
ChatResponse,
|
|
99
|
+
} from '@llm-translate/cli';
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## 实用函数
|
|
103
|
+
|
|
104
|
+
### Chunking
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { chunkContent, chunkMarkdown } from '@llm-translate/cli';
|
|
108
|
+
|
|
109
|
+
const chunks = chunkContent(text, { maxTokens: 1024 });
|
|
110
|
+
const mdChunks = chunkMarkdown(markdown, { maxTokens: 1024 });
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 术语表
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { loadGlossary, resolveGlossary, createGlossaryLookup } from '@llm-translate/cli';
|
|
117
|
+
|
|
118
|
+
const glossary = await loadGlossary('./glossary.json');
|
|
119
|
+
const resolved = resolveGlossary(glossary, 'ko');
|
|
120
|
+
const lookup = createGlossaryLookup(resolved);
|
|
121
|
+
|
|
122
|
+
const terms = lookup.findAll(sourceText);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 令牌估算
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { estimateTokens, calculateTokenBudget } from '@llm-translate/cli';
|
|
129
|
+
|
|
130
|
+
const tokens = estimateTokens(text);
|
|
131
|
+
const budget = calculateTokenBudget(text, { glossaryTokens: 500 });
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## 错误处理
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { TranslationError, ErrorCode } from '@llm-translate/cli';
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
await engine.translateFile(options);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
if (error instanceof TranslationError) {
|
|
143
|
+
switch (error.code) {
|
|
144
|
+
case ErrorCode.FILE_NOT_FOUND:
|
|
145
|
+
// Handle missing file
|
|
146
|
+
break;
|
|
147
|
+
case ErrorCode.QUALITY_THRESHOLD_NOT_MET:
|
|
148
|
+
// Handle quality issue
|
|
149
|
+
console.log('Score:', error.details.score);
|
|
150
|
+
break;
|
|
151
|
+
case ErrorCode.PROVIDER_RATE_LIMITED:
|
|
152
|
+
// Handle rate limit
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 错误代码
|
|
160
|
+
|
|
161
|
+
| 代码 | 描述 |
|
|
162
|
+
|------|-------------|
|
|
163
|
+
|`FILE_NOT_FOUND`| 输入文件不存在 |
|
|
164
|
+
|`INVALID_CONFIG`| 配置验证失败 |
|
|
165
|
+
|`GLOSSARY_NOT_FOUND`| 术语表文件未找到 |
|
|
166
|
+
|`GLOSSARY_INVALID`| 术语表验证失败 |
|
|
167
|
+
|`PROVIDER_AUTH_FAILED`| API 密钥无效 |
|
|
168
|
+
|`PROVIDER_RATE_LIMITED`| 超出速率限制 |
|
|
169
|
+
|`PROVIDER_ERROR`| 一般提供商错误 |
|
|
170
|
+
|`QUALITY_THRESHOLD_NOT_MET`| 翻译质量低于阈值 |
|
|
171
|
+
|`PARSE_ERROR`| 文档解析失败 |
|