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.
package/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # docs-i18n
2
+
3
+ Universal documentation translation engine. Parse markdown/MDX into translatable nodes, translate via LLM, cache in SQLite/D1, assemble translated files.
4
+
5
+ ## Features
6
+
7
+ - **AST-based parsing** — splits markdown into translatable nodes with MD5 keys
8
+ - **Incremental translation** — only translates changed/new content
9
+ - **Smart chunking** — respects LLM context window and output token limits
10
+ - **YAML-aware frontmatter** — translates title/description fields individually
11
+ - **SQLite cache** — concurrent-safe with WAL mode, portable to Cloudflare D1
12
+ - **Admin dashboard** — web UI for managing translation progress and jobs
13
+ - **Framework-agnostic** — works with any docs site (Next.js, Astro, TanStack Start, etc.)
14
+
15
+ ## Quick Start
16
+
17
+ ```bash
18
+ npm install docs-i18n
19
+ ```
20
+
21
+ Create `docs-i18n.config.ts`:
22
+
23
+ ```ts
24
+ import { defineConfig } from 'docs-i18n';
25
+
26
+ export default defineConfig({
27
+ projects: {
28
+ mydocs: {
29
+ sources: { latest: 'content/latest' },
30
+ },
31
+ },
32
+ languages: ['zh-hans', 'ja', 'es'],
33
+ context: 'MyProject is a TypeScript library for building web apps.',
34
+ });
35
+ ```
36
+
37
+ ```bash
38
+ # Translate
39
+ docs-i18n translate --lang zh-hans
40
+
41
+ # Check status
42
+ docs-i18n status
43
+
44
+ # Start admin dashboard
45
+ docs-i18n admin
46
+ ```
47
+
48
+ ## Runtime Translation (for SSR sites)
49
+
50
+ ```ts
51
+ import { createTranslator } from 'docs-i18n/serve';
52
+
53
+ const translator = createTranslator();
54
+ const translated = await translator.translate(enMarkdown, 'zh-hans', env.DB);
55
+ ```
56
+
57
+ ## License
58
+
59
+ MIT
@@ -0,0 +1,74 @@
1
+ import {
2
+ assemble
3
+ } from "./chunk-QSVWLTGQ.js";
4
+ import "./chunk-SUIDX6IZ.js";
5
+ import {
6
+ TranslationCache
7
+ } from "./chunk-XEOYZUHS.js";
8
+ import {
9
+ flattenSources
10
+ } from "./chunk-3YNFMSJH.js";
11
+ import "./chunk-AKLW2MUS.js";
12
+
13
+ // src/commands/assemble.ts
14
+ import {
15
+ existsSync,
16
+ mkdirSync,
17
+ readdirSync,
18
+ readFileSync,
19
+ writeFileSync
20
+ } from "fs";
21
+ import { dirname, join, resolve } from "path";
22
+ function walkFiles(dir, extensions) {
23
+ const results = [];
24
+ if (!existsSync(dir)) return results;
25
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
26
+ const fullPath = join(dir, entry.name);
27
+ if (entry.isDirectory()) results.push(...walkFiles(fullPath, extensions));
28
+ else if (extensions.some((ext) => entry.name.endsWith(ext))) results.push(fullPath);
29
+ }
30
+ return results;
31
+ }
32
+ async function assembleAll(config, opts) {
33
+ const cacheDir = resolve(config.cacheDir ?? ".cache");
34
+ const outputBase = resolve(opts.outputDir ?? join(cacheDir, "content"));
35
+ const cache = new TranslationCache(cacheDir);
36
+ const sources = flattenSources(config);
37
+ const langs = opts.lang ? [opts.lang] : config.languages;
38
+ const extensions = (config.include ?? ["**/*.mdx", "**/*.md"]).map(
39
+ (p) => p.replace("**/*", "")
40
+ );
41
+ const t0 = Date.now();
42
+ let totalWritten = 0;
43
+ for (const source of sources) {
44
+ if (opts.project && source.project !== opts.project) continue;
45
+ if (opts.version && source.version !== opts.version) continue;
46
+ const enDir = resolve(source.sourcePath);
47
+ if (!existsSync(enDir)) {
48
+ console.log(`\u26A0 ${source.versionKey}: source dir not found, skipping`);
49
+ continue;
50
+ }
51
+ const enFiles = walkFiles(enDir, extensions);
52
+ for (const lang of langs) {
53
+ let written = 0;
54
+ for (const enFile of enFiles) {
55
+ const relPath = enFile.slice(enDir.length + 1);
56
+ const content = readFileSync(enFile, "utf8");
57
+ const result = assemble(content, lang, cache, relPath, true);
58
+ const outPath = join(outputBase, source.versionKey, lang, relPath);
59
+ mkdirSync(dirname(outPath), { recursive: true });
60
+ writeFileSync(outPath, result.content);
61
+ written++;
62
+ }
63
+ totalWritten += written;
64
+ console.log(`[${source.versionKey}/${lang}] ${written} files`);
65
+ }
66
+ }
67
+ const elapsed = ((Date.now() - t0) / 1e3).toFixed(1);
68
+ console.log(`
69
+ \u2705 Assembled ${totalWritten} files in ${elapsed}s`);
70
+ cache.db.close();
71
+ }
72
+ export {
73
+ assembleAll
74
+ };
@@ -0,0 +1,12 @@
1
+ import {
2
+ createBuilder,
3
+ resolveBuildPlugins
4
+ } from "./chunk-FYDB7MZX.js";
5
+ import "./chunk-PTIH4GGE.js";
6
+ import "./chunk-VKKNQBDN.js";
7
+ import "./chunk-O35QHRY6.js";
8
+ import "./chunk-AKLW2MUS.js";
9
+ export {
10
+ createBuilder,
11
+ resolveBuildPlugins
12
+ };