better-translation 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,32 @@
1
+ //#region src/message-id.ts
2
+ function normalizeMeta(meta) {
3
+ if (!meta) return {};
4
+ return Object.fromEntries(Object.entries(meta).filter(([key, value]) => key !== "id" && value !== void 0).sort(([a], [b]) => a.localeCompare(b)));
5
+ }
6
+ function serializeMeta(meta) {
7
+ if (!meta) return "";
8
+ const normalized = normalizeMeta(meta);
9
+ return Object.keys(normalized).length > 0 ? JSON.stringify(normalized) : "";
10
+ }
11
+ function getMessageIdentity(message, meta) {
12
+ const serializedMeta = serializeMeta(meta);
13
+ return serializedMeta ? `${message}\0${serializedMeta}` : message;
14
+ }
15
+ /** Generates the stable hashed id used to store and look up a translated message. */
16
+ function getMessageId(message, meta) {
17
+ const value = getMessageIdentity(message, meta);
18
+ let hash = 2166136261;
19
+ for (let i = 0; i < value.length; i++) {
20
+ hash ^= value.charCodeAt(i);
21
+ hash = Math.imul(hash, 16777619);
22
+ }
23
+ return `m_${(hash >>> 0).toString(36)}`;
24
+ }
25
+ /** Resolves the lookup id for function-style `t()` calls, preferring an explicit `options.id`. */
26
+ function getCallMessageId(message, options) {
27
+ return options?.id ?? getMessageId(message, options);
28
+ }
29
+ //#endregion
30
+ export { getMessageId as n, serializeMeta as r, getCallMessageId as t };
31
+
32
+ //# sourceMappingURL=message-id-7Mx7G9xT.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-id-7Mx7G9xT.mjs","names":[],"sources":["../src/message-id.ts"],"sourcesContent":["import type { TranslateOptions } from \"./types.js\"\n\nexport function normalizeMeta(meta?: TranslateOptions): TranslateOptions {\n if (!meta) return {}\n\n return Object.fromEntries(\n Object.entries(meta)\n .filter(([key, value]) => key !== \"id\" && value !== undefined)\n .sort(([a], [b]) => a.localeCompare(b)),\n ) as TranslateOptions\n}\n\nexport function serializeMeta(meta?: TranslateOptions) {\n if (!meta) return \"\"\n\n const normalized = normalizeMeta(meta)\n return Object.keys(normalized).length > 0 ? JSON.stringify(normalized) : \"\"\n}\n\nexport function getMessageIdentity(message: string, meta?: TranslateOptions) {\n const serializedMeta = serializeMeta(meta)\n return serializedMeta ? `${message}\\0${serializedMeta}` : message\n}\n\n/** Generates the stable hashed id used to store and look up a translated message. */\nexport function getMessageId(message: string, meta?: TranslateOptions) {\n const value = getMessageIdentity(message, meta)\n let hash = 2166136261\n\n for (let i = 0; i < value.length; i++) {\n hash ^= value.charCodeAt(i)\n hash = Math.imul(hash, 16777619)\n }\n\n return `m_${(hash >>> 0).toString(36)}`\n}\n\n/** Resolves the lookup id for function-style `t()` calls, preferring an explicit `options.id`. */\nexport function getCallMessageId(message: string, options?: TranslateOptions) {\n return options?.id ?? getMessageId(message, options)\n}\n"],"mappings":";AAEA,SAAgB,cAAc,MAA2C;AACvE,KAAI,CAAC,KAAM,QAAO,EAAE;AAEpB,QAAO,OAAO,YACZ,OAAO,QAAQ,KAAK,CACjB,QAAQ,CAAC,KAAK,WAAW,QAAQ,QAAQ,UAAU,KAAA,EAAU,CAC7D,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC,CAC1C;;AAGH,SAAgB,cAAc,MAAyB;AACrD,KAAI,CAAC,KAAM,QAAO;CAElB,MAAM,aAAa,cAAc,KAAK;AACtC,QAAO,OAAO,KAAK,WAAW,CAAC,SAAS,IAAI,KAAK,UAAU,WAAW,GAAG;;AAG3E,SAAgB,mBAAmB,SAAiB,MAAyB;CAC3E,MAAM,iBAAiB,cAAc,KAAK;AAC1C,QAAO,iBAAiB,GAAG,QAAQ,IAAI,mBAAmB;;;AAI5D,SAAgB,aAAa,SAAiB,MAAyB;CACrE,MAAM,QAAQ,mBAAmB,SAAS,KAAK;CAC/C,IAAI,OAAO;AAEX,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAQ,MAAM,WAAW,EAAE;AAC3B,SAAO,KAAK,KAAK,MAAM,SAAS;;AAGlC,QAAO,MAAM,SAAS,GAAG,SAAS,GAAG;;;AAIvC,SAAgB,iBAAiB,SAAiB,SAA4B;AAC5E,QAAO,SAAS,MAAM,aAAa,SAAS,QAAQ"}
@@ -0,0 +1,45 @@
1
+ import { u as TranslateOptions } from "./types-Di93oTw4.mjs";
2
+ import { ReactNode } from "react";
3
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
4
+
5
+ //#region src/react.d.ts
6
+ /** Props for `TranslateProvider`. */
7
+ interface TranslateProviderProps {
8
+ /** Flattened locale message map keyed by stable message id. */
9
+ messages: Record<string, string>;
10
+ /** React subtree that should have access to translations. */
11
+ children: ReactNode;
12
+ }
13
+ /** Provides translated messages to React components below it. */
14
+ declare function TranslateProvider({
15
+ messages,
16
+ children
17
+ }: TranslateProviderProps): _$react_jsx_runtime0.JSX.Element;
18
+ /** Returns the raw locale message map from the current provider. */
19
+ declare function useMessages(): Record<string, string>;
20
+ /** Returns a translator function for text used in props, labels, and other non-JSX positions. */
21
+ declare function useT(): (message: string, options?: TranslateOptions) => string;
22
+ /** Props for `Var`. */
23
+ type VarProps = {
24
+ /** Optional shorthand child form, normalized at build time for simple identifiers. */children?: ReactNode;
25
+ } & Record<string, ReactNode | undefined>;
26
+ /** Marks a runtime value for placeholder interpolation inside `<T>` content. */
27
+ declare function Var(props: VarProps): _$react_jsx_runtime0.JSX.Element;
28
+ /** Props for `T`. */
29
+ interface TProps {
30
+ /** Explicit stable id to use instead of hashing the rendered source text, whether provided manually or by a transform. */
31
+ id?: string;
32
+ /** Extra disambiguating context for translators and custom grouping. */
33
+ context?: string;
34
+ /** Source-language JSX content to translate. */
35
+ children?: ReactNode;
36
+ }
37
+ /** Renders translated JSX content and supports placeholders through `<Var>`. */
38
+ declare function T({
39
+ id,
40
+ context,
41
+ children
42
+ }: TProps): _$react_jsx_runtime0.JSX.Element;
43
+ //#endregion
44
+ export { T, TProps, TranslateProvider, TranslateProviderProps, Var, VarProps, useMessages, useT };
45
+ //# sourceMappingURL=react.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.d.mts","names":[],"sources":["../src/react.tsx"],"mappings":";;;;;;UAaiB,sBAAA;;EAEf,QAAA,EAAU,MAAA;EAF2B;EAIrC,QAAA,EAAU,SAAA;AAAA;;iBAII,iBAAA,CAAA;EAAoB,QAAA;EAAU;AAAA,GAAY,sBAAA,GAAsB,oBAAA,CAAA,GAAA,CAAA,OAAA;;iBAMhE,WAAA,CAAA,GAAW,MAAA;;iBAOX,IAAA,CAAA,IAAS,OAAA,UAAiB,OAAA,GAAU,gBAAA;AAbpD;AAAA,KAmBY,QAAA;wFAEV,QAAA,GAAW,SAAA;AAAA,IACT,MAAA,SAAe,SAAA;;iBAGH,GAAA,CAAI,KAAA,EAAO,QAAA,GAAQ,oBAAA,CAAA,GAAA,CAAA,OAAA;;UAKlB,MAAA;EA9BmB;EAgClC,EAAA;EAhC4C;EAkC5C,OAAA;EAlCwD;EAoCxD,QAAA,GAAW,SAAA;AAAA;;iBAIG,CAAA,CAAA;EAAI,EAAA;EAAI,OAAA;EAAS;AAAA,GAAY,MAAA,GAAM,oBAAA,CAAA,GAAA,CAAA,OAAA"}
package/dist/react.mjs ADDED
@@ -0,0 +1,91 @@
1
+ import { n as getMessageId, t as getCallMessageId } from "./message-id-7Mx7G9xT.mjs";
2
+ import { Children, createContext, isValidElement, useContext, useMemo } from "react";
3
+ import { Fragment, jsx } from "react/jsx-runtime";
4
+ //#region src/react.tsx
5
+ const TranslateContext = createContext({ messages: {} });
6
+ /** Provides translated messages to React components below it. */
7
+ function TranslateProvider({ messages, children }) {
8
+ const value = useMemo(() => ({ messages }), [messages]);
9
+ return /* @__PURE__ */ jsx(TranslateContext.Provider, {
10
+ value,
11
+ children
12
+ });
13
+ }
14
+ /** Returns the raw locale message map from the current provider. */
15
+ function useMessages() {
16
+ return useContext(TranslateContext).messages;
17
+ }
18
+ /** Returns a translator function for text used in props, labels, and other non-JSX positions. */
19
+ function useT() {
20
+ const { messages } = useContext(TranslateContext);
21
+ return useMemo(() => (message, options) => messages[getCallMessageId(message, options)] ?? message, [messages]);
22
+ }
23
+ /** Marks a runtime value for placeholder interpolation inside `<T>` content. */
24
+ function Var(props) {
25
+ return /* @__PURE__ */ jsx(Fragment, { children: getRuntimeVarEntry(props)?.value ?? props.children });
26
+ }
27
+ /** Renders translated JSX content and supports placeholders through `<Var>`. */
28
+ function T({ id, context, children }) {
29
+ const { messages } = useContext(TranslateContext);
30
+ const resolvedMeta = context ? { context } : void 0;
31
+ const runtimeContent = useMemo(() => extractRuntimeContent(children), [children]);
32
+ const template = messages[id ?? (runtimeContent.message ? getMessageId(runtimeContent.message, resolvedMeta) : "")];
33
+ const vars = template?.includes("{") ? runtimeContent.vars : void 0;
34
+ const interpolated = useMemo(() => interpolate(template, vars), [template, vars]);
35
+ if (!template) return /* @__PURE__ */ jsx(Fragment, { children });
36
+ if (!vars) return /* @__PURE__ */ jsx(Fragment, { children: template });
37
+ if (!interpolated.length) return /* @__PURE__ */ jsx(Fragment, { children });
38
+ return /* @__PURE__ */ jsx(Fragment, { children: interpolated });
39
+ }
40
+ function interpolate(template, vars) {
41
+ if (!template || !vars) return [];
42
+ const result = [];
43
+ const re = /\{(\w+)\}/g;
44
+ let lastIndex = 0;
45
+ let match;
46
+ while ((match = re.exec(template)) !== null) {
47
+ if (match.index > lastIndex) result.push(template.slice(lastIndex, match.index));
48
+ result.push(vars[match[1]] ?? `{${match[1]}}`);
49
+ lastIndex = re.lastIndex;
50
+ }
51
+ if (lastIndex < template.length) result.push(template.slice(lastIndex));
52
+ return result;
53
+ }
54
+ function extractRuntimeContent(children) {
55
+ const parts = [];
56
+ const vars = {};
57
+ Children.forEach(children, (child) => {
58
+ if (typeof child === "string" || typeof child === "number") {
59
+ parts.push(String(child));
60
+ return;
61
+ }
62
+ if (isValidElement(child) && child.type === Var) {
63
+ const entry = getRuntimeVarEntry(child.props);
64
+ if (entry) {
65
+ parts.push(`{${entry.name}}`);
66
+ vars[entry.name] = entry.value;
67
+ }
68
+ }
69
+ });
70
+ return {
71
+ message: parts.join("").replace(/\s+/g, " ").trim(),
72
+ vars: Object.keys(vars).length > 0 ? vars : void 0
73
+ };
74
+ }
75
+ function getRuntimeVarEntry(props) {
76
+ if (typeof props.name === "string" && props.children !== void 0) return {
77
+ name: props.name,
78
+ value: props.children
79
+ };
80
+ const entries = Object.entries(props).filter(([key]) => key !== "children");
81
+ if (entries.length !== 1) return void 0;
82
+ const [name, value] = entries[0];
83
+ return {
84
+ name,
85
+ value
86
+ };
87
+ }
88
+ //#endregion
89
+ export { T, TranslateProvider, Var, useMessages, useT };
90
+
91
+ //# sourceMappingURL=react.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.mjs","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import { Children, createContext, isValidElement, useContext, useMemo, type ReactNode } from \"react\"\n\nimport type { TranslateOptions } from \"./types.js\"\n\nimport { getCallMessageId, getMessageId } from \"./message-id.js\"\n\ninterface TranslateContextValue {\n messages: Record<string, string>\n}\n\nconst TranslateContext = createContext<TranslateContextValue>({ messages: {} })\n\n/** Props for `TranslateProvider`. */\nexport interface TranslateProviderProps {\n /** Flattened locale message map keyed by stable message id. */\n messages: Record<string, string>\n /** React subtree that should have access to translations. */\n children: ReactNode\n}\n\n/** Provides translated messages to React components below it. */\nexport function TranslateProvider({ messages, children }: TranslateProviderProps) {\n const value = useMemo(() => ({ messages }), [messages])\n return <TranslateContext.Provider value={value}>{children}</TranslateContext.Provider>\n}\n\n/** Returns the raw locale message map from the current provider. */\nexport function useMessages() {\n return useContext(TranslateContext).messages\n}\n\ntype TranslateFn = (id: string, options?: TranslateOptions) => string\n\n/** Returns a translator function for text used in props, labels, and other non-JSX positions. */\nexport function useT(): (message: string, options?: TranslateOptions) => string {\n const { messages } = useContext(TranslateContext)\n return useMemo<TranslateFn>(() => (message, options) => messages[getCallMessageId(message, options)] ?? message, [messages])\n}\n\n/** Props for `Var`. */\nexport type VarProps = {\n /** Optional shorthand child form, normalized at build time for simple identifiers. */\n children?: ReactNode\n} & Record<string, ReactNode | undefined>\n\n/** Marks a runtime value for placeholder interpolation inside `<T>` content. */\nexport function Var(props: VarProps) {\n return <>{getRuntimeVarEntry(props)?.value ?? props.children}</>\n}\n\n/** Props for `T`. */\nexport interface TProps {\n /** Explicit stable id to use instead of hashing the rendered source text, whether provided manually or by a transform. */\n id?: string\n /** Extra disambiguating context for translators and custom grouping. */\n context?: string\n /** Source-language JSX content to translate. */\n children?: ReactNode\n}\n\n/** Renders translated JSX content and supports placeholders through `<Var>`. */\nexport function T({ id, context, children }: TProps) {\n const { messages } = useContext(TranslateContext)\n const resolvedMeta = context ? { context } : undefined\n const runtimeContent = useMemo(() => extractRuntimeContent(children), [children])\n const template = messages[id ?? (runtimeContent.message ? getMessageId(runtimeContent.message, resolvedMeta) : \"\")]\n const vars = template?.includes(\"{\") ? runtimeContent.vars : undefined\n const interpolated = useMemo(() => interpolate(template, vars), [template, vars])\n\n if (!template) return <>{children}</>\n if (!vars) return <>{template}</>\n if (!interpolated.length) return <>{children}</>\n return <>{interpolated}</>\n}\n\nfunction interpolate(template?: string, vars?: Record<string, ReactNode>): ReactNode[] {\n if (!template || !vars) return []\n const result: ReactNode[] = []\n const re = /\\{(\\w+)\\}/g\n let lastIndex = 0\n let match: RegExpExecArray | null\n\n while ((match = re.exec(template)) !== null) {\n if (match.index > lastIndex) result.push(template.slice(lastIndex, match.index))\n result.push(vars[match[1]!] ?? `{${match[1]}}`)\n lastIndex = re.lastIndex\n }\n\n if (lastIndex < template.length) result.push(template.slice(lastIndex))\n return result\n}\n\nfunction extractRuntimeContent(children: ReactNode) {\n const parts: string[] = []\n const vars: Record<string, ReactNode> = {}\n\n Children.forEach(children, (child) => {\n if (typeof child === \"string\" || typeof child === \"number\") {\n parts.push(String(child))\n return\n }\n\n if (isValidElement<VarProps>(child) && child.type === Var) {\n const entry = getRuntimeVarEntry(child.props)\n if (entry) {\n parts.push(`{${entry.name}}`)\n vars[entry.name] = entry.value\n }\n }\n })\n\n return {\n message: parts.join(\"\").replace(/\\s+/g, \" \").trim(),\n vars: Object.keys(vars).length > 0 ? vars : undefined,\n }\n}\n\nfunction getRuntimeVarEntry(props: VarProps) {\n if (typeof props.name === \"string\" && props.children !== undefined) {\n return { name: props.name, value: props.children }\n }\n\n const entries = Object.entries(props).filter(([key]) => key !== \"children\")\n if (entries.length !== 1) return undefined\n\n const [name, value] = entries[0]!\n return { name, value }\n}\n"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { u as TranslateOptions } from "./types-Di93oTw4.mjs";
2
+
3
+ //#region src/server.d.ts
4
+ /** A server-side placeholder value used by `msg()` template interpolation. */
5
+ interface VarResult {
6
+ /** Internal marker used to identify placeholder values. */
7
+ __i18n: true;
8
+ /** Placeholder name used inside the translated template. */
9
+ name: string;
10
+ /** Runtime value that should replace the placeholder. */
11
+ value: unknown;
12
+ }
13
+ /** Marks a value for replacement into a translated server-side template message. */
14
+ declare function v(name: string, value: unknown): VarResult;
15
+ /** The server-side translation helpers returned by `createTranslator()`. */
16
+ interface ServerTranslator {
17
+ /** Translates a plain string in non-JSX contexts such as errors or email helpers. */
18
+ t: (id: string, options?: TranslateOptions) => string;
19
+ /** Translates a template message with runtime placeholders. */
20
+ msg: (id: string) => (strings: TemplateStringsArray, ...expressions: VarResult[]) => string;
21
+ }
22
+ /** Creates lightweight server-side translation helpers from a loaded message map. */
23
+ declare function createTranslator(messages: Record<string, string>): ServerTranslator;
24
+ //#endregion
25
+ export { ServerTranslator, VarResult, createTranslator, v };
26
+ //# sourceMappingURL=server.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../src/server.ts"],"mappings":";;;;UAKiB,SAAA;EAAA;EAEf,MAAA;;EAEA,IAAA;EAFA;EAIA,KAAA;AAAA;;iBAIc,CAAA,CAAE,IAAA,UAAc,KAAA,YAAiB,SAAA;AAAjD;AAAA,UAKiB,gBAAA;;EAEf,CAAA,GAAI,EAAA,UAAY,OAAA,GAAU,gBAAA;EAPV;EAShB,GAAA,GAAM,EAAA,cAAgB,OAAA,EAAS,oBAAA,KAAyB,WAAA,EAAa,SAAA;AAAA;;iBAIvD,gBAAA,CAAiB,QAAA,EAAU,MAAA,mBAAyB,gBAAA"}
@@ -0,0 +1,35 @@
1
+ import { t as getCallMessageId } from "./message-id-7Mx7G9xT.mjs";
2
+ //#region src/server.ts
3
+ /** Marks a value for replacement into a translated server-side template message. */
4
+ function v(name, value) {
5
+ return {
6
+ __i18n: true,
7
+ name,
8
+ value
9
+ };
10
+ }
11
+ /** Creates lightweight server-side translation helpers from a loaded message map. */
12
+ function createTranslator(messages) {
13
+ function t(id, options) {
14
+ return messages[getCallMessageId(id, options)] ?? id;
15
+ }
16
+ function msg(id) {
17
+ return (strings, ...expressions) => {
18
+ const template = messages[id];
19
+ if (!template) return strings.reduce((acc, str, i) => {
20
+ const expr = expressions[i];
21
+ return acc + str + (expr ? String(expr.value) : "");
22
+ }, "");
23
+ const values = Object.fromEntries(expressions.filter((expr) => Boolean(expr?.__i18n)).map((expr) => [expr.name, String(expr.value)]));
24
+ return template.replace(/\{(\w+)\}/g, (_, name) => values[name] ?? `{${name}}`);
25
+ };
26
+ }
27
+ return {
28
+ t,
29
+ msg
30
+ };
31
+ }
32
+ //#endregion
33
+ export { createTranslator, v };
34
+
35
+ //# sourceMappingURL=server.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.mjs","names":[],"sources":["../src/server.ts"],"sourcesContent":["import type { TranslateOptions } from \"./types.js\"\n\nimport { getCallMessageId } from \"./message-id.js\"\n\n/** A server-side placeholder value used by `msg()` template interpolation. */\nexport interface VarResult {\n /** Internal marker used to identify placeholder values. */\n __i18n: true\n /** Placeholder name used inside the translated template. */\n name: string\n /** Runtime value that should replace the placeholder. */\n value: unknown\n}\n\n/** Marks a value for replacement into a translated server-side template message. */\nexport function v(name: string, value: unknown): VarResult {\n return { __i18n: true, name, value }\n}\n\n/** The server-side translation helpers returned by `createTranslator()`. */\nexport interface ServerTranslator {\n /** Translates a plain string in non-JSX contexts such as errors or email helpers. */\n t: (id: string, options?: TranslateOptions) => string\n /** Translates a template message with runtime placeholders. */\n msg: (id: string) => (strings: TemplateStringsArray, ...expressions: VarResult[]) => string\n}\n\n/** Creates lightweight server-side translation helpers from a loaded message map. */\nexport function createTranslator(messages: Record<string, string>): ServerTranslator {\n function t(id: string, options?: TranslateOptions) {\n return messages[getCallMessageId(id, options)] ?? id\n }\n\n function msg(id: string) {\n return (strings: TemplateStringsArray, ...expressions: VarResult[]) => {\n const template = messages[id]\n\n if (!template) {\n return strings.reduce((acc, str, i) => {\n const expr = expressions[i]\n return acc + str + (expr ? String(expr.value) : \"\")\n }, \"\")\n }\n\n const values = Object.fromEntries(\n expressions.filter((expr): expr is VarResult => Boolean(expr?.__i18n)).map((expr) => [expr.name, String(expr.value)]),\n )\n return template.replace(/\\{(\\w+)\\}/g, (_, name: string) => values[name] ?? `{${name}}`)\n }\n }\n\n return { t, msg }\n}\n"],"mappings":";;;AAeA,SAAgB,EAAE,MAAc,OAA2B;AACzD,QAAO;EAAE,QAAQ;EAAM;EAAM;EAAO;;;AAYtC,SAAgB,iBAAiB,UAAoD;CACnF,SAAS,EAAE,IAAY,SAA4B;AACjD,SAAO,SAAS,iBAAiB,IAAI,QAAQ,KAAK;;CAGpD,SAAS,IAAI,IAAY;AACvB,UAAQ,SAA+B,GAAG,gBAA6B;GACrE,MAAM,WAAW,SAAS;AAE1B,OAAI,CAAC,SACH,QAAO,QAAQ,QAAQ,KAAK,KAAK,MAAM;IACrC,MAAM,OAAO,YAAY;AACzB,WAAO,MAAM,OAAO,OAAO,OAAO,KAAK,MAAM,GAAG;MAC/C,GAAG;GAGR,MAAM,SAAS,OAAO,YACpB,YAAY,QAAQ,SAA4B,QAAQ,MAAM,OAAO,CAAC,CAAC,KAAK,SAAS,CAAC,KAAK,MAAM,OAAO,KAAK,MAAM,CAAC,CAAC,CACtH;AACD,UAAO,SAAS,QAAQ,eAAe,GAAG,SAAiB,OAAO,SAAS,IAAI,KAAK,GAAG;;;AAI3F,QAAO;EAAE;EAAG;EAAK"}
@@ -0,0 +1,106 @@
1
+ //#region src/types.d.ts
2
+ /** Source metadata for a single extracted message occurrence. */
3
+ interface MessageSource {
4
+ /** File path relative to the Vite root where the message came from. */
5
+ file: string;
6
+ /** Extraction marker that produced the message. */
7
+ kind: "call" | "component" | "tagged-template";
8
+ /** Concrete marker name encountered in source, such as `t` or `T`. */
9
+ marker: string;
10
+ /** 1-based starting line number of the extracted node. */
11
+ line: number;
12
+ /** 1-based starting column number of the extracted node. */
13
+ column: number;
14
+ /** 1-based ending line number of the extracted node. */
15
+ endLine: number;
16
+ /** 1-based ending column number of the extracted node. */
17
+ endColumn: number;
18
+ /** Zero-based starting byte offset in the source file. */
19
+ start: number;
20
+ /** Zero-based ending byte offset in the source file. */
21
+ end: number;
22
+ }
23
+ /** Internal manifest entry used while aggregating extracted messages. */
24
+ interface ManifestEntry {
25
+ /** Source-language text that should be translated. */
26
+ defaultMessage: string;
27
+ /** Optional metadata that affects translation or message grouping. */
28
+ meta: TranslateOptions;
29
+ /** Placeholder names discovered in the message text. */
30
+ placeholders: string[];
31
+ /** Source locations that contributed to this manifest entry. */
32
+ sources: MessageSource[];
33
+ }
34
+ /** In-memory manifest keyed by stable message id. */
35
+ type MessageManifest = Record<string, ManifestEntry>;
36
+ /** Private on-disk manifest keyed by stable message id. */
37
+ type MessageManifestFile = MessageManifest;
38
+ /** Flat runtime message map keyed by stable message id. */
39
+ type RuntimeMessages = Record<string, string>;
40
+ /** Extra metadata that can influence translation and message grouping. */
41
+ interface TranslateOptions {
42
+ /** Explicit stable message id for direct runtime lookups, whether provided manually or by a transform. */
43
+ id?: string;
44
+ /** Extra disambiguating context for translators and custom ids. */
45
+ context?: string;
46
+ }
47
+ /** A full message payload passed to the translate callback. */
48
+ interface TranslateMessage {
49
+ /** Stable message id used for locale file keys and translation results. */
50
+ id: string;
51
+ /** Source-language text that should be translated. */
52
+ text: string;
53
+ /** Optional metadata that affects translation or message grouping. */
54
+ meta: TranslateOptions;
55
+ /** Placeholder names discovered in the message text. */
56
+ placeholders: string[];
57
+ /** Source locations that produced this message. */
58
+ sources: MessageSource[];
59
+ }
60
+ /** User-provided translation function used to fill missing locale entries. */
61
+ type TranslateFn = (messages: TranslateMessage[], locale: string) => Promise<Record<string, string>>;
62
+ /** Stores messages in a remote backend. */
63
+ interface BetterTranslateRemoteStorageOptions {
64
+ /** Selects remote storage. */
65
+ type: "remote";
66
+ /** Optional remote backend URL. */
67
+ url?: string;
68
+ }
69
+ /** Bundles locale JSON files into the app source tree or deployed artifact. */
70
+ interface BetterTranslateBundleStorageOptions {
71
+ /** Selects bundled storage. */
72
+ type: "bundle";
73
+ /** Output directory where locale JSON files are written. */
74
+ output?: string;
75
+ }
76
+ /** Controls where translated locale artifacts are written or synced. */
77
+ type BetterTranslateStorageOptions = BetterTranslateRemoteStorageOptions | BetterTranslateBundleStorageOptions;
78
+ /** Runtime metadata emitted by the plugin for server-side loaders. */
79
+ interface BetterTranslateRuntimeConfig {
80
+ /** Storage backend configured for emitted locale artifacts. */
81
+ storage: BetterTranslateStorageOptions;
82
+ /** Locale code treated as the source language. */
83
+ defaultLocale: string;
84
+ /** All locale codes emitted by the plugin. */
85
+ locales: string[];
86
+ }
87
+ /** Public configuration for the Better Translation Vite plugin. */
88
+ interface BetterTranslatePluginOptions {
89
+ /** All locale codes that should be emitted. */
90
+ locales: string[];
91
+ /** Locale code treated as the source language. */
92
+ defaultLocale?: string;
93
+ /** Source directory or directories, relative to the Vite root. Defaults to `"src"`. */
94
+ rootDir?: string | string[];
95
+ /** Cache file path, relative to the Vite root. */
96
+ cacheFile?: string;
97
+ /** Enables or disables plugin logging. */
98
+ logging?: boolean;
99
+ /** Storage backend configuration. */
100
+ storage?: BetterTranslateStorageOptions;
101
+ /** Custom translation function used for messages missing from non-default locales. */
102
+ translate?: TranslateFn;
103
+ }
104
+ //#endregion
105
+ export { BetterTranslateStorageOptions as a, TranslateFn as c, BetterTranslateRuntimeConfig as i, TranslateMessage as l, BetterTranslatePluginOptions as n, MessageManifestFile as o, BetterTranslateRemoteStorageOptions as r, RuntimeMessages as s, BetterTranslateBundleStorageOptions as t, TranslateOptions as u };
106
+ //# sourceMappingURL=types-Di93oTw4.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-Di93oTw4.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;UAeiB,aAAA;EAkBZ;EAhBH,IAAA;EAoB4B;EAlB5B,IAAA;EA0BsB;EAxBtB,MAAA;EAoBA;EAlBA,IAAA;EAoBA;EAlBA,MAAA;EAoBS;EAlBT,OAAA;EAkBsB;EAhBtB,SAAA;EAoByB;EAlBzB,KAAA;EAkB4B;EAhB5B,GAAA;AAAA;;UAIe,aAAA;EAeiB;EAbhC,cAAA;EAgBU;EAdV,IAAA,EAAM,gBAAA;;EAEN,YAAA;EAYkC;EAVlC,OAAA,EAAS,aAAA;AAAA;;KAIC,eAAA,GAAkB,MAAA,SAAe,aAAA;;KAGjC,mBAAA,GAAsB,eAAA;;KAGtB,eAAA,GAAkB,MAAA;AA6F9B;AAAA,UA5CiB,gBAAA;;EAEf,EAAA;EA4CA;EA1CA,OAAA;AAAA;;UAIe,gBAAA;EA0CR;EAxCP,EAAA;EA4C2C;EA1C3C,IAAA;EAwDuB;EAtDvB,IAAA,EAAM,gBAAA;EA4CN;EA1CA,YAAA;EA8CA;EA5CA,OAAA,EAAS,aAAA;AAAA;;KAIC,WAAA,IAAe,QAAA,EAAU,gBAAA,IAAoB,MAAA,aAAmB,OAAA,CAAQ,MAAA;;UAGnE,mCAAA;EA2CQ;EAzCvB,IAAA;;EAEA,GAAA;AAAA;;UAIe,mCAAA;;EAEf,IAAA;;EAEA,MAAA;AAAA;;KAIU,6BAAA,GAAgC,mCAAA,GAAsC,mCAAA;;UAGjE,4BAAA;;EAEf,OAAA,EAAS,6BAAA;;EAET,aAAA;;EAEA,OAAA;AAAA;;UAIe,4BAAA;;EAEf,OAAA;;EAEA,aAAA;;EAEA,OAAA;;EAEA,SAAA;;EAEA,OAAA;;EAEA,OAAA,GAAU,6BAAA;;EAEV,SAAA,GAAY,WAAA;AAAA"}
@@ -0,0 +1,9 @@
1
+ import { a as BetterTranslateStorageOptions, c as TranslateFn, i as BetterTranslateRuntimeConfig, l as TranslateMessage, n as BetterTranslatePluginOptions, o as MessageManifestFile, r as BetterTranslateRemoteStorageOptions, s as RuntimeMessages, t as BetterTranslateBundleStorageOptions, u as TranslateOptions } from "./types-Di93oTw4.mjs";
2
+ import { Plugin } from "vite";
3
+
4
+ //#region src/plugin.d.ts
5
+ /** Scans source files for translatable messages and keeps locale JSON files in sync. */
6
+ declare function betterTranslate(options: BetterTranslatePluginOptions): Plugin;
7
+ //#endregion
8
+ export { type BetterTranslateBundleStorageOptions, type BetterTranslatePluginOptions, type BetterTranslateRemoteStorageOptions, type BetterTranslateRuntimeConfig, type BetterTranslateStorageOptions, type MessageManifestFile, type RuntimeMessages, type TranslateFn, type TranslateMessage, type TranslateOptions, betterTranslate };
9
+ //# sourceMappingURL=vite.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite.d.mts","names":[],"sources":["../src/plugin.ts"],"mappings":";;;;;iBAuDgB,eAAA,CAAgB,OAAA,EAAS,4BAAA,GAA+B,MAAA"}