i18n-keyless-react 1.17.0 → 1.17.2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "i18n-keyless-react",
3
3
  "private": false,
4
- "version": "1.17.0",
4
+ "version": "1.17.2",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
@@ -17,7 +17,7 @@
17
17
  "postpublish": "rm -rf ./dist && rm *.tgz"
18
18
  },
19
19
  "dependencies": {
20
- "i18n-keyless-core": "1.17.0",
20
+ "i18n-keyless-core": "1.17.2",
21
21
  "zustand": "^5.0.3"
22
22
  },
23
23
  "peerDependencies": {
@@ -34,8 +34,9 @@
34
34
  "eslint": "^9.9.0",
35
35
  "eslint-plugin-react-hooks": "^5.1.0-rc.0",
36
36
  "eslint-plugin-react-refresh": "^0.4.9",
37
- "happy-dom": "^17.4.4",
37
+ "happy-dom": "^20.0.11",
38
38
  "jsdom": "^26.0.0",
39
+ "typescript": "^5.9.3",
39
40
  "vitest": "^3.1.1"
40
41
  }
41
42
  }
@@ -1 +0,0 @@
1
- export {};
@@ -1,151 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { render, screen } from "@testing-library/react";
3
- import { I18nKeylessText } from "../I18nKeylessText";
4
- import { vi, beforeEach, describe, it, expect, afterEach } from "vitest";
5
- import { getTranslationCore } from "i18n-keyless-core";
6
- // Create a mock store before vi.mock call using vi.hoisted
7
- const mockStore = vi.hoisted(() => {
8
- const store = {
9
- config: {
10
- API_KEY: "any-fucking-key",
11
- languages: {
12
- primary: "en",
13
- supported: ["en"],
14
- },
15
- },
16
- currentLanguage: "en",
17
- translations: {},
18
- uniqueId: null,
19
- lastRefresh: null,
20
- setTranslations: vi.fn(),
21
- setLanguage: vi.fn((lang) => {
22
- store.currentLanguage = lang;
23
- }),
24
- };
25
- // Create a function that supports the selector pattern
26
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
- const useI18nKeylessMock = (selectorOrStore) => {
28
- // If it's a function (selector), call it with the store
29
- if (typeof selectorOrStore === "function") {
30
- return selectorOrStore(store);
31
- }
32
- // Otherwise return the store
33
- return store;
34
- };
35
- // Add the getState and setState methods to the mock function
36
- useI18nKeylessMock.getState = vi.fn(() => store);
37
- useI18nKeylessMock.setState = vi.fn((newState) => Object.assign(store, newState));
38
- return useI18nKeylessMock;
39
- });
40
- // Mock the store module - this is hoisted to the top of the file
41
- vi.mock("../store", async () => {
42
- return {
43
- useI18nKeyless: mockStore,
44
- getTranslation: vi.fn((key, options) => {
45
- return getTranslationCore(key, mockStore.getState(), options);
46
- }),
47
- };
48
- });
49
- vi.mock("../utils", () => ({
50
- validateLanguage: vi.fn((lang) => lang),
51
- }));
52
- describe("I18nKeylessText", () => {
53
- // Save original console methods
54
- const originalConsoleWarn = console.warn;
55
- const originalConsoleLog = console.log;
56
- beforeEach(() => {
57
- vi.clearAllMocks();
58
- // Mock console methods for testing
59
- console.warn = vi.fn();
60
- console.log = vi.fn();
61
- // Reset store to default state
62
- mockStore.setState({
63
- translations: {},
64
- currentLanguage: "en",
65
- config: {
66
- API_KEY: "any-fucking-key",
67
- languages: {
68
- primary: "en",
69
- supported: ["en"],
70
- },
71
- },
72
- });
73
- });
74
- afterEach(() => {
75
- // Restore original console methods
76
- console.warn = originalConsoleWarn;
77
- console.log = originalConsoleLog;
78
- });
79
- it("renders the original text when language is primary", () => {
80
- render(_jsx(I18nKeylessText, { children: "Hello World" }));
81
- expect(screen.getByText("Hello World")).toBeInTheDocument();
82
- });
83
- it("renders translated text when available", () => {
84
- mockStore.setState({
85
- currentLanguage: "fr",
86
- translations: {
87
- "Hello World": "Bonjour le monde",
88
- },
89
- });
90
- render(_jsx(I18nKeylessText, { children: "Hello World" }));
91
- expect(screen.getByText("Bonjour le monde")).toBeInTheDocument();
92
- });
93
- it("handles whitespace trimming and warns in development", () => {
94
- const originalNodeEnv = process.env.NODE_ENV;
95
- process.env.NODE_ENV = "development";
96
- render(_jsx(I18nKeylessText, { children: " Hello World " }));
97
- expect(screen.getByText("Hello World")).toBeInTheDocument();
98
- expect(console.warn).toHaveBeenCalledWith(expect.stringContaining("received text with leading/trailing whitespace"));
99
- process.env.NODE_ENV = originalNodeEnv;
100
- });
101
- it("handles text replacement", () => {
102
- render(_jsx(I18nKeylessText, { replace: { "{{name}}": "John" }, children: `Hello {{name}}` }));
103
- expect(screen.getByText("Hello John")).toBeInTheDocument();
104
- });
105
- it("handles context-specific translations", () => {
106
- mockStore.setState({
107
- currentLanguage: "fr",
108
- translations: {
109
- Welcome__header: "Bienvenue",
110
- },
111
- });
112
- render(_jsx(I18nKeylessText, { context: "header", children: "Welcome" }));
113
- expect(screen.getByText("Bienvenue")).toBeInTheDocument();
114
- });
115
- it("logs debug information when debug is true", () => {
116
- render(_jsx(I18nKeylessText, { debug: true, children: "Hello World" }));
117
- expect(console.log).toHaveBeenCalledWith(expect.objectContaining({
118
- children: "Hello World",
119
- sourceText: "Hello World",
120
- currentLanguage: "en",
121
- }));
122
- });
123
- it("handles force temporary translations", () => {
124
- const forceTemp = {
125
- fr: "Bonjour temporaire",
126
- };
127
- render(_jsx(I18nKeylessText, { forceTemporary: forceTemp, children: "Hello World" }));
128
- expect(screen.getByText("Hello World")).toBeInTheDocument();
129
- });
130
- it("falls back to source text when translation is missing", () => {
131
- mockStore.setState({
132
- currentLanguage: "fr",
133
- translations: {}, // Empty translations
134
- });
135
- render(_jsx(I18nKeylessText, { children: "Hello World" }));
136
- expect(screen.getByText("Hello World")).toBeInTheDocument();
137
- });
138
- it("handles multiple replacements in text", () => {
139
- render(_jsx(I18nKeylessText, { replace: {
140
- "{{name}}": "John",
141
- "{{age}}": "30",
142
- }, children: `{{name}} is {{age}} years old` }));
143
- expect(screen.getByText("John is 30 years old")).toBeInTheDocument();
144
- });
145
- it("preserves special characters in replacements", () => {
146
- render(_jsx(I18nKeylessText, { replace: {
147
- "{{special}}": "$@#!",
148
- }, children: `Special chars: {{special}}` }));
149
- expect(screen.getByText("Special chars: $@#!")).toBeInTheDocument();
150
- });
151
- });
@@ -1,9 +0,0 @@
1
- import { type TranslationStore } from "../../types";
2
- export declare const store: TranslationStore;
3
- export declare const mockStore: any;
4
- export declare const mockStorage: {
5
- getItem: import("vitest").Mock<(...args: any[]) => any>;
6
- setItem: import("vitest").Mock<(...args: any[]) => any>;
7
- removeItem: import("vitest").Mock<(...args: any[]) => any>;
8
- clearAll: import("vitest").Mock<(...args: any[]) => any>;
9
- };
@@ -1,44 +0,0 @@
1
- import { vi } from "vitest";
2
- import { validateLanguage } from "../../utils";
3
- export const store = {
4
- config: {
5
- API_KEY: "any-fucking-keyk",
6
- languages: {
7
- primary: "fr",
8
- supported: ["fr"],
9
- },
10
- },
11
- currentLanguage: "fr",
12
- translations: {},
13
- translationsUsage: {},
14
- uniqueId: null,
15
- lastRefresh: null,
16
- setTranslations: vi.fn(),
17
- setLanguage: vi.fn((lang) => {
18
- const validated = validateLanguage(lang, store.config);
19
- store.currentLanguage = validated;
20
- }),
21
- sendTranslationsUsage: vi.fn(),
22
- setTranslationUsage: vi.fn(),
23
- };
24
- // Create a function that supports the selector pattern
25
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
- const useI18nKeylessMock = ((selectorOrStore) => {
27
- // If it's a function (selector), call it with the store
28
- if (typeof selectorOrStore === "function") {
29
- return selectorOrStore(store);
30
- }
31
- // Otherwise return the store
32
- return store;
33
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
- });
35
- // Add the getState and setState methods to the mock function
36
- useI18nKeylessMock.getState = vi.fn(() => store);
37
- useI18nKeylessMock.setState = vi.fn((newState) => Object.assign(store, newState));
38
- export const mockStore = useI18nKeylessMock;
39
- export const mockStorage = {
40
- getItem: vi.fn(),
41
- setItem: vi.fn(),
42
- removeItem: vi.fn(),
43
- clearAll: vi.fn(),
44
- };
File without changes
@@ -1,70 +0,0 @@
1
- "use strict";
2
- // // __mocks__/zustand.ts
3
- // import { act } from '@testing-library/react'
4
- // import type * as ZustandExportedTypes from 'zustand'
5
- // export * from 'zustand'
6
- // const { create: actualCreate, createStore: actualCreateStore } =
7
- // await vi.importActual<typeof ZustandExportedTypes>('zustand')
8
- // // a variable to hold reset functions for all stores declared in the app
9
- // export const storeResetFns = new Set<() => void>()
10
- // const createUncurried = <T>(
11
- // stateCreator: ZustandExportedTypes.StateCreator<T>,
12
- // ) => {
13
- // const store = actualCreate(stateCreator)
14
- // const initialState = store.getInitialState()
15
- // storeResetFns.add(() => {
16
- // store.setState(initialState, true)
17
- // })
18
- // return store
19
- // }
20
- // // when creating a store, we get its initial state, create a reset function and add it in the set
21
- // export const create = (<T>(
22
- // stateCreator: ZustandExportedTypes.StateCreator<T>,
23
- // ) => {
24
- // console.log('zustand create mock')
25
- // // to support curried version of create
26
- // return typeof stateCreator === 'function'
27
- // ? createUncurried(stateCreator)
28
- // : createUncurried
29
- // }) as typeof ZustandExportedTypes.create
30
- // const createStoreUncurried = <T>(
31
- // stateCreator: ZustandExportedTypes.StateCreator<T>,
32
- // ) => {
33
- // const store = actualCreateStore(stateCreator)
34
- // const initialState = store.getInitialState()
35
- // storeResetFns.add(() => {
36
- // store.setState(initialState, true)
37
- // })
38
- // return store
39
- // }
40
- // // when creating a store, we get its initial state, create a reset function and add it in the set
41
- // export const createStore = (<T>(
42
- // stateCreator: ZustandExportedTypes.StateCreator<T>,
43
- // ) => {
44
- // console.log('zustand createStore mock')
45
- // // to support curried version of createStore
46
- // return typeof stateCreator === 'function'
47
- // ? createStoreUncurried(stateCreator)
48
- // : createStoreUncurried
49
- // }) as typeof ZustandExportedTypes.createStore
50
- // // reset all stores after each test run
51
- // afterEach(() => {
52
- // act(() => {
53
- // storeResetFns.forEach((resetFn) => {
54
- // resetFn()
55
- // })
56
- // })
57
- // })
58
- // export const createStore = (<T>(stateCreator: ZustandExportedTypes.StateCreator<T>) => {
59
- // console.log("zustand createStore mock");
60
- // // to support curried version of createStore
61
- // return typeof stateCreator === "function" ? createStoreUncurried(stateCreator) : createStoreUncurried;
62
- // }) as typeof ZustandExportedTypes.createStore;
63
- // // reset all stores after each test run
64
- // afterEach(() => {
65
- // act(() => {
66
- // storeResetFns.forEach((resetFn) => {
67
- // resetFn();
68
- // });
69
- // });
70
- // });
@@ -1 +0,0 @@
1
- import "@testing-library/jest-dom";
@@ -1,3 +0,0 @@
1
- import "@testing-library/jest-dom";
2
- import { vi } from "vitest";
3
- vi.mock("zustand");
@@ -1 +0,0 @@
1
- export {};
@@ -1,362 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
- import { act } from "@testing-library/react";
3
- import packageJson from "../package.json";
4
- import { mockStore, mockStorage } from "./__mocks__/store";
5
- import { useI18nKeyless, init } from "../store";
6
- import { getTranslationCore, queue } from "i18n-keyless-core";
7
- // These vi.mock calls must be at the top level, outside of any function or block
8
- vi.mock("zustand", () => ({
9
- create: () => ({
10
- getState: mockStore.getState,
11
- setState: mockStore.setState,
12
- subscribe: mockStore.subscribe,
13
- }),
14
- }));
15
- vi.mock("../store", async () => {
16
- const actual = await vi.importActual("../store");
17
- return {
18
- useI18nKeyless: mockStore,
19
- useCurrentLanguage: vi.fn(),
20
- getTranslationCore: vi.fn(),
21
- setCurrentLanguage: vi.fn(),
22
- getAllTranslationsFromLanguage: vi.fn(),
23
- clearI18nKeylessStorage: vi.fn(),
24
- init: actual.init,
25
- };
26
- });
27
- // Mock fetch for API calls
28
- global.fetch = vi.fn();
29
- describe("i18n-keyless store", () => {
30
- // Save original console methods
31
- const originalConsoleError = console.error;
32
- const originalConsoleWarn = console.warn;
33
- const originalConsoleLog = console.log;
34
- beforeEach(() => {
35
- vi.clearAllMocks();
36
- console.error = vi.fn();
37
- console.warn = vi.fn();
38
- console.log = vi.fn();
39
- useI18nKeyless.setState({ translations: {} });
40
- // The store is automatically reset by the zustand mock
41
- });
42
- afterEach(() => {
43
- // Restore original console methods
44
- console.error = originalConsoleError;
45
- console.warn = originalConsoleWarn;
46
- console.log = originalConsoleLog;
47
- });
48
- describe("init function", () => {
49
- it("should throw an error if languages is not provided", async () => {
50
- // @ts-expect-error Testing invalid config
51
- await expect(init({ storage: mockStorage })).rejects.toThrow("i18n-keyless: languages is required");
52
- });
53
- it("should throw an error if primary language is not provided", async () => {
54
- await expect(
55
- // @ts-expect-error Testing invalid config
56
- init({ languages: { supported: ["en", "fr"] }, storage: mockStorage })).rejects.toThrow("i18n-keyless: primary is required");
57
- });
58
- it("should throw an error if storage is not provided", async () => {
59
- await expect(
60
- // @ts-expect-error Testing invalid config
61
- init({ languages: { primary: "en", supported: ["en", "fr"] } })).rejects.toThrow("i18n-keyless: storage is required");
62
- });
63
- it("should throw an error if no API or custom handlers are provided", async () => {
64
- await expect(
65
- // @ts-expect-error Testing invalid config
66
- init({
67
- languages: { primary: "en", supported: ["en", "fr"] },
68
- storage: mockStorage,
69
- })).rejects.toThrow("i18n-keyless: you didn't provide an API_KEY nor an API_URL nor a handleTranslate + getAllTranslations function");
70
- });
71
- it("should initialize with API_KEY correctly", async () => {
72
- await init({
73
- languages: {
74
- primary: "en",
75
- supported: ["en", "fr"],
76
- },
77
- storage: mockStorage,
78
- API_KEY: "test-api-key",
79
- });
80
- expect(useI18nKeyless.getState().config).toEqual({
81
- addMissingTranslations: true,
82
- languages: {
83
- fallback: "en",
84
- initWithDefault: "en",
85
- primary: "en",
86
- supported: ["en", "fr"],
87
- },
88
- storage: mockStorage,
89
- API_KEY: "test-api-key",
90
- });
91
- });
92
- it("should initialize with custom handlers correctly", async () => {
93
- const handleTranslate = vi.fn();
94
- const getAllTranslations = vi.fn();
95
- await init({
96
- languages: {
97
- primary: "en",
98
- supported: ["en", "fr"],
99
- },
100
- API_KEY: "test-api-key",
101
- storage: mockStorage,
102
- handleTranslate,
103
- getAllTranslations,
104
- });
105
- expect(useI18nKeyless.getState().config).toEqual({
106
- API_KEY: "test-api-key",
107
- addMissingTranslations: true,
108
- languages: {
109
- fallback: "en",
110
- initWithDefault: "en",
111
- primary: "en",
112
- supported: ["en", "fr"],
113
- },
114
- storage: mockStorage,
115
- handleTranslate,
116
- getAllTranslations,
117
- });
118
- });
119
- it("should add initWithDefault to supported languages if not already included", async () => {
120
- await init({
121
- languages: {
122
- primary: "en",
123
- supported: ["fr"],
124
- initWithDefault: "en",
125
- },
126
- API_KEY: "test-api-key",
127
- storage: mockStorage,
128
- });
129
- expect(useI18nKeyless.getState().config?.languages.supported).toContain("en");
130
- });
131
- it("should call onInit callback with current language", async () => {
132
- const onInit = vi.fn().mockImplementation((lang) => lang);
133
- const onInitReturned = onInit("fr");
134
- await act(async () => {
135
- await init({
136
- languages: {
137
- primary: "en",
138
- supported: ["en", "fr"],
139
- },
140
- storage: mockStorage,
141
- API_KEY: "test-api-key",
142
- onInit,
143
- });
144
- });
145
- expect(onInit.mock.calls[0][0]).toBe("fr");
146
- expect(onInitReturned).toBe("fr");
147
- });
148
- });
149
- describe("hydration", () => {
150
- it("should hydrate from storage correctly", async () => {
151
- mockStorage.getItem.mockImplementation((key) => {
152
- if (key === "i18n-keyless-current-language")
153
- return "fr";
154
- if (key === "i18n-keyless-translations")
155
- return JSON.stringify({ Hello: { fr: "Bonjour" } });
156
- return Promise.resolve(null);
157
- });
158
- await init({
159
- languages: {
160
- primary: "en",
161
- supported: ["en", "fr"],
162
- },
163
- storage: mockStorage,
164
- API_KEY: "test-api-key",
165
- });
166
- expect(useI18nKeyless.getState().currentLanguage).toBe("fr");
167
- expect(useI18nKeyless.getState().translations).toEqual({ Hello: { fr: "Bonjour" } });
168
- });
169
- it("should use initWithDefault when no language is stored", async () => {
170
- mockStorage.getItem.mockResolvedValue(null);
171
- await init({
172
- languages: {
173
- primary: "en",
174
- supported: ["en", "fr"],
175
- initWithDefault: "fr",
176
- },
177
- storage: mockStorage,
178
- API_KEY: "test-api-key",
179
- });
180
- expect(useI18nKeyless.getState().currentLanguage).toBe("fr");
181
- });
182
- });
183
- describe("Translation functionality", () => {
184
- beforeEach(async () => {
185
- // Reset store and initialize with basic config
186
- await init({
187
- languages: {
188
- primary: "en",
189
- supported: ["en", "fr", "es"],
190
- },
191
- storage: mockStorage,
192
- API_KEY: "test-api-key",
193
- });
194
- });
195
- it("should return original text when current language is primary language", () => {
196
- useI18nKeyless.setState({ currentLanguage: "en" });
197
- const store = useI18nKeyless.getState();
198
- const result = getTranslationCore("Hello World", store);
199
- expect(result).toBe("Hello World");
200
- });
201
- it("should return original text when current language is primary language whatever context there is", () => {
202
- useI18nKeyless.setState({ currentLanguage: "en" });
203
- const store = useI18nKeyless.getState();
204
- const result = getTranslationCore("Hello World again", store, { context: "whatever" });
205
- expect(result).toBe("Hello World again");
206
- });
207
- it("should handle translations with context", () => {
208
- useI18nKeyless.setState({
209
- currentLanguage: "fr",
210
- translations: {
211
- Welcome__header: "Bienvenue",
212
- "Good bye__footer": "Au revoir",
213
- },
214
- });
215
- const store = useI18nKeyless.getState();
216
- const headerResult = getTranslationCore("Welcome", store, { context: "header" });
217
- const footerResult = getTranslationCore("Good bye", store, { context: "footer" });
218
- expect(headerResult).toBe("Bienvenue");
219
- expect(footerResult).toBe("Au revoir");
220
- });
221
- it("forceTemporary should works when no translation is available", () => {
222
- useI18nKeyless.setState({ currentLanguage: "fr" });
223
- const store = useI18nKeyless.getState();
224
- // Mock fetch for API calls
225
- global.fetch = vi.fn().mockResolvedValue({
226
- json: () => Promise.resolve({ ok: true, data: { translations: {} } }),
227
- });
228
- const result = getTranslationCore("Hungry", store, {
229
- forceTemporary: {
230
- fr: "J'ai faim",
231
- },
232
- });
233
- // return Hello because translation is not available in fr
234
- expect(result).toBe("Hungry");
235
- // expect fetch to have been called with the correct params
236
- expect(fetch).toHaveBeenCalledWith("https://api.i18n-keyless.com/translate", {
237
- body: JSON.stringify({
238
- key: "Hungry",
239
- forceTemporary: {
240
- fr: "J'ai faim",
241
- },
242
- languages: ["en", "fr", "es"],
243
- primaryLanguage: "en",
244
- }),
245
- headers: {
246
- Authorization: "Bearer test-api-key",
247
- "Content-Type": "application/json",
248
- Version: packageJson.version,
249
- unique_id: "",
250
- },
251
- method: "POST",
252
- });
253
- });
254
- it("forceTemporary should works when translation is available", () => {
255
- useI18nKeyless.setState({ currentLanguage: "fr", translations: { Happiness: "Joie" } });
256
- const store = useI18nKeyless.getState();
257
- // Mock fetch for API calls
258
- global.fetch = vi.fn().mockResolvedValue({
259
- json: () => Promise.resolve({ ok: true }),
260
- });
261
- const result = getTranslationCore("Happiness", store, {
262
- forceTemporary: {
263
- fr: "Joie temporaire",
264
- },
265
- });
266
- // return Joie because translation forced is not there yet
267
- expect(result).toBe("Joie");
268
- // expect fetch to have been called with the correct params
269
- expect(fetch).toHaveBeenCalledWith("https://api.i18n-keyless.com/translate", {
270
- body: JSON.stringify({
271
- key: "Happiness",
272
- forceTemporary: {
273
- fr: "Joie temporaire",
274
- },
275
- languages: ["en", "fr", "es"],
276
- primaryLanguage: "en",
277
- }),
278
- headers: {
279
- Authorization: "Bearer test-api-key",
280
- "Content-Type": "application/json",
281
- Version: packageJson.version,
282
- unique_id: "",
283
- },
284
- method: "POST",
285
- });
286
- });
287
- it("should queue translation requests when translation is missing", () => {
288
- useI18nKeyless.setState({ currentLanguage: "fr" });
289
- const store = useI18nKeyless.getState();
290
- const queueSpy = vi.spyOn(queue, "add");
291
- getTranslationCore("Missing Translation", store);
292
- expect(queueSpy).toHaveBeenCalled();
293
- });
294
- it("should handle API translation errors gracefully", async () => {
295
- useI18nKeyless.setState({ currentLanguage: "fr" });
296
- const store = useI18nKeyless.getState();
297
- // Mock a failed API call
298
- global.fetch = vi.fn().mockRejectedValue(new Error("API Error"));
299
- useI18nKeyless.setState({ currentLanguage: "fr" });
300
- getTranslationCore("Test Error", store);
301
- // Wait for async queue to process
302
- await new Promise((resolve) => setTimeout(resolve, 0));
303
- expect(console.error).toHaveBeenCalledWith(expect.stringContaining("i18n-keyless: fetch all translations error:"), new Error("API Error"));
304
- });
305
- it("should not translate empty strings", () => {
306
- useI18nKeyless.setState({ currentLanguage: "fr" });
307
- const store = useI18nKeyless.getState();
308
- const queueSpy = vi.spyOn(queue, "add");
309
- getTranslationCore("", store);
310
- expect(queueSpy).not.toHaveBeenCalled();
311
- });
312
- it("should handle debug mode logging", async () => {
313
- // Clear any previous async operations
314
- vi.clearAllMocks();
315
- useI18nKeyless.setState({ currentLanguage: "fr" });
316
- const store = useI18nKeyless.getState();
317
- getTranslationCore("Debug Test", store, { debug: true });
318
- // Wait for any async operations to complete
319
- await new Promise((resolve) => setTimeout(resolve, 0));
320
- expect(console.log).toHaveBeenCalled();
321
- });
322
- });
323
- describe("Storage operations", () => {
324
- it("should handle malformed JSON in storage", async () => {
325
- vi.clearAllMocks();
326
- mockStorage.getItem.mockImplementation((key) => {
327
- if (key === "i18n-keyless-translations")
328
- return "invalid json";
329
- return null;
330
- });
331
- await init({
332
- languages: {
333
- primary: "en",
334
- supported: ["en", "fr"],
335
- },
336
- storage: mockStorage,
337
- API_KEY: "test-api-key",
338
- });
339
- expect(useI18nKeyless.getState().translations).toEqual({});
340
- });
341
- });
342
- describe("Language fallback behavior", () => {
343
- it("should use fallback language when current language is not supported", () => {
344
- useI18nKeyless.setState({
345
- currentLanguage: "fr",
346
- translations: {},
347
- config: {
348
- languages: {
349
- primary: "en",
350
- supported: ["en", "fr", "es"],
351
- fallback: "es",
352
- },
353
- API_KEY: "test-api-key",
354
- storage: mockStorage,
355
- },
356
- });
357
- useI18nKeyless.getState().setLanguage("pt"); // pt is not supported
358
- const store = useI18nKeyless.getState();
359
- expect(store.currentLanguage).toBe("es");
360
- });
361
- });
362
- });
package/dist/package.json DELETED
@@ -1,41 +0,0 @@
1
- {
2
- "name": "i18n-keyless-react",
3
- "private": false,
4
- "version": "1.17.0",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "module": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
- "files": [
10
- "dist"
11
- ],
12
- "scripts": {
13
- "prepublishOnly": "rm -rf ./dist && tsc --project tsconfig.json && npm run test && npm pack",
14
- "test": "vitest run",
15
- "test:watch": "vitest",
16
- "test:coverage": "vitest run --coverage",
17
- "postpublish": "rm -rf ./dist && rm *.tgz"
18
- },
19
- "dependencies": {
20
- "i18n-keyless-core": "1.17.0",
21
- "zustand": "^5.0.3"
22
- },
23
- "peerDependencies": {
24
- "react": ">=18.0.0"
25
- },
26
- "devDependencies": {
27
- "@eslint/js": "^9.9.0",
28
- "@testing-library/jest-dom": "^6.6.3",
29
- "@testing-library/react": "^16.2.0",
30
- "@types/node": "^22.5.5",
31
- "@types/react": "^19.0.8",
32
- "@vitejs/plugin-react": "^4.3.4",
33
- "@vitest/coverage-v8": "^3.1.1",
34
- "eslint": "^9.9.0",
35
- "eslint-plugin-react-hooks": "^5.1.0-rc.0",
36
- "eslint-plugin-react-refresh": "^0.4.9",
37
- "happy-dom": "^17.4.4",
38
- "jsdom": "^26.0.0",
39
- "vitest": "^3.1.1"
40
- }
41
- }