@kopynator/core 1.0.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/README.md +37 -0
- package/dist/index.d.mts +73 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +191 -0
- package/dist/index.mjs +159 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# @kopynator/core
|
|
2
|
+
|
|
3
|
+
The agnostic core engine for the Kopynator i18n platform.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
- **Zero Dependencies**: Lightweight and fast.
|
|
7
|
+
- **ICU Pluralization**: `{n, plural, =0 {None} =1 {One} other {# items}}`.
|
|
8
|
+
- **Variable Interpolation**: `Hello {{name}}`.
|
|
9
|
+
- **Intelligent Caching**: Syncs with `localStorage` (Web) or uses Memory (Node).
|
|
10
|
+
- **Agnostic**: Works in Browser, React, Vue, Angular, Node.js, and more.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
```bash
|
|
14
|
+
npm install @kopynator/core
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Basic Usage
|
|
18
|
+
```typescript
|
|
19
|
+
import { Kopynator } from '@kopynator/core';
|
|
20
|
+
|
|
21
|
+
const kopy = new Kopynator({
|
|
22
|
+
apiKey: 'YOUR_PROJECT_TOKEN',
|
|
23
|
+
projectId: 'YOUR_PROJECT_ID',
|
|
24
|
+
defaultLocale: 'en'
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
await kopy.init();
|
|
28
|
+
|
|
29
|
+
// Simple translation
|
|
30
|
+
console.log(kopy.t('welcome_message'));
|
|
31
|
+
|
|
32
|
+
// Interpolation
|
|
33
|
+
console.log(kopy.t('greeting', { name: 'Carlos' }));
|
|
34
|
+
|
|
35
|
+
// Pluralization
|
|
36
|
+
console.log(kopy.t('inbox_count', { n: 5 }));
|
|
37
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
interface KopyConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
projectId?: string;
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
defaultLocale?: string;
|
|
6
|
+
mode?: 'local' | 'live';
|
|
7
|
+
}
|
|
8
|
+
interface TranslationResponse {
|
|
9
|
+
[key: string]: string;
|
|
10
|
+
}
|
|
11
|
+
declare class KopyFetcher {
|
|
12
|
+
private config;
|
|
13
|
+
private baseUrl;
|
|
14
|
+
constructor(config: KopyConfig);
|
|
15
|
+
fetchTranslations(locale: string): Promise<TranslationResponse>;
|
|
16
|
+
fetchAvailableLanguages(): Promise<string[]>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare class KopyCompiler {
|
|
20
|
+
/**
|
|
21
|
+
* Interpolates variables and handles pluralization in a string template.
|
|
22
|
+
* Interpolation: "Hello {{name}}" -> "Hello Carlos"
|
|
23
|
+
* Pluralization: "{n, plural, =0 {No items} =1 {One item} other {# items}}"
|
|
24
|
+
*/
|
|
25
|
+
static compile(template: string, params?: Record<string, any>): string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface KopyStorage {
|
|
29
|
+
get(key: string): string | null;
|
|
30
|
+
set(key: string, value: string): void;
|
|
31
|
+
}
|
|
32
|
+
declare class MemoryStorage implements KopyStorage {
|
|
33
|
+
private cache;
|
|
34
|
+
get(key: string): string | null;
|
|
35
|
+
set(key: string, value: string): void;
|
|
36
|
+
}
|
|
37
|
+
declare class LocalStorageWrapper implements KopyStorage {
|
|
38
|
+
get(key: string): string | null;
|
|
39
|
+
set(key: string, value: string): void;
|
|
40
|
+
}
|
|
41
|
+
declare const getBestStorage: () => KopyStorage;
|
|
42
|
+
|
|
43
|
+
declare class Kopynator {
|
|
44
|
+
private config;
|
|
45
|
+
private fetcher;
|
|
46
|
+
private storage;
|
|
47
|
+
private translations;
|
|
48
|
+
private currentLocale;
|
|
49
|
+
constructor(config: KopyConfig);
|
|
50
|
+
/**
|
|
51
|
+
* Initialize the SDK and load initial translations.
|
|
52
|
+
*/
|
|
53
|
+
init(): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Load translations for a specific locale.
|
|
56
|
+
* Priority: Memory > Storage (Cache) > API
|
|
57
|
+
*/
|
|
58
|
+
loadLocale(locale: string): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Change current locale and load it if necessary.
|
|
61
|
+
*/
|
|
62
|
+
setLocale(locale: string): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Translate a key with optional parameters for interpolation.
|
|
65
|
+
*/
|
|
66
|
+
translate(key: string, params?: Record<string, any>): string;
|
|
67
|
+
/**
|
|
68
|
+
* Shorthand for translate
|
|
69
|
+
*/
|
|
70
|
+
t(key: string, params?: Record<string, any>): string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { KopyCompiler, type KopyConfig, KopyFetcher, type KopyStorage, Kopynator, LocalStorageWrapper, MemoryStorage, type TranslationResponse, getBestStorage };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
interface KopyConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
projectId?: string;
|
|
4
|
+
baseUrl?: string;
|
|
5
|
+
defaultLocale?: string;
|
|
6
|
+
mode?: 'local' | 'live';
|
|
7
|
+
}
|
|
8
|
+
interface TranslationResponse {
|
|
9
|
+
[key: string]: string;
|
|
10
|
+
}
|
|
11
|
+
declare class KopyFetcher {
|
|
12
|
+
private config;
|
|
13
|
+
private baseUrl;
|
|
14
|
+
constructor(config: KopyConfig);
|
|
15
|
+
fetchTranslations(locale: string): Promise<TranslationResponse>;
|
|
16
|
+
fetchAvailableLanguages(): Promise<string[]>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare class KopyCompiler {
|
|
20
|
+
/**
|
|
21
|
+
* Interpolates variables and handles pluralization in a string template.
|
|
22
|
+
* Interpolation: "Hello {{name}}" -> "Hello Carlos"
|
|
23
|
+
* Pluralization: "{n, plural, =0 {No items} =1 {One item} other {# items}}"
|
|
24
|
+
*/
|
|
25
|
+
static compile(template: string, params?: Record<string, any>): string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface KopyStorage {
|
|
29
|
+
get(key: string): string | null;
|
|
30
|
+
set(key: string, value: string): void;
|
|
31
|
+
}
|
|
32
|
+
declare class MemoryStorage implements KopyStorage {
|
|
33
|
+
private cache;
|
|
34
|
+
get(key: string): string | null;
|
|
35
|
+
set(key: string, value: string): void;
|
|
36
|
+
}
|
|
37
|
+
declare class LocalStorageWrapper implements KopyStorage {
|
|
38
|
+
get(key: string): string | null;
|
|
39
|
+
set(key: string, value: string): void;
|
|
40
|
+
}
|
|
41
|
+
declare const getBestStorage: () => KopyStorage;
|
|
42
|
+
|
|
43
|
+
declare class Kopynator {
|
|
44
|
+
private config;
|
|
45
|
+
private fetcher;
|
|
46
|
+
private storage;
|
|
47
|
+
private translations;
|
|
48
|
+
private currentLocale;
|
|
49
|
+
constructor(config: KopyConfig);
|
|
50
|
+
/**
|
|
51
|
+
* Initialize the SDK and load initial translations.
|
|
52
|
+
*/
|
|
53
|
+
init(): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Load translations for a specific locale.
|
|
56
|
+
* Priority: Memory > Storage (Cache) > API
|
|
57
|
+
*/
|
|
58
|
+
loadLocale(locale: string): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Change current locale and load it if necessary.
|
|
61
|
+
*/
|
|
62
|
+
setLocale(locale: string): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Translate a key with optional parameters for interpolation.
|
|
65
|
+
*/
|
|
66
|
+
translate(key: string, params?: Record<string, any>): string;
|
|
67
|
+
/**
|
|
68
|
+
* Shorthand for translate
|
|
69
|
+
*/
|
|
70
|
+
t(key: string, params?: Record<string, any>): string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export { KopyCompiler, type KopyConfig, KopyFetcher, type KopyStorage, Kopynator, LocalStorageWrapper, MemoryStorage, type TranslationResponse, getBestStorage };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
KopyCompiler: () => KopyCompiler,
|
|
24
|
+
KopyFetcher: () => KopyFetcher,
|
|
25
|
+
Kopynator: () => Kopynator,
|
|
26
|
+
LocalStorageWrapper: () => LocalStorageWrapper,
|
|
27
|
+
MemoryStorage: () => MemoryStorage,
|
|
28
|
+
getBestStorage: () => getBestStorage
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
|
|
32
|
+
// src/services/fetcher.ts
|
|
33
|
+
var KopyFetcher = class {
|
|
34
|
+
constructor(config) {
|
|
35
|
+
this.config = config;
|
|
36
|
+
this.baseUrl = config.baseUrl || "http://localhost:7300/api";
|
|
37
|
+
}
|
|
38
|
+
baseUrl;
|
|
39
|
+
async fetchTranslations(locale) {
|
|
40
|
+
try {
|
|
41
|
+
const url = `${this.baseUrl}/tokens/fetch?token=${this.config.apiKey}&lang=${locale}&nested=false&includeLangKey=false`;
|
|
42
|
+
const response = await fetch(url);
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
throw new Error(`Failed to fetch translations: ${response.statusText}`);
|
|
45
|
+
}
|
|
46
|
+
return await response.json();
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error("[Kopynator] Error fetching translations:", error);
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async fetchAvailableLanguages() {
|
|
53
|
+
try {
|
|
54
|
+
const url = `${this.baseUrl}/tokens/languages?token=${this.config.apiKey}`;
|
|
55
|
+
const response = await fetch(url);
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
throw new Error(`Failed to fetch languages: ${response.statusText}`);
|
|
58
|
+
}
|
|
59
|
+
return await response.json();
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error("[Kopynator] Error fetching available languages:", error);
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// src/utils/compiler.ts
|
|
68
|
+
var KopyCompiler = class {
|
|
69
|
+
/**
|
|
70
|
+
* Interpolates variables and handles pluralization in a string template.
|
|
71
|
+
* Interpolation: "Hello {{name}}" -> "Hello Carlos"
|
|
72
|
+
* Pluralization: "{n, plural, =0 {No items} =1 {One item} other {# items}}"
|
|
73
|
+
*/
|
|
74
|
+
static compile(template, params = {}) {
|
|
75
|
+
if (!template) return "";
|
|
76
|
+
let compiled = template.replace(/\{(\w+),\s*plural,\s*((?:[^{}]*|\{[^{}]*\})*)\}/g, (match, key, rules) => {
|
|
77
|
+
const count = Number(params[key]);
|
|
78
|
+
if (isNaN(count)) return match;
|
|
79
|
+
const parts = rules.split(/\s*(=?\d+|other)\s*\{/);
|
|
80
|
+
const ruleMap = {};
|
|
81
|
+
for (let i = 1; i < parts.length; i += 2) {
|
|
82
|
+
const ruleKey = parts[i];
|
|
83
|
+
const ruleValue = parts[i + 1].split("}")[0];
|
|
84
|
+
ruleMap[ruleKey] = ruleValue;
|
|
85
|
+
}
|
|
86
|
+
const result = ruleMap[`=${count}`] || ruleMap[count.toString()] || ruleMap["other"] || "";
|
|
87
|
+
return result.replace("#", count.toString());
|
|
88
|
+
});
|
|
89
|
+
return compiled.replace(/\{\{\s*([\w.-]+)\s*\}\}/g, (match, key) => {
|
|
90
|
+
const value = params[key];
|
|
91
|
+
return value !== void 0 ? String(value) : match;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// src/services/storage.ts
|
|
97
|
+
var MemoryStorage = class {
|
|
98
|
+
cache = /* @__PURE__ */ new Map();
|
|
99
|
+
get(key) {
|
|
100
|
+
return this.cache.get(key) || null;
|
|
101
|
+
}
|
|
102
|
+
set(key, value) {
|
|
103
|
+
this.cache.set(key, value);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var LocalStorageWrapper = class {
|
|
107
|
+
get(key) {
|
|
108
|
+
return typeof localStorage !== "undefined" ? localStorage.getItem(key) : null;
|
|
109
|
+
}
|
|
110
|
+
set(key, value) {
|
|
111
|
+
if (typeof localStorage !== "undefined") localStorage.setItem(key, value);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var memoryStorage = new MemoryStorage();
|
|
115
|
+
var getBestStorage = () => {
|
|
116
|
+
if (typeof localStorage !== "undefined") {
|
|
117
|
+
return new LocalStorageWrapper();
|
|
118
|
+
}
|
|
119
|
+
return memoryStorage;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// src/index.ts
|
|
123
|
+
var Kopynator = class {
|
|
124
|
+
constructor(config) {
|
|
125
|
+
this.config = config;
|
|
126
|
+
this.fetcher = new KopyFetcher(config);
|
|
127
|
+
this.storage = getBestStorage();
|
|
128
|
+
this.currentLocale = config.defaultLocale || "en";
|
|
129
|
+
}
|
|
130
|
+
fetcher;
|
|
131
|
+
storage;
|
|
132
|
+
translations = {};
|
|
133
|
+
currentLocale;
|
|
134
|
+
/**
|
|
135
|
+
* Initialize the SDK and load initial translations.
|
|
136
|
+
*/
|
|
137
|
+
async init() {
|
|
138
|
+
await this.loadLocale(this.currentLocale);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Load translations for a specific locale.
|
|
142
|
+
* Priority: Memory > Storage (Cache) > API
|
|
143
|
+
*/
|
|
144
|
+
async loadLocale(locale) {
|
|
145
|
+
const identifier = this.config.projectId || this.config.apiKey;
|
|
146
|
+
if (this.translations[locale]) return;
|
|
147
|
+
const cached = this.storage.get(`kopy_${identifier}_${locale}`);
|
|
148
|
+
if (cached) {
|
|
149
|
+
try {
|
|
150
|
+
this.translations[locale] = JSON.parse(cached);
|
|
151
|
+
return;
|
|
152
|
+
} catch (e) {
|
|
153
|
+
console.warn("[Kopynator] Failed to parse cached translations");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const data = await this.fetcher.fetchTranslations(locale);
|
|
157
|
+
this.translations[locale] = data;
|
|
158
|
+
this.storage.set(`kopy_${identifier}_${locale}`, JSON.stringify(data));
|
|
159
|
+
this.currentLocale = locale;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Change current locale and load it if necessary.
|
|
163
|
+
*/
|
|
164
|
+
async setLocale(locale) {
|
|
165
|
+
await this.loadLocale(locale);
|
|
166
|
+
this.currentLocale = locale;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Translate a key with optional parameters for interpolation.
|
|
170
|
+
*/
|
|
171
|
+
translate(key, params = {}) {
|
|
172
|
+
const localeTranslations = this.translations[this.currentLocale] || {};
|
|
173
|
+
const template = localeTranslations[key] || key;
|
|
174
|
+
return KopyCompiler.compile(template, params);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Shorthand for translate
|
|
178
|
+
*/
|
|
179
|
+
t(key, params = {}) {
|
|
180
|
+
return this.translate(key, params);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
184
|
+
0 && (module.exports = {
|
|
185
|
+
KopyCompiler,
|
|
186
|
+
KopyFetcher,
|
|
187
|
+
Kopynator,
|
|
188
|
+
LocalStorageWrapper,
|
|
189
|
+
MemoryStorage,
|
|
190
|
+
getBestStorage
|
|
191
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// src/services/fetcher.ts
|
|
2
|
+
var KopyFetcher = class {
|
|
3
|
+
constructor(config) {
|
|
4
|
+
this.config = config;
|
|
5
|
+
this.baseUrl = config.baseUrl || "http://localhost:7300/api";
|
|
6
|
+
}
|
|
7
|
+
baseUrl;
|
|
8
|
+
async fetchTranslations(locale) {
|
|
9
|
+
try {
|
|
10
|
+
const url = `${this.baseUrl}/tokens/fetch?token=${this.config.apiKey}&lang=${locale}&nested=false&includeLangKey=false`;
|
|
11
|
+
const response = await fetch(url);
|
|
12
|
+
if (!response.ok) {
|
|
13
|
+
throw new Error(`Failed to fetch translations: ${response.statusText}`);
|
|
14
|
+
}
|
|
15
|
+
return await response.json();
|
|
16
|
+
} catch (error) {
|
|
17
|
+
console.error("[Kopynator] Error fetching translations:", error);
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async fetchAvailableLanguages() {
|
|
22
|
+
try {
|
|
23
|
+
const url = `${this.baseUrl}/tokens/languages?token=${this.config.apiKey}`;
|
|
24
|
+
const response = await fetch(url);
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
throw new Error(`Failed to fetch languages: ${response.statusText}`);
|
|
27
|
+
}
|
|
28
|
+
return await response.json();
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error("[Kopynator] Error fetching available languages:", error);
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// src/utils/compiler.ts
|
|
37
|
+
var KopyCompiler = class {
|
|
38
|
+
/**
|
|
39
|
+
* Interpolates variables and handles pluralization in a string template.
|
|
40
|
+
* Interpolation: "Hello {{name}}" -> "Hello Carlos"
|
|
41
|
+
* Pluralization: "{n, plural, =0 {No items} =1 {One item} other {# items}}"
|
|
42
|
+
*/
|
|
43
|
+
static compile(template, params = {}) {
|
|
44
|
+
if (!template) return "";
|
|
45
|
+
let compiled = template.replace(/\{(\w+),\s*plural,\s*((?:[^{}]*|\{[^{}]*\})*)\}/g, (match, key, rules) => {
|
|
46
|
+
const count = Number(params[key]);
|
|
47
|
+
if (isNaN(count)) return match;
|
|
48
|
+
const parts = rules.split(/\s*(=?\d+|other)\s*\{/);
|
|
49
|
+
const ruleMap = {};
|
|
50
|
+
for (let i = 1; i < parts.length; i += 2) {
|
|
51
|
+
const ruleKey = parts[i];
|
|
52
|
+
const ruleValue = parts[i + 1].split("}")[0];
|
|
53
|
+
ruleMap[ruleKey] = ruleValue;
|
|
54
|
+
}
|
|
55
|
+
const result = ruleMap[`=${count}`] || ruleMap[count.toString()] || ruleMap["other"] || "";
|
|
56
|
+
return result.replace("#", count.toString());
|
|
57
|
+
});
|
|
58
|
+
return compiled.replace(/\{\{\s*([\w.-]+)\s*\}\}/g, (match, key) => {
|
|
59
|
+
const value = params[key];
|
|
60
|
+
return value !== void 0 ? String(value) : match;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/services/storage.ts
|
|
66
|
+
var MemoryStorage = class {
|
|
67
|
+
cache = /* @__PURE__ */ new Map();
|
|
68
|
+
get(key) {
|
|
69
|
+
return this.cache.get(key) || null;
|
|
70
|
+
}
|
|
71
|
+
set(key, value) {
|
|
72
|
+
this.cache.set(key, value);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var LocalStorageWrapper = class {
|
|
76
|
+
get(key) {
|
|
77
|
+
return typeof localStorage !== "undefined" ? localStorage.getItem(key) : null;
|
|
78
|
+
}
|
|
79
|
+
set(key, value) {
|
|
80
|
+
if (typeof localStorage !== "undefined") localStorage.setItem(key, value);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
var memoryStorage = new MemoryStorage();
|
|
84
|
+
var getBestStorage = () => {
|
|
85
|
+
if (typeof localStorage !== "undefined") {
|
|
86
|
+
return new LocalStorageWrapper();
|
|
87
|
+
}
|
|
88
|
+
return memoryStorage;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// src/index.ts
|
|
92
|
+
var Kopynator = class {
|
|
93
|
+
constructor(config) {
|
|
94
|
+
this.config = config;
|
|
95
|
+
this.fetcher = new KopyFetcher(config);
|
|
96
|
+
this.storage = getBestStorage();
|
|
97
|
+
this.currentLocale = config.defaultLocale || "en";
|
|
98
|
+
}
|
|
99
|
+
fetcher;
|
|
100
|
+
storage;
|
|
101
|
+
translations = {};
|
|
102
|
+
currentLocale;
|
|
103
|
+
/**
|
|
104
|
+
* Initialize the SDK and load initial translations.
|
|
105
|
+
*/
|
|
106
|
+
async init() {
|
|
107
|
+
await this.loadLocale(this.currentLocale);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Load translations for a specific locale.
|
|
111
|
+
* Priority: Memory > Storage (Cache) > API
|
|
112
|
+
*/
|
|
113
|
+
async loadLocale(locale) {
|
|
114
|
+
const identifier = this.config.projectId || this.config.apiKey;
|
|
115
|
+
if (this.translations[locale]) return;
|
|
116
|
+
const cached = this.storage.get(`kopy_${identifier}_${locale}`);
|
|
117
|
+
if (cached) {
|
|
118
|
+
try {
|
|
119
|
+
this.translations[locale] = JSON.parse(cached);
|
|
120
|
+
return;
|
|
121
|
+
} catch (e) {
|
|
122
|
+
console.warn("[Kopynator] Failed to parse cached translations");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const data = await this.fetcher.fetchTranslations(locale);
|
|
126
|
+
this.translations[locale] = data;
|
|
127
|
+
this.storage.set(`kopy_${identifier}_${locale}`, JSON.stringify(data));
|
|
128
|
+
this.currentLocale = locale;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Change current locale and load it if necessary.
|
|
132
|
+
*/
|
|
133
|
+
async setLocale(locale) {
|
|
134
|
+
await this.loadLocale(locale);
|
|
135
|
+
this.currentLocale = locale;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Translate a key with optional parameters for interpolation.
|
|
139
|
+
*/
|
|
140
|
+
translate(key, params = {}) {
|
|
141
|
+
const localeTranslations = this.translations[this.currentLocale] || {};
|
|
142
|
+
const template = localeTranslations[key] || key;
|
|
143
|
+
return KopyCompiler.compile(template, params);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Shorthand for translate
|
|
147
|
+
*/
|
|
148
|
+
t(key, params = {}) {
|
|
149
|
+
return this.translate(key, params);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
export {
|
|
153
|
+
KopyCompiler,
|
|
154
|
+
KopyFetcher,
|
|
155
|
+
Kopynator,
|
|
156
|
+
LocalStorageWrapper,
|
|
157
|
+
MemoryStorage,
|
|
158
|
+
getBestStorage
|
|
159
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kopynator/core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Core agnostic logic for Kopynator SDKs",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
20
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
21
|
+
"lint": "eslint src/**/*.ts",
|
|
22
|
+
"test": "jest"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/jest": "^29.5.0",
|
|
26
|
+
"jest": "^29.5.0",
|
|
27
|
+
"ts-jest": "^29.1.0",
|
|
28
|
+
"tsup": "^8.0.0",
|
|
29
|
+
"typescript": "^5.0.0"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
}
|
|
34
|
+
}
|