vite-plugin-ai-auto-i18n 0.3.1 → 0.4.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/dist/cli/prune.d.ts +1 -2
- package/dist/cli/prune.js +1 -74
- package/dist/index.d.ts +94 -99
- package/dist/index.js +4 -758
- package/dist/registry-Cj5gJsxW.js +2 -0
- package/dist/resolve-ELDMKdoA.js +1 -0
- package/dist/runtime/index.d.ts +6 -8
- package/dist/runtime/index.js +1 -8
- package/package.json +23 -18
- package/dist/chunk-LLL7ZSKW.js +0 -169
- package/dist/chunk-ZDZ3YVET.js +0 -38
package/dist/cli/prune.d.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { }
|
|
1
|
+
export {}
|
package/dist/cli/prune.js
CHANGED
|
@@ -1,74 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DEFAULT_ORPHAN_RETENTION_MINUTES,
|
|
3
|
-
debugLog,
|
|
4
|
-
loadRegistry,
|
|
5
|
-
pruneCatalog,
|
|
6
|
-
pruneOrphans,
|
|
7
|
-
readLocaleFile,
|
|
8
|
-
saveRegistry,
|
|
9
|
-
writeLocaleFile
|
|
10
|
-
} from "../chunk-LLL7ZSKW.js";
|
|
11
|
-
|
|
12
|
-
// src/cli/prune.ts
|
|
13
|
-
import { existsSync } from "fs";
|
|
14
|
-
import { readdir } from "fs/promises";
|
|
15
|
-
import path from "path";
|
|
16
|
-
async function pruneLocaleFiles(localesDir, activeIds) {
|
|
17
|
-
if (!existsSync(localesDir)) return [];
|
|
18
|
-
const results = [];
|
|
19
|
-
for (const name of await readdir(localesDir)) {
|
|
20
|
-
if (!name.endsWith(".json")) continue;
|
|
21
|
-
const file = path.join(localesDir, name);
|
|
22
|
-
const current = await readLocaleFile(file, (message) => console.warn(message));
|
|
23
|
-
const messages = pruneCatalog(current.messages, activeIds);
|
|
24
|
-
const sources = pruneCatalog(current.sources, activeIds);
|
|
25
|
-
const removed = [.../* @__PURE__ */ new Set([...messages.removed, ...sources.removed])];
|
|
26
|
-
if (!removed.length) continue;
|
|
27
|
-
await writeLocaleFile(file, { messages: messages.catalog, sources: sources.catalog });
|
|
28
|
-
results.push({ file, removed });
|
|
29
|
-
}
|
|
30
|
-
return results;
|
|
31
|
-
}
|
|
32
|
-
function parseArgs(argv) {
|
|
33
|
-
const args = { directory: ".autoi18n", retentionMinutes: DEFAULT_ORPHAN_RETENTION_MINUTES, debug: false };
|
|
34
|
-
for (let i = 0; i < argv.length; i++) {
|
|
35
|
-
const arg = argv[i];
|
|
36
|
-
if (arg === "--debug") {
|
|
37
|
-
args.debug = true;
|
|
38
|
-
} else if (arg === "--directory" || arg === "--retention-minutes") {
|
|
39
|
-
const value = argv[++i];
|
|
40
|
-
if (value === void 0) throw new Error(`${arg} needs a value`);
|
|
41
|
-
if (arg === "--directory") args.directory = value;
|
|
42
|
-
else args.retentionMinutes = Number(value);
|
|
43
|
-
} else {
|
|
44
|
-
throw new Error(`Unknown option ${arg}`);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (!(args.retentionMinutes >= 0)) throw new Error("--retention-minutes must be a number of minutes, 0 or more");
|
|
48
|
-
return args;
|
|
49
|
-
}
|
|
50
|
-
async function main() {
|
|
51
|
-
const args = parseArgs(process.argv.slice(2));
|
|
52
|
-
const registryFile = path.resolve(process.cwd(), args.directory, "registry.json");
|
|
53
|
-
if (!existsSync(registryFile)) {
|
|
54
|
-
console.log(`autoi18n: no registry found at ${registryFile}; nothing to prune.`);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const registry = await loadRegistry(registryFile, (message) => console.warn(message));
|
|
58
|
-
const removed = pruneOrphans(registry, args.retentionMinutes);
|
|
59
|
-
if (removed.length) await saveRegistry(registryFile, registry);
|
|
60
|
-
const activeIds = new Set(Object.values(registry.entries).filter((entry) => entry.status === "active").map((entry) => entry.id));
|
|
61
|
-
const catalogs = await pruneLocaleFiles(path.join(path.dirname(registryFile), "locales"), activeIds);
|
|
62
|
-
if (args.debug) {
|
|
63
|
-
for (const entry of removed) debugLog(`removed ${entry.id} ${JSON.stringify(entry.source)} (last seen ${entry.lastSeen})`);
|
|
64
|
-
for (const { file, removed: ids } of catalogs) {
|
|
65
|
-
for (const id of ids) debugLog(`removed ${id} from ${file}`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
console.log(`autoi18n: removed ${removed.length} registry entries orphaned for more than ${args.retentionMinutes} minutes.`);
|
|
69
|
-
if (catalogs.length) console.log(`autoi18n: removed stale keys from ${catalogs.length} locale files.`);
|
|
70
|
-
}
|
|
71
|
-
main().catch((error) => {
|
|
72
|
-
console.error(`autoi18n: ${error.message}`);
|
|
73
|
-
process.exitCode = 1;
|
|
74
|
-
});
|
|
1
|
+
import{a as e,c as t,h as n,l as r,n as i,r as a,t as o,u as s}from"../registry-Cj5gJsxW.js";import{readdir as c}from"node:fs/promises";import l from"node:path";import{existsSync as u}from"node:fs";async function d(e,n){if(!u(e))return[];let i=[];for(let a of await c(e)){if(!a.endsWith(`.json`))continue;let o=l.join(e,a),c=await r(o,e=>console.warn(e)),u=t(c.messages,n),d=t(c.sources,n),f=[.../* @__PURE__ */ new Set([...u.removed,...d.removed])];f.length&&(await s(o,{messages:u.catalog,sources:d.catalog}),i.push({file:o,removed:f}))}return i}function f(e){let t={directory:`.autoi18n`,retentionMinutes:o,debug:!1};for(let n=0;n<e.length;n++){let r=e[n];if(r===`--debug`)t.debug=!0;else if(r===`--directory`||r===`--retention-minutes`){let i=e[++n];if(i===void 0)throw Error(`${r} needs a value`);r===`--directory`?t.directory=i:t.retentionMinutes=Number(i)}else throw Error(`Unknown option ${r}`)}if(!(t.retentionMinutes>=0))throw Error(`--retention-minutes must be a number of minutes, 0 or more`);return t}async function p(){let t=f(process.argv.slice(2)),r=l.resolve(process.cwd(),t.directory,`registry.json`);if(!u(r)){console.log(`autoi18n: no registry found at ${r}; nothing to prune.`);return}let o=await i(r,e=>console.warn(e)),s=a(o,t.retentionMinutes);s.length&&await e(r,o);let c=new Set(Object.values(o.entries).filter(e=>e.status===`active`).map(e=>e.id)),p=await d(l.join(l.dirname(r),`locales`),c);if(t.debug){for(let e of s)n(`removed ${e.id} ${JSON.stringify(e.source)} (last seen ${e.lastSeen})`);for(let{file:e,removed:t}of p)for(let r of t)n(`removed ${r} from ${e}`)}console.log(`autoi18n: removed ${s.length} registry entries orphaned for more than ${t.retentionMinutes} minutes.`),p.length&&console.log(`autoi18n: removed stale keys from ${p.length} locale files.`)}p().catch(e=>{console.error(`autoi18n: ${e.message}`),process.exitCode=1});export{};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,123 +1,118 @@
|
|
|
1
|
-
import { Plugin } from
|
|
2
|
-
|
|
1
|
+
import { Plugin } from "vite";
|
|
3
2
|
type MessageKind = "text" | "attribute" | "mixed" | "string";
|
|
4
3
|
interface ExtractedMessage {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
4
|
+
source: string;
|
|
5
|
+
prefix?: string;
|
|
6
|
+
suffix?: string;
|
|
7
|
+
kind: MessageKind;
|
|
8
|
+
/** For "mixed" messages: placeholder names in the order of the element's expression children. */
|
|
9
|
+
placeholders?: string[];
|
|
10
|
+
file: string;
|
|
11
|
+
start: number;
|
|
12
|
+
end: number;
|
|
13
|
+
tag: string;
|
|
14
|
+
component: string;
|
|
15
|
+
attribute?: string;
|
|
16
|
+
context: string;
|
|
17
|
+
fingerprint: string;
|
|
19
18
|
}
|
|
20
19
|
/** A message with the stable ID that the registry assigned to it. */
|
|
21
20
|
type ResolvedMessage = ExtractedMessage & {
|
|
22
|
-
|
|
21
|
+
id: string;
|
|
23
22
|
};
|
|
24
23
|
type RegistryEntry = Pick<ExtractedMessage, "source" | "kind" | "tag" | "component" | "attribute" | "context" | "fingerprint"> & {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
id: string;
|
|
25
|
+
location: string;
|
|
26
|
+
status: "active" | "orphaned";
|
|
27
|
+
firstSeen: string;
|
|
28
|
+
lastSeen: string;
|
|
30
29
|
};
|
|
31
30
|
interface Registry {
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
version: 1;
|
|
32
|
+
entries: Record<string, RegistryEntry>;
|
|
34
33
|
}
|
|
35
34
|
type Catalog = Record<string, string>;
|
|
36
35
|
interface TranslationRequest {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
id: string;
|
|
37
|
+
source: string;
|
|
38
|
+
context: string;
|
|
39
|
+
kind: MessageKind;
|
|
40
|
+
placeholders?: string[];
|
|
42
41
|
}
|
|
43
42
|
interface TranslationProvider {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
translate(input: {
|
|
44
|
+
sourceLocale: string;
|
|
45
|
+
targetLocale: string;
|
|
46
|
+
messages: TranslationRequest[];
|
|
47
|
+
}): Promise<Catalog>;
|
|
49
48
|
}
|
|
50
|
-
|
|
51
49
|
/**
|
|
52
50
|
* Some batches of a translation request failed while others succeeded. `partial` holds the translations
|
|
53
51
|
* that did come back, so the caller can keep them and report the rest.
|
|
54
52
|
*/
|
|
55
|
-
declare class PartialTranslationError extends Error {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
export declare class PartialTranslationError extends Error {
|
|
54
|
+
readonly partial: Catalog;
|
|
55
|
+
readonly failed: number;
|
|
56
|
+
constructor(message: string, partial: Catalog, failed: number);
|
|
59
57
|
}
|
|
60
|
-
|
|
61
58
|
interface OpenAICompatibleOptions {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
59
|
+
apiKey: string;
|
|
60
|
+
model: string;
|
|
61
|
+
baseURL?: string;
|
|
62
|
+
/** Messages sent per request. Smaller batches keep responses within output limits. Default 40. */
|
|
63
|
+
batchSize?: number;
|
|
64
|
+
/** Abort a single request after this many milliseconds. Default 60000. */
|
|
65
|
+
timeoutMs?: number;
|
|
66
|
+
/** Extra attempts for network errors, timeouts, 408/409/429/5xx and malformed responses. Default 2. */
|
|
67
|
+
maxRetries?: number;
|
|
68
|
+
/** Base delay before a retry; doubles on each attempt and is jittered. A Retry-After header overrides it (max 60 s). Default 500. */
|
|
69
|
+
retryDelayMs?: number;
|
|
70
|
+
/** Batches sent in parallel. Default 4. */
|
|
71
|
+
concurrency?: number;
|
|
75
72
|
}
|
|
76
|
-
declare class OpenAICompatibleProvider implements TranslationProvider {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
73
|
+
export declare class OpenAICompatibleProvider implements TranslationProvider {
|
|
74
|
+
private options;
|
|
75
|
+
constructor(options: OpenAICompatibleOptions);
|
|
76
|
+
/**
|
|
77
|
+
* Translates in parallel batches. If every batch fails, the first error is thrown. If only some fail,
|
|
78
|
+
* a PartialTranslationError carries the translations that succeeded.
|
|
79
|
+
*/
|
|
80
|
+
translate(input: {
|
|
81
|
+
sourceLocale: string;
|
|
82
|
+
targetLocale: string;
|
|
83
|
+
messages: TranslationRequest[];
|
|
84
|
+
}): Promise<Catalog>;
|
|
85
|
+
private translateBatch;
|
|
86
|
+
private request;
|
|
90
87
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
debug?: boolean;
|
|
88
|
+
export interface AutoI18nOptions {
|
|
89
|
+
locales: string[];
|
|
90
|
+
sourceLocale?: string;
|
|
91
|
+
/**
|
|
92
|
+
* "build" (default) compiles one locale per build. "runtime" ships every catalogue and
|
|
93
|
+
* switches locale in the browser via `setLocale()` from the `virtual:autoi18n` module.
|
|
94
|
+
*/
|
|
95
|
+
delivery?: "build" | "runtime";
|
|
96
|
+
/** Compile this build for one locale. Defaults to sourceLocale; set AUTOI18N_LOCALE for CI matrix builds. */
|
|
97
|
+
locale?: string;
|
|
98
|
+
include?: string[];
|
|
99
|
+
exclude?: string[];
|
|
100
|
+
directory?: string;
|
|
101
|
+
provider?: TranslationProvider;
|
|
102
|
+
failOnMissingProvider?: boolean;
|
|
103
|
+
onAmbiguous?: "warn" | "error";
|
|
104
|
+
/**
|
|
105
|
+
* Minutes an orphaned message (one no longer in the source) is kept in the registry before it is deleted.
|
|
106
|
+
* Default 43200 (30 days). `0` deletes orphans on the next build; `Infinity` keeps them forever.
|
|
107
|
+
*/
|
|
108
|
+
orphanRetentionMinutes?: number;
|
|
109
|
+
/**
|
|
110
|
+
* Locales translated at the same time. Default 2. Batches within a locale are limited separately by
|
|
111
|
+
* `OpenAICompatibleOptions.concurrency`. Lower this if your provider rate-limits per account.
|
|
112
|
+
*/
|
|
113
|
+
localeConcurrency?: number;
|
|
114
|
+
/** Log each message sent to the translation provider and each translation received, with timestamps. Default false. */
|
|
115
|
+
debug?: boolean;
|
|
120
116
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
export { type AutoI18nOptions, type Catalog, type ExtractedMessage, type MessageKind, type OpenAICompatibleOptions, OpenAICompatibleProvider, PartialTranslationError, type Registry, type RegistryEntry, type ResolvedMessage, type TranslationProvider, type TranslationRequest, autoI18n as default };
|
|
117
|
+
export default function autoI18n(options: AutoI18nOptions): Plugin;
|
|
118
|
+
export type { Catalog, ExtractedMessage, MessageKind, OpenAICompatibleOptions, Registry, RegistryEntry, ResolvedMessage, TranslationProvider, TranslationRequest };
|