@gravito/cosmos 3.0.0 → 3.0.1

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.
Files changed (81) hide show
  1. package/.turbo/turbo-build.log +20 -0
  2. package/.turbo/turbo-test$colon$ci.log +35 -0
  3. package/.turbo/turbo-test$colon$coverage.log +35 -0
  4. package/.turbo/turbo-test.log +27 -0
  5. package/.turbo/turbo-typecheck.log +2 -0
  6. package/CHANGELOG.md +7 -0
  7. package/build.ts +35 -0
  8. package/dist/index.cjs +309 -0
  9. package/dist/index.d.cts +274 -0
  10. package/dist/index.d.ts +274 -0
  11. package/dist/index.js +139 -30
  12. package/package.json +18 -6
  13. package/src/I18nService.ts +94 -15
  14. package/src/index.ts +32 -6
  15. package/tests/manager.test.ts +0 -1
  16. package/tests/service.test.ts +5 -0
  17. package/dist/core/src/Application.d.ts +0 -185
  18. package/dist/core/src/ConfigManager.d.ts +0 -21
  19. package/dist/core/src/Container.d.ts +0 -38
  20. package/dist/core/src/Event.d.ts +0 -5
  21. package/dist/core/src/EventManager.d.ts +0 -123
  22. package/dist/core/src/GlobalErrorHandlers.d.ts +0 -31
  23. package/dist/core/src/GravitoServer.d.ts +0 -20
  24. package/dist/core/src/HookManager.d.ts +0 -70
  25. package/dist/core/src/Listener.d.ts +0 -4
  26. package/dist/core/src/Logger.d.ts +0 -20
  27. package/dist/core/src/PlanetCore.d.ts +0 -207
  28. package/dist/core/src/Route.d.ts +0 -25
  29. package/dist/core/src/Router.d.ts +0 -232
  30. package/dist/core/src/ServiceProvider.d.ts +0 -150
  31. package/dist/core/src/adapters/PhotonAdapter.d.ts +0 -142
  32. package/dist/core/src/adapters/bun/BunContext.d.ts +0 -36
  33. package/dist/core/src/adapters/bun/BunNativeAdapter.d.ts +0 -21
  34. package/dist/core/src/adapters/bun/BunRequest.d.ts +0 -27
  35. package/dist/core/src/adapters/bun/RadixNode.d.ts +0 -15
  36. package/dist/core/src/adapters/bun/RadixRouter.d.ts +0 -31
  37. package/dist/core/src/adapters/bun/types.d.ts +0 -20
  38. package/dist/core/src/adapters/types.d.ts +0 -186
  39. package/dist/core/src/engine/AOTRouter.d.ts +0 -117
  40. package/dist/core/src/engine/FastContext.d.ts +0 -34
  41. package/dist/core/src/engine/Gravito.d.ts +0 -191
  42. package/dist/core/src/engine/MinimalContext.d.ts +0 -36
  43. package/dist/core/src/engine/analyzer.d.ts +0 -21
  44. package/dist/core/src/engine/index.d.ts +0 -26
  45. package/dist/core/src/engine/path.d.ts +0 -26
  46. package/dist/core/src/engine/pool.d.ts +0 -83
  47. package/dist/core/src/engine/types.d.ts +0 -107
  48. package/dist/core/src/exceptions/AuthenticationException.d.ts +0 -4
  49. package/dist/core/src/exceptions/AuthorizationException.d.ts +0 -4
  50. package/dist/core/src/exceptions/GravitoException.d.ts +0 -15
  51. package/dist/core/src/exceptions/HttpException.d.ts +0 -5
  52. package/dist/core/src/exceptions/ModelNotFoundException.d.ts +0 -6
  53. package/dist/core/src/exceptions/ValidationException.d.ts +0 -14
  54. package/dist/core/src/exceptions/index.d.ts +0 -6
  55. package/dist/core/src/helpers/Arr.d.ts +0 -14
  56. package/dist/core/src/helpers/Str.d.ts +0 -18
  57. package/dist/core/src/helpers/data.d.ts +0 -5
  58. package/dist/core/src/helpers/errors.d.ts +0 -12
  59. package/dist/core/src/helpers/response.d.ts +0 -17
  60. package/dist/core/src/helpers.d.ts +0 -38
  61. package/dist/core/src/http/CookieJar.d.ts +0 -37
  62. package/dist/core/src/http/middleware/BodySizeLimit.d.ts +0 -6
  63. package/dist/core/src/http/middleware/Cors.d.ts +0 -12
  64. package/dist/core/src/http/middleware/Csrf.d.ts +0 -11
  65. package/dist/core/src/http/middleware/HeaderTokenGate.d.ts +0 -11
  66. package/dist/core/src/http/middleware/SecurityHeaders.d.ts +0 -17
  67. package/dist/core/src/http/middleware/ThrottleRequests.d.ts +0 -12
  68. package/dist/core/src/http/types.d.ts +0 -312
  69. package/dist/core/src/index.d.ts +0 -60
  70. package/dist/core/src/runtime.d.ts +0 -63
  71. package/dist/core/src/security/Encrypter.d.ts +0 -24
  72. package/dist/core/src/security/Hasher.d.ts +0 -29
  73. package/dist/core/src/testing/HttpTester.d.ts +0 -38
  74. package/dist/core/src/testing/TestResponse.d.ts +0 -78
  75. package/dist/core/src/testing/index.d.ts +0 -2
  76. package/dist/core/src/types/events.d.ts +0 -94
  77. package/dist/cosmos/src/I18nService.d.ts +0 -144
  78. package/dist/cosmos/src/index.d.ts +0 -21
  79. package/dist/cosmos/src/loader.d.ts +0 -11
  80. package/dist/photon/src/index.d.ts +0 -2
  81. package/dist/src/index.js +0 -173
package/dist/index.js CHANGED
@@ -1,40 +1,87 @@
1
1
  // src/I18nService.ts
2
- class I18nInstance {
3
- manager;
4
- _locale;
2
+ var I18nInstance = class _I18nInstance {
3
+ /**
4
+ * Create a new I18nInstance.
5
+ *
6
+ * @param manager - The I18nManager instance.
7
+ * @param initialLocale - The initial locale for this instance.
8
+ */
5
9
  constructor(manager, initialLocale) {
6
10
  this.manager = manager;
7
11
  this._locale = initialLocale;
8
12
  }
13
+ _locale;
9
14
  get locale() {
10
15
  return this._locale;
11
16
  }
12
17
  set locale(value) {
13
18
  this.setLocale(value);
14
19
  }
20
+ /**
21
+ * Set the current locale.
22
+ *
23
+ * @param locale - The locale to set.
24
+ */
15
25
  setLocale(locale) {
16
26
  if (this.manager.getConfig().supportedLocales.includes(locale)) {
17
27
  this._locale = locale;
18
28
  }
19
29
  }
30
+ /**
31
+ * Get the current locale.
32
+ *
33
+ * @returns The current locale string.
34
+ */
20
35
  getLocale() {
21
36
  return this._locale;
22
37
  }
38
+ /**
39
+ * Translate a key.
40
+ *
41
+ * @param key - The translation key (e.g., 'messages.welcome').
42
+ * @param replacements - Optional replacements for parameters in the translation string.
43
+ * @returns The translated string, or the key if not found.
44
+ */
23
45
  t(key, replacements) {
24
46
  return this.manager.translate(this._locale, key, replacements);
25
47
  }
48
+ /**
49
+ * Check if a translation key exists.
50
+ *
51
+ * @param key - The translation key to check.
52
+ * @returns True if the key exists, false otherwise.
53
+ */
26
54
  has(key) {
27
55
  return this.t(key) !== key;
28
56
  }
57
+ /**
58
+ * Clone the current instance with a potentially new locale.
59
+ *
60
+ * @param locale - Optional new locale for the cloned instance.
61
+ * @returns A new I18nInstance.
62
+ */
29
63
  clone(locale) {
30
- return new I18nInstance(this.manager, locale || this._locale);
64
+ return new _I18nInstance(this.manager, locale || this._locale);
31
65
  }
32
- }
33
-
34
- class I18nManager {
35
- config;
36
- translations = {};
37
- globalInstance;
66
+ /**
67
+ * Get the I18n configuration.
68
+ */
69
+ getConfig() {
70
+ return this.manager.getConfig();
71
+ }
72
+ /**
73
+ * Get the translations.
74
+ */
75
+ get translations() {
76
+ return this.manager.translations;
77
+ }
78
+ };
79
+ var I18nManager = class {
80
+ /**
81
+ * Create a new I18nManager.
82
+ *
83
+ * @param config - The I18n configuration.
84
+ */
38
85
  constructor(config) {
39
86
  this.config = config;
40
87
  if (config.translations) {
@@ -42,36 +89,84 @@ class I18nManager {
42
89
  }
43
90
  this.globalInstance = new I18nInstance(this, config.defaultLocale);
44
91
  }
92
+ translations = {};
93
+ // Default instance for global usage (e.g. CLI or background jobs)
94
+ globalInstance;
95
+ // --- I18nService Implementation (Delegates to global instance) ---
45
96
  get locale() {
46
97
  return this.globalInstance.locale;
47
98
  }
48
99
  set locale(value) {
49
100
  this.globalInstance.locale = value;
50
101
  }
102
+ /**
103
+ * Set the global locale.
104
+ *
105
+ * @param locale - The locale to set.
106
+ */
51
107
  setLocale(locale) {
52
108
  this.globalInstance.setLocale(locale);
53
109
  }
110
+ /**
111
+ * Get the global locale.
112
+ *
113
+ * @returns The global locale string.
114
+ */
54
115
  getLocale() {
55
116
  return this.globalInstance.getLocale();
56
117
  }
118
+ /**
119
+ * Translate a key using the global locale.
120
+ *
121
+ * @param key - The translation key.
122
+ * @param replacements - Optional replacements.
123
+ * @returns The translated string.
124
+ */
57
125
  t(key, replacements) {
58
126
  return this.globalInstance.t(key, replacements);
59
127
  }
128
+ /**
129
+ * Check if a translation key exists in the global locale.
130
+ *
131
+ * @param key - The translation key.
132
+ * @returns True if found.
133
+ */
60
134
  has(key) {
61
135
  return this.globalInstance.has(key);
62
136
  }
137
+ /**
138
+ * Clone the global instance.
139
+ *
140
+ * @param locale - Optional locale for the clone.
141
+ * @returns A new I18nInstance.
142
+ */
63
143
  clone(locale) {
64
144
  return new I18nInstance(this, locale || this.config.defaultLocale);
65
145
  }
146
+ // --- Manager Internal API ---
147
+ /**
148
+ * Get the I18n configuration.
149
+ *
150
+ * @returns The configuration object.
151
+ */
66
152
  getConfig() {
67
153
  return this.config;
68
154
  }
155
+ /**
156
+ * Add a resource bundle for a specific locale.
157
+ *
158
+ * @param locale - The locale string.
159
+ * @param translations - The translations object.
160
+ */
69
161
  addResource(locale, translations) {
70
162
  this.translations[locale] = {
71
163
  ...this.translations[locale] || {},
72
164
  ...translations
73
165
  };
74
166
  }
167
+ /**
168
+ * Internal translation logic used by instances
169
+ */
75
170
  translate(locale, key, replacements) {
76
171
  const keys = key.split(".");
77
172
  let value = this.translations[locale];
@@ -79,33 +174,34 @@ class I18nManager {
79
174
  if (value && typeof value === "object" && k in value) {
80
175
  value = value[k];
81
176
  } else {
82
- value = undefined;
177
+ value = void 0;
83
178
  break;
84
179
  }
85
180
  }
86
- if (value === undefined && locale !== this.config.defaultLocale) {
181
+ if (value === void 0 && locale !== this.config.defaultLocale) {
87
182
  let fallbackValue = this.translations[this.config.defaultLocale];
88
183
  for (const k of keys) {
89
184
  if (fallbackValue && typeof fallbackValue === "object" && k in fallbackValue) {
90
185
  fallbackValue = fallbackValue[k];
91
186
  } else {
92
- fallbackValue = undefined;
187
+ fallbackValue = void 0;
93
188
  break;
94
189
  }
95
190
  }
96
191
  value = fallbackValue;
97
192
  }
98
- if (value === undefined || typeof value !== "string") {
193
+ if (value === void 0 || typeof value !== "string") {
99
194
  return key;
100
195
  }
101
- if (replacements) {
102
- for (const [search, replace] of Object.entries(replacements)) {
103
- value = value.replace(new RegExp(`:${search}`, "g"), String(replace));
104
- }
196
+ if (replacements && Object.keys(replacements).length > 0) {
197
+ value = value.replace(REPLACEMENT_REGEX, (match, key2) => {
198
+ return replacements[key2] !== void 0 ? String(replacements[key2]) : match;
199
+ });
105
200
  }
106
201
  return value;
107
202
  }
108
- }
203
+ };
204
+ var REPLACEMENT_REGEX = /:([a-zA-Z0-9_]+)/g;
109
205
  var localeMiddleware = (i18nManager) => {
110
206
  return async (c, next) => {
111
207
  let locale = c.req.param("locale") || c.req.query("lang");
@@ -120,9 +216,10 @@ var localeMiddleware = (i18nManager) => {
120
216
  return await next();
121
217
  };
122
218
  };
219
+
123
220
  // src/loader.ts
124
- import { readdir, readFile } from "node:fs/promises";
125
- import { join, parse } from "node:path";
221
+ import { readdir, readFile } from "fs/promises";
222
+ import { join, parse } from "path";
126
223
  async function loadTranslations(directory) {
127
224
  const translations = {};
128
225
  try {
@@ -140,29 +237,41 @@ async function loadTranslations(directory) {
140
237
  }
141
238
  }
142
239
  } catch (_e) {
143
- console.warn(`[Orbit-I18n] Could not load translations from ${directory}. Directory might not exist.`);
240
+ console.warn(
241
+ `[Orbit-I18n] Could not load translations from ${directory}. Directory might not exist.`
242
+ );
144
243
  }
145
244
  return translations;
146
245
  }
147
246
 
148
247
  // src/index.ts
149
- class OrbitCosmos {
150
- config;
248
+ var OrbitCosmos = class {
249
+ /**
250
+ * Create a new OrbitCosmos instance.
251
+ * @param config - The i18n configuration options.
252
+ */
151
253
  constructor(config) {
152
254
  this.config = config;
153
255
  }
256
+ /**
257
+ * Install the i18n service into PlanetCore.
258
+ * Registers the I18nManager and sets up the locale middleware.
259
+ *
260
+ * @param core - The PlanetCore instance.
261
+ */
154
262
  install(core) {
155
263
  const i18nManager = new I18nManager(this.config);
264
+ core.container.instance("i18n", i18nManager);
156
265
  core.adapter.use("*", localeMiddleware(i18nManager));
157
266
  core.logger.info(`[OrbitCosmos] I18n initialized with locale: ${this.config.defaultLocale}`);
158
267
  }
159
- }
268
+ };
160
269
  var I18nOrbit = OrbitCosmos;
161
270
  export {
162
- localeMiddleware,
163
- loadTranslations,
164
- OrbitCosmos,
165
- I18nOrbit,
271
+ I18nInstance,
166
272
  I18nManager,
167
- I18nInstance
273
+ I18nOrbit,
274
+ OrbitCosmos,
275
+ loadTranslations,
276
+ localeMiddleware
168
277
  };
package/package.json CHANGED
@@ -1,11 +1,21 @@
1
1
  {
2
2
  "name": "@gravito/cosmos",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "description": "Internationalization orbit for Gravito framework",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.js",
7
+ "type": "module",
8
+ "sideEffects": false,
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs"
15
+ }
16
+ },
7
17
  "scripts": {
8
- "build": "bun build ./src/index.ts --outdir ./dist --target node --external @gravito/core --external @gravito/photon",
18
+ "build": "bun run build.ts",
9
19
  "test": "bun test",
10
20
  "test:coverage": "bun test --coverage --coverage-threshold=80",
11
21
  "test:ci": "bun test --coverage --coverage-threshold=80",
@@ -24,7 +34,9 @@
24
34
  "@gravito/photon": "workspace:*"
25
35
  },
26
36
  "devDependencies": {
27
- "bun-types": "latest"
37
+ "bun-types": "latest",
38
+ "tsup": "^8.5.1",
39
+ "typescript": "^5.9.3"
28
40
  },
29
41
  "publishConfig": {
30
42
  "access": "public"
@@ -35,4 +47,4 @@
35
47
  "url": "git+https://github.com/gravito-framework/gravito.git",
36
48
  "directory": "packages/cosmos"
37
49
  }
38
- }
50
+ }
@@ -1,24 +1,84 @@
1
- import type { MiddlewareHandler } from '@gravito/photon'
1
+ import type { GravitoMiddleware } from '@gravito/core'
2
2
 
3
+ /**
4
+ * A map of translations where keys are translation keys and values
5
+ * are either the translated string or a nested map for grouping.
6
+ *
7
+ * @public
8
+ * @since 3.0.0
9
+ */
3
10
  export type TranslationMap = {
4
11
  [key: string]: string | TranslationMap
5
12
  }
6
13
 
14
+ /**
15
+ * Configuration for the I18n service.
16
+ *
17
+ * @public
18
+ * @since 3.0.0
19
+ */
7
20
  export interface I18nConfig {
21
+ /** The fallback locale to use when the requested one is not found. */
8
22
  defaultLocale: string
23
+ /** List of locales officially supported by the application. */
9
24
  supportedLocales: string[]
10
- // Path to translation files, or a Record of translations
11
- // If undefined, it will look into `resources/lang` by default (conceptually, handled by loader)
25
+ /**
26
+ * Optional record of translations indexed by locale.
27
+ * Keys are locale strings (e.g., 'en', 'zh-TW').
28
+ */
12
29
  translations?: Record<string, TranslationMap>
13
30
  }
14
31
 
32
+ /**
33
+ * Interface for the I18n service providing translation capabilities.
34
+ *
35
+ * It allows for setting and getting the current locale, translating strings
36
+ * with optional replacements, and checking for key existence.
37
+ *
38
+ * @public
39
+ * @since 3.0.0
40
+ */
15
41
  export interface I18nService {
42
+ /** The current active locale. */
16
43
  locale: string
44
+ /**
45
+ * Set the active locale for this service instance.
46
+ *
47
+ * @param locale - Valid locale string from supportedLocales.
48
+ */
17
49
  setLocale(locale: string): void
50
+ /**
51
+ * Get the current active locale.
52
+ *
53
+ * @returns Current locale string.
54
+ */
18
55
  getLocale(): string
56
+ /**
57
+ * Translate a key into the current locale.
58
+ *
59
+ * @param key - The translation key (e.g., 'auth.login_success').
60
+ * @param replacements - Optional placeholders in the format `:key` replaced by values.
61
+ * @returns The translated string, or the key itself if not found.
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * i18n.t('messages.hello', { name: 'John' }); // "Hello John"
66
+ * ```
67
+ */
19
68
  t(key: string, replacements?: Record<string, string | number>): string
69
+ /**
70
+ * Check if a translation key exists for the current locale.
71
+ *
72
+ * @param key - The key to check.
73
+ * @returns True if the key exists, false otherwise.
74
+ */
20
75
  has(key: string): boolean
21
- // Create a request-scoped instance
76
+ /**
77
+ * Create a new request-scoped instance of the I18n service.
78
+ *
79
+ * @param locale - Optional initial locale for the new instance.
80
+ * @returns A new I18nService instance.
81
+ */
22
82
  clone(locale?: string): I18nService
23
83
  }
24
84
 
@@ -36,7 +96,7 @@ export class I18nInstance implements I18nService {
36
96
  * @param initialLocale - The initial locale for this instance.
37
97
  */
38
98
  constructor(
39
- private manager: I18nManager,
99
+ public readonly manager: I18nManager,
40
100
  initialLocale: string
41
101
  ) {
42
102
  this._locale = initialLocale
@@ -100,6 +160,20 @@ export class I18nInstance implements I18nService {
100
160
  clone(locale?: string): I18nService {
101
161
  return new I18nInstance(this.manager, locale || this._locale)
102
162
  }
163
+
164
+ /**
165
+ * Get the I18n configuration.
166
+ */
167
+ getConfig(): I18nConfig {
168
+ return this.manager.getConfig()
169
+ }
170
+
171
+ /**
172
+ * Get the translations.
173
+ */
174
+ get translations(): Record<string, TranslationMap> {
175
+ return this.manager.translations
176
+ }
103
177
  }
104
178
 
105
179
  /**
@@ -107,7 +181,7 @@ export class I18nInstance implements I18nService {
107
181
  * Holds shared configuration and translation resources
108
182
  */
109
183
  export class I18nManager implements I18nService {
110
- private translations: Record<string, TranslationMap> = {}
184
+ public translations: Record<string, TranslationMap> = {}
111
185
  // Default instance for global usage (e.g. CLI or background jobs)
112
186
  private globalInstance: I18nInstance
113
187
 
@@ -211,12 +285,12 @@ export class I18nManager implements I18nService {
211
285
  */
212
286
  translate(locale: string, key: string, replacements?: Record<string, string | number>): string {
213
287
  const keys = key.split('.')
214
- let value: any = this.translations[locale]
288
+ let value: string | TranslationMap | undefined = this.translations[locale]
215
289
 
216
290
  // 1. Try current locale
217
291
  for (const k of keys) {
218
292
  if (value && typeof value === 'object' && k in value) {
219
- value = value[k]
293
+ value = (value as TranslationMap)[k]
220
294
  } else {
221
295
  value = undefined
222
296
  break
@@ -225,10 +299,11 @@ export class I18nManager implements I18nService {
225
299
 
226
300
  // 2. If not found, try fallback (defaultLocale)
227
301
  if (value === undefined && locale !== this.config.defaultLocale) {
228
- let fallbackValue: any = this.translations[this.config.defaultLocale]
302
+ let fallbackValue: string | TranslationMap | undefined =
303
+ this.translations[this.config.defaultLocale]
229
304
  for (const k of keys) {
230
305
  if (fallbackValue && typeof fallbackValue === 'object' && k in fallbackValue) {
231
- fallbackValue = fallbackValue[k]
306
+ fallbackValue = (fallbackValue as TranslationMap)[k]
232
307
  } else {
233
308
  fallbackValue = undefined
234
309
  break
@@ -242,16 +317,20 @@ export class I18nManager implements I18nService {
242
317
  }
243
318
 
244
319
  // 3. Replacements
245
- if (replacements) {
246
- for (const [search, replace] of Object.entries(replacements)) {
247
- value = value.replace(new RegExp(`:${search}`, 'g'), String(replace))
248
- }
320
+ if (replacements && Object.keys(replacements).length > 0) {
321
+ value = value.replace(REPLACEMENT_REGEX, (match, key) => {
322
+ return (replacements as Record<string, unknown>)[key] !== undefined
323
+ ? String((replacements as Record<string, unknown>)[key])
324
+ : match
325
+ })
249
326
  }
250
327
 
251
328
  return value
252
329
  }
253
330
  }
254
331
 
332
+ const REPLACEMENT_REGEX = /:([a-zA-Z0-9_]+)/g
333
+
255
334
  /**
256
335
  * Locale Middleware
257
336
  *
@@ -259,7 +338,7 @@ export class I18nManager implements I18nService {
259
338
  * 1. Route Parameter (e.g. /:locale/foo) - Recommended for SEO
260
339
  * 2. Header (Accept-Language) - Recommended for APIs
261
340
  */
262
- export const localeMiddleware = (i18nManager: I18nService): MiddlewareHandler => {
341
+ export const localeMiddleware = (i18nManager: I18nService): GravitoMiddleware => {
263
342
  return async (c, next) => {
264
343
  // Determine initial locale
265
344
  // Priority: 1. Route Param 2. Query ?lang= 3. Header 4. Default
package/src/index.ts CHANGED
@@ -2,24 +2,48 @@ import type { GravitoMiddleware, GravitoOrbit, PlanetCore } from '@gravito/core'
2
2
  import { type I18nConfig, I18nManager, type I18nService, localeMiddleware } from './I18nService'
3
3
 
4
4
  declare module '@gravito/core' {
5
- interface Variables {
5
+ interface GravitoVariables {
6
+ /** I18n service for translations */
6
7
  i18n: I18nService
7
8
  }
8
9
  }
9
10
 
10
11
  /**
11
- * OrbitCosmos - Internationalization Orbit
12
+ * OrbitCosmos provides internationalization (i18n) support for Gravito.
13
+ * It manages translations, locale switching, and provides a middleware for request-scoped locale detection.
12
14
  *
13
- * Provides i18n functionality for Gravito applications.
15
+ * @example
16
+ * ```typescript
17
+ * const cosmos = new OrbitCosmos({
18
+ * defaultLocale: 'en',
19
+ * supportedLocales: ['en', 'zh-TW'],
20
+ * translations: {
21
+ * en: { welcome: 'Welcome!' },
22
+ * 'zh-TW': { welcome: '歡迎!' }
23
+ * }
24
+ * });
25
+ * core.addOrbit(cosmos);
26
+ * ```
27
+ * @public
14
28
  */
15
29
  export class OrbitCosmos implements GravitoOrbit {
30
+ /**
31
+ * Create a new OrbitCosmos instance.
32
+ * @param config - The i18n configuration options.
33
+ */
16
34
  constructor(private config: I18nConfig) {}
17
35
 
36
+ /**
37
+ * Install the i18n service into PlanetCore.
38
+ * Registers the I18nManager and sets up the locale middleware.
39
+ *
40
+ * @param core - The PlanetCore instance.
41
+ */
18
42
  install(core: PlanetCore): void {
19
43
  const i18nManager = new I18nManager(this.config)
20
44
 
21
- // Register globally if needed (for CLI/Jobs)
22
- // core.services.set('i18n', i18nManager);
45
+ // Register globally for CLI/Jobs using the container
46
+ core.container.instance('i18n', i18nManager)
23
47
 
24
48
  // Inject locale middleware into every request
25
49
  // This middleware handles cloning the i18n instance per request
@@ -29,7 +53,9 @@ export class OrbitCosmos implements GravitoOrbit {
29
53
  }
30
54
  }
31
55
 
32
- /** @deprecated Use OrbitCosmos instead */
56
+ /**
57
+ * @deprecated Use OrbitCosmos instead. Will be removed in v4.0.0.
58
+ */
33
59
  export const I18nOrbit = OrbitCosmos
34
60
 
35
61
  export * from './I18nService'
@@ -30,7 +30,6 @@ describe('Orbit I18n Manager', () => {
30
30
  en: {
31
31
  title: 'Hello',
32
32
  auth: {
33
- // @ts-expect-error
34
33
  failed: 'Failed Login',
35
34
  } as any,
36
35
  },
@@ -90,8 +90,12 @@ describe('localeMiddleware', () => {
90
90
 
91
91
  describe('OrbitCosmos', () => {
92
92
  it('installs locale middleware and logs initialization', () => {
93
+ const instances = new Map<string, unknown>()
93
94
  const core = {
94
95
  adapter: { use: jest.fn() },
96
+ container: {
97
+ instance: (key: string, value: unknown) => instances.set(key, value),
98
+ },
95
99
  logger: { info: jest.fn() },
96
100
  }
97
101
  const orbit = new OrbitCosmos({
@@ -104,6 +108,7 @@ describe('OrbitCosmos', () => {
104
108
 
105
109
  expect(core.adapter.use).toHaveBeenCalledWith('*', expect.any(Function))
106
110
  expect(core.logger.info).toHaveBeenCalledWith('[OrbitCosmos] I18n initialized with locale: en')
111
+ expect(instances.get('i18n')).toBeDefined()
107
112
  expect(I18nOrbit).toBe(OrbitCosmos)
108
113
  })
109
114
  })