@geenius/i18n 0.1.0 → 0.3.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 +134 -1
- package/package.json +16 -3
- package/packages/convex/dist/index.d.ts +62 -0
- package/packages/convex/dist/index.js +157 -0
- package/packages/convex/dist/index.js.map +1 -0
- package/packages/react/README.md +1 -1
- package/packages/react/dist/index.d.ts +100 -0
- package/packages/react/dist/index.js +284 -0
- package/packages/react/dist/index.js.map +1 -0
- package/packages/react-css/README.md +1 -1
- package/packages/react-css/dist/index.d.ts +34 -0
- package/packages/react-css/dist/index.js +134 -0
- package/packages/react-css/dist/index.js.map +1 -0
- package/packages/shared/README.md +1 -1
- package/packages/shared/dist/index.d.ts +77 -0
- package/packages/shared/dist/index.js +158 -0
- package/packages/shared/dist/index.js.map +1 -0
- package/packages/solidjs/README.md +1 -1
- package/packages/solidjs/dist/index.d.ts +105 -0
- package/packages/solidjs/dist/index.js +328 -0
- package/packages/solidjs/dist/index.js.map +1 -0
- package/packages/solidjs-css/README.md +1 -1
- package/packages/solidjs-css/dist/index.d.ts +59 -0
- package/packages/solidjs-css/dist/index.js +244 -0
- package/packages/solidjs-css/dist/index.js.map +1 -0
- package/.changeset/config.json +0 -11
- package/.github/CODEOWNERS +0 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -16
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -11
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -10
- package/.github/dependabot.yml +0 -11
- package/.github/workflows/ci.yml +0 -23
- package/.github/workflows/release.yml +0 -29
- package/.nvmrc +0 -1
- package/.project/ACCOUNT.yaml +0 -4
- package/.project/IDEAS.yaml +0 -7
- package/.project/PROJECT.yaml +0 -11
- package/.project/ROADMAP.yaml +0 -15
- package/CODE_OF_CONDUCT.md +0 -16
- package/CONTRIBUTING.md +0 -26
- package/SECURITY.md +0 -15
- package/SUPPORT.md +0 -8
- package/packages/convex/package.json +0 -42
- package/packages/convex/src/index.ts +0 -3
- package/packages/convex/src/mutations.ts +0 -65
- package/packages/convex/src/queries.ts +0 -54
- package/packages/convex/src/schema.ts +0 -26
- package/packages/convex/tsconfig.json +0 -18
- package/packages/convex/tsup.config.ts +0 -17
- package/packages/react/package.json +0 -51
- package/packages/react/src/components/index.tsx +0 -87
- package/packages/react/src/hooks/index.ts +0 -4
- package/packages/react/src/hooks/useI18n.tsx +0 -50
- package/packages/react/src/hooks/useI18nAdmin.ts +0 -12
- package/packages/react/src/hooks/useLocaleDetect.ts +0 -10
- package/packages/react/src/hooks/useTranslations.ts +0 -11
- package/packages/react/src/index.tsx +0 -8
- package/packages/react/src/pages/I18nAdminPage.tsx +0 -42
- package/packages/react/src/pages/LocalePreviewPage.tsx +0 -54
- package/packages/react/src/pages/index.ts +0 -2
- package/packages/react/tsconfig.json +0 -19
- package/packages/react/tsup.config.ts +0 -12
- package/packages/react-css/package.json +0 -36
- package/packages/react-css/src/components/index.tsx +0 -66
- package/packages/react-css/src/hooks/index.ts +0 -4
- package/packages/react-css/src/index.tsx +0 -4
- package/packages/react-css/src/pages/LocaleSettingsPage.tsx +0 -74
- package/packages/react-css/src/pages/TranslationsPage.tsx +0 -98
- package/packages/react-css/src/styles.css +0 -210
- package/packages/react-css/tsconfig.json +0 -19
- package/packages/react-css/tsup.config.ts +0 -10
- package/packages/shared/package.json +0 -44
- package/packages/shared/src/__tests__/i18n.test.ts +0 -78
- package/packages/shared/src/config.ts +0 -344
- package/packages/shared/src/index.ts +0 -106
- package/packages/shared/src/types.ts +0 -51
- package/packages/shared/tsconfig.json +0 -18
- package/packages/shared/tsup.config.ts +0 -11
- package/packages/shared/vitest.config.ts +0 -4
- package/packages/solidjs/package.json +0 -47
- package/packages/solidjs/src/components/LocaleCard.tsx +0 -44
- package/packages/solidjs/src/components/LocaleStatsCard.tsx +0 -35
- package/packages/solidjs/src/components/LocaleSwitcher.tsx +0 -65
- package/packages/solidjs/src/components/MissingKeyAlert.tsx +0 -21
- package/packages/solidjs/src/components/RTLWrapper.tsx +0 -13
- package/packages/solidjs/src/components/TranslationKeyRow.tsx +0 -41
- package/packages/solidjs/src/components/index.ts +0 -6
- package/packages/solidjs/src/index.tsx +0 -8
- package/packages/solidjs/src/pages/I18nAdminPage.tsx +0 -188
- package/packages/solidjs/src/pages/LocalePreviewPage.tsx +0 -99
- package/packages/solidjs/src/pages/index.ts +0 -2
- package/packages/solidjs/src/primitives/I18nProvider.tsx +0 -56
- package/packages/solidjs/src/primitives/createI18nAdmin.ts +0 -7
- package/packages/solidjs/src/primitives/createLocaleDetect.ts +0 -8
- package/packages/solidjs/src/primitives/createTranslations.ts +0 -22
- package/packages/solidjs/src/primitives/index.ts +0 -4
- package/packages/solidjs/tsconfig.json +0 -20
- package/packages/solidjs/tsup.config.ts +0 -12
- package/packages/solidjs-css/package.json +0 -33
- package/packages/solidjs-css/src/components/LocaleCard.tsx +0 -45
- package/packages/solidjs-css/src/components/LocaleStatsCard.tsx +0 -43
- package/packages/solidjs-css/src/components/LocaleSwitcher.tsx +0 -51
- package/packages/solidjs-css/src/components/MissingKeyAlert.tsx +0 -24
- package/packages/solidjs-css/src/components/RTLWrapper.tsx +0 -16
- package/packages/solidjs-css/src/components/TranslationKeyRow.tsx +0 -47
- package/packages/solidjs-css/src/components/index.ts +0 -6
- package/packages/solidjs-css/src/i18n.css +0 -1322
- package/packages/solidjs-css/src/index.tsx +0 -3
- package/packages/solidjs-css/src/pages/I18nAdminPage.tsx +0 -134
- package/packages/solidjs-css/src/pages/LocalePreviewPage.tsx +0 -116
- package/packages/solidjs-css/src/pages/index.ts +0 -2
- package/packages/solidjs-css/src/primitives/index.ts +0 -1
- package/packages/solidjs-css/tsconfig.json +0 -20
- package/packages/solidjs-css/tsup.config.bundled_dcjc4sct21j.mjs +0 -18
- package/packages/solidjs-css/tsup.config.ts +0 -14
- package/pnpm-workspace.yaml +0 -2
- package/tsconfig.json +0 -23
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
type Locale = 'en' | 'fr' | 'de' | 'es' | 'pt' | 'it' | 'nl' | 'ru' | 'zh' | 'ja' | 'ko' | 'ar' | 'he' | 'tr';
|
|
2
|
+
type Direction = 'ltr' | 'rtl';
|
|
3
|
+
type I18nNamespace = 'common' | 'auth' | 'dashboard' | 'billing' | 'errors' | string;
|
|
4
|
+
interface TranslationDict {
|
|
5
|
+
[key: string]: string | TranslationDict;
|
|
6
|
+
}
|
|
7
|
+
interface I18nConfig {
|
|
8
|
+
defaultLocale: Locale;
|
|
9
|
+
supportedLocales: Locale[];
|
|
10
|
+
fallbackLocale?: Locale;
|
|
11
|
+
namespaces?: I18nNamespace[];
|
|
12
|
+
/** Active namespace identifier (used by I18nConfigBuilder) */
|
|
13
|
+
namespace?: string;
|
|
14
|
+
detectBrowser?: boolean;
|
|
15
|
+
persistLocale?: boolean;
|
|
16
|
+
dateFormat?: string;
|
|
17
|
+
numberFormat?: Intl.NumberFormatOptions;
|
|
18
|
+
/** Enable debug mode — logs missing keys and translation lookups */
|
|
19
|
+
debug?: boolean;
|
|
20
|
+
/** Show console warnings for missing translation keys */
|
|
21
|
+
missingKeyWarnings?: boolean;
|
|
22
|
+
/** Prefix prepended to missing key fallback text */
|
|
23
|
+
missingKeyPrefix?: string;
|
|
24
|
+
}
|
|
25
|
+
interface LocaleInfo {
|
|
26
|
+
code: Locale;
|
|
27
|
+
name: string;
|
|
28
|
+
nativeName: string;
|
|
29
|
+
direction: Direction;
|
|
30
|
+
flag: string;
|
|
31
|
+
}
|
|
32
|
+
interface TranslationEntry {
|
|
33
|
+
id: string;
|
|
34
|
+
locale: Locale;
|
|
35
|
+
namespace: string;
|
|
36
|
+
key: string;
|
|
37
|
+
value: string;
|
|
38
|
+
lastEditedBy?: string;
|
|
39
|
+
updatedAt: string;
|
|
40
|
+
createdAt: string;
|
|
41
|
+
}
|
|
42
|
+
interface MissingKey {
|
|
43
|
+
id: string;
|
|
44
|
+
locale: Locale;
|
|
45
|
+
namespace: string;
|
|
46
|
+
key: string;
|
|
47
|
+
detectedAt: string;
|
|
48
|
+
count: number;
|
|
49
|
+
}
|
|
50
|
+
interface LocaleStat {
|
|
51
|
+
locale: Locale;
|
|
52
|
+
totalKeys: number;
|
|
53
|
+
missingKeys: number;
|
|
54
|
+
coverage: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
declare const LOCALE_INFO: Record<Locale, LocaleInfo>;
|
|
58
|
+
declare const ALL_LOCALES: Locale[];
|
|
59
|
+
declare const RTL_LOCALES: Locale[];
|
|
60
|
+
declare function interpolate(template: string, params: Record<string, string | number>): string;
|
|
61
|
+
declare function t(key: string, dict: TranslationDict, params?: Record<string, string | number>): string;
|
|
62
|
+
declare function plural(key: string, count: number, dict: TranslationDict): string;
|
|
63
|
+
declare function formatDate(date: Date | string, locale: Locale, format?: Intl.DateTimeFormatOptions): string;
|
|
64
|
+
declare function formatNumber(n: number, locale: Locale, opts?: Intl.NumberFormatOptions): string;
|
|
65
|
+
declare function formatCurrency(amount: number, currency: string, locale: Locale): string;
|
|
66
|
+
declare function detectLocale(supportedLocales: Locale[]): Locale;
|
|
67
|
+
declare function getDirection(locale: Locale): Direction;
|
|
68
|
+
declare function isRTL(locale: Locale): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Load a translation namespace for a locale.
|
|
71
|
+
* Delegates to the default translation loader (fetches from /locales/{locale}/{ns}.json).
|
|
72
|
+
* Falls back to an empty dict if the fetch fails (e.g., during SSR or when no translations are deployed).
|
|
73
|
+
*/
|
|
74
|
+
declare function loadNamespace(locale: Locale, ns: string): Promise<TranslationDict>;
|
|
75
|
+
declare function flattenDict(dict: TranslationDict, prefix?: string): Record<string, string>;
|
|
76
|
+
|
|
77
|
+
export { ALL_LOCALES, type Direction, type I18nConfig, type I18nNamespace, LOCALE_INFO, type Locale, type LocaleInfo, type LocaleStat, type MissingKey, RTL_LOCALES, type TranslationDict, type TranslationEntry, detectLocale, flattenDict, formatCurrency, formatDate, formatNumber, getDirection, interpolate, isRTL, loadNamespace, plural, t };
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// src/config.ts
|
|
2
|
+
function createTranslationLoader(config = {}) {
|
|
3
|
+
const cache = /* @__PURE__ */ new Map();
|
|
4
|
+
const {
|
|
5
|
+
baseUrl = "/locales",
|
|
6
|
+
cache: enableCache = true,
|
|
7
|
+
cacheDuration = 36e5
|
|
8
|
+
// 1 hour
|
|
9
|
+
} = config;
|
|
10
|
+
return {
|
|
11
|
+
/**
|
|
12
|
+
* Loads translations for a locale and namespace
|
|
13
|
+
*/
|
|
14
|
+
async load(locale, namespace) {
|
|
15
|
+
const cacheKey = `${locale}:${namespace}`;
|
|
16
|
+
if (enableCache) {
|
|
17
|
+
const cached = cache.get(cacheKey);
|
|
18
|
+
if (cached && Date.now() - cached.timestamp < cacheDuration) {
|
|
19
|
+
return cached.data;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const url = `${baseUrl}/${locale}/${namespace}.json`;
|
|
24
|
+
const response = await fetch(url);
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
console.warn(
|
|
27
|
+
`Failed to load translations from ${url}: ${response.statusText}`
|
|
28
|
+
);
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
const data = await response.json();
|
|
32
|
+
if (enableCache) {
|
|
33
|
+
cache.set(cacheKey, {
|
|
34
|
+
data,
|
|
35
|
+
timestamp: Date.now()
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return data;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(`Error loading translations for ${locale}/${namespace}:`, error);
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
/**
|
|
45
|
+
* Preloads all locales for a namespace
|
|
46
|
+
*/
|
|
47
|
+
async preload(locales, namespace) {
|
|
48
|
+
await Promise.all(locales.map((locale) => this.load(locale, namespace)));
|
|
49
|
+
},
|
|
50
|
+
/**
|
|
51
|
+
* Clears cache
|
|
52
|
+
*/
|
|
53
|
+
clearCache(locale, namespace) {
|
|
54
|
+
if (locale && namespace) {
|
|
55
|
+
cache.delete(`${locale}:${namespace}`);
|
|
56
|
+
} else {
|
|
57
|
+
cache.clear();
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
/**
|
|
61
|
+
* Gets cache stats
|
|
62
|
+
*/
|
|
63
|
+
getCacheStats() {
|
|
64
|
+
return {
|
|
65
|
+
size: cache.size,
|
|
66
|
+
entries: Array.from(cache.keys())
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/index.ts
|
|
73
|
+
var LOCALE_INFO = {
|
|
74
|
+
en: { code: "en", name: "English", nativeName: "English", direction: "ltr", flag: "\u{1F1EC}\u{1F1E7}" },
|
|
75
|
+
fr: { code: "fr", name: "French", nativeName: "Fran\xE7ais", direction: "ltr", flag: "\u{1F1EB}\u{1F1F7}" },
|
|
76
|
+
de: { code: "de", name: "German", nativeName: "Deutsch", direction: "ltr", flag: "\u{1F1E9}\u{1F1EA}" },
|
|
77
|
+
es: { code: "es", name: "Spanish", nativeName: "Espa\xF1ol", direction: "ltr", flag: "\u{1F1EA}\u{1F1F8}" },
|
|
78
|
+
pt: { code: "pt", name: "Portuguese", nativeName: "Portugu\xEAs", direction: "ltr", flag: "\u{1F1F5}\u{1F1F9}" },
|
|
79
|
+
it: { code: "it", name: "Italian", nativeName: "Italiano", direction: "ltr", flag: "\u{1F1EE}\u{1F1F9}" },
|
|
80
|
+
nl: { code: "nl", name: "Dutch", nativeName: "Nederlands", direction: "ltr", flag: "\u{1F1F3}\u{1F1F1}" },
|
|
81
|
+
ru: { code: "ru", name: "Russian", nativeName: "\u0420\u0443\u0441\u0441\u043A\u0438\u0439", direction: "ltr", flag: "\u{1F1F7}\u{1F1FA}" },
|
|
82
|
+
zh: { code: "zh", name: "Chinese", nativeName: "\u4E2D\u6587", direction: "ltr", flag: "\u{1F1E8}\u{1F1F3}" },
|
|
83
|
+
ja: { code: "ja", name: "Japanese", nativeName: "\u65E5\u672C\u8A9E", direction: "ltr", flag: "\u{1F1EF}\u{1F1F5}" },
|
|
84
|
+
ko: { code: "ko", name: "Korean", nativeName: "\uD55C\uAD6D\uC5B4", direction: "ltr", flag: "\u{1F1F0}\u{1F1F7}" },
|
|
85
|
+
ar: { code: "ar", name: "Arabic", nativeName: "\u0627\u0644\u0639\u0631\u0628\u064A\u0629", direction: "rtl", flag: "\u{1F1F8}\u{1F1E6}" },
|
|
86
|
+
he: { code: "he", name: "Hebrew", nativeName: "\u05E2\u05D1\u05E8\u05D9\u05EA", direction: "rtl", flag: "\u{1F1EE}\u{1F1F1}" },
|
|
87
|
+
tr: { code: "tr", name: "Turkish", nativeName: "T\xFCrk\xE7e", direction: "ltr", flag: "\u{1F1F9}\u{1F1F7}" }
|
|
88
|
+
};
|
|
89
|
+
var ALL_LOCALES = Object.keys(LOCALE_INFO);
|
|
90
|
+
var RTL_LOCALES = ["ar", "he"];
|
|
91
|
+
function interpolate(template, params) {
|
|
92
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => String(params[key] ?? `{{${key}}}`));
|
|
93
|
+
}
|
|
94
|
+
function t(key, dict, params) {
|
|
95
|
+
const parts = key.split(".");
|
|
96
|
+
let current = dict;
|
|
97
|
+
for (const part of parts) {
|
|
98
|
+
if (typeof current !== "object" || current === null) return key;
|
|
99
|
+
current = current[part];
|
|
100
|
+
if (current === void 0) return key;
|
|
101
|
+
}
|
|
102
|
+
if (typeof current !== "string") return key;
|
|
103
|
+
return params ? interpolate(current, params) : current;
|
|
104
|
+
}
|
|
105
|
+
function plural(key, count, dict) {
|
|
106
|
+
if (count === 0) {
|
|
107
|
+
const zero = t(`${key}_zero`, dict);
|
|
108
|
+
if (zero !== `${key}_zero`) return zero;
|
|
109
|
+
}
|
|
110
|
+
if (count === 1) {
|
|
111
|
+
const one = t(`${key}_one`, dict);
|
|
112
|
+
if (one !== `${key}_one`) return one;
|
|
113
|
+
}
|
|
114
|
+
const other = t(`${key}_other`, dict);
|
|
115
|
+
if (other !== `${key}_other`) return interpolate(other, { count });
|
|
116
|
+
return t(key, dict, { count });
|
|
117
|
+
}
|
|
118
|
+
function formatDate(date, locale, format) {
|
|
119
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
120
|
+
return new Intl.DateTimeFormat(locale, format ?? { dateStyle: "medium" }).format(d);
|
|
121
|
+
}
|
|
122
|
+
function formatNumber(n, locale, opts) {
|
|
123
|
+
return new Intl.NumberFormat(locale, opts).format(n);
|
|
124
|
+
}
|
|
125
|
+
function formatCurrency(amount, currency, locale) {
|
|
126
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(amount);
|
|
127
|
+
}
|
|
128
|
+
function detectLocale(supportedLocales) {
|
|
129
|
+
if (typeof navigator === "undefined") return supportedLocales[0] ?? "en";
|
|
130
|
+
const browserLang = navigator.language.split("-")[0];
|
|
131
|
+
if (supportedLocales.includes(browserLang)) return browserLang;
|
|
132
|
+
const full = navigator.language;
|
|
133
|
+
if (supportedLocales.includes(full)) return full;
|
|
134
|
+
return supportedLocales[0] ?? "en";
|
|
135
|
+
}
|
|
136
|
+
function getDirection(locale) {
|
|
137
|
+
return LOCALE_INFO[locale]?.direction ?? "ltr";
|
|
138
|
+
}
|
|
139
|
+
function isRTL(locale) {
|
|
140
|
+
return getDirection(locale) === "rtl";
|
|
141
|
+
}
|
|
142
|
+
var _defaultLoader = createTranslationLoader({ baseUrl: "/locales", cache: true });
|
|
143
|
+
async function loadNamespace(locale, ns) {
|
|
144
|
+
return _defaultLoader.load(locale, ns);
|
|
145
|
+
}
|
|
146
|
+
function flattenDict(dict, prefix = "") {
|
|
147
|
+
const result = {};
|
|
148
|
+
for (const [key, value] of Object.entries(dict)) {
|
|
149
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
150
|
+
if (typeof value === "string") result[fullKey] = value;
|
|
151
|
+
else Object.assign(result, flattenDict(value, fullKey));
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export { ALL_LOCALES, LOCALE_INFO, RTL_LOCALES, detectLocale, flattenDict, formatCurrency, formatDate, formatNumber, getDirection, interpolate, isRTL, loadNamespace, plural, t };
|
|
157
|
+
//# sourceMappingURL=index.js.map
|
|
158
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * I18n configuration and setup\n */\n\nimport type { Locale, I18nConfig, TranslationDict } from './types'\n\n/**\n * I18n configuration builder\n *\n * @example\n * ```ts\n * const i18nConfig = createI18nConfig()\n * .withDefaultLocale('en')\n * .withSupportedLocales(['en', 'fr', 'de'])\n * .withFallbackLocale('en')\n * .withNamespace('common')\n * ```\n */\nexport class I18nConfigBuilder {\n private config: I18nConfig = {\n defaultLocale: 'en',\n supportedLocales: ['en'],\n fallbackLocale: 'en',\n namespace: 'translations',\n debug: false,\n }\n\n /**\n * Sets default locale\n */\n withDefaultLocale(locale: Locale): this {\n this.config.defaultLocale = locale\n return this\n }\n\n /**\n * Sets supported locales\n */\n withSupportedLocales(locales: Locale[]): this {\n this.config.supportedLocales = locales\n return this\n }\n\n /**\n * Sets fallback locale when translation is missing\n */\n withFallbackLocale(locale: Locale): this {\n this.config.fallbackLocale = locale\n return this\n }\n\n /**\n * Sets translation namespace\n */\n withNamespace(namespace: string): this {\n this.config.namespace = namespace\n return this\n }\n\n /**\n * Sets debug mode\n */\n withDebug(enabled: boolean): this {\n this.config.debug = enabled\n return this\n }\n\n /**\n * Enables missing key warnings\n */\n withMissingKeyWarnings(enabled: boolean): this {\n this.config.missingKeyWarnings = enabled\n return this\n }\n\n /**\n * Sets missing key prefix\n */\n withMissingKeyPrefix(prefix: string): this {\n this.config.missingKeyPrefix = prefix\n return this\n }\n\n /**\n * Builds the configuration\n */\n build(): I18nConfig {\n if (!this.config.supportedLocales.includes(this.config.defaultLocale)) {\n throw new Error(\n `Default locale ${this.config.defaultLocale} must be in supported locales`\n )\n }\n\n if (!this.config.supportedLocales.includes(this.config.fallbackLocale)) {\n throw new Error(\n `Fallback locale ${this.config.fallbackLocale} must be in supported locales`\n )\n }\n\n return this.config\n }\n}\n\n/**\n * Creates a new I18n configuration builder\n */\nexport function createI18nConfig(): I18nConfigBuilder {\n return new I18nConfigBuilder()\n}\n\n/**\n * Translation loader configuration\n */\nexport interface TranslationLoaderConfig {\n /** Base URL for loading translations */\n baseUrl?: string\n /** Whether to cache loaded translations */\n cache?: boolean\n /** Cache duration in milliseconds */\n cacheDuration?: number\n /** Whether to load all locales on init */\n preloadAll?: boolean\n}\n\n/**\n * Creates a translation loader\n *\n * @example\n * ```ts\n * const loader = createTranslationLoader({\n * baseUrl: '/locales',\n * cache: true,\n * cacheDuration: 3600000\n * })\n *\n * const translations = await loader.load('en', 'common')\n * ```\n */\nexport function createTranslationLoader(config: TranslationLoaderConfig = {}) {\n const cache = new Map<string, { data: TranslationDict; timestamp: number }>()\n const {\n baseUrl = '/locales',\n cache: enableCache = true,\n cacheDuration = 3600000, // 1 hour\n } = config\n\n return {\n /**\n * Loads translations for a locale and namespace\n */\n async load(locale: Locale, namespace: string): Promise<TranslationDict> {\n const cacheKey = `${locale}:${namespace}`\n\n // Check cache\n if (enableCache) {\n const cached = cache.get(cacheKey)\n if (cached && Date.now() - cached.timestamp < cacheDuration) {\n return cached.data\n }\n }\n\n try {\n const url = `${baseUrl}/${locale}/${namespace}.json`\n const response = await fetch(url)\n\n if (!response.ok) {\n console.warn(\n `Failed to load translations from ${url}: ${response.statusText}`\n )\n return {}\n }\n\n const data = (await response.json()) as TranslationDict\n\n // Cache result\n if (enableCache) {\n cache.set(cacheKey, {\n data,\n timestamp: Date.now(),\n })\n }\n\n return data\n } catch (error) {\n console.error(`Error loading translations for ${locale}/${namespace}:`, error)\n return {}\n }\n },\n\n /**\n * Preloads all locales for a namespace\n */\n async preload(locales: Locale[], namespace: string): Promise<void> {\n await Promise.all(locales.map((locale) => this.load(locale, namespace)))\n },\n\n /**\n * Clears cache\n */\n clearCache(locale?: Locale, namespace?: string) {\n if (locale && namespace) {\n cache.delete(`${locale}:${namespace}`)\n } else {\n cache.clear()\n }\n },\n\n /**\n * Gets cache stats\n */\n getCacheStats() {\n return {\n size: cache.size,\n entries: Array.from(cache.keys()),\n }\n },\n }\n}\n\n/**\n * Namespace loader for managing multiple translation namespaces\n *\n * @example\n * ```ts\n * const loader = createNamespaceLoader(createTranslationLoader())\n * const translations = await loader.loadMultiple('en', ['common', 'errors'])\n * ```\n */\nexport function createNamespaceLoader(\n translationLoader: ReturnType<typeof createTranslationLoader>\n) {\n const namespaces = new Map<string, TranslationDict>()\n\n return {\n /**\n * Loads a single namespace\n */\n async load(locale: Locale, namespace: string): Promise<TranslationDict> {\n const translations = await translationLoader.load(locale, namespace)\n const key = `${locale}:${namespace}`\n namespaces.set(key, translations)\n return translations\n },\n\n /**\n * Loads multiple namespaces\n */\n async loadMultiple(\n locale: Locale,\n namespaceList: string[]\n ): Promise<Record<string, TranslationDict>> {\n const result: Record<string, TranslationDict> = {}\n\n for (const ns of namespaceList) {\n result[ns] = await this.load(locale, ns)\n }\n\n return result\n },\n\n /**\n * Gets loaded namespace\n */\n get(locale: Locale, namespace: string): TranslationDict | undefined {\n return namespaces.get(`${locale}:${namespace}`)\n },\n\n /**\n * Merges multiple translations into one\n */\n merge(\n locale: Locale,\n namespaceList: string[]\n ): TranslationDict {\n const merged: TranslationDict = {}\n\n for (const ns of namespaceList) {\n const trans = this.get(locale, ns)\n if (trans) {\n Object.assign(merged, trans)\n }\n }\n\n return merged\n },\n }\n}\n\n/**\n * Default i18n configurations for different scenarios\n */\nexport const i18nPresets = {\n /**\n * Simple single-language setup\n */\n simple: (locale: Locale = 'en'): I18nConfig => {\n return createI18nConfig()\n .withDefaultLocale(locale)\n .withSupportedLocales([locale])\n .withFallbackLocale(locale)\n .build()\n },\n\n /**\n * Multi-language with common locales\n */\n multi: (defaultLocale: Locale = 'en'): I18nConfig => {\n return createI18nConfig()\n .withDefaultLocale(defaultLocale)\n .withSupportedLocales(['en', 'fr', 'de', 'es', 'it'])\n .build()\n },\n\n /**\n * Global localization\n */\n global: (defaultLocale: Locale = 'en'): I18nConfig => {\n return createI18nConfig()\n .withDefaultLocale(defaultLocale)\n .withSupportedLocales([\n 'en',\n 'fr',\n 'de',\n 'es',\n 'it',\n 'pt',\n 'ru',\n 'zh',\n 'ja',\n 'ko',\n ] as Locale[])\n .build()\n },\n\n /**\n * Development configuration with debug output\n */\n development: (): I18nConfig => {\n return createI18nConfig()\n .withDebug(true)\n .withMissingKeyWarnings(true)\n .withMissingKeyPrefix('[MISSING] ')\n .build()\n },\n}\n","export type {\n Locale, Direction, I18nNamespace, TranslationDict, I18nConfig,\n LocaleInfo, TranslationEntry, MissingKey, LocaleStat,\n} from './types'\n\nimport type { Locale, Direction, LocaleInfo, TranslationDict } from './types'\n\n// ─── LOCALE_INFO (14 locales) ─────────────────────────\nexport const LOCALE_INFO: Record<Locale, LocaleInfo> = {\n en: { code: 'en', name: 'English', nativeName: 'English', direction: 'ltr', flag: '🇬🇧' },\n fr: { code: 'fr', name: 'French', nativeName: 'Français', direction: 'ltr', flag: '🇫🇷' },\n de: { code: 'de', name: 'German', nativeName: 'Deutsch', direction: 'ltr', flag: '🇩🇪' },\n es: { code: 'es', name: 'Spanish', nativeName: 'Español', direction: 'ltr', flag: '🇪🇸' },\n pt: { code: 'pt', name: 'Portuguese', nativeName: 'Português', direction: 'ltr', flag: '🇵🇹' },\n it: { code: 'it', name: 'Italian', nativeName: 'Italiano', direction: 'ltr', flag: '🇮🇹' },\n nl: { code: 'nl', name: 'Dutch', nativeName: 'Nederlands', direction: 'ltr', flag: '🇳🇱' },\n ru: { code: 'ru', name: 'Russian', nativeName: 'Русский', direction: 'ltr', flag: '🇷🇺' },\n zh: { code: 'zh', name: 'Chinese', nativeName: '中文', direction: 'ltr', flag: '🇨🇳' },\n ja: { code: 'ja', name: 'Japanese', nativeName: '日本語', direction: 'ltr', flag: '🇯🇵' },\n ko: { code: 'ko', name: 'Korean', nativeName: '한국어', direction: 'ltr', flag: '🇰🇷' },\n ar: { code: 'ar', name: 'Arabic', nativeName: 'العربية', direction: 'rtl', flag: '🇸🇦' },\n he: { code: 'he', name: 'Hebrew', nativeName: 'עברית', direction: 'rtl', flag: '🇮🇱' },\n tr: { code: 'tr', name: 'Turkish', nativeName: 'Türkçe', direction: 'ltr', flag: '🇹🇷' },\n}\n\nexport const ALL_LOCALES: Locale[] = Object.keys(LOCALE_INFO) as Locale[]\nexport const RTL_LOCALES: Locale[] = ['ar', 'he']\n\n// ─── Translation Utilities ────────────────────────────\nexport function interpolate(template: string, params: Record<string, string | number>): string {\n return template.replace(/\\{\\{(\\w+)\\}\\}/g, (_, key) => String(params[key] ?? `{{${key}}}`))\n}\n\nexport function t(key: string, dict: TranslationDict, params?: Record<string, string | number>): string {\n const parts = key.split('.')\n let current: string | TranslationDict = dict\n for (const part of parts) {\n if (typeof current !== 'object' || current === null) return key\n current = (current as TranslationDict)[part]\n if (current === undefined) return key\n }\n if (typeof current !== 'string') return key\n return params ? interpolate(current, params) : current\n}\n\nexport function plural(key: string, count: number, dict: TranslationDict): string {\n if (count === 0) { const zero = t(`${key}_zero`, dict); if (zero !== `${key}_zero`) return zero }\n if (count === 1) { const one = t(`${key}_one`, dict); if (one !== `${key}_one`) return one }\n const other = t(`${key}_other`, dict)\n if (other !== `${key}_other`) return interpolate(other, { count })\n return t(key, dict, { count })\n}\n\n// ─── Formatting ───────────────────────────────────────\nexport function formatDate(date: Date | string, locale: Locale, format?: Intl.DateTimeFormatOptions): string {\n const d = typeof date === 'string' ? new Date(date) : date\n return new Intl.DateTimeFormat(locale, format ?? { dateStyle: 'medium' }).format(d)\n}\n\nexport function formatNumber(n: number, locale: Locale, opts?: Intl.NumberFormatOptions): string {\n return new Intl.NumberFormat(locale, opts).format(n)\n}\n\nexport function formatCurrency(amount: number, currency: string, locale: Locale): string {\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(amount)\n}\n\n// ─── Detection & Direction ────────────────────────────\nexport function detectLocale(supportedLocales: Locale[]): Locale {\n if (typeof navigator === 'undefined') return supportedLocales[0] ?? 'en'\n const browserLang = navigator.language.split('-')[0] as Locale\n if (supportedLocales.includes(browserLang)) return browserLang\n const full = navigator.language as Locale\n if (supportedLocales.includes(full)) return full\n return supportedLocales[0] ?? 'en'\n}\n\nexport function getDirection(locale: Locale): Direction {\n return LOCALE_INFO[locale]?.direction ?? 'ltr'\n}\n\nexport function isRTL(locale: Locale): boolean {\n return getDirection(locale) === 'rtl'\n}\n\n// ─── Namespace Loader ─────────────────────────────────\nimport { createTranslationLoader } from './config'\n\nconst _defaultLoader = createTranslationLoader({ baseUrl: '/locales', cache: true })\n\n/**\n * Load a translation namespace for a locale.\n * Delegates to the default translation loader (fetches from /locales/{locale}/{ns}.json).\n * Falls back to an empty dict if the fetch fails (e.g., during SSR or when no translations are deployed).\n */\nexport async function loadNamespace(locale: Locale, ns: string): Promise<TranslationDict> {\n return _defaultLoader.load(locale, ns)\n}\n\nexport function flattenDict(dict: TranslationDict, prefix = ''): Record<string, string> {\n const result: Record<string, string> = {}\n for (const [key, value] of Object.entries(dict)) {\n const fullKey = prefix ? `${prefix}.${key}` : key\n if (typeof value === 'string') result[fullKey] = value\n else Object.assign(result, flattenDict(value, fullKey))\n }\n return result\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
# ✦ @geenius-
|
|
1
|
+
# ✦ @geenius/i18n-solidjs\n\n> Geenius I18n — SolidJS components & primitives\n\n---\n\n## Overview\nBuilt with Steve Jobs-level minimalism and Jony Ive-level craftsmanship, this package is designed to deliver unparalleled developer experience (DX) and rock-solid performance.\n\n## Installation\n\n```bash\npnpm add @geenius/i18n-solidjs\n```\n\n## Usage\n\n```typescript\nimport { init } from '@geenius/i18n-solidjs';\n\n// Initialize the module with absolute precision\ninit({\n mode: 'premium',\n});\n```\n\n## Architecture\n- **Zero-config**: It just works.\n- **Strictly Typed**: Fully written in TypeScript for flawless IntelliSense.\n- **Framework Agnostic**: seamlessly integrates into the Geenius ecosystem.\n\n---\n\n*Designed by Antigravity HQ*\n
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import * as solid_js from 'solid-js';
|
|
2
|
+
import { ParentComponent, Accessor, Component } from 'solid-js';
|
|
3
|
+
import { I18nConfig, TranslationDict, Locale, Direction, TranslationEntry, MissingKey, LocaleStat } from '@geenius/i18n-shared';
|
|
4
|
+
export { Direction, I18nConfig, I18nNamespace, Locale, LocaleInfo, LocaleStat, MissingKey, TranslationDict, TranslationEntry } from '@geenius/i18n-shared';
|
|
5
|
+
|
|
6
|
+
interface I18nCtx {
|
|
7
|
+
locale: () => Locale;
|
|
8
|
+
direction: () => Direction;
|
|
9
|
+
isRTL: () => boolean;
|
|
10
|
+
setLocale: (l: Locale) => void;
|
|
11
|
+
t: (key: string, params?: Record<string, string | number>) => string;
|
|
12
|
+
formatDate: (d: Date | string, o?: Intl.DateTimeFormatOptions) => string;
|
|
13
|
+
formatNumber: (n: number, o?: Intl.NumberFormatOptions) => string;
|
|
14
|
+
formatCurrency: (a: number, c: string) => string;
|
|
15
|
+
}
|
|
16
|
+
declare const I18nProvider: ParentComponent<{
|
|
17
|
+
config: I18nConfig;
|
|
18
|
+
translations?: TranslationDict;
|
|
19
|
+
}>;
|
|
20
|
+
declare function createI18n(): I18nCtx;
|
|
21
|
+
|
|
22
|
+
declare function createLocaleDetect(supportedLocales: Locale[]): {
|
|
23
|
+
detectedLocale: solid_js.Accessor<Locale>;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
declare function createTranslations(locale: Accessor<Locale>, namespace: string): {
|
|
27
|
+
dict: Accessor<TranslationDict>;
|
|
28
|
+
isLoading: Accessor<boolean>;
|
|
29
|
+
error: Accessor<string | undefined>;
|
|
30
|
+
t: (key: string, params?: Record<string, string | number>) => string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
declare function createI18nAdmin(data: {
|
|
34
|
+
translations?: TranslationEntry[];
|
|
35
|
+
missingKeys?: MissingKey[];
|
|
36
|
+
localeStats?: LocaleStat[];
|
|
37
|
+
}, mutations: {
|
|
38
|
+
upsert: (locale: string, ns: string, key: string, value: string) => Promise<void>;
|
|
39
|
+
deleteKey: (locale: string, key: string) => Promise<void>;
|
|
40
|
+
importDict: (locale: string, ns: string, dict: Record<string, string>) => Promise<void>;
|
|
41
|
+
clearMissing: (id: string) => Promise<void>;
|
|
42
|
+
}): {
|
|
43
|
+
upsert: (locale: string, ns: string, key: string, value: string) => Promise<void>;
|
|
44
|
+
deleteKey: (locale: string, key: string) => Promise<void>;
|
|
45
|
+
importDict: (locale: string, ns: string, dict: Record<string, string>) => Promise<void>;
|
|
46
|
+
clearMissing: (id: string) => Promise<void>;
|
|
47
|
+
translations: solid_js.Accessor<TranslationEntry[]>;
|
|
48
|
+
missingKeys: () => MissingKey[];
|
|
49
|
+
localeStats: () => LocaleStat[];
|
|
50
|
+
search: solid_js.Accessor<string>;
|
|
51
|
+
setSearch: solid_js.Setter<string>;
|
|
52
|
+
isLoading: () => boolean;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
interface Props$3 {
|
|
56
|
+
locales: Locale[];
|
|
57
|
+
current: Locale;
|
|
58
|
+
onChange: (l: Locale) => void;
|
|
59
|
+
}
|
|
60
|
+
declare const LocaleSwitcher: Component<Props$3>;
|
|
61
|
+
|
|
62
|
+
declare const RTLWrapper: ParentComponent<{
|
|
63
|
+
locale?: Locale;
|
|
64
|
+
}>;
|
|
65
|
+
|
|
66
|
+
declare const LocaleStatsCard: Component<{
|
|
67
|
+
stats: LocaleStat[];
|
|
68
|
+
}>;
|
|
69
|
+
|
|
70
|
+
declare const MissingKeyAlert: Component<{
|
|
71
|
+
count: number;
|
|
72
|
+
locale: Locale;
|
|
73
|
+
}>;
|
|
74
|
+
|
|
75
|
+
interface Props$2 {
|
|
76
|
+
translationKey: string;
|
|
77
|
+
value: string;
|
|
78
|
+
locale: Locale;
|
|
79
|
+
namespace?: string;
|
|
80
|
+
onEdit?: (key: string) => void;
|
|
81
|
+
onDelete?: (key: string) => void;
|
|
82
|
+
}
|
|
83
|
+
declare const TranslationKeyRow: Component<Props$2>;
|
|
84
|
+
|
|
85
|
+
interface Props$1 {
|
|
86
|
+
locale: Locale;
|
|
87
|
+
coverage?: number;
|
|
88
|
+
}
|
|
89
|
+
declare const LocaleCard: Component<Props$1>;
|
|
90
|
+
|
|
91
|
+
interface Props {
|
|
92
|
+
translations?: TranslationEntry[];
|
|
93
|
+
missingKeys?: MissingKey[];
|
|
94
|
+
localeStats?: LocaleStat[];
|
|
95
|
+
onUpsert?: (locale: string, namespace: string, key: string, value: string) => void;
|
|
96
|
+
onDelete?: (locale: string, key: string, namespace?: string) => void;
|
|
97
|
+
}
|
|
98
|
+
declare const I18nAdminPage: Component<Props>;
|
|
99
|
+
|
|
100
|
+
declare const LocalePreviewPage: Component<{
|
|
101
|
+
config?: Partial<I18nConfig>;
|
|
102
|
+
translations?: TranslationDict;
|
|
103
|
+
}>;
|
|
104
|
+
|
|
105
|
+
export { I18nAdminPage, I18nProvider, LocaleCard, LocalePreviewPage, LocaleStatsCard, LocaleSwitcher, MissingKeyAlert, RTLWrapper, TranslationKeyRow, createI18n, createI18nAdmin, createLocaleDetect, createTranslations };
|