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