@djangocfg/i18n 2.1.216 → 2.1.218

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.
@@ -1,208 +0,0 @@
1
- /**
2
- * Translate text or JSON using LLM
3
- */
4
-
5
- import { defineCommand } from 'citty';
6
- import { consola } from 'consola';
7
- import * as path from 'node:path';
8
- import * as fs from 'node:fs';
9
- import {
10
- detectLocaleConfig,
11
- getDefaultLocalesDir,
12
- loadLocale,
13
- readLocaleFile,
14
- writeLocaleFile,
15
- getExportName,
16
- translateText,
17
- translateJson,
18
- getTranslatorStats,
19
- } from '../utils';
20
-
21
- export const translateCommand = defineCommand({
22
- meta: {
23
- name: 'translate',
24
- description: 'Translate text or locale file using LLM',
25
- },
26
- args: {
27
- text: {
28
- type: 'positional',
29
- description: 'Text to translate or locale code (e.g., "Hello" or "ru")',
30
- required: false,
31
- },
32
- dir: {
33
- type: 'string',
34
- alias: 'd',
35
- description: 'Locales directory',
36
- },
37
- from: {
38
- type: 'string',
39
- alias: 'f',
40
- description: 'Source locale (default: en)',
41
- default: 'en',
42
- },
43
- to: {
44
- type: 'string',
45
- alias: 't',
46
- description: 'Target locales (comma-separated, e.g., "ru,ko,ja")',
47
- },
48
- json: {
49
- type: 'boolean',
50
- alias: 'j',
51
- description: 'Output as JSON',
52
- default: false,
53
- },
54
- file: {
55
- type: 'boolean',
56
- description: 'Translate entire locale file',
57
- default: false,
58
- },
59
- stats: {
60
- type: 'boolean',
61
- alias: 's',
62
- description: 'Show translation cache stats',
63
- default: false,
64
- },
65
- },
66
- async run({ args }) {
67
- // Show stats
68
- if (args.stats) {
69
- const stats = getTranslatorStats();
70
- if (stats) {
71
- consola.info('Translation Cache Stats:');
72
- consola.log(` Memory size: ${stats.memorySize}`);
73
- consola.log(` Hits: ${stats.hits}`);
74
- consola.log(` Misses: ${stats.misses}`);
75
- if (stats.languagePairs.length > 0) {
76
- consola.log(' Language pairs:');
77
- for (const { pair, translations } of stats.languagePairs) {
78
- consola.log(` ${pair}: ${translations} translations`);
79
- }
80
- }
81
- } else {
82
- consola.info('No translations performed yet.');
83
- }
84
- return;
85
- }
86
-
87
- const localesDir = args.dir
88
- ? path.resolve(process.cwd(), args.dir)
89
- : getDefaultLocalesDir();
90
-
91
- try {
92
- const config = detectLocaleConfig(localesDir);
93
- const sourceLocale = args.from || 'en';
94
-
95
- // Determine target locales
96
- let targetLocales: string[];
97
- if (args.to) {
98
- targetLocales = args.to.split(',').map((l) => l.trim());
99
- } else {
100
- // All locales except source
101
- targetLocales = config.locales.filter((l) => l !== sourceLocale);
102
- }
103
-
104
- // Translate entire file
105
- if (args.file || (args.text && config.locales.includes(args.text))) {
106
- const targetLocale = args.text || targetLocales[0];
107
- if (!targetLocale) {
108
- consola.error('Please specify target locale');
109
- return;
110
- }
111
-
112
- consola.info(`Translating ${sourceLocale} -> ${targetLocale}`);
113
- consola.info(`Directory: ${localesDir}`);
114
-
115
- const sourceData = await loadLocale(config, sourceLocale);
116
- const startTime = Date.now();
117
-
118
- // Translate section-by-section to avoid LLM output truncation on large files
119
- const topLevelKeys = Object.keys(sourceData);
120
- const translated: Record<string, unknown> = {};
121
-
122
- for (const section of topLevelKeys) {
123
- const sectionData = sourceData[section];
124
- consola.info(` [${section}] translating...`);
125
- const sectionTranslated = await translateJson(
126
- sectionData as Record<string, unknown>,
127
- targetLocale,
128
- sourceLocale,
129
- );
130
- translated[section] = sectionTranslated;
131
- consola.success(` [${section}] done`);
132
- }
133
-
134
- const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
135
- consola.success(`Translated in ${elapsed}s`);
136
-
137
- // Write to file
138
- if (config.fileExtension === '.ts') {
139
- const exportName = getExportName(targetLocale);
140
- const { content } = readLocaleFile(config, targetLocale);
141
- const jsonStr = JSON.stringify(translated, null, 2);
142
- // Replace the exported object (from `export const X... = {` to end of file)
143
- const newContent = content.replace(
144
- /(export const \w+[^=]*=\s*)\{[\s\S]*$/,
145
- `$1${jsonStr};\n`
146
- );
147
- const finalContent = newContent !== content
148
- ? newContent
149
- : `import type { DocsTranslations } from './en';\n\nexport const ${exportName}: DocsTranslations = ${jsonStr};\n`;
150
- writeLocaleFile(config, targetLocale, finalContent);
151
- consola.success(`Written to ${targetLocale}.ts`);
152
- } else {
153
- writeLocaleFile(config, targetLocale, JSON.stringify(translated, null, 2));
154
- consola.success(`Written to ${targetLocale}.json`);
155
- }
156
-
157
- if (args.json) {
158
- console.log(JSON.stringify(translated, null, 2));
159
- } else {
160
- // Show sample
161
- const sample = JSON.stringify(translated, null, 2).slice(0, 300);
162
- consola.log(sample + (sample.length >= 300 ? '\n...' : ''));
163
- }
164
-
165
- return;
166
- }
167
-
168
- // Translate text
169
- const text = args.text;
170
- if (!text) {
171
- consola.error('Please provide text to translate or use --file flag');
172
- consola.log('');
173
- consola.log('Examples:');
174
- consola.log(' pnpm i18n translate "Hello World" --to ru,ko');
175
- consola.log(' pnpm i18n translate --file --to ru');
176
- consola.log(' pnpm i18n translate ru # Translate en.ts to ru');
177
- return;
178
- }
179
-
180
- consola.info(`Translating: "${text}"`);
181
- consola.log('');
182
-
183
- const translations: Record<string, string> = {
184
- [sourceLocale]: text,
185
- };
186
-
187
- for (const locale of targetLocales) {
188
- try {
189
- const translated = await translateText(text, locale, sourceLocale);
190
- translations[locale] = translated;
191
- consola.log(` ${locale}: ${translated}`);
192
- } catch (error) {
193
- consola.warn(` ${locale}: [FAILED] ${error instanceof Error ? error.message : error}`);
194
- }
195
- }
196
-
197
- consola.log('');
198
- if (args.json) {
199
- console.log(JSON.stringify(translations, null, 2));
200
- } else {
201
- consola.log('Copy-paste JSON:');
202
- console.log(JSON.stringify(translations));
203
- }
204
- } catch (error) {
205
- consola.error(error);
206
- }
207
- },
208
- });
@@ -1,97 +0,0 @@
1
- /**
2
- * LLM Translator utility for i18n CLI
3
- *
4
- * Uses @djangocfg/llm for translations
5
- */
6
-
7
- import { createLLMClient, createTranslator, type JsonTranslator } from '@djangocfg/llm';
8
-
9
- /** Default API key for testing */
10
- const DEFAULT_API_KEY = 'test-api-key';
11
-
12
- let translator: JsonTranslator | null = null;
13
-
14
- /**
15
- * Get or create translator instance
16
- */
17
- export function getTranslator(): JsonTranslator {
18
- if (!translator) {
19
- // Use env key or default test key
20
- const apiKey = process.env.SDKROUTER_API_KEY ||
21
- process.env.OPENAI_API_KEY ||
22
- process.env.ANTHROPIC_API_KEY ||
23
- DEFAULT_API_KEY;
24
-
25
- const llm = createLLMClient({
26
- provider: 'sdkrouter',
27
- apiKey
28
- });
29
- translator = createTranslator(llm);
30
- }
31
- return translator;
32
- }
33
-
34
- /**
35
- * Translate text to target language
36
- */
37
- export async function translateText(
38
- text: string,
39
- targetLocale: string,
40
- sourceLocale: string = 'en'
41
- ): Promise<string> {
42
- const t = getTranslator();
43
- return t.translateText(text, targetLocale, { sourceLanguage: sourceLocale });
44
- }
45
-
46
- /**
47
- * Translate JSON object to target language
48
- */
49
- export async function translateJson<T extends Record<string, unknown>>(
50
- data: T,
51
- targetLocale: string,
52
- sourceLocale: string = 'en'
53
- ): Promise<T> {
54
- const t = getTranslator();
55
- const result = await t.translate(data, targetLocale, { sourceLanguage: sourceLocale });
56
- return result.data;
57
- }
58
-
59
- /**
60
- * Translate to multiple languages in parallel
61
- */
62
- export async function translateToMany<T extends Record<string, unknown>>(
63
- data: T,
64
- targetLocales: string[],
65
- sourceLocale: string = 'en'
66
- ): Promise<Map<string, T>> {
67
- const t = getTranslator();
68
- const results = await t.translateToMany(data, targetLocales, { sourceLanguage: sourceLocale });
69
-
70
- const output = new Map<string, T>();
71
- for (const [locale, result] of results) {
72
- output.set(locale, result.data);
73
- }
74
- return output;
75
- }
76
-
77
- /**
78
- * Get translator stats
79
- */
80
- export function getTranslatorStats(): {
81
- memorySize: number;
82
- hits: number;
83
- misses: number;
84
- languagePairs: Array<{ pair: string; translations: number }>;
85
- } | null {
86
- if (!translator) return null;
87
- return translator.getStats();
88
- }
89
-
90
- /**
91
- * Clear translator cache
92
- */
93
- export function clearTranslatorCache() {
94
- if (translator) {
95
- translator.clearCache();
96
- }
97
- }