@i18n-micro/devtools-ui 1.2.1 → 1.2.2
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,80 +1,77 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { buildSourceRootPath as g, buildSourcePagePath as p } from "@i18n-micro/utils/merge-source";
|
|
2
|
+
import { parseTranslationRelativePath as b } from "@i18n-micro/utils/parse-path";
|
|
3
|
+
function w(u) {
|
|
4
|
+
const { adapter: n, locales: f = [], defaultLocale: i = "en", translationDir: c = "src/locales" } = u, d = () => {
|
|
5
|
+
const o = {}, t = n.getRouteCache();
|
|
6
|
+
for (const [e, a] of Object.entries(t)) {
|
|
7
|
+
if (!a || typeof a != "object" || Array.isArray(a) || Object.keys(a).length === 0)
|
|
6
8
|
continue;
|
|
7
|
-
const
|
|
8
|
-
if (
|
|
9
|
+
const s = e.indexOf(":");
|
|
10
|
+
if (s === -1)
|
|
9
11
|
continue;
|
|
10
|
-
const
|
|
11
|
-
o === "index" ? r
|
|
12
|
+
const r = e.substring(0, s), l = e.substring(s + 1);
|
|
13
|
+
o[l === "index" ? g(r) : p(l, r)] = a;
|
|
12
14
|
}
|
|
13
|
-
return
|
|
15
|
+
return o;
|
|
14
16
|
};
|
|
15
17
|
return {
|
|
16
18
|
async getLocalesAndTranslations() {
|
|
17
|
-
return
|
|
19
|
+
return d();
|
|
18
20
|
},
|
|
19
21
|
async getConfigs() {
|
|
20
22
|
return {
|
|
21
|
-
defaultLocale: i ||
|
|
22
|
-
fallbackLocale:
|
|
23
|
-
locales:
|
|
24
|
-
translationDir:
|
|
23
|
+
defaultLocale: i || n.getCurrentLocale?.() || "en",
|
|
24
|
+
fallbackLocale: n.getFallbackLocale?.() || i || "en",
|
|
25
|
+
locales: f || [],
|
|
26
|
+
translationDir: c || "locales"
|
|
25
27
|
};
|
|
26
28
|
},
|
|
27
|
-
async saveTranslation(
|
|
29
|
+
async saveTranslation(o, t) {
|
|
28
30
|
try {
|
|
29
|
-
const
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
o && s.addTranslations(o, n, !1);
|
|
38
|
-
} else
|
|
39
|
-
throw new Error(`Unknown file path format: ${r}`);
|
|
40
|
-
}
|
|
41
|
-
const c = l ? `${l}/${a}` : a;
|
|
31
|
+
const e = o.replace(/^\/+/, "").replace(/\/+/g, "/"), a = b(e);
|
|
32
|
+
if (a.type === "page")
|
|
33
|
+
n.addRouteTranslations(a.locale, a.pageName, t, !1);
|
|
34
|
+
else if (a.type === "root")
|
|
35
|
+
n.addTranslations(a.locale, t, !1);
|
|
36
|
+
else
|
|
37
|
+
throw new Error(`Unknown file path format: ${o}`);
|
|
38
|
+
const s = c ? `${c}/${e}` : e;
|
|
42
39
|
try {
|
|
43
|
-
const
|
|
40
|
+
const r = await fetch("/__i18n_api/save", {
|
|
44
41
|
method: "POST",
|
|
45
42
|
headers: {
|
|
46
43
|
"Content-Type": "application/json"
|
|
47
44
|
},
|
|
48
45
|
body: JSON.stringify({
|
|
49
|
-
file:
|
|
50
|
-
content:
|
|
46
|
+
file: s,
|
|
47
|
+
content: t
|
|
51
48
|
})
|
|
52
49
|
});
|
|
53
|
-
if (!
|
|
54
|
-
const
|
|
55
|
-
throw new Error(
|
|
50
|
+
if (!r.ok) {
|
|
51
|
+
const l = await r.json().catch(() => ({ error: "Unknown error" }));
|
|
52
|
+
throw new Error(l.error || `Network response was not ok: ${r.statusText}`);
|
|
56
53
|
}
|
|
57
|
-
console.log(`[i18n-bridge] Saved to disk: ${
|
|
58
|
-
} catch (
|
|
54
|
+
console.log(`[i18n-bridge] Saved to disk: ${s}`);
|
|
55
|
+
} catch (r) {
|
|
59
56
|
if (typeof localStorage < "u") {
|
|
60
|
-
console.warn("[i18n-bridge] Server save failed, falling back to localStorage:",
|
|
61
|
-
const
|
|
62
|
-
localStorage.setItem(
|
|
57
|
+
console.warn("[i18n-bridge] Server save failed, falling back to localStorage:", r);
|
|
58
|
+
const l = `i18n_save_${o}`;
|
|
59
|
+
localStorage.setItem(l, JSON.stringify(t, null, 2));
|
|
63
60
|
} else
|
|
64
|
-
throw
|
|
61
|
+
throw r;
|
|
65
62
|
}
|
|
66
|
-
} catch (
|
|
67
|
-
throw new Error(`Failed to save: ${
|
|
63
|
+
} catch (e) {
|
|
64
|
+
throw new Error(`Failed to save: ${e instanceof Error ? e.message : String(e)}`);
|
|
68
65
|
}
|
|
69
66
|
},
|
|
70
|
-
onLocalesUpdate(
|
|
71
|
-
return
|
|
72
|
-
|
|
67
|
+
onLocalesUpdate(o) {
|
|
68
|
+
return n.subscribe(() => {
|
|
69
|
+
o(d());
|
|
73
70
|
});
|
|
74
71
|
}
|
|
75
72
|
};
|
|
76
73
|
}
|
|
77
74
|
export {
|
|
78
|
-
|
|
75
|
+
w as createBridge
|
|
79
76
|
};
|
|
80
77
|
//# sourceMappingURL=create-bridge.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-bridge.js","sources":["../../src/bridge/create-bridge.ts"],"sourcesContent":["import type { Locale, ModuleOptions } from '@i18n-micro/types'\nimport type { I18nDevToolsBridge, LocaleData, TranslationContent } from './interface'\n\n/**\n * Adapter interface for accessing i18n instance data\n * Each framework package will implement this adapter for their specific i18n instance\n */\nexport interface BridgeAdapter {\n /**\n * Get translations cache\n * Keys are in format \"locale:routeName\" (e.g., \"en:index\", \"en:home\")\n */\n getRouteCache: () => Record<string, TranslationContent>\n\n /**\n * Add or update translations for a locale\n */\n addTranslations: (locale: string, content: TranslationContent, merge: boolean) => void\n\n /**\n * Add or update route-specific translations\n */\n addRouteTranslations: (locale: string, routeName: string, content: TranslationContent, merge: boolean) => void\n\n /**\n * Subscribe to changes in translations\n * @returns Unsubscribe function\n */\n subscribe: (callback: () => void) => () => void\n\n /**\n * Get current locale (optional)\n */\n getCurrentLocale?: () => string\n\n /**\n * Get fallback locale (optional)\n */\n getFallbackLocale?: () => string\n}\n\nexport interface CreateBridgeOptions {\n adapter: BridgeAdapter\n locales?: Locale[]\n defaultLocale?: string\n translationDir?: string\n}\n\n/**\n * Create a universal bridge for DevTools communication\n * This bridge works with any framework by using an adapter pattern\n */\nexport function createBridge(options: CreateBridgeOptions): I18nDevToolsBridge {\n const { adapter, locales = [], defaultLocale = 'en', translationDir = 'src/locales' } = options\n\n // Helper function to build locale data from cache\n const buildLocaleData = (): LocaleData => {\n const data: LocaleData = {}\n\n // All translations are stored as \"locale:routeName\" (e.g., \"en:index\", \"en:about\")\n const routeCache = adapter.getRouteCache()\n for (const [key, content] of Object.entries(routeCache)) {\n if (!content || typeof content !== 'object' || Array.isArray(content) || Object.keys(content).length === 0) {\n continue\n }\n\n const separatorIndex = key.indexOf(':')\n if (separatorIndex === -1) {\n continue\n }\n\n const locale = key.substring(0, separatorIndex)\n const routeName = key.substring(separatorIndex + 1)\n\n
|
|
1
|
+
{"version":3,"file":"create-bridge.js","sources":["../../src/bridge/create-bridge.ts"],"sourcesContent":["import type { Locale, ModuleOptions } from '@i18n-micro/types'\nimport { buildSourcePagePath, buildSourceRootPath } from '@i18n-micro/utils/merge-source'\nimport { parseTranslationRelativePath } from '@i18n-micro/utils/parse-path'\nimport type { I18nDevToolsBridge, LocaleData, TranslationContent } from './interface'\n\n/**\n * Adapter interface for accessing i18n instance data\n * Each framework package will implement this adapter for their specific i18n instance\n */\nexport interface BridgeAdapter {\n /**\n * Get translations cache\n * Keys are in format \"locale:routeName\" (e.g., \"en:index\", \"en:home\")\n */\n getRouteCache: () => Record<string, TranslationContent>\n\n /**\n * Add or update translations for a locale\n */\n addTranslations: (locale: string, content: TranslationContent, merge: boolean) => void\n\n /**\n * Add or update route-specific translations\n */\n addRouteTranslations: (locale: string, routeName: string, content: TranslationContent, merge: boolean) => void\n\n /**\n * Subscribe to changes in translations\n * @returns Unsubscribe function\n */\n subscribe: (callback: () => void) => () => void\n\n /**\n * Get current locale (optional)\n */\n getCurrentLocale?: () => string\n\n /**\n * Get fallback locale (optional)\n */\n getFallbackLocale?: () => string\n}\n\nexport interface CreateBridgeOptions {\n adapter: BridgeAdapter\n locales?: Locale[]\n defaultLocale?: string\n translationDir?: string\n}\n\n/**\n * Create a universal bridge for DevTools communication\n * This bridge works with any framework by using an adapter pattern\n */\nexport function createBridge(options: CreateBridgeOptions): I18nDevToolsBridge {\n const { adapter, locales = [], defaultLocale = 'en', translationDir = 'src/locales' } = options\n\n // Helper function to build locale data from cache\n const buildLocaleData = (): LocaleData => {\n const data: LocaleData = {}\n\n // All translations are stored as \"locale:routeName\" (e.g., \"en:index\", \"en:about\")\n const routeCache = adapter.getRouteCache()\n for (const [key, content] of Object.entries(routeCache)) {\n if (!content || typeof content !== 'object' || Array.isArray(content) || Object.keys(content).length === 0) {\n continue\n }\n\n const separatorIndex = key.indexOf(':')\n if (separatorIndex === -1) {\n continue\n }\n\n const locale = key.substring(0, separatorIndex)\n const routeName = key.substring(separatorIndex + 1)\n\n data[routeName === 'index' ? buildSourceRootPath(locale) : buildSourcePagePath(routeName, locale)] = content\n }\n\n return data\n }\n\n return {\n async getLocalesAndTranslations(): Promise<LocaleData> {\n return buildLocaleData()\n },\n\n async getConfigs(): Promise<ModuleOptions> {\n return {\n defaultLocale: defaultLocale || adapter.getCurrentLocale?.() || 'en',\n fallbackLocale: adapter.getFallbackLocale?.() || defaultLocale || 'en',\n locales: locales || [],\n translationDir: translationDir || 'locales',\n } as ModuleOptions\n },\n\n async saveTranslation(filePath: string, content: TranslationContent): Promise<void> {\n try {\n // 1. Update state in memory (Hot Update)\n // Normalize path: remove leading / and extra slashes\n const normalizedPath = filePath.replace(/^\\/+/, '').replace(/\\/+/g, '/')\n\n const parsedPath = parseTranslationRelativePath(normalizedPath)\n\n if (parsedPath.type === 'page') {\n adapter.addRouteTranslations(parsedPath.locale, parsedPath.pageName, content, false)\n } else if (parsedPath.type === 'root') {\n adapter.addTranslations(parsedPath.locale, content, false)\n } else {\n throw new Error(`Unknown file path format: ${filePath}`)\n }\n\n // 2. Send request to server to save file to disk\n // Build real path relative to project root\n const realFilePath = translationDir ? `${translationDir}/${normalizedPath}` : normalizedPath\n\n try {\n const response = await fetch('/__i18n_api/save', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n file: realFilePath,\n content,\n }),\n })\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({ error: 'Unknown error' }))\n throw new Error(errorData.error || `Network response was not ok: ${response.statusText}`)\n }\n\n console.log(`[i18n-bridge] Saved to disk: ${realFilePath}`)\n } catch (serverError) {\n // Fallback: Save to localStorage if server is unavailable (e.g., in production preview)\n if (typeof localStorage !== 'undefined') {\n console.warn('[i18n-bridge] Server save failed, falling back to localStorage:', serverError)\n const storageKey = `i18n_save_${filePath}`\n localStorage.setItem(storageKey, JSON.stringify(content, null, 2))\n } else {\n // If no server and no localStorage, throw error\n throw serverError\n }\n }\n } catch (error) {\n throw new Error(`Failed to save: ${error instanceof Error ? error.message : String(error)}`)\n }\n },\n\n onLocalesUpdate(callback: (data: LocaleData) => void): () => void {\n // Subscribe to changes in i18n instance\n const unsubscribe = adapter.subscribe(() => {\n // On any change, rebuild data and send to DevTools\n callback(buildLocaleData())\n })\n return unsubscribe\n },\n }\n}\n"],"names":["createBridge","options","adapter","locales","defaultLocale","translationDir","buildLocaleData","data","routeCache","key","content","separatorIndex","locale","routeName","buildSourceRootPath","buildSourcePagePath","filePath","normalizedPath","parsedPath","parseTranslationRelativePath","realFilePath","response","errorData","serverError","storageKey","error","callback"],"mappings":";;AAsDO,SAASA,EAAaC,GAAkD;AAC7E,QAAM,EAAE,SAAAC,GAAS,SAAAC,IAAU,CAAA,GAAI,eAAAC,IAAgB,MAAM,gBAAAC,IAAiB,cAAA,IAAkBJ,GAGlFK,IAAkB,MAAkB;AACxC,UAAMC,IAAmB,CAAA,GAGnBC,IAAaN,EAAQ,cAAA;AAC3B,eAAW,CAACO,GAAKC,CAAO,KAAK,OAAO,QAAQF,CAAU,GAAG;AACvD,UAAI,CAACE,KAAW,OAAOA,KAAY,YAAY,MAAM,QAAQA,CAAO,KAAK,OAAO,KAAKA,CAAO,EAAE,WAAW;AACvG;AAGF,YAAMC,IAAiBF,EAAI,QAAQ,GAAG;AACtC,UAAIE,MAAmB;AACrB;AAGF,YAAMC,IAASH,EAAI,UAAU,GAAGE,CAAc,GACxCE,IAAYJ,EAAI,UAAUE,IAAiB,CAAC;AAElD,MAAAJ,EAAKM,MAAc,UAAUC,EAAoBF,CAAM,IAAIG,EAAoBF,GAAWD,CAAM,CAAC,IAAIF;AAAA,IACvG;AAEA,WAAOH;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM,4BAAiD;AACrD,aAAOD,EAAA;AAAA,IACT;AAAA,IAEA,MAAM,aAAqC;AACzC,aAAO;AAAA,QACL,eAAeF,KAAiBF,EAAQ,mBAAA,KAAwB;AAAA,QAChE,gBAAgBA,EAAQ,oBAAA,KAAyBE,KAAiB;AAAA,QAClE,SAASD,KAAW,CAAA;AAAA,QACpB,gBAAgBE,KAAkB;AAAA,MAAA;AAAA,IAEtC;AAAA,IAEA,MAAM,gBAAgBW,GAAkBN,GAA4C;AAClF,UAAI;AAGF,cAAMO,IAAiBD,EAAS,QAAQ,QAAQ,EAAE,EAAE,QAAQ,QAAQ,GAAG,GAEjEE,IAAaC,EAA6BF,CAAc;AAE9D,YAAIC,EAAW,SAAS;AACtB,UAAAhB,EAAQ,qBAAqBgB,EAAW,QAAQA,EAAW,UAAUR,GAAS,EAAK;AAAA,iBAC1EQ,EAAW,SAAS;AAC7B,UAAAhB,EAAQ,gBAAgBgB,EAAW,QAAQR,GAAS,EAAK;AAAA;AAEzD,gBAAM,IAAI,MAAM,6BAA6BM,CAAQ,EAAE;AAKzD,cAAMI,IAAef,IAAiB,GAAGA,CAAc,IAAIY,CAAc,KAAKA;AAE9E,YAAI;AACF,gBAAMI,IAAW,MAAM,MAAM,oBAAoB;AAAA,YAC/C,QAAQ;AAAA,YACR,SAAS;AAAA,cACP,gBAAgB;AAAA,YAAA;AAAA,YAElB,MAAM,KAAK,UAAU;AAAA,cACnB,MAAMD;AAAA,cACN,SAAAV;AAAA,YAAA,CACD;AAAA,UAAA,CACF;AAED,cAAI,CAACW,EAAS,IAAI;AAChB,kBAAMC,IAAY,MAAMD,EAAS,KAAA,EAAO,MAAM,OAAO,EAAE,OAAO,gBAAA,EAAkB;AAChF,kBAAM,IAAI,MAAMC,EAAU,SAAS,gCAAgCD,EAAS,UAAU,EAAE;AAAA,UAC1F;AAEA,kBAAQ,IAAI,gCAAgCD,CAAY,EAAE;AAAA,QAC5D,SAASG,GAAa;AAEpB,cAAI,OAAO,eAAiB,KAAa;AACvC,oBAAQ,KAAK,mEAAmEA,CAAW;AAC3F,kBAAMC,IAAa,aAAaR,CAAQ;AACxC,yBAAa,QAAQQ,GAAY,KAAK,UAAUd,GAAS,MAAM,CAAC,CAAC;AAAA,UACnE;AAEE,kBAAMa;AAAA,QAEV;AAAA,MACF,SAASE,GAAO;AACd,cAAM,IAAI,MAAM,mBAAmBA,aAAiB,QAAQA,EAAM,UAAU,OAAOA,CAAK,CAAC,EAAE;AAAA,MAC7F;AAAA,IACF;AAAA,IAEA,gBAAgBC,GAAkD;AAMhE,aAJoBxB,EAAQ,UAAU,MAAM;AAE1C,QAAAwB,EAASpB,GAAiB;AAAA,MAC5B,CAAC;AAAA,IAEH;AAAA,EAAA;AAEJ;"}
|
|
@@ -34,6 +34,16 @@ export declare function createI18nState(): {
|
|
|
34
34
|
apiBaseClientHost?: string | undefined;
|
|
35
35
|
apiBaseServerHost?: string | undefined;
|
|
36
36
|
translationDir?: string | undefined;
|
|
37
|
+
translationPayloads?: {
|
|
38
|
+
mode?: "premerged" | "source" | undefined;
|
|
39
|
+
serverAssets?: boolean | undefined;
|
|
40
|
+
serverHandler?: boolean | undefined;
|
|
41
|
+
publicAssets?: boolean | undefined;
|
|
42
|
+
prerenderRoutes?: boolean | undefined;
|
|
43
|
+
publicDir?: string | undefined;
|
|
44
|
+
warnFileCount?: number | undefined;
|
|
45
|
+
warnSizeBytes?: number | undefined;
|
|
46
|
+
} | undefined;
|
|
37
47
|
autoDetectLanguage?: boolean | undefined;
|
|
38
48
|
autoDetectPath?: string | undefined;
|
|
39
49
|
disableWatcher?: boolean | undefined;
|
|
@@ -89,6 +99,16 @@ export declare function createI18nState(): {
|
|
|
89
99
|
apiBaseClientHost?: string | undefined;
|
|
90
100
|
apiBaseServerHost?: string | undefined;
|
|
91
101
|
translationDir?: string | undefined;
|
|
102
|
+
translationPayloads?: {
|
|
103
|
+
mode?: "premerged" | "source" | undefined;
|
|
104
|
+
serverAssets?: boolean | undefined;
|
|
105
|
+
serverHandler?: boolean | undefined;
|
|
106
|
+
publicAssets?: boolean | undefined;
|
|
107
|
+
prerenderRoutes?: boolean | undefined;
|
|
108
|
+
publicDir?: string | undefined;
|
|
109
|
+
warnFileCount?: number | undefined;
|
|
110
|
+
warnSizeBytes?: number | undefined;
|
|
111
|
+
} | undefined;
|
|
92
112
|
autoDetectLanguage?: boolean | undefined;
|
|
93
113
|
autoDetectPath?: string | undefined;
|
|
94
114
|
disableWatcher?: boolean | undefined;
|
|
@@ -169,6 +189,16 @@ export declare function useI18nState(): {
|
|
|
169
189
|
apiBaseClientHost?: string | undefined;
|
|
170
190
|
apiBaseServerHost?: string | undefined;
|
|
171
191
|
translationDir?: string | undefined;
|
|
192
|
+
translationPayloads?: {
|
|
193
|
+
mode?: "premerged" | "source" | undefined;
|
|
194
|
+
serverAssets?: boolean | undefined;
|
|
195
|
+
serverHandler?: boolean | undefined;
|
|
196
|
+
publicAssets?: boolean | undefined;
|
|
197
|
+
prerenderRoutes?: boolean | undefined;
|
|
198
|
+
publicDir?: string | undefined;
|
|
199
|
+
warnFileCount?: number | undefined;
|
|
200
|
+
warnSizeBytes?: number | undefined;
|
|
201
|
+
} | undefined;
|
|
172
202
|
autoDetectLanguage?: boolean | undefined;
|
|
173
203
|
autoDetectPath?: string | undefined;
|
|
174
204
|
disableWatcher?: boolean | undefined;
|
|
@@ -224,6 +254,16 @@ export declare function useI18nState(): {
|
|
|
224
254
|
apiBaseClientHost?: string | undefined;
|
|
225
255
|
apiBaseServerHost?: string | undefined;
|
|
226
256
|
translationDir?: string | undefined;
|
|
257
|
+
translationPayloads?: {
|
|
258
|
+
mode?: "premerged" | "source" | undefined;
|
|
259
|
+
serverAssets?: boolean | undefined;
|
|
260
|
+
serverHandler?: boolean | undefined;
|
|
261
|
+
publicAssets?: boolean | undefined;
|
|
262
|
+
prerenderRoutes?: boolean | undefined;
|
|
263
|
+
publicDir?: string | undefined;
|
|
264
|
+
warnFileCount?: number | undefined;
|
|
265
|
+
warnSizeBytes?: number | undefined;
|
|
266
|
+
} | undefined;
|
|
227
267
|
autoDetectLanguage?: boolean | undefined;
|
|
228
268
|
autoDetectPath?: string | undefined;
|
|
229
269
|
disableWatcher?: boolean | undefined;
|