@better-i18n/core 0.1.2 → 0.1.4
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 +32 -22
- package/dist/cache.d.ts +31 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +51 -0
- package/dist/cache.js.map +1 -0
- package/dist/cdn.d.ts +21 -0
- package/dist/cdn.d.ts.map +1 -0
- package/dist/cdn.js +103 -0
- package/dist/cdn.js.map +1 -0
- package/dist/config.d.ts +14 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/i18n/detection.d.ts +6 -0
- package/dist/i18n/detection.d.ts.map +1 -0
- package/dist/i18n/detection.js +29 -0
- package/dist/i18n/detection.js.map +1 -0
- package/dist/i18n/types.d.ts +24 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/types.js +2 -0
- package/dist/i18n/types.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +6 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +31 -0
- package/dist/logger.js.map +1 -0
- package/dist/manifest.d.ts +6 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +23 -0
- package/dist/manifest.js.map +1 -0
- package/dist/types.d.ts +146 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Framework-agnostic core utilities for fetching translations from Better i18n CDN.
|
|
4
4
|
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Framework Agnostic** - Works with any JavaScript runtime
|
|
8
|
+
- **Edge-Ready** - Optimized for edge environments (Cloudflare, Vercel, etc.)
|
|
9
|
+
- **Type-Safe** - Full TypeScript support
|
|
10
|
+
- **Cached** - Built-in manifest caching with configurable TTL
|
|
11
|
+
|
|
5
12
|
## Installation
|
|
6
13
|
|
|
7
14
|
```bash
|
|
@@ -13,26 +20,26 @@ bun add @better-i18n/core
|
|
|
13
20
|
## Usage
|
|
14
21
|
|
|
15
22
|
```typescript
|
|
16
|
-
import { createI18nCore } from
|
|
23
|
+
import { createI18nCore } from "@better-i18n/core";
|
|
17
24
|
|
|
18
25
|
const i18n = createI18nCore({
|
|
19
|
-
project:
|
|
20
|
-
defaultLocale:
|
|
21
|
-
})
|
|
26
|
+
project: "your-org/your-project",
|
|
27
|
+
defaultLocale: "en",
|
|
28
|
+
});
|
|
22
29
|
|
|
23
30
|
// Fetch messages for a locale
|
|
24
|
-
const messages = await i18n.getMessages(
|
|
31
|
+
const messages = await i18n.getMessages("en");
|
|
25
32
|
|
|
26
33
|
// Get available locales
|
|
27
|
-
const locales = await i18n.getLocales()
|
|
28
|
-
// [
|
|
34
|
+
const locales = await i18n.getLocales();
|
|
35
|
+
// ["en", "tr", "de", ...]
|
|
29
36
|
|
|
30
37
|
// Get language options with metadata (for UI)
|
|
31
|
-
const languages = await i18n.getLanguages()
|
|
32
|
-
// [{ code:
|
|
38
|
+
const languages = await i18n.getLanguages();
|
|
39
|
+
// [{ code: "en", name: "English", nativeName: "English", flagUrl: "..." }, ...]
|
|
33
40
|
|
|
34
41
|
// Get manifest
|
|
35
|
-
const manifest = await i18n.getManifest()
|
|
42
|
+
const manifest = await i18n.getManifest();
|
|
36
43
|
```
|
|
37
44
|
|
|
38
45
|
## Configuration
|
|
@@ -40,26 +47,29 @@ const manifest = await i18n.getManifest()
|
|
|
40
47
|
```typescript
|
|
41
48
|
interface I18nCoreConfig {
|
|
42
49
|
// Required
|
|
43
|
-
project: string // "org/project" format
|
|
44
|
-
defaultLocale: string // e.g., "en"
|
|
50
|
+
project: string; // "org/project" format
|
|
51
|
+
defaultLocale: string; // e.g., "en"
|
|
45
52
|
|
|
46
53
|
// Optional
|
|
47
|
-
cdnBaseUrl?: string // default: "https://cdn.better-i18n.com"
|
|
48
|
-
manifestCacheTtlMs?: number // default: 300000 (5 minutes)
|
|
49
|
-
debug?: boolean // default: false
|
|
50
|
-
logLevel?: LogLevel // default: "warn"
|
|
51
|
-
fetch?: typeof fetch // custom fetch function
|
|
54
|
+
cdnBaseUrl?: string; // default: "https://cdn.better-i18n.com"
|
|
55
|
+
manifestCacheTtlMs?: number; // default: 300000 (5 minutes)
|
|
56
|
+
debug?: boolean; // default: false
|
|
57
|
+
logLevel?: LogLevel; // default: "warn"
|
|
58
|
+
fetch?: typeof fetch; // custom fetch function
|
|
52
59
|
}
|
|
53
60
|
```
|
|
54
61
|
|
|
55
|
-
##
|
|
62
|
+
## Framework Integrations
|
|
56
63
|
|
|
57
64
|
This package is the foundation for:
|
|
58
65
|
|
|
59
|
-
- `@better-i18n/next` - Next.js integration
|
|
60
|
-
- `@better-i18n/
|
|
61
|
-
|
|
66
|
+
- `@better-i18n/next` - Next.js integration with ISR support
|
|
67
|
+
- `@better-i18n/react` - React/TanStack integration (coming soon)
|
|
68
|
+
|
|
69
|
+
## Documentation
|
|
70
|
+
|
|
71
|
+
Full documentation available at [docs.better-i18n.com](https://docs.better-i18n.com)
|
|
62
72
|
|
|
63
73
|
## License
|
|
64
74
|
|
|
65
|
-
MIT
|
|
75
|
+
MIT © [Better i18n](https://better-i18n.com)
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple in-memory TTL cache
|
|
3
|
+
*/
|
|
4
|
+
export declare class TtlCache<T> {
|
|
5
|
+
private cache;
|
|
6
|
+
/**
|
|
7
|
+
* Get a value from cache if not expired
|
|
8
|
+
*/
|
|
9
|
+
get(key: string): T | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Set a value in cache with TTL
|
|
12
|
+
*/
|
|
13
|
+
set(key: string, value: T, ttlMs: number): void;
|
|
14
|
+
/**
|
|
15
|
+
* Check if a key exists and is not expired
|
|
16
|
+
*/
|
|
17
|
+
has(key: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Delete a key from cache
|
|
20
|
+
*/
|
|
21
|
+
delete(key: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Clear all entries
|
|
24
|
+
*/
|
|
25
|
+
clear(): void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Build a cache key from config
|
|
29
|
+
*/
|
|
30
|
+
export declare const buildCacheKey: (cdnBaseUrl: string, project: string) => string;
|
|
31
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,CAAC,KAAK,CAAoC;IAEjD;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAY/B;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAO/C;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI5B;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,YAAY,MAAM,EAAE,SAAS,MAAM,KAAG,MACxC,CAAC"}
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple in-memory TTL cache
|
|
3
|
+
*/
|
|
4
|
+
export class TtlCache {
|
|
5
|
+
cache = new Map();
|
|
6
|
+
/**
|
|
7
|
+
* Get a value from cache if not expired
|
|
8
|
+
*/
|
|
9
|
+
get(key) {
|
|
10
|
+
const entry = this.cache.get(key);
|
|
11
|
+
if (!entry)
|
|
12
|
+
return undefined;
|
|
13
|
+
if (entry.expiresAt <= Date.now()) {
|
|
14
|
+
this.cache.delete(key);
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
return entry.value;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Set a value in cache with TTL
|
|
21
|
+
*/
|
|
22
|
+
set(key, value, ttlMs) {
|
|
23
|
+
this.cache.set(key, {
|
|
24
|
+
value,
|
|
25
|
+
expiresAt: Date.now() + ttlMs,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if a key exists and is not expired
|
|
30
|
+
*/
|
|
31
|
+
has(key) {
|
|
32
|
+
return this.get(key) !== undefined;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Delete a key from cache
|
|
36
|
+
*/
|
|
37
|
+
delete(key) {
|
|
38
|
+
return this.cache.delete(key);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Clear all entries
|
|
42
|
+
*/
|
|
43
|
+
clear() {
|
|
44
|
+
this.cache.clear();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build a cache key from config
|
|
49
|
+
*/
|
|
50
|
+
export const buildCacheKey = (cdnBaseUrl, project) => `${cdnBaseUrl}|${project}`;
|
|
51
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,OAAO,QAAQ;IACX,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAEjD;;OAEG;IACH,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAE7B,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,GAAW,EAAE,KAAQ,EAAE,KAAa;QACtC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC9B,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,UAAkB,EAAE,OAAe,EAAU,EAAE,CAC3E,GAAG,UAAU,IAAI,OAAO,EAAE,CAAC"}
|
package/dist/cdn.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { I18nCore, I18nCoreConfig } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Create an i18n core instance
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* const i18n = createI18nCore({
|
|
8
|
+
* project: 'acme/dashboard',
|
|
9
|
+
* defaultLocale: 'en',
|
|
10
|
+
* })
|
|
11
|
+
*
|
|
12
|
+
* const messages = await i18n.getMessages('en')
|
|
13
|
+
* const locales = await i18n.getLocales()
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare const createI18nCore: (config: I18nCoreConfig) => I18nCore;
|
|
17
|
+
/**
|
|
18
|
+
* Clear the manifest cache (useful for testing)
|
|
19
|
+
*/
|
|
20
|
+
export declare const clearManifestCache: () => void;
|
|
21
|
+
//# sourceMappingURL=cdn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdn.d.ts","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EAKf,MAAM,SAAS,CAAC;AAmFjB;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,cAAc,KAAG,QAkCvD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,QAAO,IAErC,CAAC"}
|
package/dist/cdn.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { TtlCache, buildCacheKey } from "./cache";
|
|
2
|
+
import { getProjectBaseUrl, normalizeConfig } from "./config";
|
|
3
|
+
import { createLogger } from "./logger";
|
|
4
|
+
import { extractLanguages } from "./manifest";
|
|
5
|
+
// Global manifest cache (shared across instances)
|
|
6
|
+
const manifestCache = new TtlCache();
|
|
7
|
+
/**
|
|
8
|
+
* Fetch manifest from CDN
|
|
9
|
+
*/
|
|
10
|
+
const fetchManifest = async (config, fetchFn) => {
|
|
11
|
+
const logger = createLogger(config, "manifest");
|
|
12
|
+
const url = `${getProjectBaseUrl(config)}/manifest.json`;
|
|
13
|
+
logger.debug("fetching", url);
|
|
14
|
+
const response = await fetchFn(url);
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
const message = `Manifest fetch failed (${response.status})`;
|
|
17
|
+
logger.error(message);
|
|
18
|
+
throw new Error(`[better-i18n] ${message}`);
|
|
19
|
+
}
|
|
20
|
+
const data = (await response.json());
|
|
21
|
+
if (!Array.isArray(data.languages)) {
|
|
22
|
+
throw new Error("[better-i18n] Manifest payload missing languages array");
|
|
23
|
+
}
|
|
24
|
+
logger.debug("fetched", { languages: data.languages.length });
|
|
25
|
+
return data;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Get manifest with caching
|
|
29
|
+
*/
|
|
30
|
+
const getManifestWithCache = async (config, fetchFn, forceRefresh = false) => {
|
|
31
|
+
const cacheKey = buildCacheKey(config.cdnBaseUrl, config.project);
|
|
32
|
+
if (!forceRefresh) {
|
|
33
|
+
const cached = manifestCache.get(cacheKey);
|
|
34
|
+
if (cached)
|
|
35
|
+
return cached;
|
|
36
|
+
}
|
|
37
|
+
const manifest = await fetchManifest(config, fetchFn);
|
|
38
|
+
manifestCache.set(cacheKey, manifest, config.manifestCacheTtlMs);
|
|
39
|
+
return manifest;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Fetch messages for a locale
|
|
43
|
+
*/
|
|
44
|
+
const fetchMessages = async (config, locale, fetchFn) => {
|
|
45
|
+
const logger = createLogger(config, "messages");
|
|
46
|
+
const url = `${getProjectBaseUrl(config)}/${locale}/translations.json`;
|
|
47
|
+
logger.debug("fetching", url);
|
|
48
|
+
const response = await fetchFn(url);
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
const message = `Messages fetch failed for locale "${locale}" (${response.status})`;
|
|
51
|
+
logger.error(message);
|
|
52
|
+
throw new Error(`[better-i18n] ${message}`);
|
|
53
|
+
}
|
|
54
|
+
const data = (await response.json());
|
|
55
|
+
logger.debug("fetched", { locale, keys: Object.keys(data).length });
|
|
56
|
+
return data;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Create an i18n core instance
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const i18n = createI18nCore({
|
|
64
|
+
* project: 'acme/dashboard',
|
|
65
|
+
* defaultLocale: 'en',
|
|
66
|
+
* })
|
|
67
|
+
*
|
|
68
|
+
* const messages = await i18n.getMessages('en')
|
|
69
|
+
* const locales = await i18n.getLocales()
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export const createI18nCore = (config) => {
|
|
73
|
+
const normalized = normalizeConfig(config);
|
|
74
|
+
const fetchFn = normalized.fetch ?? fetch;
|
|
75
|
+
return {
|
|
76
|
+
config: normalized,
|
|
77
|
+
getManifest: (options) => getManifestWithCache(normalized, fetchFn, options?.forceRefresh),
|
|
78
|
+
getMessages: (locale) => fetchMessages(normalized, locale, fetchFn),
|
|
79
|
+
getLocales: async () => {
|
|
80
|
+
const manifest = await getManifestWithCache(normalized, fetchFn);
|
|
81
|
+
const languages = extractLanguages(manifest);
|
|
82
|
+
if (languages.length === 0) {
|
|
83
|
+
throw new Error("[better-i18n] No locales found in manifest");
|
|
84
|
+
}
|
|
85
|
+
return languages.map((lang) => lang.code);
|
|
86
|
+
},
|
|
87
|
+
getLanguages: async () => {
|
|
88
|
+
const manifest = await getManifestWithCache(normalized, fetchFn);
|
|
89
|
+
const languages = extractLanguages(manifest);
|
|
90
|
+
if (languages.length === 0) {
|
|
91
|
+
throw new Error("[better-i18n] No languages found in manifest");
|
|
92
|
+
}
|
|
93
|
+
return languages;
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Clear the manifest cache (useful for testing)
|
|
99
|
+
*/
|
|
100
|
+
export const clearManifestCache = () => {
|
|
101
|
+
manifestCache.clear();
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=cdn.js.map
|
package/dist/cdn.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdn.js","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAU9C,kDAAkD;AAClD,MAAM,aAAa,GAAG,IAAI,QAAQ,EAAoB,CAAC;AAEvD;;GAEG;AACH,MAAM,aAAa,GAAG,KAAK,EACzB,MAAwB,EACxB,OAAqB,EACM,EAAE;IAC7B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,GAAG,iBAAiB,CAAC,MAAM,CAAC,gBAAgB,CAAC;IAEzD,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAE9B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAEpC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,0BAA0B,QAAQ,CAAC,MAAM,GAAG,CAAC;QAC7D,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,iBAAiB,OAAO,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAqB,CAAC;IAEzD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9D,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,oBAAoB,GAAG,KAAK,EAChC,MAAwB,EACxB,OAAqB,EACrB,YAAY,GAAG,KAAK,EACO,EAAE;IAC7B,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAElE,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;IAC5B,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,kBAAkB,CAAC,CAAC;IAEjE,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,aAAa,GAAG,KAAK,EACzB,MAAwB,EACxB,MAAc,EACd,OAAqB,EACF,EAAE;IACrB,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,GAAG,iBAAiB,CAAC,MAAM,CAAC,IAAI,MAAM,oBAAoB,CAAC;IAEvE,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAE9B,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAEpC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,qCAAqC,MAAM,MAAM,QAAQ,CAAC,MAAM,GAAG,CAAC;QACpF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,iBAAiB,OAAO,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAa,CAAC;IACjD,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAEpE,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAsB,EAAY,EAAE;IACjE,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,IAAI,KAAK,CAAC;IAE1C,OAAO;QACL,MAAM,EAAE,UAAU;QAElB,WAAW,EAAE,CAAC,OAAoC,EAAE,EAAE,CACpD,oBAAoB,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC;QAElE,WAAW,EAAE,CAAC,MAAc,EAAE,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC;QAE3E,UAAU,EAAE,KAAK,IAAuB,EAAE;YACxC,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACjE,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAE7C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAChE,CAAC;YAED,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC;QAED,YAAY,EAAE,KAAK,IAA+B,EAAE;YAClD,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACjE,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;YAE7C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAClE,CAAC;YAED,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAS,EAAE;IAC3C,aAAa,CAAC,KAAK,EAAE,CAAC;AACxB,CAAC,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { I18nCoreConfig, NormalizedConfig, ParsedProject } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Parse project string "org/slug" into workspaceId and projectSlug
|
|
4
|
+
*/
|
|
5
|
+
export declare const parseProject: (project: string) => ParsedProject;
|
|
6
|
+
/**
|
|
7
|
+
* Normalize config with defaults
|
|
8
|
+
*/
|
|
9
|
+
export declare const normalizeConfig: (config: I18nCoreConfig) => NormalizedConfig;
|
|
10
|
+
/**
|
|
11
|
+
* Build the project base URL on CDN
|
|
12
|
+
*/
|
|
13
|
+
export declare const getProjectBaseUrl: (config: NormalizedConfig) => string;
|
|
14
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAK/E;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,KAAG,aAW9C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,QAAQ,cAAc,KAAG,gBAiBxD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,gBAAgB,KAAG,MACO,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const DEFAULT_CDN_BASE_URL = "https://cdn.better-i18n.com";
|
|
2
|
+
const DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
3
|
+
/**
|
|
4
|
+
* Parse project string "org/slug" into workspaceId and projectSlug
|
|
5
|
+
*/
|
|
6
|
+
export const parseProject = (project) => {
|
|
7
|
+
const parts = project.split("/");
|
|
8
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
9
|
+
throw new Error(`[better-i18n] Invalid project format "${project}". Expected "org/project" (e.g., "acme/dashboard")`);
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
workspaceId: parts[0],
|
|
13
|
+
projectSlug: parts[1],
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Normalize config with defaults
|
|
18
|
+
*/
|
|
19
|
+
export const normalizeConfig = (config) => {
|
|
20
|
+
if (!config.project?.trim()) {
|
|
21
|
+
throw new Error("[better-i18n] project is required");
|
|
22
|
+
}
|
|
23
|
+
if (!config.defaultLocale?.trim()) {
|
|
24
|
+
throw new Error("[better-i18n] defaultLocale is required");
|
|
25
|
+
}
|
|
26
|
+
const { workspaceId, projectSlug } = parseProject(config.project);
|
|
27
|
+
return {
|
|
28
|
+
...config,
|
|
29
|
+
workspaceId,
|
|
30
|
+
projectSlug,
|
|
31
|
+
cdnBaseUrl: config.cdnBaseUrl?.replace(/\/$/, "") || DEFAULT_CDN_BASE_URL,
|
|
32
|
+
manifestCacheTtlMs: config.manifestCacheTtlMs ?? DEFAULT_CACHE_TTL_MS,
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Build the project base URL on CDN
|
|
37
|
+
*/
|
|
38
|
+
export const getProjectBaseUrl = (config) => `${config.cdnBaseUrl}/${config.workspaceId}/${config.projectSlug}`;
|
|
39
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,MAAM,oBAAoB,GAAG,6BAA6B,CAAC;AAC3D,MAAM,oBAAoB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,YAAY;AAExD;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAe,EAAiB,EAAE;IAC7D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CACb,yCAAyC,OAAO,oDAAoD,CACrG,CAAC;IACJ,CAAC;IACD,OAAO;QACL,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;QACrB,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;KACtB,CAAC;AACJ,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAsB,EAAoB,EAAE;IAC1E,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,IAAI,EAAE,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IAED,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAElE,OAAO;QACL,GAAG,MAAM;QACT,WAAW;QACX,WAAW;QACX,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,oBAAoB;QACzE,kBAAkB,EAAE,MAAM,CAAC,kBAAkB,IAAI,oBAAoB;KACtE,CAAC;AACJ,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAwB,EAAU,EAAE,CACpE,GAAG,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { LocaleDetectionOptions, LocaleDetectionResult } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Framework-agnostic locale detection logic
|
|
4
|
+
*/
|
|
5
|
+
export declare function detectLocale(options: LocaleDetectionOptions): LocaleDetectionResult;
|
|
6
|
+
//# sourceMappingURL=detection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detection.d.ts","sourceRoot":"","sources":["../../src/i18n/detection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAE7E;;GAEG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CA+BvB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-agnostic locale detection logic
|
|
3
|
+
*/
|
|
4
|
+
export function detectLocale(options) {
|
|
5
|
+
const { pathLocale, cookieLocale, headerLocale, defaultLocale, availableLocales, } = options;
|
|
6
|
+
let locale;
|
|
7
|
+
let detectedFrom;
|
|
8
|
+
// Priority: path > cookie > header > default
|
|
9
|
+
if (pathLocale && availableLocales.includes(pathLocale)) {
|
|
10
|
+
locale = pathLocale;
|
|
11
|
+
detectedFrom = "path";
|
|
12
|
+
}
|
|
13
|
+
else if (cookieLocale && availableLocales.includes(cookieLocale)) {
|
|
14
|
+
locale = cookieLocale;
|
|
15
|
+
detectedFrom = "cookie";
|
|
16
|
+
}
|
|
17
|
+
else if (headerLocale && availableLocales.includes(headerLocale)) {
|
|
18
|
+
locale = headerLocale;
|
|
19
|
+
detectedFrom = "header";
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
locale = defaultLocale;
|
|
23
|
+
detectedFrom = "default";
|
|
24
|
+
}
|
|
25
|
+
// Should set cookie if locale differs from current cookie
|
|
26
|
+
const shouldSetCookie = cookieLocale !== locale;
|
|
27
|
+
return { locale, detectedFrom, shouldSetCookie };
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=detection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detection.js","sourceRoot":"","sources":["../../src/i18n/detection.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,OAA+B;IAE/B,MAAM,EACJ,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,gBAAgB,GACjB,GAAG,OAAO,CAAC;IAEZ,IAAI,MAAc,CAAC;IACnB,IAAI,YAAmD,CAAC;IAExD,6CAA6C;IAC7C,IAAI,UAAU,IAAI,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACxD,MAAM,GAAG,UAAU,CAAC;QACpB,YAAY,GAAG,MAAM,CAAC;IACxB,CAAC;SAAM,IAAI,YAAY,IAAI,gBAAgB,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACnE,MAAM,GAAG,YAAY,CAAC;QACtB,YAAY,GAAG,QAAQ,CAAC;IAC1B,CAAC;SAAM,IAAI,YAAY,IAAI,gBAAgB,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACnE,MAAM,GAAG,YAAY,CAAC;QACtB,YAAY,GAAG,QAAQ,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,aAAa,CAAC;QACvB,YAAY,GAAG,SAAS,CAAC;IAC3B,CAAC;IAED,0DAA0D;IAC1D,MAAM,eAAe,GAAG,YAAY,KAAK,MAAM,CAAC;IAEhD,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface I18nMiddlewareConfig {
|
|
2
|
+
project: string;
|
|
3
|
+
defaultLocale: string;
|
|
4
|
+
detection?: {
|
|
5
|
+
cookie?: boolean;
|
|
6
|
+
browserLanguage?: boolean;
|
|
7
|
+
cookieName?: string;
|
|
8
|
+
cookieMaxAge?: number;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface LocaleDetectionOptions {
|
|
12
|
+
project: string;
|
|
13
|
+
defaultLocale: string;
|
|
14
|
+
pathLocale?: string | null;
|
|
15
|
+
cookieLocale?: string | null;
|
|
16
|
+
headerLocale?: string | null;
|
|
17
|
+
availableLocales: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface LocaleDetectionResult {
|
|
20
|
+
locale: string;
|
|
21
|
+
detectedFrom: "path" | "cookie" | "header" | "default";
|
|
22
|
+
shouldSetCookie: boolean;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/i18n/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE;QACV,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACvD,eAAe,EAAE,OAAO,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/i18n/types.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { createI18nCore, clearManifestCache } from "./cdn";
|
|
2
|
+
export { normalizeConfig, parseProject, getProjectBaseUrl } from "./config";
|
|
3
|
+
export { extractLanguages } from "./manifest";
|
|
4
|
+
export { createLogger } from "./logger";
|
|
5
|
+
export { detectLocale } from "./i18n/detection";
|
|
6
|
+
export { TtlCache, buildCacheKey } from "./cache";
|
|
7
|
+
export type { I18nCoreConfig, NormalizedConfig, ParsedProject, ManifestResponse, ManifestLanguage, ManifestFile, LanguageOption, Messages, Locale, I18nCore, Logger, LogLevel, CacheEntry, } from "./types";
|
|
8
|
+
export type { I18nMiddlewareConfig, LocaleDetectionOptions, LocaleDetectionResult, } from "./i18n/types";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAG3D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAG5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG9C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGxC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGlD,YAAY,EAEV,cAAc,EACd,gBAAgB,EAChB,aAAa,EAGb,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,cAAc,EAGd,QAAQ,EACR,MAAM,EAGN,QAAQ,EAGR,MAAM,EACN,QAAQ,EACR,UAAU,GACX,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Main API
|
|
2
|
+
export { createI18nCore, clearManifestCache } from "./cdn";
|
|
3
|
+
// Configuration utilities
|
|
4
|
+
export { normalizeConfig, parseProject, getProjectBaseUrl } from "./config";
|
|
5
|
+
// Manifest utilities
|
|
6
|
+
export { extractLanguages } from "./manifest";
|
|
7
|
+
// Logger
|
|
8
|
+
export { createLogger } from "./logger";
|
|
9
|
+
// Middleware logic
|
|
10
|
+
export { detectLocale } from "./i18n/detection";
|
|
11
|
+
// Cache utilities
|
|
12
|
+
export { TtlCache, buildCacheKey } from "./cache";
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC;AAE3D,0BAA0B;AAC1B,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE5E,qBAAqB;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,mBAAmB;AACnB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,kBAAkB;AAClB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAY,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAalE;;GAEG;AACH,eAAO,MAAM,YAAY,GACvB,QAAQ,gBAAgB,EACxB,WAAW,MAAM,KAChB,MAoBF,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const LOG_LEVELS = {
|
|
2
|
+
debug: 0,
|
|
3
|
+
info: 1,
|
|
4
|
+
warn: 2,
|
|
5
|
+
error: 3,
|
|
6
|
+
silent: 4,
|
|
7
|
+
};
|
|
8
|
+
const shouldLog = (targetLevel, configLevel) => LOG_LEVELS[targetLevel] >= LOG_LEVELS[configLevel];
|
|
9
|
+
/**
|
|
10
|
+
* Create a logger instance with namespace prefix
|
|
11
|
+
*/
|
|
12
|
+
export const createLogger = (config, namespace) => {
|
|
13
|
+
const prefix = `[better-i18n:${namespace}]`;
|
|
14
|
+
const level = config.logLevel ?? (config.debug ? "debug" : "warn");
|
|
15
|
+
const noop = () => { };
|
|
16
|
+
return {
|
|
17
|
+
debug: shouldLog("debug", level)
|
|
18
|
+
? (...args) => console.debug(prefix, ...args)
|
|
19
|
+
: noop,
|
|
20
|
+
info: shouldLog("info", level)
|
|
21
|
+
? (...args) => console.info(prefix, ...args)
|
|
22
|
+
: noop,
|
|
23
|
+
warn: shouldLog("warn", level)
|
|
24
|
+
? (...args) => console.warn(prefix, ...args)
|
|
25
|
+
: noop,
|
|
26
|
+
error: shouldLog("error", level)
|
|
27
|
+
? (...args) => console.error(prefix, ...args)
|
|
28
|
+
: noop,
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAA6B;IAC3C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC;CACV,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,WAAqB,EAAE,WAAqB,EAAW,EAAE,CAC1E,UAAU,CAAC,WAAW,CAAC,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;AAErD;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,MAAwB,EACxB,SAAiB,EACT,EAAE;IACV,MAAM,MAAM,GAAG,gBAAgB,SAAS,GAAG,CAAC;IAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAEnE,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;IAEtB,OAAO;QACL,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC;YAC9B,CAAC,CAAC,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;YACxD,CAAC,CAAC,IAAI;QACR,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC;YAC5B,CAAC,CAAC,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;YACvD,CAAC,CAAC,IAAI;QACR,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC;YAC5B,CAAC,CAAC,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;YACvD,CAAC,CAAC,IAAI;QACR,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC;YAC9B,CAAC,CAAC,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;YACxD,CAAC,CAAC,IAAI;KACT,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAEd,gBAAgB,EACjB,MAAM,SAAS,CAAC;AAajB;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,UAAU,gBAAgB,KACzB,cAAc,EAahB,CAAC"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize a manifest language to a simplified language option
|
|
3
|
+
*/
|
|
4
|
+
const normalizeLanguage = (language) => ({
|
|
5
|
+
code: language.code,
|
|
6
|
+
name: language.name,
|
|
7
|
+
nativeName: language.nativeName || language.name || language.code.toUpperCase(),
|
|
8
|
+
flagUrl: language.flagUrl ?? null,
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* Extract and normalize languages from manifest
|
|
12
|
+
*/
|
|
13
|
+
export const extractLanguages = (manifest) => {
|
|
14
|
+
const languages = Array.isArray(manifest.languages)
|
|
15
|
+
? manifest.languages
|
|
16
|
+
: [];
|
|
17
|
+
return languages
|
|
18
|
+
.filter((language) => !!language &&
|
|
19
|
+
typeof language.code === "string" &&
|
|
20
|
+
language.code.length > 0)
|
|
21
|
+
.map(normalizeLanguage);
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,iBAAiB,GAAG,CAAC,QAA0B,EAAkB,EAAE,CAAC,CAAC;IACzE,IAAI,EAAE,QAAQ,CAAC,IAAI;IACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;IACnB,UAAU,EACR,QAAQ,CAAC,UAAU,IAAI,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE;IACrE,OAAO,EAAE,QAAQ,CAAC,OAAO,IAAI,IAAI;CAClC,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,QAA0B,EACR,EAAE;IACpB,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;QACjD,CAAC,CAAC,QAAQ,CAAC,SAAS;QACpB,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,SAAS;SACb,MAAM,CACL,CAAC,QAAQ,EAAgC,EAAE,CACzC,CAAC,CAAC,QAAQ;QACV,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ;QACjC,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAC3B;SACA,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAC5B,CAAC,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supported locale string (e.g., "en", "en-US", "tr")
|
|
3
|
+
*/
|
|
4
|
+
export type Locale = string;
|
|
5
|
+
/**
|
|
6
|
+
* Log level for debugging
|
|
7
|
+
*/
|
|
8
|
+
export type LogLevel = "debug" | "info" | "warn" | "error" | "silent";
|
|
9
|
+
/**
|
|
10
|
+
* Core i18n configuration
|
|
11
|
+
*/
|
|
12
|
+
export interface I18nCoreConfig {
|
|
13
|
+
/**
|
|
14
|
+
* Project identifier in format "org/project" (e.g., "acme/dashboard")
|
|
15
|
+
*/
|
|
16
|
+
project: string;
|
|
17
|
+
/**
|
|
18
|
+
* Default locale to use when no locale is specified
|
|
19
|
+
*/
|
|
20
|
+
defaultLocale: string;
|
|
21
|
+
/**
|
|
22
|
+
* CDN base URL
|
|
23
|
+
* @default "https://cdn.better-i18n.com"
|
|
24
|
+
*/
|
|
25
|
+
cdnBaseUrl?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Cache TTL in milliseconds for manifest
|
|
28
|
+
* @default 300000 (5 minutes)
|
|
29
|
+
*/
|
|
30
|
+
manifestCacheTtlMs?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Enable debug logging
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
debug?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Log level
|
|
38
|
+
* @default "warn"
|
|
39
|
+
*/
|
|
40
|
+
logLevel?: LogLevel;
|
|
41
|
+
/**
|
|
42
|
+
* Custom fetch function (useful for testing or custom environments)
|
|
43
|
+
*/
|
|
44
|
+
fetch?: typeof fetch;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Parsed project identifier
|
|
48
|
+
*/
|
|
49
|
+
export interface ParsedProject {
|
|
50
|
+
workspaceId: string;
|
|
51
|
+
projectSlug: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Normalized configuration with all defaults applied
|
|
55
|
+
*/
|
|
56
|
+
export interface NormalizedConfig extends I18nCoreConfig, ParsedProject {
|
|
57
|
+
cdnBaseUrl: string;
|
|
58
|
+
manifestCacheTtlMs: number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Language information from manifest
|
|
62
|
+
*/
|
|
63
|
+
export interface ManifestLanguage {
|
|
64
|
+
code: string;
|
|
65
|
+
name?: string;
|
|
66
|
+
nativeName?: string;
|
|
67
|
+
flagUrl?: string | null;
|
|
68
|
+
isSource?: boolean;
|
|
69
|
+
lastUpdated?: string | null;
|
|
70
|
+
keyCount?: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* File information in manifest
|
|
74
|
+
*/
|
|
75
|
+
export interface ManifestFile {
|
|
76
|
+
url: string;
|
|
77
|
+
size: number;
|
|
78
|
+
lastModified: string | null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* CDN manifest response
|
|
82
|
+
*/
|
|
83
|
+
export interface ManifestResponse {
|
|
84
|
+
projectSlug?: string;
|
|
85
|
+
sourceLanguage?: string;
|
|
86
|
+
languages: ManifestLanguage[];
|
|
87
|
+
files?: Record<string, ManifestFile>;
|
|
88
|
+
updatedAt?: string;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Simplified language option for UI components
|
|
92
|
+
*/
|
|
93
|
+
export interface LanguageOption {
|
|
94
|
+
code: string;
|
|
95
|
+
name?: string;
|
|
96
|
+
nativeName?: string;
|
|
97
|
+
flagUrl?: string | null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Translation messages (flat or nested key-value pairs)
|
|
101
|
+
*/
|
|
102
|
+
export type Messages = Record<string, unknown>;
|
|
103
|
+
/**
|
|
104
|
+
* Logger interface
|
|
105
|
+
*/
|
|
106
|
+
export interface Logger {
|
|
107
|
+
debug: (...args: unknown[]) => void;
|
|
108
|
+
info: (...args: unknown[]) => void;
|
|
109
|
+
warn: (...args: unknown[]) => void;
|
|
110
|
+
error: (...args: unknown[]) => void;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Cache entry with expiration
|
|
114
|
+
*/
|
|
115
|
+
export interface CacheEntry<T> {
|
|
116
|
+
value: T;
|
|
117
|
+
expiresAt: number;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* i18n core instance returned by createI18nCore
|
|
121
|
+
*/
|
|
122
|
+
export interface I18nCore {
|
|
123
|
+
/**
|
|
124
|
+
* Resolved configuration
|
|
125
|
+
*/
|
|
126
|
+
config: NormalizedConfig;
|
|
127
|
+
/**
|
|
128
|
+
* Fetch manifest from CDN
|
|
129
|
+
*/
|
|
130
|
+
getManifest: (options?: {
|
|
131
|
+
forceRefresh?: boolean;
|
|
132
|
+
}) => Promise<ManifestResponse>;
|
|
133
|
+
/**
|
|
134
|
+
* Get messages for a specific locale
|
|
135
|
+
*/
|
|
136
|
+
getMessages: (locale: string) => Promise<Messages>;
|
|
137
|
+
/**
|
|
138
|
+
* Get available locale codes
|
|
139
|
+
*/
|
|
140
|
+
getLocales: () => Promise<string[]>;
|
|
141
|
+
/**
|
|
142
|
+
* Get language options with metadata (for UI components)
|
|
143
|
+
*/
|
|
144
|
+
getLanguages: () => Promise<LanguageOption[]>;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-i18n/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Framework-agnostic core utilities for Better i18n",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/better-i18n/better-i18n/issues"
|
|
13
13
|
},
|
|
14
|
-
"homepage": "https://github.com/better-i18n/better-i18n/tree/main/packages/
|
|
14
|
+
"homepage": "https://github.com/better-i18n/better-i18n/tree/main/packages/core",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"main": "./dist/index.js",
|
|
17
17
|
"types": "./dist/index.d.ts",
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsc",
|
|
42
42
|
"typecheck": "tsc --noEmit",
|
|
43
|
-
"clean": "rm -rf dist"
|
|
43
|
+
"clean": "rm -rf dist",
|
|
44
|
+
"prepublishOnly": "bun run build"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
|
-
"@better-i18n/typescript-config": "workspace:*",
|
|
47
47
|
"@types/node": "^20.0.0",
|
|
48
48
|
"typescript": "~5.9.2"
|
|
49
49
|
}
|