i18n-keyless-react 1.9.6 → 1.10.1

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.
@@ -19,7 +19,7 @@ vi.mock("../store", async () => {
19
19
  useCurrentLanguage: vi.fn(),
20
20
  getTranslationCore: vi.fn(),
21
21
  setCurrentLanguage: vi.fn(),
22
- fetchAllTranslations: vi.fn(),
22
+ getAllTranslationsFromLanguage: vi.fn(),
23
23
  clearI18nKeylessStorage: vi.fn(),
24
24
  init: actual.init,
25
25
  };
package/dist/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export { I18nKeylessText } from "./I18nKeylessText";
2
2
  export { init, setCurrentLanguage, useCurrentLanguage, getTranslation } from "./store";
3
3
  export { clearI18nKeylessStorage } from "./utils";
4
4
  export type { I18nKeylessTextProps } from "./I18nKeylessText";
5
- export { type I18nConfig, type Lang, type PrimaryLang, type Translations, type TranslationStore, type TranslationStoreState, type I18nKeylessRequestBody, type I18nKeylessResponse, type TranslationOptions, fetchAllTranslations, validateLanguage, queue, } from "i18n-keyless-core";
5
+ export { type I18nConfig, type Lang, type PrimaryLang, type Translations, type TranslationStore, type TranslationStoreState, type I18nKeylessRequestBody, type I18nKeylessResponse, type TranslationOptions, getAllTranslationsFromLanguage, validateLanguage, queue, } from "i18n-keyless-core";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { I18nKeylessText } from "./I18nKeylessText";
2
2
  export { init, setCurrentLanguage, useCurrentLanguage, getTranslation } from "./store";
3
3
  export { clearI18nKeylessStorage } from "./utils";
4
- export { fetchAllTranslations, validateLanguage, queue, } from "i18n-keyless-core";
4
+ export { getAllTranslationsFromLanguage, validateLanguage, queue, } from "i18n-keyless-core";
package/dist/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "i18n-keyless-react",
3
3
  "private": false,
4
- "version": "1.9.6",
4
+ "version": "1.10.1",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
package/dist/store.d.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  import { type I18nConfig, type Lang, type TranslationStore, type TranslationOptions } from "i18n-keyless-core";
2
2
  export declare const useI18nKeyless: import("zustand").UseBoundStore<import("zustand").StoreApi<TranslationStore>>;
3
- export declare function init(newConfig: I18nConfig): Promise<void>;
3
+ /**
4
+ * Initializes the i18n configuration with defaults and validation
5
+ * @param newConfig - The configuration object to initialize
6
+ * @returns The validated and completed configuration
7
+ * @throws Error if required configuration properties are missing
8
+ */
9
+ export declare function init(newConfig: Omit<I18nConfig, "getAllTranslationsForAllLanguages">): Promise<void>;
4
10
  export declare function useCurrentLanguage(): Lang | null;
5
11
  export declare function getTranslation(key: string, options?: TranslationOptions): string;
6
12
  export declare function setCurrentLanguage(lang: I18nConfig["languages"]["supported"][number]): void;
package/dist/store.js CHANGED
@@ -1,10 +1,10 @@
1
- import { queue, fetchAllTranslations, validateLanguage, getTranslationCore, } from "i18n-keyless-core";
1
+ import { queue, getAllTranslationsFromLanguage, validateLanguage, getTranslationCore, } from "i18n-keyless-core";
2
2
  import { create } from "zustand";
3
- import { init as initRoot, storeKeys, setItem, getItem, clearI18nKeylessStorage } from "./utils";
3
+ import { storeKeys, setItem, getItem, clearI18nKeylessStorage } from "./utils";
4
4
  queue.on("empty", () => {
5
5
  // when each word is translated, fetch the translations for the current language
6
6
  const store = useI18nKeyless.getState();
7
- fetchAllTranslations(store.currentLanguage, store).then(store.setTranslations);
7
+ getAllTranslationsFromLanguage(store.currentLanguage, store).then(store.setTranslations);
8
8
  });
9
9
  export const useI18nKeyless = create((set, get) => ({
10
10
  uniqueId: null,
@@ -58,7 +58,7 @@ export const useI18nKeyless = create((set, get) => ({
58
58
  }
59
59
  // Only fetch translations if the new language is not the primary language
60
60
  if (lang !== config.languages.primary) {
61
- await fetchAllTranslations(lang, get()).then(get().setTranslations);
61
+ await getAllTranslationsFromLanguage(lang, get()).then(get().setTranslations);
62
62
  }
63
63
  },
64
64
  }));
@@ -102,12 +102,47 @@ async function hydrate() {
102
102
  useI18nKeyless.setState({ lastRefresh: lastRefresh });
103
103
  }
104
104
  }
105
+ /**
106
+ * Initializes the i18n configuration with defaults and validation
107
+ * @param newConfig - The configuration object to initialize
108
+ * @returns The validated and completed configuration
109
+ * @throws Error if required configuration properties are missing
110
+ */
105
111
  export async function init(newConfig) {
106
- const config = await initRoot(newConfig);
107
- useI18nKeyless.setState({ config });
112
+ if (!newConfig.languages) {
113
+ throw new Error("i18n-keyless: languages is required");
114
+ }
115
+ if (!newConfig.languages.primary) {
116
+ throw new Error("i18n-keyless: primary is required");
117
+ }
118
+ if (!newConfig.languages.initWithDefault) {
119
+ newConfig.languages.initWithDefault = newConfig.languages.primary;
120
+ }
121
+ if (!newConfig.languages.fallback) {
122
+ newConfig.languages.fallback = newConfig.languages.primary;
123
+ }
124
+ if (!newConfig.languages.supported.includes(newConfig.languages.initWithDefault)) {
125
+ newConfig.languages.supported.push(newConfig.languages.initWithDefault);
126
+ }
127
+ if (!newConfig.storage) {
128
+ console.log("storage is required", newConfig.storage);
129
+ throw new Error("i18n-keyless: storage is required. You can use react-native-mmkv, @react-native-async-storage/async-storage, or window.localStorage, or any storage that has a getItem, setItem, removeItem, or get, set, and remove method");
130
+ }
131
+ if (!newConfig.getAllTranslations || !newConfig.handleTranslate) {
132
+ if (!newConfig.API_KEY) {
133
+ if (!newConfig.API_URL) {
134
+ throw new Error("i18n-keyless: you didn't provide an API_KEY nor an API_URL nor a handleTranslate + getAllTranslations function. You need to provide one of them to make i18n-keyless work");
135
+ }
136
+ }
137
+ }
138
+ if (newConfig.addMissingTranslations !== false) {
139
+ // default to true
140
+ newConfig.addMissingTranslations = true;
141
+ }
142
+ useI18nKeyless.setState({ config: newConfig });
108
143
  await hydrate();
109
144
  const currentLanguage = useI18nKeyless.getState().currentLanguage;
110
- config.onInit?.(currentLanguage);
145
+ newConfig.onInit?.(currentLanguage);
111
146
  }
112
147
  export function useCurrentLanguage() {
113
148
  const currentLanguage = useI18nKeyless((state) => state.currentLanguage);
package/dist/utils.d.ts CHANGED
@@ -31,13 +31,6 @@ export declare function setItem(key: string, value: string, storage: I18nConfig[
31
31
  * @throws Error if storage is not initialized
32
32
  */
33
33
  export declare function deleteItem(key: string, storage: I18nConfig["storage"]): Promise<void>;
34
- /**
35
- * Initializes the i18n configuration with defaults and validation
36
- * @param newConfig - The configuration object to initialize
37
- * @returns The validated and completed configuration
38
- * @throws Error if required configuration properties are missing
39
- */
40
- export declare function init(newConfig: I18nConfig): Promise<I18nConfig>;
41
34
  /**
42
35
  * Clears all i18n-keyless data from storage
43
36
  * @param storage - The storage implementation to clear
package/dist/utils.js CHANGED
@@ -90,45 +90,6 @@ export async function deleteItem(key, storage) {
90
90
  console.error("i18n-keyless: Error deleting item:", error);
91
91
  }
92
92
  }
93
- /**
94
- * Initializes the i18n configuration with defaults and validation
95
- * @param newConfig - The configuration object to initialize
96
- * @returns The validated and completed configuration
97
- * @throws Error if required configuration properties are missing
98
- */
99
- export async function init(newConfig) {
100
- if (!newConfig.languages) {
101
- throw new Error("i18n-keyless: languages is required");
102
- }
103
- if (!newConfig.languages.primary) {
104
- throw new Error("i18n-keyless: primary is required");
105
- }
106
- if (!newConfig.languages.initWithDefault) {
107
- newConfig.languages.initWithDefault = newConfig.languages.primary;
108
- }
109
- if (!newConfig.languages.fallback) {
110
- newConfig.languages.fallback = newConfig.languages.primary;
111
- }
112
- if (!newConfig.languages.supported.includes(newConfig.languages.initWithDefault)) {
113
- newConfig.languages.supported.push(newConfig.languages.initWithDefault);
114
- }
115
- if (!newConfig.storage) {
116
- console.log("storage is required", newConfig.storage);
117
- throw new Error("i18n-keyless: storage is required. You can use react-native-mmkv, @react-native-async-storage/async-storage, or window.localStorage, or any storage that has a getItem, setItem, removeItem, or get, set, and remove method");
118
- }
119
- if (!newConfig.getAllTranslations || !newConfig.handleTranslate) {
120
- if (!newConfig.API_KEY) {
121
- if (!newConfig.API_URL) {
122
- throw new Error("i18n-keyless: you didn't provide an API_KEY nor an API_URL nor a handleTranslate + getAllTranslations function. You need to provide one of them to make i18n-keyless work");
123
- }
124
- }
125
- }
126
- if (newConfig.addMissingTranslations !== false) {
127
- // default to true
128
- newConfig.addMissingTranslations = true;
129
- }
130
- return newConfig;
131
- }
132
93
  /**
133
94
  * Clears all i18n-keyless data from storage
134
95
  * @param storage - The storage implementation to clear
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "i18n-keyless-react",
3
3
  "private": false,
4
- "version": "1.9.6",
4
+ "version": "1.10.1",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
package/dist/api.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export declare const api: {
2
- fetchTranslations: (url: string, options: RequestInit) => Promise<any>;
3
- fetchTranslation: (url: string, options: RequestInit) => Promise<any>;
4
- };
package/dist/api.js DELETED
@@ -1,16 +0,0 @@
1
- export const api = {
2
- fetchTranslations: async (url, options) => {
3
- return fetch(url, options)
4
- .then((res) => res.json())
5
- .catch((err) => {
6
- return { ok: false, error: err.message };
7
- });
8
- },
9
- fetchTranslation: async (url, options) => {
10
- return fetch(url, options)
11
- .then((res) => res.json())
12
- .catch((err) => {
13
- return { ok: false, error: err.message };
14
- });
15
- },
16
- };
@@ -1,24 +0,0 @@
1
- type Task<T> = () => Promise<T>;
2
- declare class EventEmitter {
3
- private events;
4
- on(event: string, callback: () => void): void;
5
- off(event: string, callback: () => void): void;
6
- emit(event: string): void;
7
- }
8
- export default class MyPQueue extends EventEmitter {
9
- private queue;
10
- private pending;
11
- private readonly concurrency;
12
- private processing;
13
- constructor(options?: {
14
- concurrency?: number;
15
- });
16
- add<T>(task: Task<T>, options?: {
17
- priority?: number;
18
- id?: string;
19
- }): Promise<T>;
20
- private processNext;
21
- get size(): number;
22
- get isPaused(): boolean;
23
- }
24
- export {};
package/dist/my-pqueue.js DELETED
@@ -1,108 +0,0 @@
1
- // https://github.com/sindresorhus/p-queue/issues/145#issuecomment-882068004
2
- // p-queu import is broken, so here is the smalle implementation of it
3
- class EventEmitter {
4
- constructor() {
5
- Object.defineProperty(this, "events", {
6
- enumerable: true,
7
- configurable: true,
8
- writable: true,
9
- value: {}
10
- });
11
- }
12
- on(event, callback) {
13
- if (!this.events[event]) {
14
- this.events[event] = [];
15
- }
16
- this.events[event].push(callback);
17
- }
18
- off(event, callback) {
19
- if (!this.events[event])
20
- return;
21
- this.events[event] = this.events[event].filter((cb) => cb !== callback);
22
- }
23
- emit(event) {
24
- if (!this.events[event])
25
- return;
26
- this.events[event].forEach((callback) => callback());
27
- }
28
- }
29
- export default class MyPQueue extends EventEmitter {
30
- constructor(options = {}) {
31
- super();
32
- Object.defineProperty(this, "queue", {
33
- enumerable: true,
34
- configurable: true,
35
- writable: true,
36
- value: []
37
- });
38
- Object.defineProperty(this, "pending", {
39
- enumerable: true,
40
- configurable: true,
41
- writable: true,
42
- value: 0
43
- });
44
- Object.defineProperty(this, "concurrency", {
45
- enumerable: true,
46
- configurable: true,
47
- writable: true,
48
- value: void 0
49
- });
50
- Object.defineProperty(this, "processing", {
51
- enumerable: true,
52
- configurable: true,
53
- writable: true,
54
- value: false
55
- });
56
- this.concurrency = options.concurrency ?? Infinity;
57
- }
58
- add(task, options = {}) {
59
- const { priority = 0, id = String(Date.now()) } = options;
60
- // If task with same ID exists, return its promise
61
- const existingTask = this.queue.find((item) => item.id === id);
62
- if (existingTask) {
63
- return existingTask.task();
64
- }
65
- return new Promise((resolve, reject) => {
66
- const wrappedTask = async () => {
67
- try {
68
- const result = await task();
69
- resolve(result);
70
- return result;
71
- }
72
- catch (error) {
73
- reject(error);
74
- throw error;
75
- }
76
- finally {
77
- this.pending--;
78
- this.processNext();
79
- }
80
- };
81
- this.queue.push({ task: wrappedTask, priority, id });
82
- this.queue.sort((a, b) => b.priority - a.priority);
83
- this.processNext();
84
- });
85
- }
86
- async processNext() {
87
- if (this.processing)
88
- return;
89
- this.processing = true;
90
- while (this.queue.length > 0 && this.pending < this.concurrency) {
91
- const task = this.queue.shift();
92
- if (task) {
93
- this.pending++;
94
- task.task().catch(() => { });
95
- }
96
- }
97
- this.processing = false;
98
- if (this.queue.length === 0 && this.pending === 0) {
99
- this.emit("empty");
100
- }
101
- }
102
- get size() {
103
- return this.queue.length;
104
- }
105
- get isPaused() {
106
- return false;
107
- }
108
- }