@djangocfg/ext-newsletter 1.0.22 → 1.0.23
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/config.cjs +3 -1
- package/dist/config.js +3 -1
- package/dist/hooks.cjs +27 -13
- package/dist/hooks.js +28 -14
- package/dist/i18n.cjs +35 -15
- package/dist/i18n.d.cts +27 -14
- package/dist/i18n.d.ts +27 -14
- package/dist/i18n.js +31 -13
- package/dist/index.cjs +3 -1
- package/dist/index.js +3 -1
- package/package.json +11 -9
- package/src/components/Hero/index.tsx +2 -8
- package/src/i18n/index.ts +20 -17
- package/src/i18n/types.ts +11 -5
- package/src/i18n/useNewsletterT.ts +60 -0
package/dist/config.cjs
CHANGED
|
@@ -27,7 +27,7 @@ var import_ext_base = require("@djangocfg/ext-base");
|
|
|
27
27
|
// package.json
|
|
28
28
|
var package_default = {
|
|
29
29
|
name: "@djangocfg/ext-newsletter",
|
|
30
|
-
version: "1.0.
|
|
30
|
+
version: "1.0.23",
|
|
31
31
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
32
32
|
keywords: [
|
|
33
33
|
"django",
|
|
@@ -98,6 +98,7 @@ var package_default = {
|
|
|
98
98
|
consola: "^3.4.2",
|
|
99
99
|
"lucide-react": "^0.545.0",
|
|
100
100
|
next: "^16",
|
|
101
|
+
"next-intl": "^4",
|
|
101
102
|
"p-retry": "^7.0.0",
|
|
102
103
|
react: "^19",
|
|
103
104
|
"react-dom": "^19",
|
|
@@ -112,6 +113,7 @@ var package_default = {
|
|
|
112
113
|
"@types/node": "^24.7.2",
|
|
113
114
|
"@types/react": "^19.0.0",
|
|
114
115
|
consola: "^3.4.2",
|
|
116
|
+
"next-intl": "^4.1.0",
|
|
115
117
|
"p-retry": "^7.0.0",
|
|
116
118
|
swr: "^2.3.7",
|
|
117
119
|
tsup: "^8.5.0",
|
package/dist/config.js
CHANGED
|
@@ -4,7 +4,7 @@ import { createExtensionConfig } from "@djangocfg/ext-base";
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "@djangocfg/ext-newsletter",
|
|
7
|
-
version: "1.0.
|
|
7
|
+
version: "1.0.23",
|
|
8
8
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
9
9
|
keywords: [
|
|
10
10
|
"django",
|
|
@@ -75,6 +75,7 @@ var package_default = {
|
|
|
75
75
|
consola: "^3.4.2",
|
|
76
76
|
"lucide-react": "^0.545.0",
|
|
77
77
|
next: "^16",
|
|
78
|
+
"next-intl": "^4",
|
|
78
79
|
"p-retry": "^7.0.0",
|
|
79
80
|
react: "^19",
|
|
80
81
|
"react-dom": "^19",
|
|
@@ -89,6 +90,7 @@ var package_default = {
|
|
|
89
90
|
"@types/node": "^24.7.2",
|
|
90
91
|
"@types/react": "^19.0.0",
|
|
91
92
|
consola: "^3.4.2",
|
|
93
|
+
"next-intl": "^4.1.0",
|
|
92
94
|
"p-retry": "^7.0.0",
|
|
93
95
|
swr: "^2.3.7",
|
|
94
96
|
tsup: "^8.5.0",
|
package/dist/hooks.cjs
CHANGED
|
@@ -10,8 +10,7 @@ var react = require('react');
|
|
|
10
10
|
var hooks = require('@djangocfg/ext-base/hooks');
|
|
11
11
|
var jsxRuntime = require('react/jsx-runtime');
|
|
12
12
|
var lucideReact = require('lucide-react');
|
|
13
|
-
var
|
|
14
|
-
var i18n$1 = require('@djangocfg/i18n');
|
|
13
|
+
var nextIntl = require('next-intl');
|
|
15
14
|
var uiCore = require('@djangocfg/ui-core');
|
|
16
15
|
|
|
17
16
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -2126,7 +2125,7 @@ var apiNewsletter = api.createExtensionAPI(API);
|
|
|
2126
2125
|
// package.json
|
|
2127
2126
|
var package_default = {
|
|
2128
2127
|
name: "@djangocfg/ext-newsletter",
|
|
2129
|
-
version: "1.0.
|
|
2128
|
+
version: "1.0.23",
|
|
2130
2129
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
2131
2130
|
keywords: [
|
|
2132
2131
|
"django",
|
|
@@ -2197,6 +2196,7 @@ var package_default = {
|
|
|
2197
2196
|
consola: "^3.4.2",
|
|
2198
2197
|
"lucide-react": "^0.545.0",
|
|
2199
2198
|
next: "^16",
|
|
2199
|
+
"next-intl": "^4",
|
|
2200
2200
|
"p-retry": "^7.0.0",
|
|
2201
2201
|
react: "^19",
|
|
2202
2202
|
"react-dom": "^19",
|
|
@@ -2211,6 +2211,7 @@ var package_default = {
|
|
|
2211
2211
|
"@types/node": "^24.7.2",
|
|
2212
2212
|
"@types/react": "^19.0.0",
|
|
2213
2213
|
consola: "^3.4.2",
|
|
2214
|
+
"next-intl": "^4.1.0",
|
|
2214
2215
|
"p-retry": "^7.0.0",
|
|
2215
2216
|
swr: "^2.3.7",
|
|
2216
2217
|
tsup: "^8.5.0",
|
|
@@ -2522,14 +2523,28 @@ var ko = {
|
|
|
2522
2523
|
}
|
|
2523
2524
|
};
|
|
2524
2525
|
|
|
2525
|
-
// src/i18n/
|
|
2526
|
-
var
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2526
|
+
// src/i18n/useNewsletterT.ts
|
|
2527
|
+
var translations = { en, ru, ko };
|
|
2528
|
+
function getNestedValue(obj, path) {
|
|
2529
|
+
const keys = path.split(".");
|
|
2530
|
+
let result = obj;
|
|
2531
|
+
for (const key of keys) {
|
|
2532
|
+
if (result && typeof result === "object" && key in result) {
|
|
2533
|
+
result = result[key];
|
|
2534
|
+
} else {
|
|
2535
|
+
return path;
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
return typeof result === "string" ? result : path;
|
|
2539
|
+
}
|
|
2540
|
+
function useNewsletterT() {
|
|
2541
|
+
const locale = nextIntl.useLocale();
|
|
2542
|
+
const t = react.useMemo(() => translations[locale] || translations.en, [locale]);
|
|
2543
|
+
return react.useCallback(
|
|
2544
|
+
(key) => getNestedValue(t, key),
|
|
2545
|
+
[t]
|
|
2546
|
+
);
|
|
2547
|
+
}
|
|
2533
2548
|
var isDevelopment = process.env.NODE_ENV === "development";
|
|
2534
2549
|
var logger = consola.createConsola({
|
|
2535
2550
|
level: isDevelopment ? 4 : 1
|
|
@@ -2546,12 +2561,11 @@ function Hero({
|
|
|
2546
2561
|
onNewsletterSubmit,
|
|
2547
2562
|
className = ""
|
|
2548
2563
|
}) {
|
|
2549
|
-
const
|
|
2564
|
+
const nt = useNewsletterT();
|
|
2550
2565
|
const [email, setEmail] = react.useState("");
|
|
2551
2566
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
2552
2567
|
const [status, setStatus] = react.useState("idle");
|
|
2553
2568
|
const [message, setMessage] = react.useState("");
|
|
2554
|
-
const nt = i18n.createTypedExtensionT(baseT, NEWSLETTER_NAMESPACE);
|
|
2555
2569
|
const labels = react.useMemo(() => ({
|
|
2556
2570
|
placeholder: newsletterPlaceholder ?? nt("hero.placeholder"),
|
|
2557
2571
|
subscribe: newsletterButtonText ?? nt("hero.subscribe"),
|
package/dist/hooks.js
CHANGED
|
@@ -4,12 +4,11 @@ import { z } from 'zod';
|
|
|
4
4
|
import { initializeExtensionAPI, createExtensionAPI } from '@djangocfg/ext-base/api';
|
|
5
5
|
import { createExtensionConfig } from '@djangocfg/ext-base';
|
|
6
6
|
import useSWR, { useSWRConfig } from 'swr';
|
|
7
|
-
import { createContext, useContext, useState, useMemo } from 'react';
|
|
7
|
+
import { createContext, useContext, useState, useMemo, useCallback } from 'react';
|
|
8
8
|
import { ExtensionProvider } from '@djangocfg/ext-base/hooks';
|
|
9
9
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
10
10
|
import { Mail, Loader2, CheckCircle2, AlertCircle } from 'lucide-react';
|
|
11
|
-
import {
|
|
12
|
-
import { useT } from '@djangocfg/i18n';
|
|
11
|
+
import { useLocale } from 'next-intl';
|
|
13
12
|
import { Button, Input } from '@djangocfg/ui-core';
|
|
14
13
|
|
|
15
14
|
var __defProp = Object.defineProperty;
|
|
@@ -2119,7 +2118,7 @@ var apiNewsletter = createExtensionAPI(API);
|
|
|
2119
2118
|
// package.json
|
|
2120
2119
|
var package_default = {
|
|
2121
2120
|
name: "@djangocfg/ext-newsletter",
|
|
2122
|
-
version: "1.0.
|
|
2121
|
+
version: "1.0.23",
|
|
2123
2122
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
2124
2123
|
keywords: [
|
|
2125
2124
|
"django",
|
|
@@ -2190,6 +2189,7 @@ var package_default = {
|
|
|
2190
2189
|
consola: "^3.4.2",
|
|
2191
2190
|
"lucide-react": "^0.545.0",
|
|
2192
2191
|
next: "^16",
|
|
2192
|
+
"next-intl": "^4",
|
|
2193
2193
|
"p-retry": "^7.0.0",
|
|
2194
2194
|
react: "^19",
|
|
2195
2195
|
"react-dom": "^19",
|
|
@@ -2204,6 +2204,7 @@ var package_default = {
|
|
|
2204
2204
|
"@types/node": "^24.7.2",
|
|
2205
2205
|
"@types/react": "^19.0.0",
|
|
2206
2206
|
consola: "^3.4.2",
|
|
2207
|
+
"next-intl": "^4.1.0",
|
|
2207
2208
|
"p-retry": "^7.0.0",
|
|
2208
2209
|
swr: "^2.3.7",
|
|
2209
2210
|
tsup: "^8.5.0",
|
|
@@ -2515,14 +2516,28 @@ var ko = {
|
|
|
2515
2516
|
}
|
|
2516
2517
|
};
|
|
2517
2518
|
|
|
2518
|
-
// src/i18n/
|
|
2519
|
-
var
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2519
|
+
// src/i18n/useNewsletterT.ts
|
|
2520
|
+
var translations = { en, ru, ko };
|
|
2521
|
+
function getNestedValue(obj, path) {
|
|
2522
|
+
const keys = path.split(".");
|
|
2523
|
+
let result = obj;
|
|
2524
|
+
for (const key of keys) {
|
|
2525
|
+
if (result && typeof result === "object" && key in result) {
|
|
2526
|
+
result = result[key];
|
|
2527
|
+
} else {
|
|
2528
|
+
return path;
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
return typeof result === "string" ? result : path;
|
|
2532
|
+
}
|
|
2533
|
+
function useNewsletterT() {
|
|
2534
|
+
const locale = useLocale();
|
|
2535
|
+
const t = useMemo(() => translations[locale] || translations.en, [locale]);
|
|
2536
|
+
return useCallback(
|
|
2537
|
+
(key) => getNestedValue(t, key),
|
|
2538
|
+
[t]
|
|
2539
|
+
);
|
|
2540
|
+
}
|
|
2526
2541
|
var isDevelopment = process.env.NODE_ENV === "development";
|
|
2527
2542
|
var logger = createConsola({
|
|
2528
2543
|
level: isDevelopment ? 4 : 1
|
|
@@ -2539,12 +2554,11 @@ function Hero({
|
|
|
2539
2554
|
onNewsletterSubmit,
|
|
2540
2555
|
className = ""
|
|
2541
2556
|
}) {
|
|
2542
|
-
const
|
|
2557
|
+
const nt = useNewsletterT();
|
|
2543
2558
|
const [email, setEmail] = useState("");
|
|
2544
2559
|
const [isLoading, setIsLoading] = useState(false);
|
|
2545
2560
|
const [status, setStatus] = useState("idle");
|
|
2546
2561
|
const [message, setMessage] = useState("");
|
|
2547
|
-
const nt = createTypedExtensionT(baseT, NEWSLETTER_NAMESPACE);
|
|
2548
2562
|
const labels = useMemo(() => ({
|
|
2549
2563
|
placeholder: newsletterPlaceholder ?? nt("hero.placeholder"),
|
|
2550
2564
|
subscribe: newsletterButtonText ?? nt("hero.subscribe"),
|
package/dist/i18n.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -19,12 +20,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
20
|
// src/i18n/index.ts
|
|
20
21
|
var i18n_exports = {};
|
|
21
22
|
__export(i18n_exports, {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
en: () => en,
|
|
24
|
+
ko: () => ko,
|
|
25
|
+
ru: () => ru,
|
|
26
|
+
useNewsletterT: () => useNewsletterT
|
|
25
27
|
});
|
|
26
28
|
module.exports = __toCommonJS(i18n_exports);
|
|
27
|
-
|
|
29
|
+
|
|
30
|
+
// src/i18n/useNewsletterT.ts
|
|
31
|
+
var import_next_intl = require("next-intl");
|
|
32
|
+
var import_react = require("react");
|
|
28
33
|
|
|
29
34
|
// src/i18n/locales/en.ts
|
|
30
35
|
var en = {
|
|
@@ -62,17 +67,32 @@ var ko = {
|
|
|
62
67
|
}
|
|
63
68
|
};
|
|
64
69
|
|
|
65
|
-
// src/i18n/
|
|
66
|
-
var
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
// src/i18n/useNewsletterT.ts
|
|
71
|
+
var translations = { en, ru, ko };
|
|
72
|
+
function getNestedValue(obj, path) {
|
|
73
|
+
const keys = path.split(".");
|
|
74
|
+
let result = obj;
|
|
75
|
+
for (const key of keys) {
|
|
76
|
+
if (result && typeof result === "object" && key in result) {
|
|
77
|
+
result = result[key];
|
|
78
|
+
} else {
|
|
79
|
+
return path;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return typeof result === "string" ? result : path;
|
|
83
|
+
}
|
|
84
|
+
function useNewsletterT() {
|
|
85
|
+
const locale = (0, import_next_intl.useLocale)();
|
|
86
|
+
const t = (0, import_react.useMemo)(() => translations[locale] || translations.en, [locale]);
|
|
87
|
+
return (0, import_react.useCallback)(
|
|
88
|
+
(key) => getNestedValue(t, key),
|
|
89
|
+
[t]
|
|
90
|
+
);
|
|
91
|
+
}
|
|
73
92
|
// Annotate the CommonJS export names for ESM import in node:
|
|
74
93
|
0 && (module.exports = {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
94
|
+
en,
|
|
95
|
+
ko,
|
|
96
|
+
ru,
|
|
97
|
+
useNewsletterT
|
|
78
98
|
});
|
package/dist/i18n.d.cts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import * as _djangocfg_ext_base_i18n from '@djangocfg/ext-base/i18n';
|
|
2
|
-
import { ExtensionKeys, PathKeys } from '@djangocfg/ext-base/i18n';
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
* Newsletter Extension I18n Types
|
|
6
3
|
*/
|
|
7
|
-
|
|
8
4
|
/**
|
|
9
|
-
*
|
|
5
|
+
* Helper type to get dot-notation paths from nested object
|
|
10
6
|
*/
|
|
11
|
-
type
|
|
7
|
+
type PathKeys<T, Prefix extends string = ''> = T extends object ? {
|
|
8
|
+
[K in keyof T]: K extends string ? T[K] extends object ? PathKeys<T[K], `${Prefix}${K}.`> : `${Prefix}${K}` : never;
|
|
9
|
+
}[keyof T] : never;
|
|
12
10
|
/**
|
|
13
|
-
* Keys
|
|
11
|
+
* Keys for newsletter translations
|
|
14
12
|
*/
|
|
15
13
|
type NewsletterLocalKeys = PathKeys<NewsletterTranslations>;
|
|
16
14
|
interface NewsletterTranslations {
|
|
@@ -25,11 +23,26 @@ interface NewsletterTranslations {
|
|
|
25
23
|
};
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Self-contained translation hook for newsletter extension
|
|
28
|
+
*
|
|
29
|
+
* Uses built-in translations based on current locale from next-intl.
|
|
30
|
+
* No need to add translations to app's i18n config.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* function SubscribeForm() {
|
|
35
|
+
* const t = useNewsletterT();
|
|
36
|
+
* return <button>{t('hero.subscribe')}</button>;
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare function useNewsletterT(): (key: NewsletterLocalKeys) => string;
|
|
41
|
+
|
|
42
|
+
declare const en: NewsletterTranslations;
|
|
43
|
+
|
|
44
|
+
declare const ru: NewsletterTranslations;
|
|
45
|
+
|
|
46
|
+
declare const ko: NewsletterTranslations;
|
|
34
47
|
|
|
35
|
-
export {
|
|
48
|
+
export { type NewsletterLocalKeys, type NewsletterTranslations, en, ko, ru, useNewsletterT };
|
package/dist/i18n.d.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import * as _djangocfg_ext_base_i18n from '@djangocfg/ext-base/i18n';
|
|
2
|
-
import { ExtensionKeys, PathKeys } from '@djangocfg/ext-base/i18n';
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
* Newsletter Extension I18n Types
|
|
6
3
|
*/
|
|
7
|
-
|
|
8
4
|
/**
|
|
9
|
-
*
|
|
5
|
+
* Helper type to get dot-notation paths from nested object
|
|
10
6
|
*/
|
|
11
|
-
type
|
|
7
|
+
type PathKeys<T, Prefix extends string = ''> = T extends object ? {
|
|
8
|
+
[K in keyof T]: K extends string ? T[K] extends object ? PathKeys<T[K], `${Prefix}${K}.`> : `${Prefix}${K}` : never;
|
|
9
|
+
}[keyof T] : never;
|
|
12
10
|
/**
|
|
13
|
-
* Keys
|
|
11
|
+
* Keys for newsletter translations
|
|
14
12
|
*/
|
|
15
13
|
type NewsletterLocalKeys = PathKeys<NewsletterTranslations>;
|
|
16
14
|
interface NewsletterTranslations {
|
|
@@ -25,11 +23,26 @@ interface NewsletterTranslations {
|
|
|
25
23
|
};
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
/**
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Self-contained translation hook for newsletter extension
|
|
28
|
+
*
|
|
29
|
+
* Uses built-in translations based on current locale from next-intl.
|
|
30
|
+
* No need to add translations to app's i18n config.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```tsx
|
|
34
|
+
* function SubscribeForm() {
|
|
35
|
+
* const t = useNewsletterT();
|
|
36
|
+
* return <button>{t('hero.subscribe')}</button>;
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare function useNewsletterT(): (key: NewsletterLocalKeys) => string;
|
|
41
|
+
|
|
42
|
+
declare const en: NewsletterTranslations;
|
|
43
|
+
|
|
44
|
+
declare const ru: NewsletterTranslations;
|
|
45
|
+
|
|
46
|
+
declare const ko: NewsletterTranslations;
|
|
34
47
|
|
|
35
|
-
export {
|
|
48
|
+
export { type NewsletterLocalKeys, type NewsletterTranslations, en, ko, ru, useNewsletterT };
|
package/dist/i18n.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/i18n/useNewsletterT.ts
|
|
4
|
+
import { useLocale } from "next-intl";
|
|
5
|
+
import { useMemo, useCallback } from "react";
|
|
3
6
|
|
|
4
7
|
// src/i18n/locales/en.ts
|
|
5
8
|
var en = {
|
|
@@ -37,16 +40,31 @@ var ko = {
|
|
|
37
40
|
}
|
|
38
41
|
};
|
|
39
42
|
|
|
40
|
-
// src/i18n/
|
|
41
|
-
var
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
// src/i18n/useNewsletterT.ts
|
|
44
|
+
var translations = { en, ru, ko };
|
|
45
|
+
function getNestedValue(obj, path) {
|
|
46
|
+
const keys = path.split(".");
|
|
47
|
+
let result = obj;
|
|
48
|
+
for (const key of keys) {
|
|
49
|
+
if (result && typeof result === "object" && key in result) {
|
|
50
|
+
result = result[key];
|
|
51
|
+
} else {
|
|
52
|
+
return path;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return typeof result === "string" ? result : path;
|
|
56
|
+
}
|
|
57
|
+
function useNewsletterT() {
|
|
58
|
+
const locale = useLocale();
|
|
59
|
+
const t = useMemo(() => translations[locale] || translations.en, [locale]);
|
|
60
|
+
return useCallback(
|
|
61
|
+
(key) => getNestedValue(t, key),
|
|
62
|
+
[t]
|
|
63
|
+
);
|
|
64
|
+
}
|
|
48
65
|
export {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
66
|
+
en,
|
|
67
|
+
ko,
|
|
68
|
+
ru,
|
|
69
|
+
useNewsletterT
|
|
52
70
|
};
|
package/dist/index.cjs
CHANGED
|
@@ -2117,7 +2117,7 @@ var apiNewsletter = api.createExtensionAPI(API);
|
|
|
2117
2117
|
// package.json
|
|
2118
2118
|
var package_default = {
|
|
2119
2119
|
name: "@djangocfg/ext-newsletter",
|
|
2120
|
-
version: "1.0.
|
|
2120
|
+
version: "1.0.23",
|
|
2121
2121
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
2122
2122
|
keywords: [
|
|
2123
2123
|
"django",
|
|
@@ -2188,6 +2188,7 @@ var package_default = {
|
|
|
2188
2188
|
consola: "^3.4.2",
|
|
2189
2189
|
"lucide-react": "^0.545.0",
|
|
2190
2190
|
next: "^16",
|
|
2191
|
+
"next-intl": "^4",
|
|
2191
2192
|
"p-retry": "^7.0.0",
|
|
2192
2193
|
react: "^19",
|
|
2193
2194
|
"react-dom": "^19",
|
|
@@ -2202,6 +2203,7 @@ var package_default = {
|
|
|
2202
2203
|
"@types/node": "^24.7.2",
|
|
2203
2204
|
"@types/react": "^19.0.0",
|
|
2204
2205
|
consola: "^3.4.2",
|
|
2206
|
+
"next-intl": "^4.1.0",
|
|
2205
2207
|
"p-retry": "^7.0.0",
|
|
2206
2208
|
swr: "^2.3.7",
|
|
2207
2209
|
tsup: "^8.5.0",
|
package/dist/index.js
CHANGED
|
@@ -2111,7 +2111,7 @@ var apiNewsletter = createExtensionAPI(API);
|
|
|
2111
2111
|
// package.json
|
|
2112
2112
|
var package_default = {
|
|
2113
2113
|
name: "@djangocfg/ext-newsletter",
|
|
2114
|
-
version: "1.0.
|
|
2114
|
+
version: "1.0.23",
|
|
2115
2115
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
2116
2116
|
keywords: [
|
|
2117
2117
|
"django",
|
|
@@ -2182,6 +2182,7 @@ var package_default = {
|
|
|
2182
2182
|
consola: "^3.4.2",
|
|
2183
2183
|
"lucide-react": "^0.545.0",
|
|
2184
2184
|
next: "^16",
|
|
2185
|
+
"next-intl": "^4",
|
|
2185
2186
|
"p-retry": "^7.0.0",
|
|
2186
2187
|
react: "^19",
|
|
2187
2188
|
"react-dom": "^19",
|
|
@@ -2196,6 +2197,7 @@ var package_default = {
|
|
|
2196
2197
|
"@types/node": "^24.7.2",
|
|
2197
2198
|
"@types/react": "^19.0.0",
|
|
2198
2199
|
consola: "^3.4.2",
|
|
2200
|
+
"next-intl": "^4.1.0",
|
|
2199
2201
|
"p-retry": "^7.0.0",
|
|
2200
2202
|
swr: "^2.3.7",
|
|
2201
2203
|
tsup: "^8.5.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ext-newsletter",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.23",
|
|
4
4
|
"description": "Newsletter and subscription management extension for DjangoCFG",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"django",
|
|
@@ -64,13 +64,14 @@
|
|
|
64
64
|
"check": "tsc --noEmit"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@djangocfg/api": "^2.1.
|
|
68
|
-
"@djangocfg/ext-base": "^1.0.
|
|
69
|
-
"@djangocfg/i18n": "^2.1.
|
|
70
|
-
"@djangocfg/ui-core": "^2.1.
|
|
67
|
+
"@djangocfg/api": "^2.1.124",
|
|
68
|
+
"@djangocfg/ext-base": "^1.0.18",
|
|
69
|
+
"@djangocfg/i18n": "^2.1.124",
|
|
70
|
+
"@djangocfg/ui-core": "^2.1.124",
|
|
71
71
|
"consola": "^3.4.2",
|
|
72
72
|
"lucide-react": "^0.545.0",
|
|
73
73
|
"next": "^16",
|
|
74
|
+
"next-intl": "^4",
|
|
74
75
|
"p-retry": "^7.0.0",
|
|
75
76
|
"react": "^19",
|
|
76
77
|
"react-dom": "^19",
|
|
@@ -78,13 +79,14 @@
|
|
|
78
79
|
"zod": "^4.3.4"
|
|
79
80
|
},
|
|
80
81
|
"devDependencies": {
|
|
81
|
-
"@djangocfg/api": "^2.1.
|
|
82
|
-
"@djangocfg/ext-base": "^1.0.
|
|
83
|
-
"@djangocfg/i18n": "^2.1.
|
|
84
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
82
|
+
"@djangocfg/api": "^2.1.124",
|
|
83
|
+
"@djangocfg/ext-base": "^1.0.18",
|
|
84
|
+
"@djangocfg/i18n": "^2.1.124",
|
|
85
|
+
"@djangocfg/typescript-config": "^2.1.124",
|
|
85
86
|
"@types/node": "^24.7.2",
|
|
86
87
|
"@types/react": "^19.0.0",
|
|
87
88
|
"consola": "^3.4.2",
|
|
89
|
+
"next-intl": "^4.1.0",
|
|
88
90
|
"p-retry": "^7.0.0",
|
|
89
91
|
"swr": "^2.3.7",
|
|
90
92
|
"tsup": "^8.5.0",
|
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
import { AlertCircle, CheckCircle2, Loader2, Mail } from 'lucide-react';
|
|
9
9
|
import React, { useMemo, useState } from 'react';
|
|
10
10
|
|
|
11
|
-
import {
|
|
12
|
-
import { useT } from '@djangocfg/i18n';
|
|
13
|
-
import { NEWSLETTER_NAMESPACE, type NewsletterTranslations } from '../../i18n';
|
|
11
|
+
import { useNewsletterT } from '../../i18n';
|
|
14
12
|
import { Button, Input } from '@djangocfg/ui-core';
|
|
15
13
|
|
|
16
14
|
import { newsletterLogger } from '../../utils/logger';
|
|
@@ -28,16 +26,12 @@ export function Hero({
|
|
|
28
26
|
onNewsletterSubmit,
|
|
29
27
|
className = '',
|
|
30
28
|
}: HeroProps) {
|
|
31
|
-
const
|
|
29
|
+
const nt = useNewsletterT();
|
|
32
30
|
const [email, setEmail] = useState('');
|
|
33
31
|
const [isLoading, setIsLoading] = useState(false);
|
|
34
32
|
const [status, setStatus] = useState<'idle' | 'success' | 'error'>('idle');
|
|
35
33
|
const [message, setMessage] = useState('');
|
|
36
34
|
|
|
37
|
-
// Type-safe translation function for newsletter extension
|
|
38
|
-
// Keys are validated at compile time: nt('hero.placeholder') OK, nt('hero.typo') Error
|
|
39
|
-
const nt = createTypedExtensionT<typeof NEWSLETTER_NAMESPACE, NewsletterTranslations>(baseT, NEWSLETTER_NAMESPACE);
|
|
40
|
-
|
|
41
35
|
// Prepare labels before JSX render
|
|
42
36
|
const labels = useMemo(() => ({
|
|
43
37
|
placeholder: newsletterPlaceholder ?? nt('hero.placeholder'),
|
package/src/i18n/index.ts
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Newsletter Extension I18n
|
|
3
|
+
*
|
|
4
|
+
* Self-contained translations - no app configuration needed.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { useNewsletterT } from '@djangocfg/ext-newsletter/i18n';
|
|
9
|
+
*
|
|
10
|
+
* function MyComponent() {
|
|
11
|
+
* const t = useNewsletterT();
|
|
12
|
+
* return <button>{t('hero.subscribe')}</button>;
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
3
15
|
*/
|
|
4
16
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { en } from './locales/en';
|
|
8
|
-
import { ru } from './locales/ru';
|
|
9
|
-
import { ko } from './locales/ko';
|
|
10
|
-
|
|
11
|
-
/** Newsletter extension namespace */
|
|
12
|
-
export const NEWSLETTER_NAMESPACE = 'newsletter' as const;
|
|
13
|
-
|
|
14
|
-
export const newsletterI18n = createExtensionI18n<NewsletterTranslations>({
|
|
15
|
-
namespace: NEWSLETTER_NAMESPACE,
|
|
16
|
-
defaultLocale: 'en',
|
|
17
|
-
locales: { en, ru, ko },
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
export const newsletterTranslations = newsletterI18n.getAllTranslations();
|
|
17
|
+
// Self-contained hook (recommended)
|
|
18
|
+
export { useNewsletterT } from './useNewsletterT';
|
|
21
19
|
|
|
22
20
|
// Types
|
|
23
|
-
export type { NewsletterTranslations,
|
|
21
|
+
export type { NewsletterTranslations, NewsletterLocalKeys } from './types';
|
|
22
|
+
|
|
23
|
+
// Locales (for direct access if needed)
|
|
24
|
+
export { en } from './locales/en';
|
|
25
|
+
export { ru } from './locales/ru';
|
|
26
|
+
export { ko } from './locales/ko';
|
package/src/i18n/types.ts
CHANGED
|
@@ -2,15 +2,21 @@
|
|
|
2
2
|
* Newsletter Extension I18n Types
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { ExtensionKeys, PathKeys } from '@djangocfg/ext-base/i18n';
|
|
6
|
-
|
|
7
5
|
/**
|
|
8
|
-
*
|
|
6
|
+
* Helper type to get dot-notation paths from nested object
|
|
9
7
|
*/
|
|
10
|
-
|
|
8
|
+
type PathKeys<T, Prefix extends string = ''> = T extends object
|
|
9
|
+
? {
|
|
10
|
+
[K in keyof T]: K extends string
|
|
11
|
+
? T[K] extends object
|
|
12
|
+
? PathKeys<T[K], `${Prefix}${K}.`>
|
|
13
|
+
: `${Prefix}${K}`
|
|
14
|
+
: never;
|
|
15
|
+
}[keyof T]
|
|
16
|
+
: never;
|
|
11
17
|
|
|
12
18
|
/**
|
|
13
|
-
* Keys
|
|
19
|
+
* Keys for newsletter translations
|
|
14
20
|
*/
|
|
15
21
|
export type NewsletterLocalKeys = PathKeys<NewsletterTranslations>;
|
|
16
22
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Self-contained translation hook for ext-newsletter
|
|
5
|
+
*
|
|
6
|
+
* Uses built-in translations, no app configuration needed.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useLocale } from 'next-intl';
|
|
10
|
+
import { useMemo, useCallback } from 'react';
|
|
11
|
+
|
|
12
|
+
import type { NewsletterTranslations, NewsletterLocalKeys } from './types';
|
|
13
|
+
import { en } from './locales/en';
|
|
14
|
+
import { ru } from './locales/ru';
|
|
15
|
+
import { ko } from './locales/ko';
|
|
16
|
+
|
|
17
|
+
const translations: Record<string, NewsletterTranslations> = { en, ru, ko };
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get nested value from object by dot-notation path
|
|
21
|
+
*/
|
|
22
|
+
function getNestedValue(obj: Record<string, unknown>, path: string): string {
|
|
23
|
+
const keys = path.split('.');
|
|
24
|
+
let result: unknown = obj;
|
|
25
|
+
|
|
26
|
+
for (const key of keys) {
|
|
27
|
+
if (result && typeof result === 'object' && key in result) {
|
|
28
|
+
result = (result as Record<string, unknown>)[key];
|
|
29
|
+
} else {
|
|
30
|
+
return path; // Return key if not found
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return typeof result === 'string' ? result : path;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Self-contained translation hook for newsletter extension
|
|
39
|
+
*
|
|
40
|
+
* Uses built-in translations based on current locale from next-intl.
|
|
41
|
+
* No need to add translations to app's i18n config.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```tsx
|
|
45
|
+
* function SubscribeForm() {
|
|
46
|
+
* const t = useNewsletterT();
|
|
47
|
+
* return <button>{t('hero.subscribe')}</button>;
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export function useNewsletterT(): (key: NewsletterLocalKeys) => string {
|
|
52
|
+
const locale = useLocale();
|
|
53
|
+
|
|
54
|
+
const t = useMemo(() => translations[locale] || translations.en, [locale]);
|
|
55
|
+
|
|
56
|
+
return useCallback(
|
|
57
|
+
(key: NewsletterLocalKeys): string => getNestedValue(t as unknown as Record<string, unknown>, key),
|
|
58
|
+
[t]
|
|
59
|
+
);
|
|
60
|
+
}
|