@hazeljs/i18n 0.2.0-alpha.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 (45) hide show
  1. package/LICENSE +192 -0
  2. package/README.md +292 -0
  3. package/dist/decorators/lang.decorator.d.ts +33 -0
  4. package/dist/decorators/lang.decorator.d.ts.map +1 -0
  5. package/dist/decorators/lang.decorator.js +53 -0
  6. package/dist/decorators/lang.decorator.test.d.ts +2 -0
  7. package/dist/decorators/lang.decorator.test.d.ts.map +1 -0
  8. package/dist/decorators/lang.decorator.test.js +61 -0
  9. package/dist/i18n.interceptor.d.ts +29 -0
  10. package/dist/i18n.interceptor.d.ts.map +1 -0
  11. package/dist/i18n.interceptor.js +52 -0
  12. package/dist/i18n.interceptor.test.d.ts +2 -0
  13. package/dist/i18n.interceptor.test.d.ts.map +1 -0
  14. package/dist/i18n.interceptor.test.js +126 -0
  15. package/dist/i18n.middleware.d.ts +59 -0
  16. package/dist/i18n.middleware.d.ts.map +1 -0
  17. package/dist/i18n.middleware.js +126 -0
  18. package/dist/i18n.middleware.test.d.ts +2 -0
  19. package/dist/i18n.middleware.test.d.ts.map +1 -0
  20. package/dist/i18n.middleware.test.js +239 -0
  21. package/dist/i18n.module.d.ts +73 -0
  22. package/dist/i18n.module.d.ts.map +1 -0
  23. package/dist/i18n.module.js +154 -0
  24. package/dist/i18n.module.test.d.ts +2 -0
  25. package/dist/i18n.module.test.d.ts.map +1 -0
  26. package/dist/i18n.module.test.js +162 -0
  27. package/dist/i18n.service.d.ts +112 -0
  28. package/dist/i18n.service.d.ts.map +1 -0
  29. package/dist/i18n.service.js +228 -0
  30. package/dist/i18n.service.test.d.ts +2 -0
  31. package/dist/i18n.service.test.d.ts.map +1 -0
  32. package/dist/i18n.service.test.js +297 -0
  33. package/dist/index.d.ts +27 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +39 -0
  36. package/dist/translation.loader.d.ts +20 -0
  37. package/dist/translation.loader.d.ts.map +1 -0
  38. package/dist/translation.loader.js +51 -0
  39. package/dist/translation.loader.test.d.ts +2 -0
  40. package/dist/translation.loader.test.d.ts.map +1 -0
  41. package/dist/translation.loader.test.js +89 -0
  42. package/dist/types.d.ts +86 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +2 -0
  45. package/package.json +51 -0
@@ -0,0 +1,73 @@
1
+ import { I18nService } from './i18n.service';
2
+ import { LocaleMiddleware } from './i18n.middleware';
3
+ import { I18nOptions } from './types';
4
+ /**
5
+ * I18nModule — internationalization module for HazelJS.
6
+ *
7
+ * Register once in your root module using `I18nModule.forRoot()`. The module
8
+ * loads all `<locale>.json` files from the configured `translationsPath` at
9
+ * startup and makes `I18nService` and `LocaleMiddleware` available for
10
+ * injection across the entire application.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * \@HazelModule({
15
+ * imports: [
16
+ * I18nModule.forRoot({
17
+ * defaultLocale: 'en',
18
+ * fallbackLocale: 'en',
19
+ * translationsPath: './translations',
20
+ * detection: ['query', 'cookie', 'header'],
21
+ * }),
22
+ * ],
23
+ * controllers: [AppController],
24
+ * })
25
+ * export class AppModule {}
26
+ * ```
27
+ */
28
+ export declare class I18nModule {
29
+ /**
30
+ * Synchronous configuration. Options are resolved eagerly, and
31
+ * translations are loaded before the service instance is made available.
32
+ */
33
+ static forRoot(options?: I18nOptions): {
34
+ module: typeof I18nModule;
35
+ providers: Array<{
36
+ provide: string | typeof I18nService | typeof LocaleMiddleware;
37
+ useFactory?: (...args: unknown[]) => unknown;
38
+ useValue?: unknown;
39
+ inject?: string[];
40
+ }>;
41
+ exports: Array<typeof I18nService | typeof LocaleMiddleware>;
42
+ global: boolean;
43
+ };
44
+ /**
45
+ * Asynchronous configuration — use when options must be resolved from the
46
+ * container (e.g. from ConfigService).
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * I18nModule.forRootAsync({
51
+ * useFactory: (config: ConfigService) => ({
52
+ * defaultLocale: config.get('LOCALE', 'en'),
53
+ * translationsPath: config.get('TRANSLATIONS_PATH', './translations'),
54
+ * }),
55
+ * inject: [ConfigService],
56
+ * })
57
+ * ```
58
+ */
59
+ static forRootAsync(options: {
60
+ useFactory: (...args: any[]) => I18nOptions;
61
+ inject?: unknown[];
62
+ }): {
63
+ module: typeof I18nModule;
64
+ providers: Array<{
65
+ provide: string | typeof I18nService | typeof LocaleMiddleware;
66
+ useFactory: (...args: unknown[]) => unknown;
67
+ inject?: unknown[];
68
+ }>;
69
+ exports: Array<typeof I18nService | typeof LocaleMiddleware>;
70
+ global: boolean;
71
+ };
72
+ }
73
+ //# sourceMappingURL=i18n.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.module.d.ts","sourceRoot":"","sources":["../src/i18n.module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAuB,MAAM,SAAS,CAAC;AAuB3D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAIa,UAAU;IACrB;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,WAAgB,GAAG;QACzC,MAAM,EAAE,OAAO,UAAU,CAAC;QAC1B,SAAS,EAAE,KAAK,CAAC;YACf,OAAO,EAAE,MAAM,GAAG,OAAO,WAAW,GAAG,OAAO,gBAAgB,CAAC;YAC/D,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;YAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;YACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;SACnB,CAAC,CAAC;QACH,OAAO,EAAE,KAAK,CAAC,OAAO,WAAW,GAAG,OAAO,gBAAgB,CAAC,CAAC;QAC7D,MAAM,EAAE,OAAO,CAAC;KACjB;IAmCD;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE;QAE3B,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,WAAW,CAAC;QAC5C,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;KACpB,GAAG;QACF,MAAM,EAAE,OAAO,UAAU,CAAC;QAC1B,SAAS,EAAE,KAAK,CAAC;YACf,OAAO,EAAE,MAAM,GAAG,OAAO,WAAW,GAAG,OAAO,gBAAgB,CAAC;YAC/D,UAAU,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;YAC5C,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;SACpB,CAAC,CAAC;QACH,OAAO,EAAE,KAAK,CAAC,OAAO,WAAW,GAAG,OAAO,gBAAgB,CAAC,CAAC;QAC7D,MAAM,EAAE,OAAO,CAAC;KACjB;CAoCF"}
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var I18nModule_1;
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.I18nModule = void 0;
11
+ const core_1 = require("@hazeljs/core");
12
+ const i18n_service_1 = require("./i18n.service");
13
+ const translation_loader_1 = require("./translation.loader");
14
+ const i18n_middleware_1 = require("./i18n.middleware");
15
+ const path_1 = require("path");
16
+ const I18N_OPTIONS_TOKEN = 'I18N_OPTIONS';
17
+ /**
18
+ * Resolves user-supplied options and fills in all defaults.
19
+ */
20
+ function resolveOptions(options) {
21
+ const defaultLocale = options.defaultLocale ?? 'en';
22
+ return {
23
+ defaultLocale,
24
+ fallbackLocale: options.fallbackLocale ?? defaultLocale,
25
+ translationsPath: options.translationsPath
26
+ ? (0, path_1.resolve)(process.cwd(), options.translationsPath)
27
+ : (0, path_1.resolve)(process.cwd(), 'translations'),
28
+ detection: options.detection ?? ['query', 'cookie', 'header'],
29
+ queryParam: options.queryParam ?? 'lang',
30
+ cookieName: options.cookieName ?? 'locale',
31
+ isGlobal: options.isGlobal ?? true,
32
+ };
33
+ }
34
+ /**
35
+ * I18nModule — internationalization module for HazelJS.
36
+ *
37
+ * Register once in your root module using `I18nModule.forRoot()`. The module
38
+ * loads all `<locale>.json` files from the configured `translationsPath` at
39
+ * startup and makes `I18nService` and `LocaleMiddleware` available for
40
+ * injection across the entire application.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * \@HazelModule({
45
+ * imports: [
46
+ * I18nModule.forRoot({
47
+ * defaultLocale: 'en',
48
+ * fallbackLocale: 'en',
49
+ * translationsPath: './translations',
50
+ * detection: ['query', 'cookie', 'header'],
51
+ * }),
52
+ * ],
53
+ * controllers: [AppController],
54
+ * })
55
+ * export class AppModule {}
56
+ * ```
57
+ */
58
+ let I18nModule = I18nModule_1 = class I18nModule {
59
+ /**
60
+ * Synchronous configuration. Options are resolved eagerly, and
61
+ * translations are loaded before the service instance is made available.
62
+ */
63
+ static forRoot(options = {}) {
64
+ const resolved = resolveOptions(options);
65
+ return {
66
+ module: I18nModule_1,
67
+ providers: [
68
+ {
69
+ provide: I18N_OPTIONS_TOKEN,
70
+ useValue: resolved,
71
+ },
72
+ {
73
+ provide: i18n_service_1.I18nService,
74
+ useFactory: (...args) => {
75
+ const opts = args[0];
76
+ const store = translation_loader_1.TranslationLoader.load(opts.translationsPath);
77
+ const service = new i18n_service_1.I18nService();
78
+ service.initialize(store, opts);
79
+ return service;
80
+ },
81
+ inject: [I18N_OPTIONS_TOKEN],
82
+ },
83
+ {
84
+ provide: i18n_middleware_1.LocaleMiddleware,
85
+ useFactory: (...args) => {
86
+ const opts = args[0];
87
+ return new i18n_middleware_1.LocaleMiddleware(opts);
88
+ },
89
+ inject: [I18N_OPTIONS_TOKEN],
90
+ },
91
+ ],
92
+ exports: [i18n_service_1.I18nService, i18n_middleware_1.LocaleMiddleware],
93
+ global: resolved.isGlobal,
94
+ };
95
+ }
96
+ /**
97
+ * Asynchronous configuration — use when options must be resolved from the
98
+ * container (e.g. from ConfigService).
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * I18nModule.forRootAsync({
103
+ * useFactory: (config: ConfigService) => ({
104
+ * defaultLocale: config.get('LOCALE', 'en'),
105
+ * translationsPath: config.get('TRANSLATIONS_PATH', './translations'),
106
+ * }),
107
+ * inject: [ConfigService],
108
+ * })
109
+ * ```
110
+ */
111
+ static forRootAsync(options) {
112
+ return {
113
+ module: I18nModule_1,
114
+ providers: [
115
+ {
116
+ provide: I18N_OPTIONS_TOKEN,
117
+ useFactory: (...args) => {
118
+ const userOptions = options.useFactory(...args);
119
+ return resolveOptions(userOptions);
120
+ },
121
+ inject: options.inject ?? [],
122
+ },
123
+ {
124
+ provide: i18n_service_1.I18nService,
125
+ useFactory: (...args) => {
126
+ const opts = args[0];
127
+ const store = translation_loader_1.TranslationLoader.load(opts.translationsPath);
128
+ const service = new i18n_service_1.I18nService();
129
+ service.initialize(store, opts);
130
+ return service;
131
+ },
132
+ inject: [I18N_OPTIONS_TOKEN],
133
+ },
134
+ {
135
+ provide: i18n_middleware_1.LocaleMiddleware,
136
+ useFactory: (...args) => {
137
+ const opts = args[0];
138
+ return new i18n_middleware_1.LocaleMiddleware(opts);
139
+ },
140
+ inject: [I18N_OPTIONS_TOKEN],
141
+ },
142
+ ],
143
+ exports: [i18n_service_1.I18nService, i18n_middleware_1.LocaleMiddleware],
144
+ global: true,
145
+ };
146
+ }
147
+ };
148
+ exports.I18nModule = I18nModule;
149
+ exports.I18nModule = I18nModule = I18nModule_1 = __decorate([
150
+ (0, core_1.HazelModule)({
151
+ providers: [],
152
+ exports: [],
153
+ })
154
+ ], I18nModule);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=i18n.module.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.module.test.d.ts","sourceRoot":"","sources":["../src/i18n.module.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ jest.mock('@hazeljs/core', () => ({
4
+ __esModule: true,
5
+ HazelModule: () => () => undefined,
6
+ Service: () => () => undefined,
7
+ }));
8
+ jest.mock('./translation.loader', () => ({
9
+ TranslationLoader: {
10
+ load: jest.fn().mockReturnValue(new Map()),
11
+ },
12
+ }));
13
+ const i18n_module_1 = require("./i18n.module");
14
+ const i18n_service_1 = require("./i18n.service");
15
+ const i18n_middleware_1 = require("./i18n.middleware");
16
+ const translation_loader_1 = require("./translation.loader");
17
+ const mockLoad = translation_loader_1.TranslationLoader.load;
18
+ describe('I18nModule', () => {
19
+ beforeEach(() => {
20
+ jest.clearAllMocks();
21
+ mockLoad.mockReturnValue(new Map());
22
+ });
23
+ describe('forRoot()', () => {
24
+ it('returns module reference', () => {
25
+ const result = i18n_module_1.I18nModule.forRoot();
26
+ expect(result.module).toBe(i18n_module_1.I18nModule);
27
+ });
28
+ it('exports I18nService and LocaleMiddleware', () => {
29
+ const result = i18n_module_1.I18nModule.forRoot();
30
+ expect(result.exports).toContain(i18n_service_1.I18nService);
31
+ expect(result.exports).toContain(i18n_middleware_1.LocaleMiddleware);
32
+ });
33
+ it('sets global to true by default', () => {
34
+ const result = i18n_module_1.I18nModule.forRoot();
35
+ expect(result.global).toBe(true);
36
+ });
37
+ it('sets global to false when isGlobal: false', () => {
38
+ const result = i18n_module_1.I18nModule.forRoot({ isGlobal: false });
39
+ expect(result.global).toBe(false);
40
+ });
41
+ it('provides I18N_OPTIONS_TOKEN, I18nService, and LocaleMiddleware', () => {
42
+ const result = i18n_module_1.I18nModule.forRoot();
43
+ expect(result.providers).toHaveLength(3);
44
+ });
45
+ it('uses custom defaultLocale', () => {
46
+ const result = i18n_module_1.I18nModule.forRoot({ defaultLocale: 'fr' });
47
+ const optionsProvider = result.providers.find((p) => p.provide === 'I18N_OPTIONS');
48
+ expect(optionsProvider?.useValue?.defaultLocale).toBe('fr');
49
+ });
50
+ it('sets fallbackLocale to defaultLocale when not specified', () => {
51
+ const result = i18n_module_1.I18nModule.forRoot({ defaultLocale: 'de' });
52
+ const optionsProvider = result.providers.find((p) => p.provide === 'I18N_OPTIONS');
53
+ expect(optionsProvider?.useValue?.fallbackLocale).toBe('de');
54
+ });
55
+ it('sets custom fallbackLocale when specified', () => {
56
+ const result = i18n_module_1.I18nModule.forRoot({ defaultLocale: 'fr', fallbackLocale: 'en' });
57
+ const optionsProvider = result.providers.find((p) => p.provide === 'I18N_OPTIONS');
58
+ expect(optionsProvider?.useValue?.fallbackLocale).toBe('en');
59
+ });
60
+ it('I18nService factory creates and initializes service', () => {
61
+ const store = new Map([['en', { hello: 'Hello' }]]);
62
+ mockLoad.mockReturnValue(store);
63
+ const result = i18n_module_1.I18nModule.forRoot({ translationsPath: './trans' });
64
+ const serviceProvider = result.providers.find((p) => p.provide === i18n_service_1.I18nService);
65
+ const optionsProvider = result.providers.find((p) => p.provide === 'I18N_OPTIONS');
66
+ const opts = optionsProvider?.useValue;
67
+ const service = serviceProvider?.useFactory?.(opts);
68
+ expect(service).toBeInstanceOf(i18n_service_1.I18nService);
69
+ expect(mockLoad).toHaveBeenCalled();
70
+ });
71
+ it('LocaleMiddleware factory creates middleware', () => {
72
+ const result = i18n_module_1.I18nModule.forRoot();
73
+ const mwProvider = result.providers.find((p) => p.provide === i18n_middleware_1.LocaleMiddleware);
74
+ const optionsProvider = result.providers.find((p) => p.provide === 'I18N_OPTIONS');
75
+ const opts = optionsProvider?.useValue;
76
+ const mw = mwProvider?.useFactory?.(opts);
77
+ expect(mw).toBeInstanceOf(i18n_middleware_1.LocaleMiddleware);
78
+ });
79
+ it('uses default translationsPath "translations" when not specified', () => {
80
+ const result = i18n_module_1.I18nModule.forRoot();
81
+ const optionsProvider = result.providers.find((p) => p.provide === 'I18N_OPTIONS');
82
+ const opts = optionsProvider?.useValue;
83
+ expect(typeof opts?.translationsPath).toBe('string');
84
+ expect((opts?.translationsPath).endsWith('translations')).toBe(true);
85
+ });
86
+ it('applies default detection strategies', () => {
87
+ const result = i18n_module_1.I18nModule.forRoot();
88
+ const optionsProvider = result.providers.find((p) => p.provide === 'I18N_OPTIONS');
89
+ const opts = optionsProvider?.useValue;
90
+ expect(opts?.detection).toEqual(['query', 'cookie', 'header']);
91
+ });
92
+ });
93
+ describe('forRootAsync()', () => {
94
+ it('returns module reference', () => {
95
+ const result = i18n_module_1.I18nModule.forRootAsync({ useFactory: () => ({}) });
96
+ expect(result.module).toBe(i18n_module_1.I18nModule);
97
+ });
98
+ it('exports I18nService and LocaleMiddleware', () => {
99
+ const result = i18n_module_1.I18nModule.forRootAsync({ useFactory: () => ({}) });
100
+ expect(result.exports).toContain(i18n_service_1.I18nService);
101
+ expect(result.exports).toContain(i18n_middleware_1.LocaleMiddleware);
102
+ });
103
+ it('sets global to true', () => {
104
+ const result = i18n_module_1.I18nModule.forRootAsync({ useFactory: () => ({}) });
105
+ expect(result.global).toBe(true);
106
+ });
107
+ it('provides 3 providers', () => {
108
+ const result = i18n_module_1.I18nModule.forRootAsync({ useFactory: () => ({}) });
109
+ expect(result.providers).toHaveLength(3);
110
+ });
111
+ it('OPTIONS factory resolves and applies defaults', () => {
112
+ const result = i18n_module_1.I18nModule.forRootAsync({
113
+ useFactory: () => ({ defaultLocale: 'ja' }),
114
+ });
115
+ const optionsProvider = result.providers.find((p) => p.provide === 'I18N_OPTIONS');
116
+ const resolved = optionsProvider?.useFactory?.();
117
+ expect(resolved.defaultLocale).toBe('ja');
118
+ });
119
+ it('passes inject args through to useFactory', () => {
120
+ const factory = jest.fn().mockReturnValue({ defaultLocale: 'ko' });
121
+ const result = i18n_module_1.I18nModule.forRootAsync({ useFactory: factory, inject: ['CONFIG'] });
122
+ const optionsProvider = result.providers.find((p) => p.provide === 'I18N_OPTIONS');
123
+ optionsProvider?.useFactory?.('some-config-value');
124
+ expect(factory).toHaveBeenCalledWith('some-config-value');
125
+ });
126
+ it('I18nService factory creates and initializes service', () => {
127
+ const result = i18n_module_1.I18nModule.forRootAsync({ useFactory: () => ({}) });
128
+ const serviceProvider = result.providers.find((p) => p.provide === i18n_service_1.I18nService);
129
+ const resolvedOpts = {
130
+ defaultLocale: 'en',
131
+ fallbackLocale: 'en',
132
+ translationsPath: '/some/path',
133
+ detection: ['query'],
134
+ queryParam: 'lang',
135
+ cookieName: 'locale',
136
+ isGlobal: true,
137
+ };
138
+ const service = serviceProvider?.useFactory?.(resolvedOpts);
139
+ expect(service).toBeInstanceOf(i18n_service_1.I18nService);
140
+ });
141
+ it('LocaleMiddleware factory creates middleware', () => {
142
+ const result = i18n_module_1.I18nModule.forRootAsync({ useFactory: () => ({}) });
143
+ const mwProvider = result.providers.find((p) => p.provide === i18n_middleware_1.LocaleMiddleware);
144
+ const resolvedOpts = {
145
+ defaultLocale: 'en',
146
+ fallbackLocale: 'en',
147
+ translationsPath: '/some/path',
148
+ detection: ['query'],
149
+ queryParam: 'lang',
150
+ cookieName: 'locale',
151
+ isGlobal: true,
152
+ };
153
+ const mw = mwProvider?.useFactory?.(resolvedOpts);
154
+ expect(mw).toBeInstanceOf(i18n_middleware_1.LocaleMiddleware);
155
+ });
156
+ it('uses empty array for inject when not specified', () => {
157
+ const result = i18n_module_1.I18nModule.forRootAsync({ useFactory: () => ({}) });
158
+ const optionsProvider = result.providers.find((p) => p.provide === 'I18N_OPTIONS');
159
+ expect(optionsProvider?.inject).toEqual([]);
160
+ });
161
+ });
162
+ });
@@ -0,0 +1,112 @@
1
+ import { LocaleStore, TranslateOptions, ResolvedI18nOptions } from './types';
2
+ /**
3
+ * The central translation and formatting service.
4
+ *
5
+ * Inject this service into any controller or provider to translate keys,
6
+ * apply interpolation and pluralization, and format numbers / dates / currency
7
+ * using the native Intl API — with zero external dependencies.
8
+ */
9
+ export declare class I18nService {
10
+ /** Exposes Intl-based formatters as a nested namespace. */
11
+ readonly format: I18nFormatter;
12
+ private store;
13
+ private options;
14
+ constructor();
15
+ /**
16
+ * Called by I18nModule after translations have been loaded from disk.
17
+ */
18
+ initialize(store: LocaleStore, options: ResolvedI18nOptions): void;
19
+ /**
20
+ * Translate a dot-notation key for the given locale.
21
+ *
22
+ * @param key Dot-separated translation key, e.g. "errors.notFound".
23
+ * @param opts Optional count (plural), vars (interpolation) and locale override.
24
+ * @returns The translated string, or the key itself if not found.
25
+ *
26
+ * @example
27
+ * i18n.t('welcome', { vars: { name: 'Alice' } })
28
+ * // → "Welcome, Alice!" (from en.json: { "welcome": "Welcome, {name}!" })
29
+ *
30
+ * i18n.t('items', { count: 3, vars: { count: '3' } })
31
+ * // → "3 items" (from en.json: { "items": { "one": "1 item", "other": "{count} items" } })
32
+ */
33
+ t(key: string, opts?: TranslateOptions): string;
34
+ /**
35
+ * Returns the current request-scoped locale, falling back to the default.
36
+ * When used with the LocaleMiddleware the locale is stored on the current
37
+ * async context; outside a request context the default locale is used.
38
+ */
39
+ getCurrentLocale(): string;
40
+ /**
41
+ * Returns all translation keys available for a given locale (flattened to
42
+ * dot-notation paths), useful for debugging and tooling.
43
+ */
44
+ getKeys(locale?: string): string[];
45
+ /**
46
+ * Returns all loaded locale codes.
47
+ */
48
+ getLocales(): string[];
49
+ /**
50
+ * Checks whether a key exists for the given locale.
51
+ */
52
+ has(key: string, locale?: string): boolean;
53
+ /**
54
+ * Traverses the translation map using a dot-notation key.
55
+ * Falls back to the fallbackLocale when the key is missing.
56
+ */
57
+ private resolve;
58
+ private resolveInMap;
59
+ /**
60
+ * Given a translation value that may be a plain string or a plural object,
61
+ * returns the appropriate form.
62
+ *
63
+ * Uses the native Intl.PluralRules API, defaulting to "other" when
64
+ * the value is not a plural object.
65
+ */
66
+ private selectPluralForm;
67
+ /**
68
+ * Replaces {placeholder} tokens in a string with values from vars.
69
+ */
70
+ private interpolate;
71
+ private flattenKeys;
72
+ }
73
+ /**
74
+ * Exposes Intl-backed formatters, accessible as `i18nService.format.*`.
75
+ */
76
+ export declare class I18nFormatter {
77
+ private readonly service;
78
+ constructor(service: I18nService);
79
+ /**
80
+ * Format a number using Intl.NumberFormat.
81
+ *
82
+ * @example
83
+ * i18n.format.number(1234567.89, 'de', { maximumFractionDigits: 2 })
84
+ * // → "1.234.567,89"
85
+ */
86
+ number(value: number, locale?: string, opts?: Intl.NumberFormatOptions): string;
87
+ /**
88
+ * Format a date using Intl.DateTimeFormat.
89
+ *
90
+ * @example
91
+ * i18n.format.date(new Date(), 'fr', { dateStyle: 'long' })
92
+ * // → "4 mars 2026"
93
+ */
94
+ date(value: Date | number, locale?: string, opts?: Intl.DateTimeFormatOptions): string;
95
+ /**
96
+ * Format a monetary value using Intl.NumberFormat with style 'currency'.
97
+ *
98
+ * @example
99
+ * i18n.format.currency(49.99, 'en', 'USD')
100
+ * // → "$49.99"
101
+ */
102
+ currency(value: number, locale?: string, currency?: string): string;
103
+ /**
104
+ * Format a relative time using Intl.RelativeTimeFormat.
105
+ *
106
+ * @example
107
+ * i18n.format.relative(-3, 'day', 'en')
108
+ * // → "3 days ago"
109
+ */
110
+ relative(value: number, unit: Intl.RelativeTimeFormatUnit, locale?: string, opts?: Intl.RelativeTimeFormatOptions): string;
111
+ }
112
+ //# sourceMappingURL=i18n.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.service.d.ts","sourceRoot":"","sources":["../src/i18n.service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EAGX,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAEjB;;;;;;GAMG;AACH,qBACa,WAAW;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAE/B,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,OAAO,CAAuB;;IAMtC;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAKlE;;;;;;;;;;;;;OAaG;IACH,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,GAAG,MAAM;IASnD;;;;OAIG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAOlC;;OAEG;IACH,UAAU,IAAI,MAAM,EAAE;IAItB;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO;IAQ1C;;;OAGG;IACH,OAAO,CAAC,OAAO;IAaf,OAAO,CAAC,YAAY;IAiBpB;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IAyBxB;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,WAAW;CAYpB;AAED;;GAEG;AACH,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,WAAW;IAEjD;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,mBAAmB,GAAG,MAAM;IAK/E;;;;;;OAMG;IACH,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,qBAAqB,GAAG,MAAM;IAKtF;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,SAAQ,GAAG,MAAM;IAKlE;;;;;;OAMG;IACH,QAAQ,CACN,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,IAAI,CAAC,sBAAsB,EACjC,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,IAAI,CAAC,yBAAyB,GACpC,MAAM;CAIV"}