@djangocfg/ext-newsletter 1.0.20 → 1.0.22
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 +8 -1
- package/dist/config.js +8 -1
- package/dist/hooks.cjs +73 -9
- package/dist/hooks.js +74 -10
- package/dist/i18n.cjs +78 -0
- package/dist/i18n.d.cts +35 -0
- package/dist/i18n.d.ts +35 -0
- package/dist/i18n.js +52 -0
- package/dist/index.cjs +8 -1
- package/dist/index.js +8 -1
- package/package.json +14 -7
- package/src/components/Hero/index.tsx +27 -9
- package/src/i18n/index.ts +23 -0
- package/src/i18n/locales/en.ts +12 -0
- package/src/i18n/locales/ko.ts +12 -0
- package/src/i18n/locales/ru.ts +12 -0
- package/src/i18n/types.ts +27 -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.22",
|
|
31
31
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
32
32
|
keywords: [
|
|
33
33
|
"django",
|
|
@@ -73,6 +73,11 @@ var package_default = {
|
|
|
73
73
|
types: "./dist/config.d.ts",
|
|
74
74
|
import: "./dist/config.js",
|
|
75
75
|
require: "./dist/config.cjs"
|
|
76
|
+
},
|
|
77
|
+
"./i18n": {
|
|
78
|
+
types: "./dist/i18n.d.ts",
|
|
79
|
+
import: "./dist/i18n.js",
|
|
80
|
+
require: "./dist/i18n.cjs"
|
|
76
81
|
}
|
|
77
82
|
},
|
|
78
83
|
files: [
|
|
@@ -88,6 +93,7 @@ var package_default = {
|
|
|
88
93
|
peerDependencies: {
|
|
89
94
|
"@djangocfg/api": "workspace:*",
|
|
90
95
|
"@djangocfg/ext-base": "workspace:*",
|
|
96
|
+
"@djangocfg/i18n": "workspace:*",
|
|
91
97
|
"@djangocfg/ui-core": "workspace:*",
|
|
92
98
|
consola: "^3.4.2",
|
|
93
99
|
"lucide-react": "^0.545.0",
|
|
@@ -101,6 +107,7 @@ var package_default = {
|
|
|
101
107
|
devDependencies: {
|
|
102
108
|
"@djangocfg/api": "workspace:*",
|
|
103
109
|
"@djangocfg/ext-base": "workspace:*",
|
|
110
|
+
"@djangocfg/i18n": "workspace:*",
|
|
104
111
|
"@djangocfg/typescript-config": "workspace:*",
|
|
105
112
|
"@types/node": "^24.7.2",
|
|
106
113
|
"@types/react": "^19.0.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.22",
|
|
8
8
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
9
9
|
keywords: [
|
|
10
10
|
"django",
|
|
@@ -50,6 +50,11 @@ var package_default = {
|
|
|
50
50
|
types: "./dist/config.d.ts",
|
|
51
51
|
import: "./dist/config.js",
|
|
52
52
|
require: "./dist/config.cjs"
|
|
53
|
+
},
|
|
54
|
+
"./i18n": {
|
|
55
|
+
types: "./dist/i18n.d.ts",
|
|
56
|
+
import: "./dist/i18n.js",
|
|
57
|
+
require: "./dist/i18n.cjs"
|
|
53
58
|
}
|
|
54
59
|
},
|
|
55
60
|
files: [
|
|
@@ -65,6 +70,7 @@ var package_default = {
|
|
|
65
70
|
peerDependencies: {
|
|
66
71
|
"@djangocfg/api": "workspace:*",
|
|
67
72
|
"@djangocfg/ext-base": "workspace:*",
|
|
73
|
+
"@djangocfg/i18n": "workspace:*",
|
|
68
74
|
"@djangocfg/ui-core": "workspace:*",
|
|
69
75
|
consola: "^3.4.2",
|
|
70
76
|
"lucide-react": "^0.545.0",
|
|
@@ -78,6 +84,7 @@ var package_default = {
|
|
|
78
84
|
devDependencies: {
|
|
79
85
|
"@djangocfg/api": "workspace:*",
|
|
80
86
|
"@djangocfg/ext-base": "workspace:*",
|
|
87
|
+
"@djangocfg/i18n": "workspace:*",
|
|
81
88
|
"@djangocfg/typescript-config": "workspace:*",
|
|
82
89
|
"@types/node": "^24.7.2",
|
|
83
90
|
"@types/react": "^19.0.0",
|
package/dist/hooks.cjs
CHANGED
|
@@ -10,6 +10,8 @@ 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 i18n = require('@djangocfg/ext-base/i18n');
|
|
14
|
+
var i18n$1 = require('@djangocfg/i18n');
|
|
13
15
|
var uiCore = require('@djangocfg/ui-core');
|
|
14
16
|
|
|
15
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -2124,7 +2126,7 @@ var apiNewsletter = api.createExtensionAPI(API);
|
|
|
2124
2126
|
// package.json
|
|
2125
2127
|
var package_default = {
|
|
2126
2128
|
name: "@djangocfg/ext-newsletter",
|
|
2127
|
-
version: "1.0.
|
|
2129
|
+
version: "1.0.22",
|
|
2128
2130
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
2129
2131
|
keywords: [
|
|
2130
2132
|
"django",
|
|
@@ -2170,6 +2172,11 @@ var package_default = {
|
|
|
2170
2172
|
types: "./dist/config.d.ts",
|
|
2171
2173
|
import: "./dist/config.js",
|
|
2172
2174
|
require: "./dist/config.cjs"
|
|
2175
|
+
},
|
|
2176
|
+
"./i18n": {
|
|
2177
|
+
types: "./dist/i18n.d.ts",
|
|
2178
|
+
import: "./dist/i18n.js",
|
|
2179
|
+
require: "./dist/i18n.cjs"
|
|
2173
2180
|
}
|
|
2174
2181
|
},
|
|
2175
2182
|
files: [
|
|
@@ -2185,6 +2192,7 @@ var package_default = {
|
|
|
2185
2192
|
peerDependencies: {
|
|
2186
2193
|
"@djangocfg/api": "workspace:*",
|
|
2187
2194
|
"@djangocfg/ext-base": "workspace:*",
|
|
2195
|
+
"@djangocfg/i18n": "workspace:*",
|
|
2188
2196
|
"@djangocfg/ui-core": "workspace:*",
|
|
2189
2197
|
consola: "^3.4.2",
|
|
2190
2198
|
"lucide-react": "^0.545.0",
|
|
@@ -2198,6 +2206,7 @@ var package_default = {
|
|
|
2198
2206
|
devDependencies: {
|
|
2199
2207
|
"@djangocfg/api": "workspace:*",
|
|
2200
2208
|
"@djangocfg/ext-base": "workspace:*",
|
|
2209
|
+
"@djangocfg/i18n": "workspace:*",
|
|
2201
2210
|
"@djangocfg/typescript-config": "workspace:*",
|
|
2202
2211
|
"@types/node": "^24.7.2",
|
|
2203
2212
|
"@types/react": "^19.0.0",
|
|
@@ -2476,6 +2485,51 @@ function useNewsletterContext() {
|
|
|
2476
2485
|
}
|
|
2477
2486
|
return context;
|
|
2478
2487
|
}
|
|
2488
|
+
|
|
2489
|
+
// src/i18n/locales/en.ts
|
|
2490
|
+
var en = {
|
|
2491
|
+
hero: {
|
|
2492
|
+
placeholder: "Enter your email",
|
|
2493
|
+
subscribe: "Subscribe",
|
|
2494
|
+
subscribing: "Subscribing...",
|
|
2495
|
+
successMessage: "Successfully subscribed!",
|
|
2496
|
+
errorMessage: "Subscription failed. Please try again.",
|
|
2497
|
+
privacyNotice: "By subscribing, you agree to our Privacy Policy and consent to receive updates."
|
|
2498
|
+
}
|
|
2499
|
+
};
|
|
2500
|
+
|
|
2501
|
+
// src/i18n/locales/ru.ts
|
|
2502
|
+
var ru = {
|
|
2503
|
+
hero: {
|
|
2504
|
+
placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 email",
|
|
2505
|
+
subscribe: "\u041F\u043E\u0434\u043F\u0438\u0441\u0430\u0442\u044C\u0441\u044F",
|
|
2506
|
+
subscribing: "\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430...",
|
|
2507
|
+
successMessage: "\u0412\u044B \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043B\u0438\u0441\u044C!",
|
|
2508
|
+
errorMessage: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u0442\u044C\u0441\u044F. \u041F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437.",
|
|
2509
|
+
privacyNotice: "\u041F\u043E\u0434\u043F\u0438\u0441\u044B\u0432\u0430\u044F\u0441\u044C, \u0432\u044B \u0441\u043E\u0433\u043B\u0430\u0448\u0430\u0435\u0442\u0435\u0441\u044C \u0441 \u041F\u043E\u043B\u0438\u0442\u0438\u043A\u043E\u0439 \u043A\u043E\u043D\u0444\u0438\u0434\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E\u0441\u0442\u0438 \u0438 \u0434\u0430\u0451\u0442\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u043D\u0430 \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0439."
|
|
2510
|
+
}
|
|
2511
|
+
};
|
|
2512
|
+
|
|
2513
|
+
// src/i18n/locales/ko.ts
|
|
2514
|
+
var ko = {
|
|
2515
|
+
hero: {
|
|
2516
|
+
placeholder: "\uC774\uBA54\uC77C\uC744 \uC785\uB825\uD558\uC138\uC694",
|
|
2517
|
+
subscribe: "\uAD6C\uB3C5\uD558\uAE30",
|
|
2518
|
+
subscribing: "\uAD6C\uB3C5 \uC911...",
|
|
2519
|
+
successMessage: "\uC131\uACF5\uC801\uC73C\uB85C \uAD6C\uB3C5\uB418\uC5C8\uC2B5\uB2C8\uB2E4!",
|
|
2520
|
+
errorMessage: "\uAD6C\uB3C5\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694.",
|
|
2521
|
+
privacyNotice: "\uAD6C\uB3C5 \uC2DC \uAC1C\uC778\uC815\uBCF4 \uCC98\uB9AC\uBC29\uCE68\uC5D0 \uB3D9\uC758\uD558\uACE0 \uC5C5\uB370\uC774\uD2B8 \uC218\uC2E0\uC5D0 \uB3D9\uC758\uD558\uB294 \uAC83\uC73C\uB85C \uAC04\uC8FC\uB429\uB2C8\uB2E4."
|
|
2522
|
+
}
|
|
2523
|
+
};
|
|
2524
|
+
|
|
2525
|
+
// src/i18n/index.ts
|
|
2526
|
+
var NEWSLETTER_NAMESPACE = "newsletter";
|
|
2527
|
+
var newsletterI18n = i18n.createExtensionI18n({
|
|
2528
|
+
namespace: NEWSLETTER_NAMESPACE,
|
|
2529
|
+
defaultLocale: "en",
|
|
2530
|
+
locales: { en, ru, ko }
|
|
2531
|
+
});
|
|
2532
|
+
newsletterI18n.getAllTranslations();
|
|
2479
2533
|
var isDevelopment = process.env.NODE_ENV === "development";
|
|
2480
2534
|
var logger = consola.createConsola({
|
|
2481
2535
|
level: isDevelopment ? 4 : 1
|
|
@@ -2487,15 +2541,25 @@ function Hero({
|
|
|
2487
2541
|
primaryAction,
|
|
2488
2542
|
secondaryAction,
|
|
2489
2543
|
showNewsletter = true,
|
|
2490
|
-
newsletterPlaceholder
|
|
2491
|
-
newsletterButtonText
|
|
2544
|
+
newsletterPlaceholder,
|
|
2545
|
+
newsletterButtonText,
|
|
2492
2546
|
onNewsletterSubmit,
|
|
2493
2547
|
className = ""
|
|
2494
2548
|
}) {
|
|
2549
|
+
const baseT = i18n$1.useT();
|
|
2495
2550
|
const [email, setEmail] = react.useState("");
|
|
2496
2551
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
2497
2552
|
const [status, setStatus] = react.useState("idle");
|
|
2498
2553
|
const [message, setMessage] = react.useState("");
|
|
2554
|
+
const nt = i18n.createTypedExtensionT(baseT, NEWSLETTER_NAMESPACE);
|
|
2555
|
+
const labels = react.useMemo(() => ({
|
|
2556
|
+
placeholder: newsletterPlaceholder ?? nt("hero.placeholder"),
|
|
2557
|
+
subscribe: newsletterButtonText ?? nt("hero.subscribe"),
|
|
2558
|
+
subscribing: nt("hero.subscribing"),
|
|
2559
|
+
successMessage: nt("hero.successMessage"),
|
|
2560
|
+
errorMessage: nt("hero.errorMessage"),
|
|
2561
|
+
privacyNotice: nt("hero.privacyNotice")
|
|
2562
|
+
}), [nt, newsletterPlaceholder, newsletterButtonText]);
|
|
2499
2563
|
const handleSubmit = async (e) => {
|
|
2500
2564
|
e.preventDefault();
|
|
2501
2565
|
if (!email || !onNewsletterSubmit) return;
|
|
@@ -2505,12 +2569,12 @@ function Hero({
|
|
|
2505
2569
|
try {
|
|
2506
2570
|
const result = await onNewsletterSubmit(email);
|
|
2507
2571
|
setStatus("success");
|
|
2508
|
-
setMessage((result && "message" in result ? result.message : void 0) ||
|
|
2572
|
+
setMessage((result && "message" in result ? result.message : void 0) || labels.successMessage);
|
|
2509
2573
|
setEmail("");
|
|
2510
2574
|
newsletterLogger.success("Newsletter subscription successful:", email);
|
|
2511
2575
|
} catch (error) {
|
|
2512
2576
|
setStatus("error");
|
|
2513
|
-
setMessage(error instanceof Error ? error.message :
|
|
2577
|
+
setMessage(error instanceof Error ? error.message : labels.errorMessage);
|
|
2514
2578
|
newsletterLogger.error("Newsletter subscription failed:", error);
|
|
2515
2579
|
} finally {
|
|
2516
2580
|
setIsLoading(false);
|
|
@@ -2553,7 +2617,7 @@ function Hero({
|
|
|
2553
2617
|
uiCore.Input,
|
|
2554
2618
|
{
|
|
2555
2619
|
type: "email",
|
|
2556
|
-
placeholder:
|
|
2620
|
+
placeholder: labels.placeholder,
|
|
2557
2621
|
value: email,
|
|
2558
2622
|
onChange: (e) => setEmail(e.target.value),
|
|
2559
2623
|
disabled: isLoading,
|
|
@@ -2570,8 +2634,8 @@ function Hero({
|
|
|
2570
2634
|
className: "w-full sm:w-auto",
|
|
2571
2635
|
children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2572
2636
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
2573
|
-
|
|
2574
|
-
] }) :
|
|
2637
|
+
labels.subscribing
|
|
2638
|
+
] }) : labels.subscribe
|
|
2575
2639
|
}
|
|
2576
2640
|
)
|
|
2577
2641
|
] }),
|
|
@@ -2584,7 +2648,7 @@ function Hero({
|
|
|
2584
2648
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: message })
|
|
2585
2649
|
] })
|
|
2586
2650
|
] }),
|
|
2587
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-3", children:
|
|
2651
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-3", children: labels.privacyNotice })
|
|
2588
2652
|
] })
|
|
2589
2653
|
] }) }) });
|
|
2590
2654
|
}
|
package/dist/hooks.js
CHANGED
|
@@ -4,10 +4,12 @@ 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 } from 'react';
|
|
7
|
+
import { createContext, useContext, useState, useMemo } 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 { createExtensionI18n, createTypedExtensionT } from '@djangocfg/ext-base/i18n';
|
|
12
|
+
import { useT } from '@djangocfg/i18n';
|
|
11
13
|
import { Button, Input } from '@djangocfg/ui-core';
|
|
12
14
|
|
|
13
15
|
var __defProp = Object.defineProperty;
|
|
@@ -2117,7 +2119,7 @@ var apiNewsletter = createExtensionAPI(API);
|
|
|
2117
2119
|
// package.json
|
|
2118
2120
|
var package_default = {
|
|
2119
2121
|
name: "@djangocfg/ext-newsletter",
|
|
2120
|
-
version: "1.0.
|
|
2122
|
+
version: "1.0.22",
|
|
2121
2123
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
2122
2124
|
keywords: [
|
|
2123
2125
|
"django",
|
|
@@ -2163,6 +2165,11 @@ var package_default = {
|
|
|
2163
2165
|
types: "./dist/config.d.ts",
|
|
2164
2166
|
import: "./dist/config.js",
|
|
2165
2167
|
require: "./dist/config.cjs"
|
|
2168
|
+
},
|
|
2169
|
+
"./i18n": {
|
|
2170
|
+
types: "./dist/i18n.d.ts",
|
|
2171
|
+
import: "./dist/i18n.js",
|
|
2172
|
+
require: "./dist/i18n.cjs"
|
|
2166
2173
|
}
|
|
2167
2174
|
},
|
|
2168
2175
|
files: [
|
|
@@ -2178,6 +2185,7 @@ var package_default = {
|
|
|
2178
2185
|
peerDependencies: {
|
|
2179
2186
|
"@djangocfg/api": "workspace:*",
|
|
2180
2187
|
"@djangocfg/ext-base": "workspace:*",
|
|
2188
|
+
"@djangocfg/i18n": "workspace:*",
|
|
2181
2189
|
"@djangocfg/ui-core": "workspace:*",
|
|
2182
2190
|
consola: "^3.4.2",
|
|
2183
2191
|
"lucide-react": "^0.545.0",
|
|
@@ -2191,6 +2199,7 @@ var package_default = {
|
|
|
2191
2199
|
devDependencies: {
|
|
2192
2200
|
"@djangocfg/api": "workspace:*",
|
|
2193
2201
|
"@djangocfg/ext-base": "workspace:*",
|
|
2202
|
+
"@djangocfg/i18n": "workspace:*",
|
|
2194
2203
|
"@djangocfg/typescript-config": "workspace:*",
|
|
2195
2204
|
"@types/node": "^24.7.2",
|
|
2196
2205
|
"@types/react": "^19.0.0",
|
|
@@ -2469,6 +2478,51 @@ function useNewsletterContext() {
|
|
|
2469
2478
|
}
|
|
2470
2479
|
return context;
|
|
2471
2480
|
}
|
|
2481
|
+
|
|
2482
|
+
// src/i18n/locales/en.ts
|
|
2483
|
+
var en = {
|
|
2484
|
+
hero: {
|
|
2485
|
+
placeholder: "Enter your email",
|
|
2486
|
+
subscribe: "Subscribe",
|
|
2487
|
+
subscribing: "Subscribing...",
|
|
2488
|
+
successMessage: "Successfully subscribed!",
|
|
2489
|
+
errorMessage: "Subscription failed. Please try again.",
|
|
2490
|
+
privacyNotice: "By subscribing, you agree to our Privacy Policy and consent to receive updates."
|
|
2491
|
+
}
|
|
2492
|
+
};
|
|
2493
|
+
|
|
2494
|
+
// src/i18n/locales/ru.ts
|
|
2495
|
+
var ru = {
|
|
2496
|
+
hero: {
|
|
2497
|
+
placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 email",
|
|
2498
|
+
subscribe: "\u041F\u043E\u0434\u043F\u0438\u0441\u0430\u0442\u044C\u0441\u044F",
|
|
2499
|
+
subscribing: "\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430...",
|
|
2500
|
+
successMessage: "\u0412\u044B \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043B\u0438\u0441\u044C!",
|
|
2501
|
+
errorMessage: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u0442\u044C\u0441\u044F. \u041F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437.",
|
|
2502
|
+
privacyNotice: "\u041F\u043E\u0434\u043F\u0438\u0441\u044B\u0432\u0430\u044F\u0441\u044C, \u0432\u044B \u0441\u043E\u0433\u043B\u0430\u0448\u0430\u0435\u0442\u0435\u0441\u044C \u0441 \u041F\u043E\u043B\u0438\u0442\u0438\u043A\u043E\u0439 \u043A\u043E\u043D\u0444\u0438\u0434\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E\u0441\u0442\u0438 \u0438 \u0434\u0430\u0451\u0442\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u043D\u0430 \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0439."
|
|
2503
|
+
}
|
|
2504
|
+
};
|
|
2505
|
+
|
|
2506
|
+
// src/i18n/locales/ko.ts
|
|
2507
|
+
var ko = {
|
|
2508
|
+
hero: {
|
|
2509
|
+
placeholder: "\uC774\uBA54\uC77C\uC744 \uC785\uB825\uD558\uC138\uC694",
|
|
2510
|
+
subscribe: "\uAD6C\uB3C5\uD558\uAE30",
|
|
2511
|
+
subscribing: "\uAD6C\uB3C5 \uC911...",
|
|
2512
|
+
successMessage: "\uC131\uACF5\uC801\uC73C\uB85C \uAD6C\uB3C5\uB418\uC5C8\uC2B5\uB2C8\uB2E4!",
|
|
2513
|
+
errorMessage: "\uAD6C\uB3C5\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694.",
|
|
2514
|
+
privacyNotice: "\uAD6C\uB3C5 \uC2DC \uAC1C\uC778\uC815\uBCF4 \uCC98\uB9AC\uBC29\uCE68\uC5D0 \uB3D9\uC758\uD558\uACE0 \uC5C5\uB370\uC774\uD2B8 \uC218\uC2E0\uC5D0 \uB3D9\uC758\uD558\uB294 \uAC83\uC73C\uB85C \uAC04\uC8FC\uB429\uB2C8\uB2E4."
|
|
2515
|
+
}
|
|
2516
|
+
};
|
|
2517
|
+
|
|
2518
|
+
// src/i18n/index.ts
|
|
2519
|
+
var NEWSLETTER_NAMESPACE = "newsletter";
|
|
2520
|
+
var newsletterI18n = createExtensionI18n({
|
|
2521
|
+
namespace: NEWSLETTER_NAMESPACE,
|
|
2522
|
+
defaultLocale: "en",
|
|
2523
|
+
locales: { en, ru, ko }
|
|
2524
|
+
});
|
|
2525
|
+
newsletterI18n.getAllTranslations();
|
|
2472
2526
|
var isDevelopment = process.env.NODE_ENV === "development";
|
|
2473
2527
|
var logger = createConsola({
|
|
2474
2528
|
level: isDevelopment ? 4 : 1
|
|
@@ -2480,15 +2534,25 @@ function Hero({
|
|
|
2480
2534
|
primaryAction,
|
|
2481
2535
|
secondaryAction,
|
|
2482
2536
|
showNewsletter = true,
|
|
2483
|
-
newsletterPlaceholder
|
|
2484
|
-
newsletterButtonText
|
|
2537
|
+
newsletterPlaceholder,
|
|
2538
|
+
newsletterButtonText,
|
|
2485
2539
|
onNewsletterSubmit,
|
|
2486
2540
|
className = ""
|
|
2487
2541
|
}) {
|
|
2542
|
+
const baseT = useT();
|
|
2488
2543
|
const [email, setEmail] = useState("");
|
|
2489
2544
|
const [isLoading, setIsLoading] = useState(false);
|
|
2490
2545
|
const [status, setStatus] = useState("idle");
|
|
2491
2546
|
const [message, setMessage] = useState("");
|
|
2547
|
+
const nt = createTypedExtensionT(baseT, NEWSLETTER_NAMESPACE);
|
|
2548
|
+
const labels = useMemo(() => ({
|
|
2549
|
+
placeholder: newsletterPlaceholder ?? nt("hero.placeholder"),
|
|
2550
|
+
subscribe: newsletterButtonText ?? nt("hero.subscribe"),
|
|
2551
|
+
subscribing: nt("hero.subscribing"),
|
|
2552
|
+
successMessage: nt("hero.successMessage"),
|
|
2553
|
+
errorMessage: nt("hero.errorMessage"),
|
|
2554
|
+
privacyNotice: nt("hero.privacyNotice")
|
|
2555
|
+
}), [nt, newsletterPlaceholder, newsletterButtonText]);
|
|
2492
2556
|
const handleSubmit = async (e) => {
|
|
2493
2557
|
e.preventDefault();
|
|
2494
2558
|
if (!email || !onNewsletterSubmit) return;
|
|
@@ -2498,12 +2562,12 @@ function Hero({
|
|
|
2498
2562
|
try {
|
|
2499
2563
|
const result = await onNewsletterSubmit(email);
|
|
2500
2564
|
setStatus("success");
|
|
2501
|
-
setMessage((result && "message" in result ? result.message : void 0) ||
|
|
2565
|
+
setMessage((result && "message" in result ? result.message : void 0) || labels.successMessage);
|
|
2502
2566
|
setEmail("");
|
|
2503
2567
|
newsletterLogger.success("Newsletter subscription successful:", email);
|
|
2504
2568
|
} catch (error) {
|
|
2505
2569
|
setStatus("error");
|
|
2506
|
-
setMessage(error instanceof Error ? error.message :
|
|
2570
|
+
setMessage(error instanceof Error ? error.message : labels.errorMessage);
|
|
2507
2571
|
newsletterLogger.error("Newsletter subscription failed:", error);
|
|
2508
2572
|
} finally {
|
|
2509
2573
|
setIsLoading(false);
|
|
@@ -2546,7 +2610,7 @@ function Hero({
|
|
|
2546
2610
|
Input,
|
|
2547
2611
|
{
|
|
2548
2612
|
type: "email",
|
|
2549
|
-
placeholder:
|
|
2613
|
+
placeholder: labels.placeholder,
|
|
2550
2614
|
value: email,
|
|
2551
2615
|
onChange: (e) => setEmail(e.target.value),
|
|
2552
2616
|
disabled: isLoading,
|
|
@@ -2563,8 +2627,8 @@ function Hero({
|
|
|
2563
2627
|
className: "w-full sm:w-auto",
|
|
2564
2628
|
children: isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2565
2629
|
/* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
2566
|
-
|
|
2567
|
-
] }) :
|
|
2630
|
+
labels.subscribing
|
|
2631
|
+
] }) : labels.subscribe
|
|
2568
2632
|
}
|
|
2569
2633
|
)
|
|
2570
2634
|
] }),
|
|
@@ -2577,7 +2641,7 @@ function Hero({
|
|
|
2577
2641
|
/* @__PURE__ */ jsx("span", { children: message })
|
|
2578
2642
|
] })
|
|
2579
2643
|
] }),
|
|
2580
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-3", children:
|
|
2644
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-3", children: labels.privacyNotice })
|
|
2581
2645
|
] })
|
|
2582
2646
|
] }) }) });
|
|
2583
2647
|
}
|
package/dist/i18n.cjs
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/i18n/index.ts
|
|
20
|
+
var i18n_exports = {};
|
|
21
|
+
__export(i18n_exports, {
|
|
22
|
+
NEWSLETTER_NAMESPACE: () => NEWSLETTER_NAMESPACE,
|
|
23
|
+
newsletterI18n: () => newsletterI18n,
|
|
24
|
+
newsletterTranslations: () => newsletterTranslations
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(i18n_exports);
|
|
27
|
+
var import_i18n = require("@djangocfg/ext-base/i18n");
|
|
28
|
+
|
|
29
|
+
// src/i18n/locales/en.ts
|
|
30
|
+
var en = {
|
|
31
|
+
hero: {
|
|
32
|
+
placeholder: "Enter your email",
|
|
33
|
+
subscribe: "Subscribe",
|
|
34
|
+
subscribing: "Subscribing...",
|
|
35
|
+
successMessage: "Successfully subscribed!",
|
|
36
|
+
errorMessage: "Subscription failed. Please try again.",
|
|
37
|
+
privacyNotice: "By subscribing, you agree to our Privacy Policy and consent to receive updates."
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/i18n/locales/ru.ts
|
|
42
|
+
var ru = {
|
|
43
|
+
hero: {
|
|
44
|
+
placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 email",
|
|
45
|
+
subscribe: "\u041F\u043E\u0434\u043F\u0438\u0441\u0430\u0442\u044C\u0441\u044F",
|
|
46
|
+
subscribing: "\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430...",
|
|
47
|
+
successMessage: "\u0412\u044B \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043B\u0438\u0441\u044C!",
|
|
48
|
+
errorMessage: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u0442\u044C\u0441\u044F. \u041F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437.",
|
|
49
|
+
privacyNotice: "\u041F\u043E\u0434\u043F\u0438\u0441\u044B\u0432\u0430\u044F\u0441\u044C, \u0432\u044B \u0441\u043E\u0433\u043B\u0430\u0448\u0430\u0435\u0442\u0435\u0441\u044C \u0441 \u041F\u043E\u043B\u0438\u0442\u0438\u043A\u043E\u0439 \u043A\u043E\u043D\u0444\u0438\u0434\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E\u0441\u0442\u0438 \u0438 \u0434\u0430\u0451\u0442\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u043D\u0430 \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0439."
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// src/i18n/locales/ko.ts
|
|
54
|
+
var ko = {
|
|
55
|
+
hero: {
|
|
56
|
+
placeholder: "\uC774\uBA54\uC77C\uC744 \uC785\uB825\uD558\uC138\uC694",
|
|
57
|
+
subscribe: "\uAD6C\uB3C5\uD558\uAE30",
|
|
58
|
+
subscribing: "\uAD6C\uB3C5 \uC911...",
|
|
59
|
+
successMessage: "\uC131\uACF5\uC801\uC73C\uB85C \uAD6C\uB3C5\uB418\uC5C8\uC2B5\uB2C8\uB2E4!",
|
|
60
|
+
errorMessage: "\uAD6C\uB3C5\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694.",
|
|
61
|
+
privacyNotice: "\uAD6C\uB3C5 \uC2DC \uAC1C\uC778\uC815\uBCF4 \uCC98\uB9AC\uBC29\uCE68\uC5D0 \uB3D9\uC758\uD558\uACE0 \uC5C5\uB370\uC774\uD2B8 \uC218\uC2E0\uC5D0 \uB3D9\uC758\uD558\uB294 \uAC83\uC73C\uB85C \uAC04\uC8FC\uB429\uB2C8\uB2E4."
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/i18n/index.ts
|
|
66
|
+
var NEWSLETTER_NAMESPACE = "newsletter";
|
|
67
|
+
var newsletterI18n = (0, import_i18n.createExtensionI18n)({
|
|
68
|
+
namespace: NEWSLETTER_NAMESPACE,
|
|
69
|
+
defaultLocale: "en",
|
|
70
|
+
locales: { en, ru, ko }
|
|
71
|
+
});
|
|
72
|
+
var newsletterTranslations = newsletterI18n.getAllTranslations();
|
|
73
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
74
|
+
0 && (module.exports = {
|
|
75
|
+
NEWSLETTER_NAMESPACE,
|
|
76
|
+
newsletterI18n,
|
|
77
|
+
newsletterTranslations
|
|
78
|
+
});
|
package/dist/i18n.d.cts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as _djangocfg_ext_base_i18n from '@djangocfg/ext-base/i18n';
|
|
2
|
+
import { ExtensionKeys, PathKeys } from '@djangocfg/ext-base/i18n';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Newsletter Extension I18n Types
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* All valid keys for newsletter translations (with namespace)
|
|
10
|
+
*/
|
|
11
|
+
type NewsletterKeys = ExtensionKeys<'newsletter', NewsletterTranslations>;
|
|
12
|
+
/**
|
|
13
|
+
* Keys without namespace prefix (for createTypedExtensionT)
|
|
14
|
+
*/
|
|
15
|
+
type NewsletterLocalKeys = PathKeys<NewsletterTranslations>;
|
|
16
|
+
interface NewsletterTranslations {
|
|
17
|
+
/** Hero */
|
|
18
|
+
hero: {
|
|
19
|
+
placeholder: string;
|
|
20
|
+
subscribe: string;
|
|
21
|
+
subscribing: string;
|
|
22
|
+
successMessage: string;
|
|
23
|
+
errorMessage: string;
|
|
24
|
+
privacyNotice: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Newsletter extension namespace */
|
|
29
|
+
declare const NEWSLETTER_NAMESPACE: "newsletter";
|
|
30
|
+
declare const newsletterI18n: _djangocfg_ext_base_i18n.ExtensionI18n<NewsletterTranslations>;
|
|
31
|
+
declare const newsletterTranslations: Record<string, {
|
|
32
|
+
[namespace: string]: NewsletterTranslations;
|
|
33
|
+
}>;
|
|
34
|
+
|
|
35
|
+
export { NEWSLETTER_NAMESPACE, type NewsletterKeys, type NewsletterLocalKeys, type NewsletterTranslations, newsletterI18n, newsletterTranslations };
|
package/dist/i18n.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as _djangocfg_ext_base_i18n from '@djangocfg/ext-base/i18n';
|
|
2
|
+
import { ExtensionKeys, PathKeys } from '@djangocfg/ext-base/i18n';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Newsletter Extension I18n Types
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* All valid keys for newsletter translations (with namespace)
|
|
10
|
+
*/
|
|
11
|
+
type NewsletterKeys = ExtensionKeys<'newsletter', NewsletterTranslations>;
|
|
12
|
+
/**
|
|
13
|
+
* Keys without namespace prefix (for createTypedExtensionT)
|
|
14
|
+
*/
|
|
15
|
+
type NewsletterLocalKeys = PathKeys<NewsletterTranslations>;
|
|
16
|
+
interface NewsletterTranslations {
|
|
17
|
+
/** Hero */
|
|
18
|
+
hero: {
|
|
19
|
+
placeholder: string;
|
|
20
|
+
subscribe: string;
|
|
21
|
+
subscribing: string;
|
|
22
|
+
successMessage: string;
|
|
23
|
+
errorMessage: string;
|
|
24
|
+
privacyNotice: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Newsletter extension namespace */
|
|
29
|
+
declare const NEWSLETTER_NAMESPACE: "newsletter";
|
|
30
|
+
declare const newsletterI18n: _djangocfg_ext_base_i18n.ExtensionI18n<NewsletterTranslations>;
|
|
31
|
+
declare const newsletterTranslations: Record<string, {
|
|
32
|
+
[namespace: string]: NewsletterTranslations;
|
|
33
|
+
}>;
|
|
34
|
+
|
|
35
|
+
export { NEWSLETTER_NAMESPACE, type NewsletterKeys, type NewsletterLocalKeys, type NewsletterTranslations, newsletterI18n, newsletterTranslations };
|
package/dist/i18n.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// src/i18n/index.ts
|
|
2
|
+
import { createExtensionI18n } from "@djangocfg/ext-base/i18n";
|
|
3
|
+
|
|
4
|
+
// src/i18n/locales/en.ts
|
|
5
|
+
var en = {
|
|
6
|
+
hero: {
|
|
7
|
+
placeholder: "Enter your email",
|
|
8
|
+
subscribe: "Subscribe",
|
|
9
|
+
subscribing: "Subscribing...",
|
|
10
|
+
successMessage: "Successfully subscribed!",
|
|
11
|
+
errorMessage: "Subscription failed. Please try again.",
|
|
12
|
+
privacyNotice: "By subscribing, you agree to our Privacy Policy and consent to receive updates."
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/i18n/locales/ru.ts
|
|
17
|
+
var ru = {
|
|
18
|
+
hero: {
|
|
19
|
+
placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 email",
|
|
20
|
+
subscribe: "\u041F\u043E\u0434\u043F\u0438\u0441\u0430\u0442\u044C\u0441\u044F",
|
|
21
|
+
subscribing: "\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430...",
|
|
22
|
+
successMessage: "\u0412\u044B \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043B\u0438\u0441\u044C!",
|
|
23
|
+
errorMessage: "\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u0442\u044C\u0441\u044F. \u041F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437.",
|
|
24
|
+
privacyNotice: "\u041F\u043E\u0434\u043F\u0438\u0441\u044B\u0432\u0430\u044F\u0441\u044C, \u0432\u044B \u0441\u043E\u0433\u043B\u0430\u0448\u0430\u0435\u0442\u0435\u0441\u044C \u0441 \u041F\u043E\u043B\u0438\u0442\u0438\u043A\u043E\u0439 \u043A\u043E\u043D\u0444\u0438\u0434\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E\u0441\u0442\u0438 \u0438 \u0434\u0430\u0451\u0442\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u043D\u0430 \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0439."
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// src/i18n/locales/ko.ts
|
|
29
|
+
var ko = {
|
|
30
|
+
hero: {
|
|
31
|
+
placeholder: "\uC774\uBA54\uC77C\uC744 \uC785\uB825\uD558\uC138\uC694",
|
|
32
|
+
subscribe: "\uAD6C\uB3C5\uD558\uAE30",
|
|
33
|
+
subscribing: "\uAD6C\uB3C5 \uC911...",
|
|
34
|
+
successMessage: "\uC131\uACF5\uC801\uC73C\uB85C \uAD6C\uB3C5\uB418\uC5C8\uC2B5\uB2C8\uB2E4!",
|
|
35
|
+
errorMessage: "\uAD6C\uB3C5\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694.",
|
|
36
|
+
privacyNotice: "\uAD6C\uB3C5 \uC2DC \uAC1C\uC778\uC815\uBCF4 \uCC98\uB9AC\uBC29\uCE68\uC5D0 \uB3D9\uC758\uD558\uACE0 \uC5C5\uB370\uC774\uD2B8 \uC218\uC2E0\uC5D0 \uB3D9\uC758\uD558\uB294 \uAC83\uC73C\uB85C \uAC04\uC8FC\uB429\uB2C8\uB2E4."
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// src/i18n/index.ts
|
|
41
|
+
var NEWSLETTER_NAMESPACE = "newsletter";
|
|
42
|
+
var newsletterI18n = createExtensionI18n({
|
|
43
|
+
namespace: NEWSLETTER_NAMESPACE,
|
|
44
|
+
defaultLocale: "en",
|
|
45
|
+
locales: { en, ru, ko }
|
|
46
|
+
});
|
|
47
|
+
var newsletterTranslations = newsletterI18n.getAllTranslations();
|
|
48
|
+
export {
|
|
49
|
+
NEWSLETTER_NAMESPACE,
|
|
50
|
+
newsletterI18n,
|
|
51
|
+
newsletterTranslations
|
|
52
|
+
};
|
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.22",
|
|
2121
2121
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
2122
2122
|
keywords: [
|
|
2123
2123
|
"django",
|
|
@@ -2163,6 +2163,11 @@ var package_default = {
|
|
|
2163
2163
|
types: "./dist/config.d.ts",
|
|
2164
2164
|
import: "./dist/config.js",
|
|
2165
2165
|
require: "./dist/config.cjs"
|
|
2166
|
+
},
|
|
2167
|
+
"./i18n": {
|
|
2168
|
+
types: "./dist/i18n.d.ts",
|
|
2169
|
+
import: "./dist/i18n.js",
|
|
2170
|
+
require: "./dist/i18n.cjs"
|
|
2166
2171
|
}
|
|
2167
2172
|
},
|
|
2168
2173
|
files: [
|
|
@@ -2178,6 +2183,7 @@ var package_default = {
|
|
|
2178
2183
|
peerDependencies: {
|
|
2179
2184
|
"@djangocfg/api": "workspace:*",
|
|
2180
2185
|
"@djangocfg/ext-base": "workspace:*",
|
|
2186
|
+
"@djangocfg/i18n": "workspace:*",
|
|
2181
2187
|
"@djangocfg/ui-core": "workspace:*",
|
|
2182
2188
|
consola: "^3.4.2",
|
|
2183
2189
|
"lucide-react": "^0.545.0",
|
|
@@ -2191,6 +2197,7 @@ var package_default = {
|
|
|
2191
2197
|
devDependencies: {
|
|
2192
2198
|
"@djangocfg/api": "workspace:*",
|
|
2193
2199
|
"@djangocfg/ext-base": "workspace:*",
|
|
2200
|
+
"@djangocfg/i18n": "workspace:*",
|
|
2194
2201
|
"@djangocfg/typescript-config": "workspace:*",
|
|
2195
2202
|
"@types/node": "^24.7.2",
|
|
2196
2203
|
"@types/react": "^19.0.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.22",
|
|
2115
2115
|
description: "Newsletter and subscription management extension for DjangoCFG",
|
|
2116
2116
|
keywords: [
|
|
2117
2117
|
"django",
|
|
@@ -2157,6 +2157,11 @@ var package_default = {
|
|
|
2157
2157
|
types: "./dist/config.d.ts",
|
|
2158
2158
|
import: "./dist/config.js",
|
|
2159
2159
|
require: "./dist/config.cjs"
|
|
2160
|
+
},
|
|
2161
|
+
"./i18n": {
|
|
2162
|
+
types: "./dist/i18n.d.ts",
|
|
2163
|
+
import: "./dist/i18n.js",
|
|
2164
|
+
require: "./dist/i18n.cjs"
|
|
2160
2165
|
}
|
|
2161
2166
|
},
|
|
2162
2167
|
files: [
|
|
@@ -2172,6 +2177,7 @@ var package_default = {
|
|
|
2172
2177
|
peerDependencies: {
|
|
2173
2178
|
"@djangocfg/api": "workspace:*",
|
|
2174
2179
|
"@djangocfg/ext-base": "workspace:*",
|
|
2180
|
+
"@djangocfg/i18n": "workspace:*",
|
|
2175
2181
|
"@djangocfg/ui-core": "workspace:*",
|
|
2176
2182
|
consola: "^3.4.2",
|
|
2177
2183
|
"lucide-react": "^0.545.0",
|
|
@@ -2185,6 +2191,7 @@ var package_default = {
|
|
|
2185
2191
|
devDependencies: {
|
|
2186
2192
|
"@djangocfg/api": "workspace:*",
|
|
2187
2193
|
"@djangocfg/ext-base": "workspace:*",
|
|
2194
|
+
"@djangocfg/i18n": "workspace:*",
|
|
2188
2195
|
"@djangocfg/typescript-config": "workspace:*",
|
|
2189
2196
|
"@types/node": "^24.7.2",
|
|
2190
2197
|
"@types/react": "^19.0.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.22",
|
|
4
4
|
"description": "Newsletter and subscription management extension for DjangoCFG",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"django",
|
|
@@ -46,6 +46,11 @@
|
|
|
46
46
|
"types": "./dist/config.d.ts",
|
|
47
47
|
"import": "./dist/config.js",
|
|
48
48
|
"require": "./dist/config.cjs"
|
|
49
|
+
},
|
|
50
|
+
"./i18n": {
|
|
51
|
+
"types": "./dist/i18n.d.ts",
|
|
52
|
+
"import": "./dist/i18n.js",
|
|
53
|
+
"require": "./dist/i18n.cjs"
|
|
49
54
|
}
|
|
50
55
|
},
|
|
51
56
|
"files": [
|
|
@@ -59,9 +64,10 @@
|
|
|
59
64
|
"check": "tsc --noEmit"
|
|
60
65
|
},
|
|
61
66
|
"peerDependencies": {
|
|
62
|
-
"@djangocfg/api": "^2.1.
|
|
63
|
-
"@djangocfg/ext-base": "^1.0.
|
|
64
|
-
"@djangocfg/
|
|
67
|
+
"@djangocfg/api": "^2.1.111",
|
|
68
|
+
"@djangocfg/ext-base": "^1.0.17",
|
|
69
|
+
"@djangocfg/i18n": "^2.1.111",
|
|
70
|
+
"@djangocfg/ui-core": "^2.1.111",
|
|
65
71
|
"consola": "^3.4.2",
|
|
66
72
|
"lucide-react": "^0.545.0",
|
|
67
73
|
"next": "^16",
|
|
@@ -72,9 +78,10 @@
|
|
|
72
78
|
"zod": "^4.3.4"
|
|
73
79
|
},
|
|
74
80
|
"devDependencies": {
|
|
75
|
-
"@djangocfg/api": "^2.1.
|
|
76
|
-
"@djangocfg/ext-base": "^1.0.
|
|
77
|
-
"@djangocfg/
|
|
81
|
+
"@djangocfg/api": "^2.1.111",
|
|
82
|
+
"@djangocfg/ext-base": "^1.0.17",
|
|
83
|
+
"@djangocfg/i18n": "^2.1.111",
|
|
84
|
+
"@djangocfg/typescript-config": "^2.1.111",
|
|
78
85
|
"@types/node": "^24.7.2",
|
|
79
86
|
"@types/react": "^19.0.0",
|
|
80
87
|
"consola": "^3.4.2",
|
|
@@ -6,8 +6,11 @@
|
|
|
6
6
|
'use client';
|
|
7
7
|
|
|
8
8
|
import { AlertCircle, CheckCircle2, Loader2, Mail } from 'lucide-react';
|
|
9
|
-
import React, { useState } from 'react';
|
|
9
|
+
import React, { useMemo, useState } from 'react';
|
|
10
10
|
|
|
11
|
+
import { createTypedExtensionT } from '@djangocfg/ext-base/i18n';
|
|
12
|
+
import { useT } from '@djangocfg/i18n';
|
|
13
|
+
import { NEWSLETTER_NAMESPACE, type NewsletterTranslations } from '../../i18n';
|
|
11
14
|
import { Button, Input } from '@djangocfg/ui-core';
|
|
12
15
|
|
|
13
16
|
import { newsletterLogger } from '../../utils/logger';
|
|
@@ -20,16 +23,31 @@ export function Hero({
|
|
|
20
23
|
primaryAction,
|
|
21
24
|
secondaryAction,
|
|
22
25
|
showNewsletter = true,
|
|
23
|
-
newsletterPlaceholder
|
|
24
|
-
newsletterButtonText
|
|
26
|
+
newsletterPlaceholder,
|
|
27
|
+
newsletterButtonText,
|
|
25
28
|
onNewsletterSubmit,
|
|
26
29
|
className = '',
|
|
27
30
|
}: HeroProps) {
|
|
31
|
+
const baseT = useT();
|
|
28
32
|
const [email, setEmail] = useState('');
|
|
29
33
|
const [isLoading, setIsLoading] = useState(false);
|
|
30
34
|
const [status, setStatus] = useState<'idle' | 'success' | 'error'>('idle');
|
|
31
35
|
const [message, setMessage] = useState('');
|
|
32
36
|
|
|
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
|
+
// Prepare labels before JSX render
|
|
42
|
+
const labels = useMemo(() => ({
|
|
43
|
+
placeholder: newsletterPlaceholder ?? nt('hero.placeholder'),
|
|
44
|
+
subscribe: newsletterButtonText ?? nt('hero.subscribe'),
|
|
45
|
+
subscribing: nt('hero.subscribing'),
|
|
46
|
+
successMessage: nt('hero.successMessage'),
|
|
47
|
+
errorMessage: nt('hero.errorMessage'),
|
|
48
|
+
privacyNotice: nt('hero.privacyNotice'),
|
|
49
|
+
}), [nt, newsletterPlaceholder, newsletterButtonText]);
|
|
50
|
+
|
|
33
51
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
34
52
|
e.preventDefault();
|
|
35
53
|
|
|
@@ -42,12 +60,12 @@ export function Hero({
|
|
|
42
60
|
try {
|
|
43
61
|
const result = await onNewsletterSubmit(email);
|
|
44
62
|
setStatus('success');
|
|
45
|
-
setMessage((result && 'message' in result ? result.message : undefined) ||
|
|
63
|
+
setMessage((result && 'message' in result ? result.message : undefined) || labels.successMessage);
|
|
46
64
|
setEmail('');
|
|
47
65
|
newsletterLogger.success('Newsletter subscription successful:', email);
|
|
48
66
|
} catch (error) {
|
|
49
67
|
setStatus('error');
|
|
50
|
-
setMessage(error instanceof Error ? error.message :
|
|
68
|
+
setMessage(error instanceof Error ? error.message : labels.errorMessage);
|
|
51
69
|
newsletterLogger.error('Newsletter subscription failed:', error);
|
|
52
70
|
} finally {
|
|
53
71
|
setIsLoading(false);
|
|
@@ -109,7 +127,7 @@ export function Hero({
|
|
|
109
127
|
<Mail className="absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-muted-foreground" />
|
|
110
128
|
<Input
|
|
111
129
|
type="email"
|
|
112
|
-
placeholder={
|
|
130
|
+
placeholder={labels.placeholder}
|
|
113
131
|
value={email}
|
|
114
132
|
onChange={(e) => setEmail(e.target.value)}
|
|
115
133
|
disabled={isLoading}
|
|
@@ -125,10 +143,10 @@ export function Hero({
|
|
|
125
143
|
{isLoading ? (
|
|
126
144
|
<>
|
|
127
145
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
128
|
-
|
|
146
|
+
{labels.subscribing}
|
|
129
147
|
</>
|
|
130
148
|
) : (
|
|
131
|
-
|
|
149
|
+
labels.subscribe
|
|
132
150
|
)}
|
|
133
151
|
</Button>
|
|
134
152
|
</div>
|
|
@@ -150,7 +168,7 @@ export function Hero({
|
|
|
150
168
|
</form>
|
|
151
169
|
|
|
152
170
|
<p className="text-xs text-muted-foreground mt-3">
|
|
153
|
-
|
|
171
|
+
{labels.privacyNotice}
|
|
154
172
|
</p>
|
|
155
173
|
</div>
|
|
156
174
|
)}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Newsletter Extension I18n
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createExtensionI18n } from '@djangocfg/ext-base/i18n';
|
|
6
|
+
import type { NewsletterTranslations } from './types';
|
|
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();
|
|
21
|
+
|
|
22
|
+
// Types
|
|
23
|
+
export type { NewsletterTranslations, NewsletterKeys, NewsletterLocalKeys } from './types';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NewsletterTranslations } from '../types';
|
|
2
|
+
|
|
3
|
+
export const en: NewsletterTranslations = {
|
|
4
|
+
hero: {
|
|
5
|
+
placeholder: 'Enter your email',
|
|
6
|
+
subscribe: 'Subscribe',
|
|
7
|
+
subscribing: 'Subscribing...',
|
|
8
|
+
successMessage: 'Successfully subscribed!',
|
|
9
|
+
errorMessage: 'Subscription failed. Please try again.',
|
|
10
|
+
privacyNotice: 'By subscribing, you agree to our Privacy Policy and consent to receive updates.',
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NewsletterTranslations } from '../types';
|
|
2
|
+
|
|
3
|
+
export const ko: NewsletterTranslations = {
|
|
4
|
+
hero: {
|
|
5
|
+
placeholder: '이메일을 입력하세요',
|
|
6
|
+
subscribe: '구독하기',
|
|
7
|
+
subscribing: '구독 중...',
|
|
8
|
+
successMessage: '성공적으로 구독되었습니다!',
|
|
9
|
+
errorMessage: '구독에 실패했습니다. 다시 시도해 주세요.',
|
|
10
|
+
privacyNotice: '구독 시 개인정보 처리방침에 동의하고 업데이트 수신에 동의하는 것으로 간주됩니다.',
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { NewsletterTranslations } from '../types';
|
|
2
|
+
|
|
3
|
+
export const ru: NewsletterTranslations = {
|
|
4
|
+
hero: {
|
|
5
|
+
placeholder: 'Введите email',
|
|
6
|
+
subscribe: 'Подписаться',
|
|
7
|
+
subscribing: 'Подписка...',
|
|
8
|
+
successMessage: 'Вы успешно подписались!',
|
|
9
|
+
errorMessage: 'Не удалось подписаться. Попробуйте ещё раз.',
|
|
10
|
+
privacyNotice: 'Подписываясь, вы соглашаетесь с Политикой конфиденциальности и даёте согласие на получение обновлений.',
|
|
11
|
+
},
|
|
12
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Newsletter Extension I18n Types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ExtensionKeys, PathKeys } from '@djangocfg/ext-base/i18n';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* All valid keys for newsletter translations (with namespace)
|
|
9
|
+
*/
|
|
10
|
+
export type NewsletterKeys = ExtensionKeys<'newsletter', NewsletterTranslations>;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Keys without namespace prefix (for createTypedExtensionT)
|
|
14
|
+
*/
|
|
15
|
+
export type NewsletterLocalKeys = PathKeys<NewsletterTranslations>;
|
|
16
|
+
|
|
17
|
+
export interface NewsletterTranslations {
|
|
18
|
+
/** Hero */
|
|
19
|
+
hero: {
|
|
20
|
+
placeholder: string;
|
|
21
|
+
subscribe: string;
|
|
22
|
+
subscribing: string;
|
|
23
|
+
successMessage: string;
|
|
24
|
+
errorMessage: string;
|
|
25
|
+
privacyNotice: string;
|
|
26
|
+
};
|
|
27
|
+
}
|