@djangocfg/nextjs 2.1.109 → 2.1.111

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +176 -7
  2. package/dist/config/index.d.mts +16 -1
  3. package/dist/config/index.mjs +83 -14
  4. package/dist/config/index.mjs.map +1 -1
  5. package/dist/i18n/client.d.mts +123 -0
  6. package/dist/i18n/client.mjs +104 -0
  7. package/dist/i18n/client.mjs.map +1 -0
  8. package/dist/i18n/components.d.mts +22 -0
  9. package/dist/i18n/components.mjs +133 -0
  10. package/dist/i18n/components.mjs.map +1 -0
  11. package/dist/i18n/index.d.mts +17 -0
  12. package/dist/i18n/index.mjs +269 -0
  13. package/dist/i18n/index.mjs.map +1 -0
  14. package/dist/i18n/navigation.d.mts +1095 -0
  15. package/dist/i18n/navigation.mjs +45 -0
  16. package/dist/i18n/navigation.mjs.map +1 -0
  17. package/dist/i18n/plugin.d.mts +41 -0
  18. package/dist/i18n/plugin.mjs +17 -0
  19. package/dist/i18n/plugin.mjs.map +1 -0
  20. package/dist/i18n/provider.d.mts +18 -0
  21. package/dist/i18n/provider.mjs +54 -0
  22. package/dist/i18n/provider.mjs.map +1 -0
  23. package/dist/i18n/proxy.d.mts +40 -0
  24. package/dist/i18n/proxy.mjs +42 -0
  25. package/dist/i18n/proxy.mjs.map +1 -0
  26. package/dist/i18n/request.d.mts +42 -0
  27. package/dist/i18n/request.mjs +63 -0
  28. package/dist/i18n/request.mjs.map +1 -0
  29. package/dist/i18n/routing.d.mts +79 -0
  30. package/dist/i18n/routing.mjs +33 -0
  31. package/dist/i18n/routing.mjs.map +1 -0
  32. package/dist/i18n/server.d.mts +90 -0
  33. package/dist/i18n/server.mjs +79 -0
  34. package/dist/i18n/server.mjs.map +1 -0
  35. package/dist/index.d.mts +3 -1
  36. package/dist/index.mjs +176 -30
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/sitemap/index.d.mts +22 -3
  39. package/dist/sitemap/index.mjs +92 -15
  40. package/dist/sitemap/index.mjs.map +1 -1
  41. package/dist/types-Cy349X20.d.mts +60 -0
  42. package/package.json +54 -4
  43. package/src/config/constants.ts +1 -0
  44. package/src/config/createNextConfig.ts +39 -17
  45. package/src/i18n/client.ts +221 -0
  46. package/src/i18n/components/LocaleSwitcher.tsx +124 -0
  47. package/src/i18n/components/index.ts +7 -0
  48. package/src/i18n/index.ts +149 -0
  49. package/src/i18n/navigation.ts +90 -0
  50. package/src/i18n/plugin.ts +66 -0
  51. package/src/i18n/provider.tsx +91 -0
  52. package/src/i18n/proxy.ts +81 -0
  53. package/src/i18n/request.ts +141 -0
  54. package/src/i18n/routing.ts +84 -0
  55. package/src/i18n/server.ts +175 -0
  56. package/src/i18n/types.ts +88 -0
  57. package/src/sitemap/generator.ts +84 -9
  58. package/src/sitemap/index.ts +1 -1
  59. package/src/sitemap/route.ts +71 -8
  60. package/src/sitemap/types.ts +9 -0
@@ -0,0 +1,90 @@
1
+ import * as next_intl from 'next-intl';
2
+ export { getFormatter, getNow, getTimeZone } from 'next-intl/server';
3
+ import { M as Messages, L as LocaleParams } from '../types-Cy349X20.mjs';
4
+ export { generateLocaleParams, isValidLocale } from './routing.mjs';
5
+ import { LocaleCode } from '@djangocfg/i18n';
6
+ import 'next-intl/routing';
7
+
8
+ /**
9
+ * Get translations for Server Components
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * const t = await getTranslations('HomePage');
14
+ * return <h1>{t('title')}</h1>;
15
+ *
16
+ * // Or without namespace
17
+ * const t = await getTranslations();
18
+ * return <h1>{t('HomePage.title')}</h1>;
19
+ * ```
20
+ */
21
+ declare function getTranslations<Namespace extends string = never>(namespace?: Namespace): Promise<next_intl._Translator<Record<string, any>, Namespace>>;
22
+ /**
23
+ * Get current locale in Server Components
24
+ */
25
+ declare function getLocale(): Promise<LocaleCode>;
26
+ /**
27
+ * Get all messages for the current request
28
+ * Useful for passing to I18nProvider in layouts
29
+ */
30
+ declare function getMessages(): Promise<Messages>;
31
+
32
+ /**
33
+ * Extract locale from page/layout params
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * // app/[locale]/page.tsx
38
+ * export default async function Page({ params }) {
39
+ * const locale = await getLocaleFromParams(params);
40
+ * // ...
41
+ * }
42
+ * ```
43
+ */
44
+ declare function getLocaleFromParams(params: Promise<LocaleParams> | LocaleParams): Promise<LocaleCode>;
45
+ /**
46
+ * Shorthand for getting locale from params
47
+ * Alias for getLocaleFromParams
48
+ */
49
+ declare const extractLocale: typeof getLocaleFromParams;
50
+ /**
51
+ * Get typed translations for a specific namespace
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * const t = await getNamespacedTranslations('payments');
56
+ * return <span>{t('balance.available')}</span>;
57
+ * ```
58
+ */
59
+ declare function getNamespacedTranslations(namespace: string): Promise<next_intl._Translator<Record<string, any>, string>>;
60
+ /**
61
+ * Generate localized metadata for pages
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * // app/[locale]/about/page.tsx
66
+ * import { generateLocalizedMetadata } from '@djangocfg/nextjs/i18n/server';
67
+ *
68
+ * export async function generateMetadata({ params }) {
69
+ * return generateLocalizedMetadata(params, {
70
+ * titleKey: 'AboutPage.meta.title',
71
+ * descriptionKey: 'AboutPage.meta.description',
72
+ * });
73
+ * }
74
+ * ```
75
+ */
76
+ declare function generateLocalizedMetadata(params: Promise<LocaleParams> | LocaleParams, options?: {
77
+ titleKey?: string;
78
+ descriptionKey?: string;
79
+ namespace?: string;
80
+ }): Promise<{
81
+ title: string;
82
+ description: string;
83
+ alternates: {
84
+ languages: {
85
+ [x: string]: string;
86
+ };
87
+ };
88
+ }>;
89
+
90
+ export { extractLocale, generateLocalizedMetadata, getLocale, getLocaleFromParams, getMessages, getNamespacedTranslations, getTranslations };
@@ -0,0 +1,79 @@
1
+ // src/i18n/server.ts
2
+ import {
3
+ getTranslations as getNextIntlTranslations,
4
+ getLocale as getNextIntlLocale,
5
+ getMessages as getNextIntlMessages,
6
+ getNow,
7
+ getTimeZone,
8
+ getFormatter
9
+ } from "next-intl/server";
10
+
11
+ // src/i18n/routing.ts
12
+ import { defineRouting } from "next-intl/routing";
13
+ var DEFAULT_LOCALES = ["en", "ru", "ko"];
14
+ var DEFAULT_LOCALE = "en";
15
+ function createRouting(config) {
16
+ const locales = config?.locales ?? DEFAULT_LOCALES;
17
+ const defaultLocale = config?.defaultLocale ?? DEFAULT_LOCALE;
18
+ const localePrefix = config?.localePrefix ?? "always";
19
+ return defineRouting({
20
+ locales,
21
+ defaultLocale,
22
+ localePrefix
23
+ });
24
+ }
25
+ var routing = createRouting();
26
+ function isValidLocale(locale, supportedLocales = DEFAULT_LOCALES) {
27
+ return supportedLocales.includes(locale);
28
+ }
29
+ function generateLocaleParams(locales = DEFAULT_LOCALES) {
30
+ return locales.map((locale) => ({ locale }));
31
+ }
32
+
33
+ // src/i18n/server.ts
34
+ async function getTranslations(namespace) {
35
+ return getNextIntlTranslations(namespace);
36
+ }
37
+ async function getLocale() {
38
+ return await getNextIntlLocale();
39
+ }
40
+ async function getMessages() {
41
+ return await getNextIntlMessages();
42
+ }
43
+ async function getLocaleFromParams(params) {
44
+ const resolved = await params;
45
+ return resolved.locale;
46
+ }
47
+ var extractLocale = getLocaleFromParams;
48
+ async function getNamespacedTranslations(namespace) {
49
+ return getNextIntlTranslations(namespace);
50
+ }
51
+ async function generateLocalizedMetadata(params, options = {}) {
52
+ const locale = await getLocaleFromParams(params);
53
+ const t = await getTranslations(options.namespace);
54
+ return {
55
+ title: options.titleKey ? t(options.titleKey) : void 0,
56
+ description: options.descriptionKey ? t(options.descriptionKey) : void 0,
57
+ // Add locale to alternate languages
58
+ alternates: {
59
+ languages: {
60
+ [locale]: `/${locale}`
61
+ }
62
+ }
63
+ };
64
+ }
65
+ export {
66
+ extractLocale,
67
+ generateLocaleParams,
68
+ generateLocalizedMetadata,
69
+ getFormatter,
70
+ getLocale,
71
+ getLocaleFromParams,
72
+ getMessages,
73
+ getNamespacedTranslations,
74
+ getNow,
75
+ getTimeZone,
76
+ getTranslations,
77
+ isValidLocale
78
+ };
79
+ //# sourceMappingURL=server.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/i18n/server.ts","../../src/i18n/routing.ts"],"sourcesContent":["/**\n * Server-side i18n Utilities\n *\n * For use in Server Components, Server Actions, and Route Handlers\n *\n * @example\n * ```tsx\n * // In a Server Component\n * import { getTranslations, getLocale } from '@djangocfg/nextjs/i18n/server';\n *\n * export default async function Page() {\n * const t = await getTranslations('HomePage');\n * const locale = await getLocale();\n *\n * return <h1>{t('title')}</h1>;\n * }\n * ```\n */\n\nimport {\n getTranslations as getNextIntlTranslations,\n getLocale as getNextIntlLocale,\n getMessages as getNextIntlMessages,\n getNow,\n getTimeZone,\n getFormatter,\n} from 'next-intl/server';\nimport type { LocaleCode, Messages, LocaleParams } from './types';\nimport { isValidLocale, generateLocaleParams } from './routing';\n\n// Re-export routing utilities for convenience\nexport { isValidLocale, generateLocaleParams };\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Core Server Functions\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Get translations for Server Components\n *\n * @example\n * ```tsx\n * const t = await getTranslations('HomePage');\n * return <h1>{t('title')}</h1>;\n *\n * // Or without namespace\n * const t = await getTranslations();\n * return <h1>{t('HomePage.title')}</h1>;\n * ```\n */\nexport async function getTranslations<Namespace extends string = never>(\n namespace?: Namespace\n) {\n return getNextIntlTranslations(namespace);\n}\n\n/**\n * Get current locale in Server Components\n */\nexport async function getLocale(): Promise<LocaleCode> {\n return (await getNextIntlLocale()) as LocaleCode;\n}\n\n/**\n * Get all messages for the current request\n * Useful for passing to I18nProvider in layouts\n */\nexport async function getMessages(): Promise<Messages> {\n return (await getNextIntlMessages()) as Messages;\n}\n\n/**\n * Get current time for the request\n * Useful for consistent time-based formatting\n */\nexport { getNow };\n\n/**\n * Get timezone for the request\n */\nexport { getTimeZone };\n\n/**\n * Get formatter for dates, numbers, etc.\n */\nexport { getFormatter };\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Locale Extraction Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Extract locale from page/layout params\n *\n * @example\n * ```tsx\n * // app/[locale]/page.tsx\n * export default async function Page({ params }) {\n * const locale = await getLocaleFromParams(params);\n * // ...\n * }\n * ```\n */\nexport async function getLocaleFromParams(\n params: Promise<LocaleParams> | LocaleParams\n): Promise<LocaleCode> {\n const resolved = await params;\n return resolved.locale as LocaleCode;\n}\n\n/**\n * Shorthand for getting locale from params\n * Alias for getLocaleFromParams\n */\nexport const extractLocale = getLocaleFromParams;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Typed Translation Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Get typed translations for a specific namespace\n *\n * @example\n * ```tsx\n * const t = await getNamespacedTranslations('payments');\n * return <span>{t('balance.available')}</span>;\n * ```\n */\nexport async function getNamespacedTranslations(namespace: string) {\n return getNextIntlTranslations(namespace);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Metadata Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Generate localized metadata for pages\n *\n * @example\n * ```tsx\n * // app/[locale]/about/page.tsx\n * import { generateLocalizedMetadata } from '@djangocfg/nextjs/i18n/server';\n *\n * export async function generateMetadata({ params }) {\n * return generateLocalizedMetadata(params, {\n * titleKey: 'AboutPage.meta.title',\n * descriptionKey: 'AboutPage.meta.description',\n * });\n * }\n * ```\n */\nexport async function generateLocalizedMetadata(\n params: Promise<LocaleParams> | LocaleParams,\n options: {\n titleKey?: string;\n descriptionKey?: string;\n namespace?: string;\n } = {}\n) {\n const locale = await getLocaleFromParams(params);\n const t = await getTranslations(options.namespace);\n\n return {\n title: options.titleKey ? t(options.titleKey as never) : undefined,\n description: options.descriptionKey ? t(options.descriptionKey as never) : undefined,\n // Add locale to alternate languages\n alternates: {\n languages: {\n [locale]: `/${locale}`,\n },\n },\n };\n}\n","/**\n * i18n Routing Configuration\n *\n * Creates routing configuration for next-intl\n * Used by proxy and navigation components\n */\n\nimport { defineRouting } from 'next-intl/routing';\nimport type { I18nConfig, LocaleCode } from './types';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Default Configuration\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst DEFAULT_LOCALES: LocaleCode[] = ['en', 'ru', 'ko'];\nconst DEFAULT_LOCALE: LocaleCode = 'en';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Routing Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Create routing configuration for next-intl\n *\n * @example\n * ```ts\n * // i18n/routing.ts\n * import { createRouting } from '@djangocfg/nextjs/i18n';\n *\n * export const routing = createRouting({\n * locales: ['en', 'ru', 'ko'],\n * defaultLocale: 'en',\n * });\n * ```\n */\nexport function createRouting(config?: Partial<I18nConfig>) {\n const locales = config?.locales ?? DEFAULT_LOCALES;\n const defaultLocale = config?.defaultLocale ?? DEFAULT_LOCALE;\n const localePrefix = config?.localePrefix ?? 'always';\n\n return defineRouting({\n locales,\n defaultLocale,\n localePrefix,\n });\n}\n\n/**\n * Default routing configuration\n * Can be overridden by app-specific configuration\n */\nexport const routing = createRouting();\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Locale Utilities\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Check if a locale is supported\n */\nexport function isValidLocale(\n locale: string,\n supportedLocales: readonly string[] = DEFAULT_LOCALES\n): locale is LocaleCode {\n return supportedLocales.includes(locale as LocaleCode);\n}\n\n/**\n * Get locale from params (handles async params in Next.js 15+)\n */\nexport async function getLocaleFromParams(\n params: Promise<{ locale: string }> | { locale: string }\n): Promise<LocaleCode> {\n const resolved = await params;\n return resolved.locale as LocaleCode;\n}\n\n/**\n * Generate static params for all locales\n * Use in generateStaticParams for locale pages\n */\nexport function generateLocaleParams(locales: readonly string[] = DEFAULT_LOCALES) {\n return locales.map((locale) => ({ locale }));\n}\n"],"mappings":";AAmBA;AAAA,EACE,mBAAmB;AAAA,EACnB,aAAa;AAAA,EACb,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACnBP,SAAS,qBAAqB;AAO9B,IAAM,kBAAgC,CAAC,MAAM,MAAM,IAAI;AACvD,IAAM,iBAA6B;AAoB5B,SAAS,cAAc,QAA8B;AAC1D,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,gBAAgB,QAAQ,iBAAiB;AAC/C,QAAM,eAAe,QAAQ,gBAAgB;AAE7C,SAAO,cAAc;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAMO,IAAM,UAAU,cAAc;AAS9B,SAAS,cACd,QACA,mBAAsC,iBAChB;AACtB,SAAO,iBAAiB,SAAS,MAAoB;AACvD;AAgBO,SAAS,qBAAqB,UAA6B,iBAAiB;AACjF,SAAO,QAAQ,IAAI,CAAC,YAAY,EAAE,OAAO,EAAE;AAC7C;;;ADjCA,eAAsB,gBACpB,WACA;AACA,SAAO,wBAAwB,SAAS;AAC1C;AAKA,eAAsB,YAAiC;AACrD,SAAQ,MAAM,kBAAkB;AAClC;AAMA,eAAsB,cAAiC;AACrD,SAAQ,MAAM,oBAAoB;AACpC;AAkCA,eAAsB,oBACpB,QACqB;AACrB,QAAM,WAAW,MAAM;AACvB,SAAO,SAAS;AAClB;AAMO,IAAM,gBAAgB;AAe7B,eAAsB,0BAA0B,WAAmB;AACjE,SAAO,wBAAwB,SAAS;AAC1C;AAsBA,eAAsB,0BACpB,QACA,UAII,CAAC,GACL;AACA,QAAM,SAAS,MAAM,oBAAoB,MAAM;AAC/C,QAAM,IAAI,MAAM,gBAAgB,QAAQ,SAAS;AAEjD,SAAO;AAAA,IACL,OAAO,QAAQ,WAAW,EAAE,QAAQ,QAAiB,IAAI;AAAA,IACzD,aAAa,QAAQ,iBAAiB,EAAE,QAAQ,cAAuB,IAAI;AAAA;AAAA,IAE3E,YAAY;AAAA,MACV,WAAW;AAAA,QACT,CAAC,MAAM,GAAG,IAAI,MAAM;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- export { SitemapGeneratorOptions, SitemapRoute, createSitemapHandler, generateSitemapXml, normalizeUrl } from './sitemap/index.mjs';
1
+ export { SitemapGeneratorOptions, SitemapI18nOptions, SitemapRoute, createSitemapHandler, generateSitemapXml, normalizeUrl } from './sitemap/index.mjs';
2
2
  export { HealthCheck, HealthConfig, createHealthHandler } from './health/index.mjs';
3
3
  export { OgImageHandlerConfig, createOgImageDynamicRoute, createOgImageHandler } from './og-image/index.mjs';
4
4
  export { DefaultTemplate, LightTemplate, OgImageTemplateProps } from './og-image/components/index.mjs';
@@ -14,4 +14,6 @@ import 'react';
14
14
  import 'next';
15
15
  import 'lucide-react';
16
16
  import 'webpack';
17
+ import './types-Cy349X20.mjs';
18
+ import '@djangocfg/i18n';
17
19
  import './plugin-DuRJ_Jq6.mjs';
package/dist/index.mjs CHANGED
@@ -14,7 +14,7 @@ var require_package = __commonJS({
14
14
  "package.json"(exports, module) {
15
15
  module.exports = {
16
16
  name: "@djangocfg/nextjs",
17
- version: "2.1.109",
17
+ version: "2.1.111",
18
18
  description: "Next.js server utilities: sitemap, health, OG images, contact forms, navigation, config",
19
19
  keywords: [
20
20
  "nextjs",
@@ -112,6 +112,46 @@ var require_package = __commonJS({
112
112
  types: "./dist/pwa/server/routes.d.mts",
113
113
  import: "./dist/pwa/server/routes.mjs",
114
114
  default: "./dist/pwa/server/routes.mjs"
115
+ },
116
+ "./i18n": {
117
+ types: "./dist/i18n/index.d.mts",
118
+ import: "./dist/i18n/index.mjs",
119
+ default: "./dist/i18n/index.mjs"
120
+ },
121
+ "./i18n/server": {
122
+ types: "./dist/i18n/server.d.mts",
123
+ import: "./dist/i18n/server.mjs",
124
+ default: "./dist/i18n/server.mjs"
125
+ },
126
+ "./i18n/client": {
127
+ types: "./dist/i18n/client.d.mts",
128
+ import: "./dist/i18n/client.mjs",
129
+ default: "./dist/i18n/client.mjs"
130
+ },
131
+ "./i18n/proxy": {
132
+ types: "./dist/i18n/proxy.d.mts",
133
+ import: "./dist/i18n/proxy.mjs",
134
+ default: "./dist/i18n/proxy.mjs"
135
+ },
136
+ "./i18n/navigation": {
137
+ types: "./dist/i18n/navigation.d.mts",
138
+ import: "./dist/i18n/navigation.mjs",
139
+ default: "./dist/i18n/navigation.mjs"
140
+ },
141
+ "./i18n/routing": {
142
+ types: "./dist/i18n/routing.d.mts",
143
+ import: "./dist/i18n/routing.mjs",
144
+ default: "./dist/i18n/routing.mjs"
145
+ },
146
+ "./i18n/request": {
147
+ types: "./dist/i18n/request.d.mts",
148
+ import: "./dist/i18n/request.mjs",
149
+ default: "./dist/i18n/request.mjs"
150
+ },
151
+ "./i18n/components": {
152
+ types: "./dist/i18n/components.d.mts",
153
+ import: "./dist/i18n/components.mjs",
154
+ default: "./dist/i18n/components.mjs"
115
155
  }
116
156
  },
117
157
  files: [
@@ -134,19 +174,29 @@ var require_package = __commonJS({
134
174
  pwa: "tsx src/pwa/cli.ts"
135
175
  },
136
176
  peerDependencies: {
177
+ "@djangocfg/i18n": "workspace:*",
178
+ "@djangocfg/ui-core": "workspace:*",
137
179
  next: "^16.0.10"
138
180
  },
181
+ peerDependenciesMeta: {
182
+ "@djangocfg/ui-core": {
183
+ optional: true
184
+ }
185
+ },
139
186
  dependencies: {
140
187
  "@serwist/next": "^9.2.3",
141
188
  "@serwist/sw": "^9.2.3",
142
189
  chalk: "^5.3.0",
143
190
  conf: "^15.0.2",
144
191
  consola: "^3.4.2",
192
+ "next-intl": "^4.1.0",
145
193
  semver: "^7.7.3",
146
194
  serwist: "^9.2.3",
147
195
  "web-push": "^3.6.7"
148
196
  },
149
197
  devDependencies: {
198
+ "@djangocfg/i18n": "workspace:*",
199
+ "@djangocfg/ui-core": "workspace:*",
150
200
  "@djangocfg/imgai": "workspace:*",
151
201
  "@djangocfg/layouts": "workspace:*",
152
202
  "@djangocfg/typescript-config": "workspace:*",
@@ -174,22 +224,58 @@ var require_package = __commonJS({
174
224
  import { NextResponse } from "next/server";
175
225
 
176
226
  // src/sitemap/generator.ts
177
- function generateSitemapXml(urls) {
178
- return `<?xml version="1.0" encoding="UTF-8"?>
179
- <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
227
+ function generateSitemapXml(urlsOrOptions) {
228
+ const isOptionsObject = !Array.isArray(urlsOrOptions);
229
+ const urls = isOptionsObject ? urlsOrOptions.urls : urlsOrOptions;
230
+ const i18n = isOptionsObject ? urlsOrOptions.i18n : void 0;
231
+ const siteUrl = isOptionsObject ? urlsOrOptions.siteUrl : "";
232
+ const namespaces = i18n ? `xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
233
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
180
234
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
181
235
  xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
182
- http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
183
- ${urls.map(
184
- ({ loc, lastmod, changefreq, priority }) => ` <url>
185
- <loc>${escapeXml(loc)}</loc>
236
+ http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"` : `xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
237
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
238
+ xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
239
+ http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"`;
240
+ return `<?xml version="1.0" encoding="UTF-8"?>
241
+ <urlset ${namespaces}>
242
+ ${urls.map(({ loc, lastmod, changefreq, priority }) => {
243
+ const hreflangLinks = i18n ? generateHreflangLinks(loc, i18n, siteUrl) : "";
244
+ return ` <url>
245
+ <loc>${escapeXml(loc)}</loc>${hreflangLinks}
186
246
  ${lastmod ? `<lastmod>${formatDate(lastmod)}</lastmod>` : ""}
187
247
  ${changefreq ? `<changefreq>${changefreq}</changefreq>` : ""}
188
248
  ${priority !== void 0 ? `<priority>${priority.toFixed(1)}</priority>` : ""}
189
- </url>`
190
- ).join("\n")}
249
+ </url>`;
250
+ }).join("\n")}
191
251
  </urlset>`;
192
252
  }
253
+ function generateHreflangLinks(loc, i18n, siteUrl) {
254
+ const { locales, defaultLocale } = i18n;
255
+ const baseSiteUrl = siteUrl.endsWith("/") ? siteUrl.slice(0, -1) : siteUrl;
256
+ let path = loc.replace(baseSiteUrl, "");
257
+ for (const locale of locales) {
258
+ const localePrefix = `/${locale}`;
259
+ if (path === localePrefix || path.startsWith(`${localePrefix}/`)) {
260
+ path = path.slice(localePrefix.length) || "/";
261
+ break;
262
+ }
263
+ }
264
+ const links = [];
265
+ for (const locale of locales) {
266
+ const localePath = path === "/" ? `/${locale}` : `/${locale}${path}`;
267
+ const fullUrl = `${baseSiteUrl}${localePath}`;
268
+ links.push(
269
+ ` <xhtml:link rel="alternate" hreflang="${locale}" href="${escapeXml(fullUrl)}"/>`
270
+ );
271
+ }
272
+ const defaultPath = path === "/" ? `/${defaultLocale}` : `/${defaultLocale}${path}`;
273
+ const defaultUrl = `${baseSiteUrl}${defaultPath}`;
274
+ links.push(
275
+ ` <xhtml:link rel="alternate" hreflang="x-default" href="${escapeXml(defaultUrl)}"/>`
276
+ );
277
+ return "\n" + links.join("\n");
278
+ }
193
279
  function formatDate(date) {
194
280
  if (typeof date === "string") {
195
281
  return date;
@@ -214,7 +300,8 @@ function createSitemapHandler(options) {
214
300
  siteUrl,
215
301
  staticPages = [],
216
302
  dynamicPages = [],
217
- cacheControl = "public, s-maxage=86400, stale-while-revalidate"
303
+ cacheControl = "public, s-maxage=86400, stale-while-revalidate",
304
+ i18n
218
305
  } = options;
219
306
  return async function GET() {
220
307
  const urls = [...staticPages];
@@ -226,11 +313,20 @@ function createSitemapHandler(options) {
226
313
  urls.push(...dynamicPages);
227
314
  }
228
315
  }
229
- const normalizedUrls = urls.map((url) => ({
230
- ...url,
231
- loc: normalizeUrl(url.loc, siteUrl)
232
- }));
233
- const sitemap = generateSitemapXml(normalizedUrls);
316
+ let expandedUrls;
317
+ if (i18n) {
318
+ expandedUrls = expandUrlsForLocales(urls, i18n.locales, siteUrl);
319
+ } else {
320
+ expandedUrls = urls.map((url) => ({
321
+ ...url,
322
+ loc: normalizeUrl(url.loc, siteUrl)
323
+ }));
324
+ }
325
+ const sitemap = generateSitemapXml({
326
+ urls: expandedUrls,
327
+ i18n,
328
+ siteUrl
329
+ });
234
330
  return new NextResponse(sitemap, {
235
331
  status: 200,
236
332
  headers: {
@@ -240,6 +336,37 @@ function createSitemapHandler(options) {
240
336
  });
241
337
  };
242
338
  }
339
+ function expandUrlsForLocales(urls, locales, siteUrl) {
340
+ const baseSiteUrl = siteUrl.endsWith("/") ? siteUrl.slice(0, -1) : siteUrl;
341
+ const expandedUrls = [];
342
+ for (const url of urls) {
343
+ let path = url.loc;
344
+ if (path.startsWith(baseSiteUrl)) {
345
+ path = path.replace(baseSiteUrl, "");
346
+ }
347
+ if (!path.startsWith("/")) {
348
+ path = "/" + path;
349
+ }
350
+ const hasLocalePrefix = locales.some(
351
+ (locale) => path === `/${locale}` || path.startsWith(`/${locale}/`)
352
+ );
353
+ if (hasLocalePrefix) {
354
+ expandedUrls.push({
355
+ ...url,
356
+ loc: normalizeUrl(path, siteUrl)
357
+ });
358
+ } else {
359
+ for (const locale of locales) {
360
+ const localePath = path === "/" ? `/${locale}` : `/${locale}${path}`;
361
+ expandedUrls.push({
362
+ ...url,
363
+ loc: `${baseSiteUrl}${localePath}`
364
+ });
365
+ }
366
+ }
367
+ }
368
+ return expandedUrls;
369
+ }
243
370
 
244
371
  // src/health/route.ts
245
372
  import { NextResponse as NextResponse2 } from "next/server";
@@ -1171,6 +1298,18 @@ function groupRoutesByNavGroups(routes, groups) {
1171
1298
  }).sort((a, b) => a.order - b.order);
1172
1299
  }
1173
1300
 
1301
+ // src/i18n/plugin.ts
1302
+ import createNextIntlPlugin from "next-intl/plugin";
1303
+ function createI18nPlugin(options) {
1304
+ const requestConfigPath = options?.requestConfig ?? "./i18n/request.ts";
1305
+ const withNextIntl = createNextIntlPlugin(requestConfigPath);
1306
+ return withNextIntl;
1307
+ }
1308
+ function withI18n(config, options) {
1309
+ const plugin = createI18nPlugin(options);
1310
+ return plugin(config);
1311
+ }
1312
+
1174
1313
  // src/pwa/plugin.ts
1175
1314
  import { consola } from "consola";
1176
1315
  function withPWA(nextConfig, options = {}) {
@@ -1227,6 +1366,7 @@ var DJANGOCFG_PACKAGES = [
1227
1366
  "@djangocfg/typescript-config"
1228
1367
  ];
1229
1368
  var DEFAULT_TRANSPILE_PACKAGES = [
1369
+ "@djangocfg/i18n",
1230
1370
  "@djangocfg/ui-core",
1231
1371
  "@djangocfg/ui-nextjs",
1232
1372
  "@djangocfg/layouts",
@@ -2383,20 +2523,26 @@ function createBaseNextConfig(options = {}) {
2383
2523
  return config;
2384
2524
  }
2385
2525
  };
2386
- let finalConfig = deepMerge(baseConfig, options);
2387
- delete finalConfig.optimizePackageImports;
2388
- delete finalConfig.isDefaultCfgAdmin;
2389
- delete finalConfig.checkUpdates;
2390
- delete finalConfig.autoUpdate;
2391
- delete finalConfig.forceCheckWorkspace;
2392
- delete finalConfig.checkPackages;
2393
- delete finalConfig.autoInstall;
2394
- delete finalConfig.allowIframeFrom;
2395
- delete finalConfig.openBrowser;
2396
- if (options.pwa) {
2397
- finalConfig = withPWA(finalConfig, options.pwa);
2398
- }
2399
- delete finalConfig.pwa;
2526
+ const {
2527
+ i18n: i18nOptions,
2528
+ pwa: pwaOptions,
2529
+ optimizePackageImports,
2530
+ isDefaultCfgAdmin,
2531
+ checkUpdates,
2532
+ autoUpdate,
2533
+ forceCheckWorkspace,
2534
+ checkPackages: checkPackages2,
2535
+ autoInstall,
2536
+ allowIframeFrom,
2537
+ ...nextConfigOptions
2538
+ } = options;
2539
+ let finalConfig = deepMerge(baseConfig, nextConfigOptions);
2540
+ if (pwaOptions) {
2541
+ finalConfig = withPWA(finalConfig, pwaOptions);
2542
+ }
2543
+ if (i18nOptions) {
2544
+ finalConfig = withI18n(finalConfig, i18nOptions);
2545
+ }
2400
2546
  return finalConfig;
2401
2547
  }
2402
2548