@djangocfg/ext-base 1.0.15 → 1.0.17
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/dist/api.js +1 -1
- package/dist/{chunk-ORQOAMQE.js → chunk-AU2RS5WG.js} +1 -1
- package/dist/{chunk-ND6PUTEV.js → chunk-Q4JJNC2D.js} +6 -1
- package/dist/hooks.cjs +1 -1
- package/dist/hooks.js +4 -4
- package/dist/i18n.cjs +52 -0
- package/dist/i18n.d.cts +189 -0
- package/dist/i18n.d.ts +189 -0
- package/dist/i18n.js +49 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +2 -2
- package/package.json +9 -4
- package/src/i18n/index.ts +58 -0
- package/src/i18n/types.ts +108 -0
- package/src/i18n/utils.ts +181 -0
package/dist/api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { createExtensionAPI, getSharedAuthStorage, initializeExtensionAPI } from './chunk-
|
|
1
|
+
export { createExtensionAPI, getSharedAuthStorage, initializeExtensionAPI } from './chunk-Q4JJNC2D.js';
|
|
2
2
|
import './chunk-3RG5ZIWI.js';
|
|
@@ -3,7 +3,7 @@ import { __require } from './chunk-3RG5ZIWI.js';
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@djangocfg/ext-base",
|
|
6
|
-
version: "1.0.
|
|
6
|
+
version: "1.0.17",
|
|
7
7
|
description: "Base utilities and common code for DjangoCFG extensions",
|
|
8
8
|
keywords: [
|
|
9
9
|
"django",
|
|
@@ -52,6 +52,11 @@ var package_default = {
|
|
|
52
52
|
types: "./dist/api.d.ts",
|
|
53
53
|
import: "./dist/api.js",
|
|
54
54
|
require: "./dist/api.cjs"
|
|
55
|
+
},
|
|
56
|
+
"./i18n": {
|
|
57
|
+
types: "./dist/i18n.d.ts",
|
|
58
|
+
import: "./dist/i18n.js",
|
|
59
|
+
require: "./dist/i18n.cjs"
|
|
55
60
|
}
|
|
56
61
|
},
|
|
57
62
|
files: [
|
package/dist/hooks.cjs
CHANGED
package/dist/hooks.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createExtensionLogger } from './chunk-
|
|
2
|
-
export { EXTENSION_CATEGORIES, createExtensionConfig, createExtensionError, createExtensionLogger, extensionConfig, formatErrorMessage, handleExtensionError, isExtensionError } from './chunk-
|
|
3
|
-
import { isDevelopment } from './chunk-
|
|
4
|
-
export { createExtensionAPI, getApiUrl, getSharedAuthStorage, initializeExtensionAPI, isDevelopment, isProduction, isStaticBuild } from './chunk-
|
|
1
|
+
import { createExtensionLogger } from './chunk-AU2RS5WG.js';
|
|
2
|
+
export { EXTENSION_CATEGORIES, createExtensionConfig, createExtensionError, createExtensionLogger, extensionConfig, formatErrorMessage, handleExtensionError, isExtensionError } from './chunk-AU2RS5WG.js';
|
|
3
|
+
import { isDevelopment } from './chunk-Q4JJNC2D.js';
|
|
4
|
+
export { createExtensionAPI, getApiUrl, getSharedAuthStorage, initializeExtensionAPI, isDevelopment, isProduction, isStaticBuild } from './chunk-Q4JJNC2D.js';
|
|
5
5
|
import './chunk-3RG5ZIWI.js';
|
|
6
6
|
import React, { createContext, useEffect, useContext } from 'react';
|
|
7
7
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
package/dist/i18n.cjs
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/i18n/utils.ts
|
|
4
|
+
function createExtensionI18n(config) {
|
|
5
|
+
const { namespace, defaultLocale, locales } = config;
|
|
6
|
+
return {
|
|
7
|
+
namespace,
|
|
8
|
+
defaultLocale,
|
|
9
|
+
locales: Object.keys(locales),
|
|
10
|
+
getTranslations(locale) {
|
|
11
|
+
return locales[locale] ?? locales[defaultLocale];
|
|
12
|
+
},
|
|
13
|
+
getAllTranslations() {
|
|
14
|
+
const result = {};
|
|
15
|
+
for (const [locale, translations] of Object.entries(locales)) {
|
|
16
|
+
result[locale] = {
|
|
17
|
+
[namespace]: translations
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function mergeExtensionTranslations(base, extensions) {
|
|
25
|
+
const result = { ...base };
|
|
26
|
+
for (const ext of extensions) {
|
|
27
|
+
for (const [key, value] of Object.entries(ext)) {
|
|
28
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
29
|
+
result[key] = {
|
|
30
|
+
...result[key] || {},
|
|
31
|
+
...value
|
|
32
|
+
};
|
|
33
|
+
} else {
|
|
34
|
+
result[key] = value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
function createNamespacedT(t, namespace) {
|
|
41
|
+
return (key, params) => {
|
|
42
|
+
return t(`${namespace}.${key}`, params);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function createTypedExtensionT(t, namespace) {
|
|
46
|
+
return (key, params) => t(`${namespace}.${key}`, params);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
exports.createExtensionI18n = createExtensionI18n;
|
|
50
|
+
exports.createNamespacedT = createNamespacedT;
|
|
51
|
+
exports.createTypedExtensionT = createTypedExtensionT;
|
|
52
|
+
exports.mergeExtensionTranslations = mergeExtensionTranslations;
|
package/dist/i18n.d.cts
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension I18n Types
|
|
3
|
+
*
|
|
4
|
+
* Base types for extension localization.
|
|
5
|
+
* Each extension defines its own translation structure.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Recursively generates dot-notation paths for nested object types
|
|
9
|
+
* Re-exported from @djangocfg/i18n for convenience
|
|
10
|
+
*/
|
|
11
|
+
type PathKeys<T, Prefix extends string = '', Depth extends number[] = []> = Depth['length'] extends 10 ? never : T extends string ? Prefix : T extends object ? {
|
|
12
|
+
[K in keyof T & string]: PathKeys<T[K], Prefix extends '' ? K : `${Prefix}.${K}`, [
|
|
13
|
+
...Depth,
|
|
14
|
+
0
|
|
15
|
+
]>;
|
|
16
|
+
}[keyof T & string] : never;
|
|
17
|
+
/**
|
|
18
|
+
* Generates extension keys with namespace prefix
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* type LeadsTranslations = {
|
|
23
|
+
* form: { title: string; submit: string }
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* type Keys = ExtensionKeys<'leads', LeadsTranslations>
|
|
27
|
+
* // = "leads.form.title" | "leads.form.submit"
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
type ExtensionKeys<Namespace extends string, T extends object> = PathKeys<T> extends infer K ? K extends string ? `${Namespace}.${K}` : never : never;
|
|
31
|
+
/**
|
|
32
|
+
* Type-safe translation function for an extension
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* type LeadsT = ExtensionTranslationFn<'leads', LeadsTranslations>
|
|
37
|
+
*
|
|
38
|
+
* const t: LeadsT = useT() as LeadsT
|
|
39
|
+
* t('leads.form.title') // OK
|
|
40
|
+
* t('leads.form.typo') // Error
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
type ExtensionTranslationFn<Namespace extends string, T extends object> = {
|
|
44
|
+
(key: ExtensionKeys<Namespace, T>, params?: Record<string, string | number>): string;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Supported locale codes for extensions
|
|
48
|
+
*/
|
|
49
|
+
type ExtensionLocale = 'en' | 'ru' | 'ko' | string;
|
|
50
|
+
/**
|
|
51
|
+
* Base structure for extension translations
|
|
52
|
+
* Extensions can use any object structure for their translations
|
|
53
|
+
*/
|
|
54
|
+
interface ExtensionTranslations {
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extension i18n configuration
|
|
58
|
+
*/
|
|
59
|
+
interface ExtensionI18nConfig<T extends object> {
|
|
60
|
+
/** Extension namespace (e.g., 'payments', 'support') */
|
|
61
|
+
namespace: string;
|
|
62
|
+
/** Default locale */
|
|
63
|
+
defaultLocale: ExtensionLocale;
|
|
64
|
+
/** Translations by locale */
|
|
65
|
+
locales: Record<ExtensionLocale, T>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Extension i18n instance returned by createExtensionI18n
|
|
69
|
+
*/
|
|
70
|
+
interface ExtensionI18n<T extends object> {
|
|
71
|
+
/** Extension namespace */
|
|
72
|
+
namespace: string;
|
|
73
|
+
/** Default locale */
|
|
74
|
+
defaultLocale: ExtensionLocale;
|
|
75
|
+
/** Get translations for a specific locale */
|
|
76
|
+
getTranslations: (locale: ExtensionLocale) => T;
|
|
77
|
+
/** Get all translations (for merging with app i18n) */
|
|
78
|
+
getAllTranslations: () => Record<ExtensionLocale, {
|
|
79
|
+
[namespace: string]: T;
|
|
80
|
+
}>;
|
|
81
|
+
/** Available locales */
|
|
82
|
+
locales: ExtensionLocale[];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Deep partial type for translation overrides
|
|
86
|
+
*/
|
|
87
|
+
type DeepPartial<T> = T extends object ? {
|
|
88
|
+
[P in keyof T]?: DeepPartial<T[P]>;
|
|
89
|
+
} : T;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Creates an extension i18n instance
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* // In ext-payments/src/i18n/index.ts
|
|
97
|
+
* import { createExtensionI18n } from '@djangocfg/ext-base/i18n';
|
|
98
|
+
* import { en } from './locales/en';
|
|
99
|
+
* import { ru } from './locales/ru';
|
|
100
|
+
* import { ko } from './locales/ko';
|
|
101
|
+
*
|
|
102
|
+
* export const paymentsI18n = createExtensionI18n({
|
|
103
|
+
* namespace: 'payments',
|
|
104
|
+
* defaultLocale: 'en',
|
|
105
|
+
* locales: { en, ru, ko },
|
|
106
|
+
* });
|
|
107
|
+
*
|
|
108
|
+
* // Export for app to merge
|
|
109
|
+
* export const paymentsTranslations = paymentsI18n.getAllTranslations();
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
declare function createExtensionI18n<T extends object>(config: ExtensionI18nConfig<T>): ExtensionI18n<T>;
|
|
113
|
+
/**
|
|
114
|
+
* Merges extension translations into app translations
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* // In app's i18n setup
|
|
119
|
+
* import { en, ru, ko, mergeTranslations } from '@djangocfg/i18n';
|
|
120
|
+
* import { paymentsTranslations } from '@djangocfg/ext-payments/i18n';
|
|
121
|
+
* import { supportTranslations } from '@djangocfg/ext-support/i18n';
|
|
122
|
+
*
|
|
123
|
+
* const appTranslations = {
|
|
124
|
+
* en: mergeExtensionTranslations(en, [
|
|
125
|
+
* paymentsTranslations.en,
|
|
126
|
+
* supportTranslations.en,
|
|
127
|
+
* ]),
|
|
128
|
+
* ru: mergeExtensionTranslations(ru, [
|
|
129
|
+
* paymentsTranslations.ru,
|
|
130
|
+
* supportTranslations.ru,
|
|
131
|
+
* ]),
|
|
132
|
+
* };
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
declare function mergeExtensionTranslations<T extends Record<string, any>>(base: T, extensions: Array<Record<string, any>>): T;
|
|
136
|
+
/**
|
|
137
|
+
* Creates a namespaced translation getter
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* // In extension component
|
|
142
|
+
* const t = useT(); // from @djangocfg/i18n
|
|
143
|
+
* const pt = createNamespacedT(t, 'payments');
|
|
144
|
+
*
|
|
145
|
+
* // Instead of t('payments.balance.available')
|
|
146
|
+
* // You can use pt('balance.available')
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
declare function createNamespacedT(t: (key: string, params?: Record<string, string | number>) => string, namespace: string): (key: string, params?: Record<string, string | number>) => string;
|
|
150
|
+
/**
|
|
151
|
+
* Creates a type-safe translation function for an extension
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* // In ext-leads component
|
|
156
|
+
* import { createTypedExtensionT } from '@djangocfg/ext-base/i18n';
|
|
157
|
+
* import { useT } from '@djangocfg/i18n';
|
|
158
|
+
* import type { LeadsTranslations } from '../i18n/types';
|
|
159
|
+
*
|
|
160
|
+
* function ContactForm() {
|
|
161
|
+
* const t = useT();
|
|
162
|
+
* const lt = createTypedExtensionT<'leads', LeadsTranslations>(t, 'leads');
|
|
163
|
+
*
|
|
164
|
+
* return <span>{lt('form.title')}</span>; // Type-safe!
|
|
165
|
+
* // lt('form.typo') // Compile error!
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
declare function createTypedExtensionT<Namespace extends string, T extends object>(t: (key: string, params?: Record<string, string | number>) => string, namespace: Namespace): <K extends PathKeys<T>>(key: K, params?: Record<string, string | number>) => string;
|
|
170
|
+
/**
|
|
171
|
+
* Type helper for creating extension key types
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* // In ext-leads/src/i18n/types.ts
|
|
176
|
+
* import type { CreateExtensionKeys } from '@djangocfg/ext-base/i18n';
|
|
177
|
+
*
|
|
178
|
+
* export interface LeadsTranslations {
|
|
179
|
+
* form: { title: string; submit: string }
|
|
180
|
+
* success: { title: string }
|
|
181
|
+
* }
|
|
182
|
+
*
|
|
183
|
+
* // Type of all valid keys: "leads.form.title" | "leads.form.submit" | "leads.success.title"
|
|
184
|
+
* export type LeadsKeys = CreateExtensionKeys<'leads', LeadsTranslations>;
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
type CreateExtensionKeys<Namespace extends string, T extends object> = ExtensionKeys<Namespace, T>;
|
|
188
|
+
|
|
189
|
+
export { type CreateExtensionKeys, type DeepPartial, type ExtensionI18n, type ExtensionI18nConfig, type ExtensionKeys, type ExtensionLocale, type ExtensionTranslationFn, type ExtensionTranslations, type PathKeys, createExtensionI18n, createNamespacedT, createTypedExtensionT, mergeExtensionTranslations };
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension I18n Types
|
|
3
|
+
*
|
|
4
|
+
* Base types for extension localization.
|
|
5
|
+
* Each extension defines its own translation structure.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Recursively generates dot-notation paths for nested object types
|
|
9
|
+
* Re-exported from @djangocfg/i18n for convenience
|
|
10
|
+
*/
|
|
11
|
+
type PathKeys<T, Prefix extends string = '', Depth extends number[] = []> = Depth['length'] extends 10 ? never : T extends string ? Prefix : T extends object ? {
|
|
12
|
+
[K in keyof T & string]: PathKeys<T[K], Prefix extends '' ? K : `${Prefix}.${K}`, [
|
|
13
|
+
...Depth,
|
|
14
|
+
0
|
|
15
|
+
]>;
|
|
16
|
+
}[keyof T & string] : never;
|
|
17
|
+
/**
|
|
18
|
+
* Generates extension keys with namespace prefix
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* type LeadsTranslations = {
|
|
23
|
+
* form: { title: string; submit: string }
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* type Keys = ExtensionKeys<'leads', LeadsTranslations>
|
|
27
|
+
* // = "leads.form.title" | "leads.form.submit"
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
type ExtensionKeys<Namespace extends string, T extends object> = PathKeys<T> extends infer K ? K extends string ? `${Namespace}.${K}` : never : never;
|
|
31
|
+
/**
|
|
32
|
+
* Type-safe translation function for an extension
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* type LeadsT = ExtensionTranslationFn<'leads', LeadsTranslations>
|
|
37
|
+
*
|
|
38
|
+
* const t: LeadsT = useT() as LeadsT
|
|
39
|
+
* t('leads.form.title') // OK
|
|
40
|
+
* t('leads.form.typo') // Error
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
type ExtensionTranslationFn<Namespace extends string, T extends object> = {
|
|
44
|
+
(key: ExtensionKeys<Namespace, T>, params?: Record<string, string | number>): string;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Supported locale codes for extensions
|
|
48
|
+
*/
|
|
49
|
+
type ExtensionLocale = 'en' | 'ru' | 'ko' | string;
|
|
50
|
+
/**
|
|
51
|
+
* Base structure for extension translations
|
|
52
|
+
* Extensions can use any object structure for their translations
|
|
53
|
+
*/
|
|
54
|
+
interface ExtensionTranslations {
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extension i18n configuration
|
|
58
|
+
*/
|
|
59
|
+
interface ExtensionI18nConfig<T extends object> {
|
|
60
|
+
/** Extension namespace (e.g., 'payments', 'support') */
|
|
61
|
+
namespace: string;
|
|
62
|
+
/** Default locale */
|
|
63
|
+
defaultLocale: ExtensionLocale;
|
|
64
|
+
/** Translations by locale */
|
|
65
|
+
locales: Record<ExtensionLocale, T>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Extension i18n instance returned by createExtensionI18n
|
|
69
|
+
*/
|
|
70
|
+
interface ExtensionI18n<T extends object> {
|
|
71
|
+
/** Extension namespace */
|
|
72
|
+
namespace: string;
|
|
73
|
+
/** Default locale */
|
|
74
|
+
defaultLocale: ExtensionLocale;
|
|
75
|
+
/** Get translations for a specific locale */
|
|
76
|
+
getTranslations: (locale: ExtensionLocale) => T;
|
|
77
|
+
/** Get all translations (for merging with app i18n) */
|
|
78
|
+
getAllTranslations: () => Record<ExtensionLocale, {
|
|
79
|
+
[namespace: string]: T;
|
|
80
|
+
}>;
|
|
81
|
+
/** Available locales */
|
|
82
|
+
locales: ExtensionLocale[];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Deep partial type for translation overrides
|
|
86
|
+
*/
|
|
87
|
+
type DeepPartial<T> = T extends object ? {
|
|
88
|
+
[P in keyof T]?: DeepPartial<T[P]>;
|
|
89
|
+
} : T;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Creates an extension i18n instance
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* // In ext-payments/src/i18n/index.ts
|
|
97
|
+
* import { createExtensionI18n } from '@djangocfg/ext-base/i18n';
|
|
98
|
+
* import { en } from './locales/en';
|
|
99
|
+
* import { ru } from './locales/ru';
|
|
100
|
+
* import { ko } from './locales/ko';
|
|
101
|
+
*
|
|
102
|
+
* export const paymentsI18n = createExtensionI18n({
|
|
103
|
+
* namespace: 'payments',
|
|
104
|
+
* defaultLocale: 'en',
|
|
105
|
+
* locales: { en, ru, ko },
|
|
106
|
+
* });
|
|
107
|
+
*
|
|
108
|
+
* // Export for app to merge
|
|
109
|
+
* export const paymentsTranslations = paymentsI18n.getAllTranslations();
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
declare function createExtensionI18n<T extends object>(config: ExtensionI18nConfig<T>): ExtensionI18n<T>;
|
|
113
|
+
/**
|
|
114
|
+
* Merges extension translations into app translations
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* // In app's i18n setup
|
|
119
|
+
* import { en, ru, ko, mergeTranslations } from '@djangocfg/i18n';
|
|
120
|
+
* import { paymentsTranslations } from '@djangocfg/ext-payments/i18n';
|
|
121
|
+
* import { supportTranslations } from '@djangocfg/ext-support/i18n';
|
|
122
|
+
*
|
|
123
|
+
* const appTranslations = {
|
|
124
|
+
* en: mergeExtensionTranslations(en, [
|
|
125
|
+
* paymentsTranslations.en,
|
|
126
|
+
* supportTranslations.en,
|
|
127
|
+
* ]),
|
|
128
|
+
* ru: mergeExtensionTranslations(ru, [
|
|
129
|
+
* paymentsTranslations.ru,
|
|
130
|
+
* supportTranslations.ru,
|
|
131
|
+
* ]),
|
|
132
|
+
* };
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
declare function mergeExtensionTranslations<T extends Record<string, any>>(base: T, extensions: Array<Record<string, any>>): T;
|
|
136
|
+
/**
|
|
137
|
+
* Creates a namespaced translation getter
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* // In extension component
|
|
142
|
+
* const t = useT(); // from @djangocfg/i18n
|
|
143
|
+
* const pt = createNamespacedT(t, 'payments');
|
|
144
|
+
*
|
|
145
|
+
* // Instead of t('payments.balance.available')
|
|
146
|
+
* // You can use pt('balance.available')
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
declare function createNamespacedT(t: (key: string, params?: Record<string, string | number>) => string, namespace: string): (key: string, params?: Record<string, string | number>) => string;
|
|
150
|
+
/**
|
|
151
|
+
* Creates a type-safe translation function for an extension
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* // In ext-leads component
|
|
156
|
+
* import { createTypedExtensionT } from '@djangocfg/ext-base/i18n';
|
|
157
|
+
* import { useT } from '@djangocfg/i18n';
|
|
158
|
+
* import type { LeadsTranslations } from '../i18n/types';
|
|
159
|
+
*
|
|
160
|
+
* function ContactForm() {
|
|
161
|
+
* const t = useT();
|
|
162
|
+
* const lt = createTypedExtensionT<'leads', LeadsTranslations>(t, 'leads');
|
|
163
|
+
*
|
|
164
|
+
* return <span>{lt('form.title')}</span>; // Type-safe!
|
|
165
|
+
* // lt('form.typo') // Compile error!
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
declare function createTypedExtensionT<Namespace extends string, T extends object>(t: (key: string, params?: Record<string, string | number>) => string, namespace: Namespace): <K extends PathKeys<T>>(key: K, params?: Record<string, string | number>) => string;
|
|
170
|
+
/**
|
|
171
|
+
* Type helper for creating extension key types
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* // In ext-leads/src/i18n/types.ts
|
|
176
|
+
* import type { CreateExtensionKeys } from '@djangocfg/ext-base/i18n';
|
|
177
|
+
*
|
|
178
|
+
* export interface LeadsTranslations {
|
|
179
|
+
* form: { title: string; submit: string }
|
|
180
|
+
* success: { title: string }
|
|
181
|
+
* }
|
|
182
|
+
*
|
|
183
|
+
* // Type of all valid keys: "leads.form.title" | "leads.form.submit" | "leads.success.title"
|
|
184
|
+
* export type LeadsKeys = CreateExtensionKeys<'leads', LeadsTranslations>;
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
type CreateExtensionKeys<Namespace extends string, T extends object> = ExtensionKeys<Namespace, T>;
|
|
188
|
+
|
|
189
|
+
export { type CreateExtensionKeys, type DeepPartial, type ExtensionI18n, type ExtensionI18nConfig, type ExtensionKeys, type ExtensionLocale, type ExtensionTranslationFn, type ExtensionTranslations, type PathKeys, createExtensionI18n, createNamespacedT, createTypedExtensionT, mergeExtensionTranslations };
|
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import './chunk-3RG5ZIWI.js';
|
|
2
|
+
|
|
3
|
+
// src/i18n/utils.ts
|
|
4
|
+
function createExtensionI18n(config) {
|
|
5
|
+
const { namespace, defaultLocale, locales } = config;
|
|
6
|
+
return {
|
|
7
|
+
namespace,
|
|
8
|
+
defaultLocale,
|
|
9
|
+
locales: Object.keys(locales),
|
|
10
|
+
getTranslations(locale) {
|
|
11
|
+
return locales[locale] ?? locales[defaultLocale];
|
|
12
|
+
},
|
|
13
|
+
getAllTranslations() {
|
|
14
|
+
const result = {};
|
|
15
|
+
for (const [locale, translations] of Object.entries(locales)) {
|
|
16
|
+
result[locale] = {
|
|
17
|
+
[namespace]: translations
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function mergeExtensionTranslations(base, extensions) {
|
|
25
|
+
const result = { ...base };
|
|
26
|
+
for (const ext of extensions) {
|
|
27
|
+
for (const [key, value] of Object.entries(ext)) {
|
|
28
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
29
|
+
result[key] = {
|
|
30
|
+
...result[key] || {},
|
|
31
|
+
...value
|
|
32
|
+
};
|
|
33
|
+
} else {
|
|
34
|
+
result[key] = value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
function createNamespacedT(t, namespace) {
|
|
41
|
+
return (key, params) => {
|
|
42
|
+
return t(`${namespace}.${key}`, params);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function createTypedExtensionT(t, namespace) {
|
|
46
|
+
return (key, params) => t(`${namespace}.${key}`, params);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { createExtensionI18n, createNamespacedT, createTypedExtensionT, mergeExtensionTranslations };
|
package/dist/index.cjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { EXTENSION_CATEGORIES, createExtensionConfig, createExtensionError, createExtensionLogger, extensionConfig, formatErrorMessage, handleExtensionError, isExtensionError } from './chunk-
|
|
2
|
-
export { createExtensionAPI, getApiUrl, getSharedAuthStorage, initializeExtensionAPI, isDevelopment, isProduction, isStaticBuild } from './chunk-
|
|
1
|
+
export { EXTENSION_CATEGORIES, createExtensionConfig, createExtensionError, createExtensionLogger, extensionConfig, formatErrorMessage, handleExtensionError, isExtensionError } from './chunk-AU2RS5WG.js';
|
|
2
|
+
export { createExtensionAPI, getApiUrl, getSharedAuthStorage, initializeExtensionAPI, isDevelopment, isProduction, isStaticBuild } from './chunk-Q4JJNC2D.js';
|
|
3
3
|
import './chunk-3RG5ZIWI.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ext-base",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.17",
|
|
4
4
|
"description": "Base utilities and common code for DjangoCFG extensions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"django",
|
|
@@ -49,6 +49,11 @@
|
|
|
49
49
|
"types": "./dist/api.d.ts",
|
|
50
50
|
"import": "./dist/api.js",
|
|
51
51
|
"require": "./dist/api.cjs"
|
|
52
|
+
},
|
|
53
|
+
"./i18n": {
|
|
54
|
+
"types": "./dist/i18n.d.ts",
|
|
55
|
+
"import": "./dist/i18n.js",
|
|
56
|
+
"require": "./dist/i18n.cjs"
|
|
52
57
|
}
|
|
53
58
|
},
|
|
54
59
|
"files": [
|
|
@@ -73,7 +78,7 @@
|
|
|
73
78
|
"cli:info": "tsx src/cli/index.ts info"
|
|
74
79
|
},
|
|
75
80
|
"peerDependencies": {
|
|
76
|
-
"@djangocfg/api": "^2.1.
|
|
81
|
+
"@djangocfg/api": "^2.1.111",
|
|
77
82
|
"consola": "^3.4.2",
|
|
78
83
|
"react": "^19",
|
|
79
84
|
"react-dom": "^19",
|
|
@@ -86,8 +91,8 @@
|
|
|
86
91
|
"prompts": "^2.4.2"
|
|
87
92
|
},
|
|
88
93
|
"devDependencies": {
|
|
89
|
-
"@djangocfg/api": "^2.1.
|
|
90
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
94
|
+
"@djangocfg/api": "^2.1.111",
|
|
95
|
+
"@djangocfg/typescript-config": "^2.1.111",
|
|
91
96
|
"@types/node": "^24.7.2",
|
|
92
97
|
"@types/prompts": "^2.4.9",
|
|
93
98
|
"@types/react": "^19.0.0",
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension I18n
|
|
3
|
+
*
|
|
4
|
+
* Base i18n infrastructure for DjangoCFG extensions.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* // Creating extension translations (in ext-payments/src/i18n/index.ts)
|
|
9
|
+
* import { createExtensionI18n } from '@djangocfg/ext-base/i18n';
|
|
10
|
+
*
|
|
11
|
+
* export const paymentsI18n = createExtensionI18n({
|
|
12
|
+
* namespace: 'payments',
|
|
13
|
+
* defaultLocale: 'en',
|
|
14
|
+
* locales: {
|
|
15
|
+
* en: { balance: { available: 'Available Balance' } },
|
|
16
|
+
* ru: { balance: { available: 'Доступный баланс' } },
|
|
17
|
+
* },
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* export const paymentsTranslations = paymentsI18n.getAllTranslations();
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // Merging in app (in apps/web/providers/I18nProvider.tsx)
|
|
26
|
+
* import { mergeExtensionTranslations } from '@djangocfg/ext-base/i18n';
|
|
27
|
+
* import { en, ru } from '@djangocfg/i18n';
|
|
28
|
+
* import { paymentsTranslations } from '@djangocfg/ext-payments/i18n';
|
|
29
|
+
*
|
|
30
|
+
* const translations = {
|
|
31
|
+
* en: mergeExtensionTranslations(en, [paymentsTranslations.en]),
|
|
32
|
+
* ru: mergeExtensionTranslations(ru, [paymentsTranslations.ru]),
|
|
33
|
+
* };
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
// Types
|
|
38
|
+
export type {
|
|
39
|
+
ExtensionLocale,
|
|
40
|
+
ExtensionTranslations,
|
|
41
|
+
ExtensionI18nConfig,
|
|
42
|
+
ExtensionI18n,
|
|
43
|
+
DeepPartial,
|
|
44
|
+
// Type-safe keys
|
|
45
|
+
PathKeys,
|
|
46
|
+
ExtensionKeys,
|
|
47
|
+
ExtensionTranslationFn,
|
|
48
|
+
} from './types';
|
|
49
|
+
|
|
50
|
+
// Utils
|
|
51
|
+
export {
|
|
52
|
+
createExtensionI18n,
|
|
53
|
+
mergeExtensionTranslations,
|
|
54
|
+
createNamespacedT,
|
|
55
|
+
createTypedExtensionT,
|
|
56
|
+
} from './utils';
|
|
57
|
+
|
|
58
|
+
export type { CreateExtensionKeys } from './utils';
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension I18n Types
|
|
3
|
+
*
|
|
4
|
+
* Base types for extension localization.
|
|
5
|
+
* Each extension defines its own translation structure.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Recursively generates dot-notation paths for nested object types
|
|
10
|
+
* Re-exported from @djangocfg/i18n for convenience
|
|
11
|
+
*/
|
|
12
|
+
export type PathKeys<T, Prefix extends string = '', Depth extends number[] = []> =
|
|
13
|
+
Depth['length'] extends 10
|
|
14
|
+
? never
|
|
15
|
+
: T extends string
|
|
16
|
+
? Prefix
|
|
17
|
+
: T extends object
|
|
18
|
+
? {
|
|
19
|
+
[K in keyof T & string]: PathKeys<
|
|
20
|
+
T[K],
|
|
21
|
+
Prefix extends '' ? K : `${Prefix}.${K}`,
|
|
22
|
+
[...Depth, 0]
|
|
23
|
+
>
|
|
24
|
+
}[keyof T & string]
|
|
25
|
+
: never;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Generates extension keys with namespace prefix
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* type LeadsTranslations = {
|
|
33
|
+
* form: { title: string; submit: string }
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* type Keys = ExtensionKeys<'leads', LeadsTranslations>
|
|
37
|
+
* // = "leads.form.title" | "leads.form.submit"
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export type ExtensionKeys<Namespace extends string, T extends object> =
|
|
41
|
+
PathKeys<T> extends infer K
|
|
42
|
+
? K extends string
|
|
43
|
+
? `${Namespace}.${K}`
|
|
44
|
+
: never
|
|
45
|
+
: never;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Type-safe translation function for an extension
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* type LeadsT = ExtensionTranslationFn<'leads', LeadsTranslations>
|
|
53
|
+
*
|
|
54
|
+
* const t: LeadsT = useT() as LeadsT
|
|
55
|
+
* t('leads.form.title') // OK
|
|
56
|
+
* t('leads.form.typo') // Error
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export type ExtensionTranslationFn<Namespace extends string, T extends object> = {
|
|
60
|
+
(key: ExtensionKeys<Namespace, T>, params?: Record<string, string | number>): string;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Supported locale codes for extensions
|
|
65
|
+
*/
|
|
66
|
+
export type ExtensionLocale = 'en' | 'ru' | 'ko' | string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Base structure for extension translations
|
|
70
|
+
* Extensions can use any object structure for their translations
|
|
71
|
+
*/
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
73
|
+
export interface ExtensionTranslations {}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Extension i18n configuration
|
|
77
|
+
*/
|
|
78
|
+
export interface ExtensionI18nConfig<T extends object> {
|
|
79
|
+
/** Extension namespace (e.g., 'payments', 'support') */
|
|
80
|
+
namespace: string;
|
|
81
|
+
/** Default locale */
|
|
82
|
+
defaultLocale: ExtensionLocale;
|
|
83
|
+
/** Translations by locale */
|
|
84
|
+
locales: Record<ExtensionLocale, T>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Extension i18n instance returned by createExtensionI18n
|
|
89
|
+
*/
|
|
90
|
+
export interface ExtensionI18n<T extends object> {
|
|
91
|
+
/** Extension namespace */
|
|
92
|
+
namespace: string;
|
|
93
|
+
/** Default locale */
|
|
94
|
+
defaultLocale: ExtensionLocale;
|
|
95
|
+
/** Get translations for a specific locale */
|
|
96
|
+
getTranslations: (locale: ExtensionLocale) => T;
|
|
97
|
+
/** Get all translations (for merging with app i18n) */
|
|
98
|
+
getAllTranslations: () => Record<ExtensionLocale, { [namespace: string]: T }>;
|
|
99
|
+
/** Available locales */
|
|
100
|
+
locales: ExtensionLocale[];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Deep partial type for translation overrides
|
|
105
|
+
*/
|
|
106
|
+
export type DeepPartial<T> = T extends object
|
|
107
|
+
? { [P in keyof T]?: DeepPartial<T[P]> }
|
|
108
|
+
: T;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension I18n Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for creating and managing extension translations.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
ExtensionI18n,
|
|
9
|
+
ExtensionI18nConfig,
|
|
10
|
+
ExtensionLocale,
|
|
11
|
+
ExtensionKeys,
|
|
12
|
+
} from './types';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Creates an extension i18n instance
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // In ext-payments/src/i18n/index.ts
|
|
20
|
+
* import { createExtensionI18n } from '@djangocfg/ext-base/i18n';
|
|
21
|
+
* import { en } from './locales/en';
|
|
22
|
+
* import { ru } from './locales/ru';
|
|
23
|
+
* import { ko } from './locales/ko';
|
|
24
|
+
*
|
|
25
|
+
* export const paymentsI18n = createExtensionI18n({
|
|
26
|
+
* namespace: 'payments',
|
|
27
|
+
* defaultLocale: 'en',
|
|
28
|
+
* locales: { en, ru, ko },
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* // Export for app to merge
|
|
32
|
+
* export const paymentsTranslations = paymentsI18n.getAllTranslations();
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function createExtensionI18n<T extends object>(
|
|
36
|
+
config: ExtensionI18nConfig<T>
|
|
37
|
+
): ExtensionI18n<T> {
|
|
38
|
+
const { namespace, defaultLocale, locales } = config;
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
namespace,
|
|
42
|
+
defaultLocale,
|
|
43
|
+
locales: Object.keys(locales) as ExtensionLocale[],
|
|
44
|
+
|
|
45
|
+
getTranslations(locale: ExtensionLocale): T {
|
|
46
|
+
return locales[locale] ?? locales[defaultLocale];
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
getAllTranslations(): Record<ExtensionLocale, { [ns: string]: T }> {
|
|
50
|
+
const result: Record<ExtensionLocale, { [ns: string]: T }> = {} as any;
|
|
51
|
+
|
|
52
|
+
for (const [locale, translations] of Object.entries(locales)) {
|
|
53
|
+
result[locale as ExtensionLocale] = {
|
|
54
|
+
[namespace]: translations as T,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return result;
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Merges extension translations into app translations
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* // In app's i18n setup
|
|
69
|
+
* import { en, ru, ko, mergeTranslations } from '@djangocfg/i18n';
|
|
70
|
+
* import { paymentsTranslations } from '@djangocfg/ext-payments/i18n';
|
|
71
|
+
* import { supportTranslations } from '@djangocfg/ext-support/i18n';
|
|
72
|
+
*
|
|
73
|
+
* const appTranslations = {
|
|
74
|
+
* en: mergeExtensionTranslations(en, [
|
|
75
|
+
* paymentsTranslations.en,
|
|
76
|
+
* supportTranslations.en,
|
|
77
|
+
* ]),
|
|
78
|
+
* ru: mergeExtensionTranslations(ru, [
|
|
79
|
+
* paymentsTranslations.ru,
|
|
80
|
+
* supportTranslations.ru,
|
|
81
|
+
* ]),
|
|
82
|
+
* };
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export function mergeExtensionTranslations<T extends Record<string, any>>(
|
|
86
|
+
base: T,
|
|
87
|
+
extensions: Array<Record<string, any>>
|
|
88
|
+
): T {
|
|
89
|
+
const result = { ...base };
|
|
90
|
+
|
|
91
|
+
for (const ext of extensions) {
|
|
92
|
+
for (const [key, value] of Object.entries(ext)) {
|
|
93
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
94
|
+
(result as any)[key] = {
|
|
95
|
+
...((result as any)[key] || {}),
|
|
96
|
+
...value,
|
|
97
|
+
};
|
|
98
|
+
} else {
|
|
99
|
+
(result as any)[key] = value;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Creates a namespaced translation getter
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* // In extension component
|
|
113
|
+
* const t = useT(); // from @djangocfg/i18n
|
|
114
|
+
* const pt = createNamespacedT(t, 'payments');
|
|
115
|
+
*
|
|
116
|
+
* // Instead of t('payments.balance.available')
|
|
117
|
+
* // You can use pt('balance.available')
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export function createNamespacedT(
|
|
121
|
+
t: (key: string, params?: Record<string, string | number>) => string,
|
|
122
|
+
namespace: string
|
|
123
|
+
): (key: string, params?: Record<string, string | number>) => string {
|
|
124
|
+
return (key: string, params?: Record<string, string | number>) => {
|
|
125
|
+
return t(`${namespace}.${key}`, params);
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Creates a type-safe translation function for an extension
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* // In ext-leads component
|
|
135
|
+
* import { createTypedExtensionT } from '@djangocfg/ext-base/i18n';
|
|
136
|
+
* import { useT } from '@djangocfg/i18n';
|
|
137
|
+
* import type { LeadsTranslations } from '../i18n/types';
|
|
138
|
+
*
|
|
139
|
+
* function ContactForm() {
|
|
140
|
+
* const t = useT();
|
|
141
|
+
* const lt = createTypedExtensionT<'leads', LeadsTranslations>(t, 'leads');
|
|
142
|
+
*
|
|
143
|
+
* return <span>{lt('form.title')}</span>; // Type-safe!
|
|
144
|
+
* // lt('form.typo') // Compile error!
|
|
145
|
+
* }
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
export function createTypedExtensionT<
|
|
149
|
+
Namespace extends string,
|
|
150
|
+
T extends object
|
|
151
|
+
>(
|
|
152
|
+
t: (key: string, params?: Record<string, string | number>) => string,
|
|
153
|
+
namespace: Namespace
|
|
154
|
+
): <K extends import('./types').PathKeys<T>>(
|
|
155
|
+
key: K,
|
|
156
|
+
params?: Record<string, string | number>
|
|
157
|
+
) => string {
|
|
158
|
+
return (key, params) => t(`${namespace}.${key}`, params);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Type helper for creating extension key types
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* // In ext-leads/src/i18n/types.ts
|
|
167
|
+
* import type { CreateExtensionKeys } from '@djangocfg/ext-base/i18n';
|
|
168
|
+
*
|
|
169
|
+
* export interface LeadsTranslations {
|
|
170
|
+
* form: { title: string; submit: string }
|
|
171
|
+
* success: { title: string }
|
|
172
|
+
* }
|
|
173
|
+
*
|
|
174
|
+
* // Type of all valid keys: "leads.form.title" | "leads.form.submit" | "leads.success.title"
|
|
175
|
+
* export type LeadsKeys = CreateExtensionKeys<'leads', LeadsTranslations>;
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
export type CreateExtensionKeys<
|
|
179
|
+
Namespace extends string,
|
|
180
|
+
T extends object
|
|
181
|
+
> = ExtensionKeys<Namespace, T>;
|