docs-i18n 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ import {
2
+ false_default
3
+ } from "./chunk-O35QHRY6.js";
4
+ import "./chunk-AKLW2MUS.js";
5
+ export {
6
+ false_default as default
7
+ };
@@ -0,0 +1,258 @@
1
+ /**
2
+ * docs-i18n configuration schema.
3
+ * Each project provides a `docs-i18n.config.ts` file.
4
+ */
5
+ interface ProjectConfig {
6
+ /** Map of version → source directory (relative to project root) */
7
+ sources: Record<string, string>;
8
+ }
9
+ interface DocsI18nConfig {
10
+ /** Project definitions — key is project ID */
11
+ projects: Record<string, ProjectConfig>;
12
+ /** Languages to translate to */
13
+ languages: string[];
14
+ /** Cache/database directory (default: '.cache') */
15
+ cacheDir?: string;
16
+ /** Frontmatter fields to translate (supports dot notation for nested) */
17
+ translatableFields?: string[];
18
+ /** LLM configuration */
19
+ llm?: {
20
+ provider?: 'openrouter' | 'openai' | 'anthropic';
21
+ model?: string;
22
+ contextLength?: number;
23
+ maxTokens?: number;
24
+ };
25
+ /** Project context injected into LLM system prompt */
26
+ context?: string;
27
+ /** File patterns to include (default: ['**\/*.mdx', '**\/*.md']) */
28
+ include?: string[];
29
+ /** Hook called after translation completes */
30
+ onTranslated?: (info: {
31
+ project: string;
32
+ version: string;
33
+ lang: string;
34
+ }) => Promise<void>;
35
+ }
36
+ declare function defineConfig(config: DocsI18nConfig): DocsI18nConfig;
37
+ /** Load config from file */
38
+ declare function loadConfig(path?: string): Promise<DocsI18nConfig>;
39
+ /** Flatten projects into version entries (project/version → source path) */
40
+ declare function flattenSources(config: DocsI18nConfig): Array<{
41
+ project: string;
42
+ version: string;
43
+ sourcePath: string;
44
+ /** Compound key for DB: "project/version" or just "version" if single project */
45
+ versionKey: string;
46
+ }>;
47
+
48
+ interface ParsedNode {
49
+ /** AST node type: paragraph, heading, code, list, blockquote, html, thematicBreak */
50
+ type: string;
51
+ /** Raw text content extracted from the original (normalized) content */
52
+ rawText: string;
53
+ /** Whether this node contains text that needs translation */
54
+ needsTranslation: boolean;
55
+ /** MD5 hash of the content (only set for translatable nodes) */
56
+ md5?: string;
57
+ /** Start offset in the normalized content */
58
+ startOffset: number;
59
+ /** End offset in the normalized content */
60
+ endOffset: number;
61
+ }
62
+ /**
63
+ * Parse MDX content into a flat list of classified AST nodes.
64
+ * Applies normalize() preprocessing before parsing.
65
+ *
66
+ * Frontmatter (---\n...\n---) is detected and emitted as a single
67
+ * "frontmatter" node spanning from the opening --- to closing ---.
68
+ */
69
+ declare function parseMdx(rawContent: string): ParsedNode[];
70
+
71
+ interface SqliteStatement {
72
+ run(...params: unknown[]): {
73
+ changes: number;
74
+ lastInsertRowid: number;
75
+ };
76
+ get(...params: unknown[]): unknown;
77
+ all(...params: unknown[]): unknown[];
78
+ }
79
+ interface SqliteDatabase {
80
+ prepare(sql: string): SqliteStatement;
81
+ exec(sql: string): void;
82
+ pragma(pragma: string): unknown;
83
+ transaction<T>(fn: () => T): () => T;
84
+ close(): void;
85
+ }
86
+
87
+ interface CacheEntry {
88
+ v: string;
89
+ /** Source locations: "relative/path/to/file.mdx:lineNumber" */
90
+ src: string[];
91
+ }
92
+ /**
93
+ * Translation cache backed by SQLite.
94
+ *
95
+ * Schema:
96
+ * sources(key PK, text, type) — EN source texts
97
+ * source_files(key, file, line, version) — which files use each source node
98
+ * translations(lang, key, value, ...) — translated texts per language
99
+ *
100
+ * All writes are immediate (no separate save step).
101
+ * WAL mode enables concurrent readers + single writer.
102
+ */
103
+ declare class TranslationCache {
104
+ db: SqliteDatabase;
105
+ private cacheDir;
106
+ private _stmts?;
107
+ constructor(cacheDir: string);
108
+ private get stmts();
109
+ /**
110
+ * Load cache for a language. No-op for SQLite (data is always available).
111
+ * Kept for API compatibility.
112
+ */
113
+ load(_lang: string): void;
114
+ /**
115
+ * Save cache for a language. No-op for SQLite (writes are immediate).
116
+ * Kept for API compatibility.
117
+ */
118
+ save(_lang: string): void;
119
+ /** Get a cached translation */
120
+ get(lang: string, md5: string): string | undefined;
121
+ /** Set a cached translation (writes immediately to disk) */
122
+ set(lang: string, md5: string, translation: string): void;
123
+ /**
124
+ * Set a cached translation with its EN source text.
125
+ * This also stores the source in the `sources` table for dashboard use.
126
+ */
127
+ setWithSource(lang: string, md5: string, translation: string, sourceText: string, sourceType?: string): void;
128
+ /** Delete a cached translation */
129
+ delete(lang: string, md5: string): boolean;
130
+ /** Iterate all entries for a language */
131
+ entries(lang: string): IterableIterator<[string, CacheEntry]>;
132
+ /** Get all cached keys for a language as a Set (fast for coverage checks) */
133
+ keys(lang: string): Set<string>;
134
+ /** Remove entries not in the provided set of md5s */
135
+ prune(lang: string, usedMd5s: Set<string>): number;
136
+ /** Get cache stats for a language */
137
+ stats(lang: string): {
138
+ size: number;
139
+ };
140
+ /**
141
+ * Update source locations for a md5 hash.
142
+ * In SQLite mode, this inserts into source_files table.
143
+ */
144
+ updateSource(_lang: string, md5: string, filePath: string, line: number, version?: string): void;
145
+ /** Clear all source file mappings for a version (call before a full rebuild) */
146
+ clearSources(_lang: string, version?: string): void;
147
+ /** Store an EN source text in the sources table */
148
+ setSource(md5: string, text: string, type?: string): void;
149
+ /** Get an EN source text from the sources table */
150
+ getSource(md5: string): {
151
+ text: string;
152
+ type: string;
153
+ } | undefined;
154
+ /**
155
+ * Get all untranslated source keys for a language and version.
156
+ * Returns keys with their EN source text and type.
157
+ */
158
+ untranslatedKeys(lang: string, version?: string, limit?: number, files?: string[]): {
159
+ key: string;
160
+ text: string;
161
+ type: string;
162
+ }[];
163
+ /** Get translation stats for all languages */
164
+ allLangStats(): {
165
+ lang: string;
166
+ count: number;
167
+ }[];
168
+ /**
169
+ * Get file-level coverage for a version and language.
170
+ * Returns how many source nodes each file has and how many are translated.
171
+ */
172
+ fileCoverage(version: string, lang: string): {
173
+ file: string;
174
+ total: number;
175
+ translated: number;
176
+ }[];
177
+ /**
178
+ * Get node-level detail for a specific file: EN source + translation side by side.
179
+ */
180
+ fileDetail(version: string, lang: string, file: string): {
181
+ key: string;
182
+ source: string;
183
+ type: string;
184
+ translation: string | null;
185
+ line: number;
186
+ }[];
187
+ /** Get total source node count for a version */
188
+ sourceCount(version: string): number;
189
+ /**
190
+ * Get section-level stats for a version and language.
191
+ * Section is derived from file path prefix (docs/, blog/, learn/).
192
+ */
193
+ sectionStats(version: string, lang: string): {
194
+ section: string;
195
+ totalFiles: number;
196
+ translatedFiles: number;
197
+ totalNodes: number;
198
+ translatedNodes: number;
199
+ }[];
200
+ /** Export cache to JSONL format (for backward compatibility / git tracking) */
201
+ exportJsonl(lang: string, outputPath: string): number;
202
+ /** Import translations from a JSONL file */
203
+ importJsonl(lang: string, inputPath: string): number;
204
+ /** Export a readable markdown index for IDE navigation */
205
+ exportIndex(lang: string): void;
206
+ /** Close the database connection */
207
+ close(): void;
208
+ }
209
+
210
+ interface AssembleResult {
211
+ /** The assembled file content */
212
+ content: string;
213
+ /** Whether all translatable nodes were found in cache */
214
+ allCached: boolean;
215
+ /** Number of translatable nodes found in cache */
216
+ cachedCount: number;
217
+ /** Number of translatable nodes not in cache */
218
+ uncachedCount: number;
219
+ /** Total number of translatable nodes */
220
+ totalTranslatable: number;
221
+ /** The parsed nodes for reference */
222
+ parsedNodes: ParsedNode[];
223
+ }
224
+ /**
225
+ * Assemble a target-language file from source content + translation cache.
226
+ *
227
+ * - Cached translations replace the original text
228
+ * - Uncached nodes are wrapped in NEEDS_TRANSLATION markers
229
+ * - Code, HTML tags, thematicBreak are kept as-is
230
+ */
231
+ declare function assemble(rawContent: string, lang: string, cache: TranslationCache,
232
+ /** Relative file path for source tracking (e.g. "docs/01-app/installation.mdx") */
233
+ sourceFilePath?: string,
234
+ /** If true, use EN source text as fallback instead of NEEDS_TRANSLATION markers */
235
+ fallbackToSource?: boolean): AssembleResult;
236
+
237
+ /**
238
+ * Extract translatable fields from frontmatter YAML.
239
+ * Supports dot notation for nested fields (e.g. "related.title").
240
+ * Returns a map of field path → value (only string fields).
241
+ */
242
+ declare function extractTranslatableFields(frontmatterText: string): Record<string, string>;
243
+ /**
244
+ * Reconstruct frontmatter with translated fields.
245
+ * Supports dot notation for nested fields.
246
+ * Preserves all non-translated fields and YAML formatting.
247
+ */
248
+ declare function reconstructFrontmatter(frontmatterText: string, translatedFields: Record<string, string>): string;
249
+
250
+ /**
251
+ * Preprocess MDX content to ensure JSX tags (<AppOnly>, <PagesOnly>, <details>, <div>)
252
+ * are separated from surrounding content by blank lines.
253
+ * This ensures remark parses them as independent HTML nodes,
254
+ * not merged with adjacent text content.
255
+ */
256
+ declare function normalize(content: string): string;
257
+
258
+ export { type DocsI18nConfig, type ProjectConfig, TranslationCache, assemble, defineConfig, extractTranslatableFields, flattenSources, loadConfig, normalize, parseMdx, reconstructFrontmatter };