@shuo-li/i18n 1.0.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 +0 -0
- package/dist/cacheEvents-kOPDM3Ed.d.cts +132 -0
- package/dist/cacheEvents-kOPDM3Ed.d.ts +132 -0
- package/dist/chunk-AJJKJPNB.cjs +88 -0
- package/dist/chunk-JDOLFHBS.cjs +664 -0
- package/dist/chunk-ONDHZEK4.js +664 -0
- package/dist/chunk-VUDMWZAA.js +88 -0
- package/dist/hooks-ClO29Chr.d.cts +16 -0
- package/dist/hooks-ClO29Chr.d.ts +16 -0
- package/dist/index.cjs +223 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +223 -0
- package/dist/mp/index.cjs +231 -0
- package/dist/mp/index.d.cts +10 -0
- package/dist/mp/index.d.ts +10 -0
- package/dist/mp/index.js +231 -0
- package/dist/native/index.cjs +175 -0
- package/dist/native/index.d.cts +12 -0
- package/dist/native/index.d.ts +12 -0
- package/dist/native/index.js +175 -0
- package/dist/workers/preload-worker-rn.cjs +91 -0
- package/dist/workers/preload-worker-rn.d.cts +2 -0
- package/dist/workers/preload-worker-rn.d.ts +2 -0
- package/dist/workers/preload-worker-rn.js +91 -0
- package/dist/workers/preload-worker.cjs +169 -0
- package/dist/workers/preload-worker.d.cts +2 -0
- package/dist/workers/preload-worker.d.ts +2 -0
- package/dist/workers/preload-worker.js +169 -0
- package/package.json +59 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// src/workers/preload-worker.ts
|
|
2
|
+
function flatToNested(flat) {
|
|
3
|
+
const result = {};
|
|
4
|
+
for (const [key, value] of Object.entries(flat)) {
|
|
5
|
+
const parts = key.split(".");
|
|
6
|
+
let cur = result;
|
|
7
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
8
|
+
const part = parts[i];
|
|
9
|
+
if (typeof cur[part] !== "object" || cur[part] === null) cur[part] = {};
|
|
10
|
+
cur = cur[part];
|
|
11
|
+
}
|
|
12
|
+
cur[parts[parts.length - 1]] = value;
|
|
13
|
+
}
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
function deepMerge(target, source) {
|
|
17
|
+
const result = { ...target };
|
|
18
|
+
for (const [key, sv] of Object.entries(source)) {
|
|
19
|
+
const tv = result[key];
|
|
20
|
+
if (sv !== null && typeof sv === "object" && !Array.isArray(sv) && tv !== null && typeof tv === "object" && !Array.isArray(tv)) {
|
|
21
|
+
result[key] = deepMerge(tv, sv);
|
|
22
|
+
} else {
|
|
23
|
+
result[key] = sv;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
function parseI18nValues(values) {
|
|
29
|
+
const result = {};
|
|
30
|
+
for (const { termCode, langValue } of values) {
|
|
31
|
+
if (termCode && langValue !== void 0) result[termCode] = langValue ?? "";
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
function buildKey(moduleCode, langCode, store) {
|
|
36
|
+
return store.cacheGroupKey ? `${moduleCode}_${langCode}_${store.cacheGroupKey}` : `${moduleCode}_${langCode}`;
|
|
37
|
+
}
|
|
38
|
+
function toQueryString(params) {
|
|
39
|
+
return new URLSearchParams(
|
|
40
|
+
Object.entries(params).filter(([, v]) => v != null).map(([k, v]) => [k, String(v)])
|
|
41
|
+
).toString();
|
|
42
|
+
}
|
|
43
|
+
var db = null;
|
|
44
|
+
function openDB(dbName, storeNames) {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
const req = indexedDB.open(dbName, 2);
|
|
47
|
+
req.onupgradeneeded = (event) => {
|
|
48
|
+
const database = event.target.result;
|
|
49
|
+
for (const name of storeNames) {
|
|
50
|
+
const storeName = `i18n_resources_${name}`;
|
|
51
|
+
if (!database.objectStoreNames.contains(storeName)) {
|
|
52
|
+
const s = database.createObjectStore(storeName, { keyPath: "key" });
|
|
53
|
+
s.createIndex("by_module", "moduleCode");
|
|
54
|
+
s.createIndex("by_language", "langCode");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (!database.objectStoreNames.contains("i18n_meta")) {
|
|
58
|
+
database.createObjectStore("i18n_meta", { keyPath: "key" });
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
req.onsuccess = () => resolve(req.result);
|
|
62
|
+
req.onerror = () => reject(req.error);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function idbGet(database, storeName, key) {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
const tx = database.transaction(storeName, "readonly");
|
|
68
|
+
const req = tx.objectStore(storeName).get(key);
|
|
69
|
+
req.onsuccess = () => resolve(req.result);
|
|
70
|
+
req.onerror = () => reject(req.error);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function idbPut(database, storeName, value) {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const tx = database.transaction(storeName, "readwrite");
|
|
76
|
+
const req = tx.objectStore(storeName).put(value);
|
|
77
|
+
req.onsuccess = () => resolve();
|
|
78
|
+
req.onerror = () => reject(req.error);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
async function processTask(task, payload) {
|
|
82
|
+
const { baseURL, headers, pullPath, pullMethod, stores } = payload;
|
|
83
|
+
const params = {};
|
|
84
|
+
if (task.storeName) params["storeName"] = task.storeName;
|
|
85
|
+
if (task.langCode) params["langCode"] = task.langCode;
|
|
86
|
+
if (task.moduleCode) params["moduleCode"] = task.moduleCode;
|
|
87
|
+
if (task.version != null) params["version"] = String(task.version);
|
|
88
|
+
const url = baseURL + pullPath;
|
|
89
|
+
let res;
|
|
90
|
+
if (pullMethod === "POST") {
|
|
91
|
+
res = await fetch(url, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
94
|
+
body: JSON.stringify(params)
|
|
95
|
+
});
|
|
96
|
+
} else {
|
|
97
|
+
res = await fetch(`${url}?${toQueryString(params)}`, { headers });
|
|
98
|
+
}
|
|
99
|
+
if (!res.ok) throw new Error(`[i18n worker] fetch failed: ${res.status}`);
|
|
100
|
+
const blocks = await res.json();
|
|
101
|
+
for (const block of blocks) {
|
|
102
|
+
for (const mod of block.modules ?? []) {
|
|
103
|
+
const store = stores.find((s) => s.name === task.storeName);
|
|
104
|
+
if (!store) continue;
|
|
105
|
+
const storeIndex = stores.indexOf(store);
|
|
106
|
+
const idbStoreName = `i18n_resources_${store.name}`;
|
|
107
|
+
const key = buildKey(mod.moduleCode, block.langCode, store);
|
|
108
|
+
const parsed = parseI18nValues(mod.i18nValues ?? []);
|
|
109
|
+
let resources;
|
|
110
|
+
if (storeIndex === 0) {
|
|
111
|
+
const existing = await idbGet(
|
|
112
|
+
db,
|
|
113
|
+
idbStoreName,
|
|
114
|
+
key
|
|
115
|
+
);
|
|
116
|
+
resources = deepMerge(
|
|
117
|
+
existing?.resources ?? {},
|
|
118
|
+
flatToNested(parsed)
|
|
119
|
+
);
|
|
120
|
+
} else {
|
|
121
|
+
const existing = await idbGet(
|
|
122
|
+
db,
|
|
123
|
+
idbStoreName,
|
|
124
|
+
key
|
|
125
|
+
);
|
|
126
|
+
resources = { ...existing?.resources ?? {}, ...parsed };
|
|
127
|
+
}
|
|
128
|
+
const record = {
|
|
129
|
+
key,
|
|
130
|
+
moduleCode: mod.moduleCode,
|
|
131
|
+
langCode: block.langCode,
|
|
132
|
+
version: mod.version,
|
|
133
|
+
resources
|
|
134
|
+
};
|
|
135
|
+
await idbPut(db, idbStoreName, record);
|
|
136
|
+
self.postMessage({
|
|
137
|
+
type: "moduleLoaded",
|
|
138
|
+
storeName: task.storeName,
|
|
139
|
+
langCode: block.langCode,
|
|
140
|
+
moduleCode: mod.moduleCode,
|
|
141
|
+
version: mod.version
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
self.onmessage = async (event) => {
|
|
147
|
+
if (event.data.type !== "start") return;
|
|
148
|
+
const { payload } = event.data;
|
|
149
|
+
const storeNames = payload.stores.map((s) => s.name);
|
|
150
|
+
try {
|
|
151
|
+
db = await openDB(payload.dbName, storeNames);
|
|
152
|
+
} catch (err) {
|
|
153
|
+
self.postMessage({ type: "error", message: String(err) });
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
for (const task of payload.tasks) {
|
|
157
|
+
try {
|
|
158
|
+
await processTask(task, payload);
|
|
159
|
+
} catch {
|
|
160
|
+
self.postMessage({
|
|
161
|
+
type: "moduleError",
|
|
162
|
+
storeName: task.storeName,
|
|
163
|
+
langCode: task.langCode,
|
|
164
|
+
moduleCode: task.moduleCode
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
self.postMessage({ type: "done" });
|
|
169
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shuo-li/i18n",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cross-platform i18n library for Web, React Native and WeChat MiniProgram",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js",
|
|
19
|
+
"require": "./dist/index.cjs"
|
|
20
|
+
},
|
|
21
|
+
"./native": {
|
|
22
|
+
"types": "./dist/native/index.d.ts",
|
|
23
|
+
"import": "./dist/native/index.js",
|
|
24
|
+
"require": "./dist/native/index.cjs"
|
|
25
|
+
},
|
|
26
|
+
"./mp": {
|
|
27
|
+
"types": "./dist/mp/index.d.ts",
|
|
28
|
+
"import": "./dist/mp/index.js",
|
|
29
|
+
"require": "./dist/mp/index.cjs"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsup",
|
|
35
|
+
"typecheck": "tsc --noEmit",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"prepublishOnly": "pnpm build"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"i18next": "^23.0.0",
|
|
41
|
+
"react-i18next": "^14.0.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@op-engineering/op-sqlite": ">=3.0.0",
|
|
45
|
+
"react": ">=18"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"@op-engineering/op-sqlite": {
|
|
49
|
+
"optional": true
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/react": "^18.0.0",
|
|
54
|
+
"miniprogram-api-typings": "^5.2.1",
|
|
55
|
+
"tsup": "^8.0.0",
|
|
56
|
+
"typescript": "^5.4.0",
|
|
57
|
+
"vitest": "^1.0.0"
|
|
58
|
+
}
|
|
59
|
+
}
|