@novely/core 0.12.4 → 0.13.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/dist/index.js CHANGED
@@ -229,15 +229,79 @@ function klona(val) {
229
229
  return val;
230
230
  }
231
231
 
232
+ // src/translation.ts
233
+ var RGX = /{{(.*?)}}/g;
234
+ var split = (input, delimeters) => {
235
+ const output = [];
236
+ for (const delimeter of delimeters) {
237
+ if (!input)
238
+ break;
239
+ const [start, end] = input.split(delimeter, 2);
240
+ output.push(start);
241
+ input = end;
242
+ }
243
+ output.push(input);
244
+ return output;
245
+ };
246
+ var unwrap = (c) => {
247
+ if (Array.isArray(c)) {
248
+ return c.map((item) => unwrap(item)).join("<br>");
249
+ }
250
+ if (typeof c === "function") {
251
+ return unwrap(c());
252
+ }
253
+ return c;
254
+ };
255
+ var replace = (str2, obj, pluralization, actions, pr) => {
256
+ return unwrap(str2).replaceAll(RGX, (x, key, y) => {
257
+ x = 0;
258
+ y = obj;
259
+ const [pathstr, plural, action] = split(key.trim(), ["@", "%"]);
260
+ if (!pathstr) {
261
+ return "";
262
+ }
263
+ const path = pathstr.split(".");
264
+ while (y && x < path.length)
265
+ y = y[path[x++]];
266
+ if (plural && pluralization && y && pr) {
267
+ y = pluralization[plural][pr.select(y)];
268
+ }
269
+ const actionHandler = actions && action && actions[action];
270
+ if (actionHandler)
271
+ y = actionHandler(y);
272
+ return y == null ? "" : y;
273
+ });
274
+ };
275
+
276
+ // src/storage.ts
277
+ var localStorageStorage = (options) => {
278
+ return {
279
+ async get() {
280
+ const fallback = { saves: [], data: {}, meta: [] };
281
+ try {
282
+ const value = localStorage.getItem(options.key);
283
+ return value ? JSON.parse(value) : fallback;
284
+ } catch {
285
+ return fallback;
286
+ }
287
+ },
288
+ async set(data) {
289
+ try {
290
+ localStorage.setItem(options.key, JSON.stringify(data));
291
+ } catch {
292
+ }
293
+ }
294
+ };
295
+ };
296
+
232
297
  // src/novely.ts
233
- import { replace as replaceT9N } from "@novely/t9n";
234
298
  var novely = ({
235
299
  characters,
236
- storage,
300
+ storage = localStorageStorage({ key: "novely-game-storage" }),
237
301
  storageDelay = Promise.resolve(),
238
302
  renderer: createRenderer,
239
303
  initialScreen = "mainmenu",
240
- t9n,
304
+ translation,
241
305
  languages,
242
306
  state: defaultState,
243
307
  data: defaultData,
@@ -358,6 +422,9 @@ var novely = ({
358
422
  storage.set(value);
359
423
  };
360
424
  const throttledOnStorageDataChange = throttle(onStorageDataChange, throttleTimeout);
425
+ const throttledEmergencyOnStorageDataChange = throttle(() => {
426
+ onStorageDataChange($.get());
427
+ }, 10);
361
428
  $.subscribe(throttledOnStorageDataChange);
362
429
  const getStoredData = async () => {
363
430
  let stored = await storage.get();
@@ -383,6 +450,12 @@ var novely = ({
383
450
  storageDelay.then(getStoredData);
384
451
  const initial = getDefaultSave(klona(defaultState));
385
452
  const stack = createStack(initial);
453
+ addEventListener("visibilitychange", () => {
454
+ if (document.visibilityState === "hidden") {
455
+ throttledEmergencyOnStorageDataChange();
456
+ }
457
+ });
458
+ addEventListener("beforeunload", throttledEmergencyOnStorageDataChange);
386
459
  const save = (override = false, type = override ? "auto" : "manual") => {
387
460
  if (!$$.get().dataLoaded)
388
461
  return;
@@ -589,6 +662,9 @@ var novely = ({
589
662
  const back = () => {
590
663
  return stack.back(), restore(stack.value);
591
664
  };
665
+ const t = (key, lang) => {
666
+ return translation[lang].internal[key];
667
+ };
592
668
  const renderer = createRenderer({
593
669
  characters,
594
670
  set,
@@ -597,9 +673,9 @@ var novely = ({
597
673
  newGame,
598
674
  exit,
599
675
  back,
676
+ t,
600
677
  stack,
601
678
  languages,
602
- t: t9n.i,
603
679
  $,
604
680
  $$
605
681
  });
@@ -646,7 +722,7 @@ var novely = ({
646
722
  }
647
723
  return c || "";
648
724
  })();
649
- const run = renderer.dialog(unwrap(content), unwrap(name), character, emotion);
725
+ const run = renderer.dialog(unwrap2(content), unwrap2(name), character, emotion);
650
726
  run(forward, goingBack);
651
727
  },
652
728
  function([fn]) {
@@ -662,10 +738,10 @@ var novely = ({
662
738
  question = "";
663
739
  }
664
740
  const unwrapped = choices.map(([content, action2, visible]) => {
665
- return [unwrap(content), action2, visible];
741
+ return [unwrap2(content), action2, visible];
666
742
  });
667
743
  const run = renderer.choices(
668
- unwrap(question),
744
+ unwrap2(question),
669
745
  unwrapped
670
746
  );
671
747
  run((selected) => {
@@ -704,7 +780,7 @@ var novely = ({
704
780
  times.clear();
705
781
  },
706
782
  input([question, onInput, setup]) {
707
- renderer.input(unwrap(question), onInput, setup)(forward);
783
+ renderer.input(unwrap2(question), onInput, setup)(forward);
708
784
  },
709
785
  custom([handler]) {
710
786
  const result = renderer.custom(handler, goingBack, () => {
@@ -744,7 +820,7 @@ var novely = ({
744
820
  match("custom", [handler]);
745
821
  },
746
822
  text(text) {
747
- renderer.text(text.map((content) => unwrap(content)).join(" "), forward, goingBack);
823
+ renderer.text(text.map((content) => unwrap2(content)).join(" "), forward, goingBack);
748
824
  },
749
825
  exit() {
750
826
  if (restoring)
@@ -836,7 +912,7 @@ var novely = ({
836
912
  const interactivity = (value = false) => {
837
913
  interacted = value ? interacted + 1 : 0;
838
914
  };
839
- const unwrap = (content, global = false) => {
915
+ const unwrap2 = (content, global = false) => {
840
916
  const {
841
917
  data: data2,
842
918
  meta: [lang]
@@ -844,7 +920,11 @@ var novely = ({
844
920
  const obj = global ? data2 : state();
845
921
  const cnt = isFunction(content) ? content(lang, obj) : typeof content === "string" ? content : content[lang];
846
922
  const str2 = isFunction(cnt) ? cnt() : cnt;
847
- return replaceT9N(str2, obj);
923
+ const trans = translation[lang];
924
+ if (trans.actions || trans.plural) {
925
+ return replace(str2, obj, trans.plural, trans.actions, new Intl.PluralRules(trans.tag || lang));
926
+ }
927
+ return replace(str2, obj);
848
928
  };
849
929
  function data(value) {
850
930
  if (!value)
@@ -877,28 +957,149 @@ var novely = ({
877
957
  * Unwraps translatable content to a string value
878
958
  */
879
959
  unwrap(content) {
880
- return unwrap(content, true);
881
- },
882
- /**
883
- * Function that is used for translation
884
- */
885
- t: t9n.t
960
+ return unwrap2(content, true);
961
+ }
886
962
  };
887
963
  };
888
964
 
889
- // src/storage.ts
890
- var localStorageStorage = (options) => {
891
- return {
892
- async get() {
893
- const value = localStorage.getItem(options.key);
894
- return value ? JSON.parse(value) : { saves: [], data: {}, meta: [] };
895
- },
896
- async set(data) {
897
- localStorage.setItem(options.key, JSON.stringify(data));
898
- }
899
- };
965
+ // src/translations.ts
966
+ var RU = {
967
+ NewGame: "\u041D\u043E\u0432\u0430\u044F \u0438\u0433\u0440\u0430",
968
+ HomeScreen: "\u0413\u043B\u0430\u0432\u043D\u044B\u0439 \u044D\u043A\u0440\u0430\u043D",
969
+ ToTheGame: "\u041A \u0438\u0433\u0440\u0435",
970
+ Language: "\u042F\u0437\u044B\u043A",
971
+ NoSaves: "\u0421\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u0439 \u043D\u0435\u0442",
972
+ LoadSave: "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C",
973
+ Saves: "\u0421\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u044F",
974
+ Settings: "\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438",
975
+ Sumbit: "\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C",
976
+ GoBack: "\u041D\u0430\u0437\u0430\u0434",
977
+ DoSave: "\u0421\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u0435",
978
+ Auto: "\u0410\u0432\u0442\u043E",
979
+ Stop: "\u0421\u0442\u043E\u043F",
980
+ Exit: "\u0412\u044B\u0445\u043E\u0434",
981
+ Automatic: "\u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u043E\u0435",
982
+ Manual: "\u0420\u0443\u0447\u043D\u043E\u0435",
983
+ Remove: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C",
984
+ LoadASaveFrom: "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u0435 \u043E\u0442",
985
+ DeleteASaveFrom: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u0435 \u043E\u0442",
986
+ TextSpeed: "\u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u0422\u0435\u043A\u0441\u0442\u0430",
987
+ TextSpeedSlow: "\u041C\u0435\u0434\u043B\u0435\u043D\u043D\u0430\u044F",
988
+ TextSpeedMedium: "\u0421\u0440\u0435\u0434\u043D\u044F\u044F",
989
+ TextSpeedFast: "\u0411\u044B\u0441\u0442\u0440\u0430\u044F",
990
+ TextSpeedAuto: "\u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0430\u044F",
991
+ CompleteText: "\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0442\u0435\u043A\u0441\u0442",
992
+ GoForward: "\u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u0432\u043F\u0435\u0440\u0451\u0434",
993
+ ExitDialogWarning: "\u0412\u044B \u0443\u0432\u0435\u0440\u0435\u043D\u044B, \u0447\u0442\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0432\u044B\u0439\u0442\u0438? \u041F\u0440\u043E\u0433\u0440\u0435\u0441\u0441 \u0431\u0443\u0434\u0435\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D.",
994
+ ExitDialogExit: "\u0412\u044B\u0439\u0442\u0438",
995
+ ExitDialogBack: "\u0412\u0435\u0440\u043D\u0443\u0442\u044C\u0441\u044F \u0432 \u0438\u0433\u0440\u0443",
996
+ OpenMenu: "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u043C\u0435\u043D\u044E",
997
+ CloseMenu: "\u0417\u0430\u043A\u0440\u044B\u0442\u044C \u043C\u0435\u043D\u044E"
998
+ };
999
+ var EN = {
1000
+ NewGame: "New Game",
1001
+ HomeScreen: "Home Screen",
1002
+ ToTheGame: "To the Game",
1003
+ Language: "Language",
1004
+ NoSaves: "No saves",
1005
+ LoadSave: "Load",
1006
+ Saves: "Saves",
1007
+ Settings: "Settings",
1008
+ Sumbit: "Submit",
1009
+ GoBack: "Go back",
1010
+ DoSave: "Save",
1011
+ Auto: "Auto",
1012
+ Stop: "Stop",
1013
+ Exit: "Exit",
1014
+ Automatic: "Automatic",
1015
+ Manual: "Manual",
1016
+ Remove: "Remove",
1017
+ LoadASaveFrom: "Load a save from",
1018
+ DeleteASaveFrom: "Delete a save from",
1019
+ TextSpeed: "Text Speed",
1020
+ TextSpeedSlow: "Slow",
1021
+ TextSpeedMedium: "Medium",
1022
+ TextSpeedFast: "Fast",
1023
+ TextSpeedAuto: "Auto",
1024
+ CompleteText: "Complete text",
1025
+ GoForward: "Go forward",
1026
+ ExitDialogWarning: "Are you sure you want to exit? Progress will be saved.",
1027
+ ExitDialogExit: "Exit",
1028
+ ExitDialogBack: "Return to game",
1029
+ OpenMenu: "Open menu",
1030
+ CloseMenu: "Close menu"
1031
+ };
1032
+ var KK = {
1033
+ NewGame: "\u0416\u0430\u04A3\u0430 \u043E\u0439\u044B\u043D",
1034
+ HomeScreen: "\u041D\u0435\u0433\u0456\u0437\u0433\u0456 \u044D\u043A\u0440\u0430\u043D",
1035
+ ToTheGame: "\u041E\u0439\u044B\u043D\u0493\u0430",
1036
+ Language: "\u0422\u0456\u043B",
1037
+ NoSaves: "\u0421\u0430\u049B\u0442\u0430\u0443 \u0436\u043E\u049B",
1038
+ LoadSave: "\u0416\u04AF\u043A\u0442\u0435\u0443",
1039
+ Saves: "\u0421\u0430\u049B\u0442\u0430\u0443",
1040
+ Settings: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043B\u0435\u0440",
1041
+ Sumbit: "\u0420\u0430\u0441\u0442\u0430\u0443",
1042
+ GoBack: "\u0410\u0440\u0442\u049B\u0430",
1043
+ DoSave: "\u0421\u0430\u049B\u0442\u0430\u0443",
1044
+ Auto: "\u0410\u0432\u0442\u043E",
1045
+ Stop: "\u0422\u043E\u049B\u0442\u0430",
1046
+ Exit: "\u0428\u044B\u0493\u0443",
1047
+ Automatic: "\u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0442\u044B",
1048
+ Manual: "\u049A\u043E\u043B\u043C\u0435\u043D",
1049
+ Remove: "\u0416\u043E\u044E",
1050
+ LoadASaveFrom: "\u0421\u0430\u049B\u0442\u0430\u0443\u0434\u044B \u0436\u04AF\u043A\u0442\u0435\u0443",
1051
+ DeleteASaveFrom: "\u0421\u0430\u049B\u0442\u0430\u0443\u0434\u044B \u0436\u043E\u044E",
1052
+ TextSpeed: "\u041C\u04D9\u0442\u0456\u043D \u0416\u044B\u043B\u0434\u0430\u043C\u0434\u044B\u0493\u044B",
1053
+ TextSpeedSlow: "\u0411\u0430\u044F\u0443",
1054
+ TextSpeedMedium: "\u041E\u0440\u0442\u0430\u0448\u0430",
1055
+ TextSpeedFast: "\u0416\u044B\u043B\u0434\u0430\u043C",
1056
+ TextSpeedAuto: "\u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0442\u044B",
1057
+ CompleteText: "\u041C\u04D9\u0442\u0456\u043D\u0434\u0456 \u0430\u044F\u049B\u0442\u0430\u0443",
1058
+ GoForward: "\u0410\u043B\u0493\u0430 \u0436\u044B\u043B\u0436\u0443",
1059
+ ExitDialogWarning: "\u0421\u0456\u0437 \u0448\u044B\u049B\u049B\u044B\u04A3\u044B\u0437 \u043A\u0435\u043B\u0435\u0442\u0456\u043D\u0456\u043D\u0435 \u0441\u0435\u043D\u0456\u043C\u0434\u0456\u0441\u0456\u0437 \u0431\u0435? \u041F\u0440\u043E\u0433\u0440\u0435\u0441\u0441 \u0441\u0430\u049B\u0442\u0430\u043B\u0430\u0434\u044B",
1060
+ ExitDialogExit: "\u0428\u044B\u0493\u0443",
1061
+ ExitDialogBack: "\u041E\u0439\u044B\u043D\u0493\u0430 \u043E\u0440\u0430\u043B\u0443",
1062
+ OpenMenu: "\u041C\u04D9\u0437\u0456\u0440\u0434\u0456 \u0430\u0448\u044B\u04A3\u044B\u0437",
1063
+ CloseMenu: "\u041C\u04D9\u0437\u0456\u0440\u0434\u0456 \u0436\u0430\u0431\u0443"
1064
+ };
1065
+ var JP = {
1066
+ NewGame: "\u300C\u65B0\u3057\u3044\u30B2\u30FC\u30E0\u300D",
1067
+ HomeScreen: "\u30DB\u30FC\u30E0\u753B\u9762",
1068
+ ToTheGame: "\u300C\u30B2\u30FC\u30E0\u306B\u623B\u308B\u300D",
1069
+ Language: "\u8A00\u8A9E",
1070
+ NoSaves: "\u30CE\u30FC\u30BB\u30FC\u30D6",
1071
+ LoadSave: "\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9",
1072
+ Saves: "\u4FDD\u5B58",
1073
+ Settings: "\u8A2D\u5B9A",
1074
+ Sumbit: "\u78BA\u8A8D",
1075
+ GoBack: "\u300C\u623B\u308B\u300D",
1076
+ DoSave: "\u4FDD\u5B58",
1077
+ Auto: "\u30AA\u30FC\u30C8",
1078
+ Stop: "\u6B62\u307E\u308C",
1079
+ Exit: "\u51FA\u53E3",
1080
+ Automatic: "\u81EA\u52D5",
1081
+ Manual: "\u30DE\u30CB\u30E5\u30A2\u30EB",
1082
+ Remove: "\u524A\u9664",
1083
+ LoadASaveFrom: "\u30ED\u30FC\u30C9\u30BB\u30FC\u30D6\u304B\u3089",
1084
+ DeleteASaveFrom: "\u304B\u3089\u4FDD\u5B58\u3092\u524A\u9664",
1085
+ TextSpeed: "\u30C6\u30AD\u30B9\u30C8\u30B9\u30D4\u30FC\u30C9",
1086
+ TextSpeedSlow: "\u300C\u9045\u3044\u300D",
1087
+ TextSpeedMedium: "\u30DF\u30C7\u30A3\u30A2\u30E0",
1088
+ TextSpeedFast: "\u300C\u901F\u3044\u300D",
1089
+ TextSpeedAuto: "\u81EA\u52D5",
1090
+ CompleteText: "\u30C6\u30AD\u30B9\u30C8\u3092\u5B8C\u6210\u3055\u305B\u308B",
1091
+ GoForward: "\u5148\u306B\u884C\u304F",
1092
+ ExitDialogWarning: "\u672C\u5F53\u306B\u7D42\u4E86\u3057\u307E\u3059\u304B\uFF1F\u9032\u884C\u72B6\u6CC1\u306F\u4FDD\u5B58\u3055\u308C\u307E\u3059",
1093
+ ExitDialogExit: "\u7D42\u4E86",
1094
+ ExitDialogBack: "\u30B2\u30FC\u30E0\u306B\u623B\u308B",
1095
+ OpenMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u958B\u304F",
1096
+ CloseMenu: "\u30E1\u30CB\u30E5\u30FC\u3092\u9589\u3058\u308B"
900
1097
  };
901
1098
  export {
1099
+ EN,
1100
+ JP,
1101
+ KK,
1102
+ RU,
902
1103
  localStorageStorage,
903
1104
  novely
904
1105
  };