@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
package/docs/index.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: home
|
|
3
|
+
|
|
4
|
+
hero:
|
|
5
|
+
name: llm-translate
|
|
6
|
+
text: LLM-Powered Document Translation
|
|
7
|
+
tagline: Translate documents with glossary enforcement, quality control, and cost optimization
|
|
8
|
+
actions:
|
|
9
|
+
- theme: brand
|
|
10
|
+
text: Get Started
|
|
11
|
+
link: ./guide/getting-started
|
|
12
|
+
- theme: alt
|
|
13
|
+
text: View on GitHub
|
|
14
|
+
link: https://github.com/selenehyun/llm-translate
|
|
15
|
+
|
|
16
|
+
features:
|
|
17
|
+
- icon: 📚
|
|
18
|
+
title: Glossary Enforcement
|
|
19
|
+
details: Ensure consistent terminology across your translations with enforced glossary terms that never get mistranslated.
|
|
20
|
+
- icon: 🔄
|
|
21
|
+
title: Self-Refine Quality Control
|
|
22
|
+
details: Iterative translation refinement using AI-powered quality evaluation to meet your quality threshold.
|
|
23
|
+
- icon: 💰
|
|
24
|
+
title: Cost Optimization
|
|
25
|
+
details: Prompt caching reduces API costs by up to 90% for repeated content like glossaries and system prompts.
|
|
26
|
+
- icon: 🔌
|
|
27
|
+
title: Multi-Provider Support
|
|
28
|
+
details: Works with Claude, OpenAI, and Ollama. Switch providers without changing your workflow.
|
|
29
|
+
- icon: 📄
|
|
30
|
+
title: Format Preservation
|
|
31
|
+
details: Maintains markdown formatting, code blocks, links, and document structure during translation.
|
|
32
|
+
- icon: ⚡
|
|
33
|
+
title: Batch Processing
|
|
34
|
+
details: Translate entire directories with parallel processing and progress tracking.
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Install globally
|
|
41
|
+
npm install -g @llm-translate/cli
|
|
42
|
+
|
|
43
|
+
# Set your API key
|
|
44
|
+
export ANTHROPIC_API_KEY=your-key-here
|
|
45
|
+
|
|
46
|
+
# Translate a file
|
|
47
|
+
llm-translate file README.md -o README.ko.md --target ko
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Why llm-translate?
|
|
51
|
+
|
|
52
|
+
Traditional translation tools struggle with technical documentation:
|
|
53
|
+
|
|
54
|
+
- **Inconsistent terminology** - "API endpoint" translated differently each time
|
|
55
|
+
- **Broken formatting** - Code blocks and markdown get mangled
|
|
56
|
+
- **No quality control** - Accept whatever the LLM outputs
|
|
57
|
+
|
|
58
|
+
llm-translate solves these problems with:
|
|
59
|
+
|
|
60
|
+
1. **Glossary enforcement** - Define terms once, apply everywhere
|
|
61
|
+
2. **AST-based chunking** - Preserves document structure
|
|
62
|
+
3. **Quality-aware refinement** - Iterates until quality threshold is met
|
|
63
|
+
4. **Prompt caching** - Reduces costs for large documents
|
|
@@ -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
|
+
エージェントは4つの基準で翻訳を評価します:
|
|
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
|
+
```
|