@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 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 '@better-i18n/core'
23
+ import { createI18nCore } from "@better-i18n/core";
17
24
 
18
25
  const i18n = createI18nCore({
19
- project: 'your-org/your-project',
20
- defaultLocale: 'en',
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('en')
31
+ const messages = await i18n.getMessages("en");
25
32
 
26
33
  // Get available locales
27
- const locales = await i18n.getLocales()
28
- // ['en', 'tr', 'de', ...]
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: 'en', name: 'English', nativeName: 'English', flagUrl: '...' }, ...]
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
- ## Used By
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/use-intl` - TanStack/React integration
61
- - `@better-i18n/i18next-backend` - i18next backend plugin
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)
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdn.js","sourceRoot":"","sources":["../src/cdn.ts"],"names":[],"mappings":"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"}
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/i18n/types.ts"],"names":[],"mappings":""}
@@ -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"}
@@ -0,0 +1,6 @@
1
+ import type { Logger, NormalizedConfig } from "./types";
2
+ /**
3
+ * Create a logger instance with namespace prefix
4
+ */
5
+ export declare const createLogger: (config: NormalizedConfig, namespace: string) => Logger;
6
+ //# sourceMappingURL=logger.d.ts.map
@@ -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,6 @@
1
+ import type { LanguageOption, ManifestResponse } from "./types";
2
+ /**
3
+ * Extract and normalize languages from manifest
4
+ */
5
+ export declare const extractLanguages: (manifest: ManifestResponse) => LanguageOption[];
6
+ //# sourceMappingURL=manifest.d.ts.map
@@ -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"}
@@ -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"}
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -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.2",
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/i18n-core",
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
  }