nfkit 1.0.9 → 1.0.11
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/index.cjs +345 -0
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +4 -0
- package/dist/index.mjs +340 -0
- package/dist/index.mjs.map +4 -4
- package/dist/src/i18n/i18n.d.ts +16 -0
- package/dist/src/i18n/index.d.ts +3 -0
- package/dist/src/i18n/middlewares/index.d.ts +1 -0
- package/dist/src/i18n/middlewares/lookup.d.ts +9 -0
- package/dist/src/i18n/types.d.ts +6 -0
- package/dist/src/middleware-dispatcher.d.ts +26 -0
- package/dist/src/patch-string-in-object.d.ts +2 -0
- package/dist/src/types.d.ts +1 -0
- package/dist/src/utility/parse-i18n.d.ts +14 -0
- package/index.ts +4 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,11 +20,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
var index_exports = {};
|
|
21
21
|
__export(index_exports, {
|
|
22
22
|
AbortedError: () => AbortedError,
|
|
23
|
+
I18n: () => I18n,
|
|
24
|
+
I18nLookupMiddleware: () => I18nLookupMiddleware,
|
|
25
|
+
MiddlewareDispatcher: () => MiddlewareDispatcher,
|
|
23
26
|
RoundRobin: () => RoundRobin,
|
|
24
27
|
WF_NODE: () => WF_NODE,
|
|
25
28
|
WorkflowDispatcher: () => WorkflowDispatcher,
|
|
26
29
|
abortable: () => abortable,
|
|
30
|
+
createI18nLookupMiddleware: () => createI18nLookupMiddleware,
|
|
27
31
|
dualizeAny: () => dualizeAny,
|
|
32
|
+
patchStringInObject: () => patchStringInObject,
|
|
28
33
|
workflow: () => workflow
|
|
29
34
|
});
|
|
30
35
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -775,14 +780,354 @@ function abortable(obj, signal, opts) {
|
|
|
775
780
|
};
|
|
776
781
|
return proxify(obj);
|
|
777
782
|
}
|
|
783
|
+
|
|
784
|
+
// src/middleware-dispatcher.ts
|
|
785
|
+
var MiddlewareDispatcher = class {
|
|
786
|
+
constructor(options = {}) {
|
|
787
|
+
this.options = options;
|
|
788
|
+
this.middlewares = [];
|
|
789
|
+
}
|
|
790
|
+
middleware(mw, prior = false) {
|
|
791
|
+
if (prior) {
|
|
792
|
+
this.middlewares.unshift(mw);
|
|
793
|
+
} else {
|
|
794
|
+
this.middlewares.push(mw);
|
|
795
|
+
}
|
|
796
|
+
return this;
|
|
797
|
+
}
|
|
798
|
+
removeMiddleware(mw) {
|
|
799
|
+
const index = this.middlewares.indexOf(mw);
|
|
800
|
+
if (index >= 0) {
|
|
801
|
+
this.middlewares.splice(index, 1);
|
|
802
|
+
}
|
|
803
|
+
return this;
|
|
804
|
+
}
|
|
805
|
+
dispatch(...args) {
|
|
806
|
+
const mws = this.middlewares;
|
|
807
|
+
const acceptResult = this.options.acceptResult || ((res) => res != null);
|
|
808
|
+
const errorHandler = this.options.errorHandler || ((e, args2, next) => next());
|
|
809
|
+
const dispatch = async (i) => {
|
|
810
|
+
if (i >= mws.length) return void 0;
|
|
811
|
+
const mw = mws[i];
|
|
812
|
+
let nextCalled = false;
|
|
813
|
+
const next = async () => {
|
|
814
|
+
if (nextCalled) {
|
|
815
|
+
return void 0;
|
|
816
|
+
}
|
|
817
|
+
nextCalled = true;
|
|
818
|
+
return dispatch(i + 1);
|
|
819
|
+
};
|
|
820
|
+
const runMw = async (cb) => {
|
|
821
|
+
const res = await cb();
|
|
822
|
+
if (!nextCalled && !await acceptResult(res)) {
|
|
823
|
+
return dispatch(i + 1);
|
|
824
|
+
}
|
|
825
|
+
return res;
|
|
826
|
+
};
|
|
827
|
+
try {
|
|
828
|
+
return await runMw(() => mw(...args, next));
|
|
829
|
+
} catch (e) {
|
|
830
|
+
return await runMw(() => errorHandler(e, args, next));
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
return dispatch(0);
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
// src/utility/parse-i18n.ts
|
|
838
|
+
var parseI18n = (text) => {
|
|
839
|
+
const pieces = [];
|
|
840
|
+
if (!text) return pieces;
|
|
841
|
+
let i = 0;
|
|
842
|
+
const n = text.length;
|
|
843
|
+
while (i < n) {
|
|
844
|
+
const start = text.indexOf("#{", i);
|
|
845
|
+
if (start === -1) {
|
|
846
|
+
if (i < n) pieces.push({ type: "raw", value: text.slice(i) });
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
849
|
+
let j = start + 2;
|
|
850
|
+
let depth = 1;
|
|
851
|
+
while (j < n && depth > 0) {
|
|
852
|
+
const ch = text.charCodeAt(j);
|
|
853
|
+
if (ch === 123) depth++;
|
|
854
|
+
else if (ch === 125) depth--;
|
|
855
|
+
j++;
|
|
856
|
+
}
|
|
857
|
+
if (depth !== 0) {
|
|
858
|
+
pieces.push({ type: "raw", value: text.slice(i) });
|
|
859
|
+
break;
|
|
860
|
+
}
|
|
861
|
+
if (start > i) {
|
|
862
|
+
pieces.push({ type: "raw", value: text.slice(i, start) });
|
|
863
|
+
}
|
|
864
|
+
const rawInner = text.slice(start + 2, j - 1);
|
|
865
|
+
const key = rawInner.trim();
|
|
866
|
+
pieces.push({ type: "ph", rawInner, key });
|
|
867
|
+
i = j;
|
|
868
|
+
}
|
|
869
|
+
return pieces;
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
// src/patch-string-in-object.ts
|
|
873
|
+
var patchStringInObject = async (obj, cb) => {
|
|
874
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
875
|
+
const isSpecialObject = (v) => {
|
|
876
|
+
if (v == null || typeof v !== "object") return false;
|
|
877
|
+
if (v instanceof Date || v instanceof RegExp || v instanceof Map || v instanceof Set || v instanceof WeakMap || v instanceof WeakSet || v instanceof ArrayBuffer || v instanceof DataView || ArrayBuffer.isView(v)) {
|
|
878
|
+
return true;
|
|
879
|
+
}
|
|
880
|
+
const tag = Object.prototype.toString.call(v);
|
|
881
|
+
switch (tag) {
|
|
882
|
+
case "[object URL]":
|
|
883
|
+
case "[object URLSearchParams]":
|
|
884
|
+
case "[object Error]":
|
|
885
|
+
case "[object Blob]":
|
|
886
|
+
case "[object File]":
|
|
887
|
+
case "[object FormData]":
|
|
888
|
+
return true;
|
|
889
|
+
default:
|
|
890
|
+
return false;
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
const checkValue = (v) => {
|
|
894
|
+
if (!v) return { ok: false };
|
|
895
|
+
const t = typeof v;
|
|
896
|
+
if (t === "number" || t === "bigint" || t === "symbol" || t === "function") {
|
|
897
|
+
return { ok: false };
|
|
898
|
+
}
|
|
899
|
+
if (t === "string") return { ok: true, kind: "string" };
|
|
900
|
+
if (t === "object") return { ok: true, kind: "object" };
|
|
901
|
+
return { ok: false };
|
|
902
|
+
};
|
|
903
|
+
const rebuildObject = async (value) => {
|
|
904
|
+
const proto = Object.getPrototypeOf(value);
|
|
905
|
+
const out = Object.create(proto);
|
|
906
|
+
const keys = Reflect.ownKeys(value);
|
|
907
|
+
await Promise.all(
|
|
908
|
+
keys.map(async (key) => {
|
|
909
|
+
const desc = Object.getOwnPropertyDescriptor(value, key);
|
|
910
|
+
if (!desc) return;
|
|
911
|
+
if ("value" in desc) {
|
|
912
|
+
const newVal = await walk(desc.value);
|
|
913
|
+
Object.defineProperty(out, key, { ...desc, value: newVal });
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
Object.defineProperty(out, key, desc);
|
|
917
|
+
let current = void 0;
|
|
918
|
+
if (typeof desc.get === "function") {
|
|
919
|
+
try {
|
|
920
|
+
current = desc.get.call(value);
|
|
921
|
+
} catch {
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
if (current === void 0) return;
|
|
925
|
+
try {
|
|
926
|
+
const newVal = await walk(current);
|
|
927
|
+
if (typeof desc.set === "function") {
|
|
928
|
+
try {
|
|
929
|
+
desc.set.call(out, newVal);
|
|
930
|
+
} catch {
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
} catch {
|
|
934
|
+
}
|
|
935
|
+
})
|
|
936
|
+
);
|
|
937
|
+
return out;
|
|
938
|
+
};
|
|
939
|
+
const walk = async (value) => {
|
|
940
|
+
const check = checkValue(value);
|
|
941
|
+
if (!check.ok) return value;
|
|
942
|
+
if (check.kind === "string") {
|
|
943
|
+
return cb(value);
|
|
944
|
+
}
|
|
945
|
+
if (value instanceof Promise) {
|
|
946
|
+
return value.then((resolved) => walk(resolved));
|
|
947
|
+
}
|
|
948
|
+
if (typeof value === "object") {
|
|
949
|
+
if (!Array.isArray(value) && isSpecialObject(value)) return value;
|
|
950
|
+
if (visited.has(value)) return value;
|
|
951
|
+
visited.add(value);
|
|
952
|
+
if (Array.isArray(value)) {
|
|
953
|
+
const out = await Promise.all(value.map((v) => walk(v)));
|
|
954
|
+
return out;
|
|
955
|
+
}
|
|
956
|
+
return rebuildObject(value);
|
|
957
|
+
}
|
|
958
|
+
return value;
|
|
959
|
+
};
|
|
960
|
+
return walk(obj);
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
// src/i18n/i18n.ts
|
|
964
|
+
var I18n = class {
|
|
965
|
+
constructor(options) {
|
|
966
|
+
this.options = options;
|
|
967
|
+
this.locales = new Set(this.options.locales);
|
|
968
|
+
this.defaultLocale = this.options.defaultLocale ?? this.options.locales[0];
|
|
969
|
+
this.mw = new MiddlewareDispatcher({
|
|
970
|
+
acceptResult: (res) => res != null,
|
|
971
|
+
errorHandler: (e) => {
|
|
972
|
+
throw e;
|
|
973
|
+
}
|
|
974
|
+
});
|
|
975
|
+
this.shadowMiddlewares = [];
|
|
976
|
+
}
|
|
977
|
+
middleware(mw, prior = false) {
|
|
978
|
+
this.mw.middleware((locale, text, ...args) => {
|
|
979
|
+
const ex = args.slice(0, -1);
|
|
980
|
+
const next = args[args.length - 1];
|
|
981
|
+
return mw(locale, text, next, ...ex);
|
|
982
|
+
}, prior);
|
|
983
|
+
if (prior) {
|
|
984
|
+
this.shadowMiddlewares.unshift(mw);
|
|
985
|
+
} else {
|
|
986
|
+
this.shadowMiddlewares.push(mw);
|
|
987
|
+
}
|
|
988
|
+
return this;
|
|
989
|
+
}
|
|
990
|
+
removeMiddleware(mw) {
|
|
991
|
+
const idx = this.shadowMiddlewares.indexOf(mw);
|
|
992
|
+
if (idx >= 0) {
|
|
993
|
+
this.shadowMiddlewares.splice(idx, 1);
|
|
994
|
+
this.mw.middlewares.splice(idx, 1);
|
|
995
|
+
}
|
|
996
|
+
return this;
|
|
997
|
+
}
|
|
998
|
+
getExactLocale(locale) {
|
|
999
|
+
const input = (locale ?? "").trim();
|
|
1000
|
+
if (!input) return this.defaultLocale;
|
|
1001
|
+
if (this.locales.has(input)) return input;
|
|
1002
|
+
const entries = Array.from(this.locales).map((l) => ({
|
|
1003
|
+
orig: l,
|
|
1004
|
+
lower: l.toLowerCase()
|
|
1005
|
+
}));
|
|
1006
|
+
const lower = input.toLowerCase();
|
|
1007
|
+
const exact = entries.find((e) => e.lower === lower);
|
|
1008
|
+
if (exact) return exact.orig;
|
|
1009
|
+
const parts = lower.split("-");
|
|
1010
|
+
while (parts.length > 1) {
|
|
1011
|
+
parts.pop();
|
|
1012
|
+
const candidate = parts.join("-");
|
|
1013
|
+
const hit = entries.find((e) => e.lower === candidate);
|
|
1014
|
+
if (hit) return hit.orig;
|
|
1015
|
+
}
|
|
1016
|
+
return this.defaultLocale;
|
|
1017
|
+
}
|
|
1018
|
+
buildFallbackChain(locale) {
|
|
1019
|
+
const best = this.getExactLocale(locale);
|
|
1020
|
+
const parts = [];
|
|
1021
|
+
const segs = best.split("-");
|
|
1022
|
+
for (let i = segs.length; i > 1; i--)
|
|
1023
|
+
parts.push(segs.slice(0, i).join("-"));
|
|
1024
|
+
parts.push(segs[0]);
|
|
1025
|
+
if (!parts.includes(this.defaultLocale)) parts.push(this.defaultLocale);
|
|
1026
|
+
return Array.from(new Set(parts)).filter((p) => this.locales.has(p));
|
|
1027
|
+
}
|
|
1028
|
+
async applyMiddlewares(locale, text, ...ex) {
|
|
1029
|
+
const tryLocale = (locale2) => this.mw.dispatch(locale2, text, ...ex);
|
|
1030
|
+
for (const loc of this.buildFallbackChain(locale)) {
|
|
1031
|
+
const result = await tryLocale(loc);
|
|
1032
|
+
if (result != null) {
|
|
1033
|
+
return result;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
return void 0;
|
|
1037
|
+
}
|
|
1038
|
+
async translateString(locale, text, ...ex) {
|
|
1039
|
+
if (!text) return text;
|
|
1040
|
+
locale = this.getExactLocale(locale);
|
|
1041
|
+
const pieces = parseI18n(text);
|
|
1042
|
+
if (!pieces.some((p) => p.type === "ph")) {
|
|
1043
|
+
return pieces.map((p) => p.type === "raw" ? p.value : `#{${p.rawInner}}`).join("");
|
|
1044
|
+
}
|
|
1045
|
+
const promises = [];
|
|
1046
|
+
for (const p of pieces) {
|
|
1047
|
+
if (p.type === "ph") {
|
|
1048
|
+
promises.push(this.applyMiddlewares(locale, p.key, ...ex));
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
const results = await Promise.all(promises);
|
|
1052
|
+
let out = "";
|
|
1053
|
+
let k = 0;
|
|
1054
|
+
for (const p of pieces) {
|
|
1055
|
+
if (p.type === "raw") {
|
|
1056
|
+
out += p.value;
|
|
1057
|
+
} else {
|
|
1058
|
+
const r = results[k++];
|
|
1059
|
+
out += r == null ? `#{${p.rawInner}}` : r;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
return out;
|
|
1063
|
+
}
|
|
1064
|
+
async translate(locale, obj, ...ex) {
|
|
1065
|
+
return patchStringInObject(
|
|
1066
|
+
obj,
|
|
1067
|
+
(s) => this.translateString(locale, s, ...ex)
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
// src/i18n/middlewares/lookup.ts
|
|
1073
|
+
var I18nLookupMiddleware = (dict, options) => {
|
|
1074
|
+
const matchType = options?.matchType ?? "exact";
|
|
1075
|
+
const dictFactory = typeof dict === "function" ? dict : () => dict;
|
|
1076
|
+
const pickBestByHierarchy = (input, locales) => {
|
|
1077
|
+
if (!input) return void 0;
|
|
1078
|
+
const entries = locales.map((l) => ({ orig: l, lower: l.toLowerCase() }));
|
|
1079
|
+
const lower = input.toLowerCase();
|
|
1080
|
+
const exact = entries.find((e) => e.lower === lower);
|
|
1081
|
+
if (exact) return exact.orig;
|
|
1082
|
+
const parts = lower.split("-");
|
|
1083
|
+
while (parts.length > 1) {
|
|
1084
|
+
parts.pop();
|
|
1085
|
+
const candidate = parts.join("-");
|
|
1086
|
+
const hit = entries.find((e) => e.lower === candidate);
|
|
1087
|
+
if (hit) return hit.orig;
|
|
1088
|
+
}
|
|
1089
|
+
return void 0;
|
|
1090
|
+
};
|
|
1091
|
+
return async (locale, key, next, ...ex) => {
|
|
1092
|
+
const dictResolved = await dictFactory(locale, key, ...ex);
|
|
1093
|
+
let dictionary = dictResolved[locale];
|
|
1094
|
+
if (!dictionary) {
|
|
1095
|
+
if (matchType === "hierarchy") {
|
|
1096
|
+
const best = pickBestByHierarchy(locale, Object.keys(dictResolved));
|
|
1097
|
+
if (best) dictionary = dictResolved[best];
|
|
1098
|
+
} else if (matchType === "startsWith") {
|
|
1099
|
+
const keys = Object.keys(dictResolved).filter(
|
|
1100
|
+
(k) => locale.startsWith(k)
|
|
1101
|
+
);
|
|
1102
|
+
if (keys.length) {
|
|
1103
|
+
const best = keys.reduce((a, b) => b.length > a.length ? b : a);
|
|
1104
|
+
dictionary = dictResolved[best];
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
if (dictionary && Object.prototype.hasOwnProperty.call(dictionary, key)) {
|
|
1109
|
+
const val = dictionary[key];
|
|
1110
|
+
if (val != null) {
|
|
1111
|
+
return val;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
return next();
|
|
1115
|
+
};
|
|
1116
|
+
};
|
|
1117
|
+
var createI18nLookupMiddleware = () => I18nLookupMiddleware;
|
|
778
1118
|
// Annotate the CommonJS export names for ESM import in node:
|
|
779
1119
|
0 && (module.exports = {
|
|
780
1120
|
AbortedError,
|
|
1121
|
+
I18n,
|
|
1122
|
+
I18nLookupMiddleware,
|
|
1123
|
+
MiddlewareDispatcher,
|
|
781
1124
|
RoundRobin,
|
|
782
1125
|
WF_NODE,
|
|
783
1126
|
WorkflowDispatcher,
|
|
784
1127
|
abortable,
|
|
1128
|
+
createI18nLookupMiddleware,
|
|
785
1129
|
dualizeAny,
|
|
1130
|
+
patchStringInObject,
|
|
786
1131
|
workflow
|
|
787
1132
|
});
|
|
788
1133
|
//# sourceMappingURL=index.cjs.map
|