@korioinc/next-core 2.0.43 → 2.0.45
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/README.md +247 -48
- package/dist/i18n/routing.d.ts +1 -0
- package/dist/i18n/routing.d.ts.map +1 -1
- package/dist/i18n/routing.js +7 -2
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/sitemap.d.ts +2 -0
- package/dist/utils/sitemap.d.ts.map +1 -1
- package/dist/utils/sitemap.js +25 -2
- package/package.json +22 -22
package/README.md
CHANGED
|
@@ -1,99 +1,298 @@
|
|
|
1
1
|
# @korioinc/next-core
|
|
2
2
|
|
|
3
|
-
Core utilities and components for Next.js
|
|
3
|
+
Core runtime utilities, providers, and components for Korio Next.js apps.
|
|
4
|
+
|
|
5
|
+
The package is organized around subpath exports. Most modules depend on
|
|
6
|
+
`@korioinc/next-conf` for app-level configuration, so apps should set up
|
|
7
|
+
`next-kit.config.ts` and wrap `next.config.ts` with `withNextKitConf`.
|
|
4
8
|
|
|
5
9
|
## Installation
|
|
6
10
|
|
|
7
11
|
```bash
|
|
8
|
-
pnpm add @korioinc/next-core
|
|
12
|
+
pnpm add @korioinc/next-core @korioinc/next-conf
|
|
9
13
|
```
|
|
10
14
|
|
|
11
|
-
##
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- Next.js `>=16.2.6`
|
|
18
|
+
- React and React DOM `>=19.2.4`
|
|
19
|
+
- Tailwind CSS `>=4.0.0`
|
|
20
|
+
- `@lingui/core` and `@lingui/react` `>=6.0.1`
|
|
21
|
+
- `@headlessui/react` `>=2.2.0`
|
|
22
|
+
|
|
23
|
+
## Required app setup
|
|
24
|
+
|
|
25
|
+
Create `next-kit.config.ts`:
|
|
12
26
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
```typescript
|
|
28
|
+
import type { NextCoreConfig } from '@korioinc/next-conf';
|
|
29
|
+
|
|
30
|
+
const config: NextCoreConfig = {
|
|
31
|
+
api: {
|
|
32
|
+
baseUrl: process.env.API_BASE_URL,
|
|
33
|
+
timeout: 5000,
|
|
34
|
+
headers: {},
|
|
35
|
+
},
|
|
36
|
+
cookie: {
|
|
37
|
+
accessTokenName: '_at',
|
|
38
|
+
domain: '.localhost',
|
|
39
|
+
maxAge: 7 * 24 * 60 * 60,
|
|
40
|
+
},
|
|
41
|
+
auth: {
|
|
42
|
+
restrictedPaths: ['/accounts/login', '/accounts/register'],
|
|
43
|
+
requiredPaths: ['/accounts/profile', '/accounts/settings'],
|
|
44
|
+
loginUrl: '/accounts/login',
|
|
45
|
+
homeUrl: '/',
|
|
46
|
+
},
|
|
47
|
+
analytics: {
|
|
48
|
+
gaId: process.env.NEXT_PUBLIC_GA_ID,
|
|
49
|
+
gtmId: process.env.NEXT_PUBLIC_GTM_ID,
|
|
50
|
+
adsensePublisherId: process.env.NEXT_PUBLIC_ADSENSE_PUBLISHER_ID,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
21
53
|
|
|
22
|
-
|
|
54
|
+
export default config;
|
|
55
|
+
```
|
|
23
56
|
|
|
24
|
-
|
|
57
|
+
Wrap `next.config.ts`:
|
|
25
58
|
|
|
26
59
|
```typescript
|
|
60
|
+
import type { NextConfig } from 'next';
|
|
61
|
+
|
|
62
|
+
import { withNextKitConf } from '@korioinc/next-conf/plugin';
|
|
63
|
+
|
|
64
|
+
const nextConfig: NextConfig = {
|
|
65
|
+
turbopack: {
|
|
66
|
+
rules: {
|
|
67
|
+
'*.po': {
|
|
68
|
+
loaders: ['@lingui/loader'],
|
|
69
|
+
as: '*.js',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export default withNextKitConf(nextConfig);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`withNextKitConf` exposes the app config, `lingui.config`, and the generated
|
|
79
|
+
Lingui loader to this package.
|
|
80
|
+
|
|
81
|
+
## Public entrypoints
|
|
82
|
+
|
|
83
|
+
| Entrypoint | Main exports |
|
|
84
|
+
| ----------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
85
|
+
| `@korioinc/next-core/ads` | `GoogleAdSense`, `AdContainer`, `MockAdDisplay`, ad types and config |
|
|
86
|
+
| `@korioinc/next-core/auth` | Server auth helpers, routing helper, client provider, permission utilities, auth types |
|
|
87
|
+
| `@korioinc/next-core/auth/server` | `getAuthData`, `getCurrentUser`, `isAuthenticated`, permission checks, `handleAuthRouting` |
|
|
88
|
+
| `@korioinc/next-core/auth/client` | `AuthContextProvider`, `useAuthContext`, client token and permission helpers |
|
|
89
|
+
| `@korioinc/next-core/navigation` | Navigation types, permission filtering, `NavigationBuilder` |
|
|
90
|
+
| `@korioinc/next-core/api-client` | `requestApi`, `ApiResponse` |
|
|
91
|
+
| `@korioinc/next-core/i18n/*` | Routing, Lingui setup, Lingui initialization, client provider |
|
|
92
|
+
| `@korioinc/next-core/utils` | `cn`, `isBrowser`, `getBaseUrl`, sitemap helpers |
|
|
93
|
+
| `@korioinc/next-core/local-storage` | `LocalStorageManager`, `createStorageInstance`, `storage`, Valtio persistence helpers |
|
|
94
|
+
| `@korioinc/next-core/components` | `LocaleSwitcher`, `ThemeSwitcher`, `Tooltip`, `HeadManifest`, `JsonLd` |
|
|
95
|
+
| `@korioinc/next-core/theme` | Client `ThemeProvider`, `useTheme`, theme types |
|
|
96
|
+
| `@korioinc/next-core/theme/server` | Server `ThemeProvider`, theme types |
|
|
97
|
+
| `@korioinc/next-core/styles/*` | Built CSS assets, including `styles/globals.css` |
|
|
98
|
+
| `@korioinc/next-core/types/*` | Published ambient type files |
|
|
99
|
+
|
|
100
|
+
## Authentication
|
|
101
|
+
|
|
102
|
+
Server helpers read the access token cookie configured in `next-kit.config.ts`
|
|
103
|
+
and cache auth data per React request.
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
import type { ReactNode } from 'react';
|
|
107
|
+
|
|
108
|
+
import { AuthContextProvider } from '@korioinc/next-core/auth/client';
|
|
109
|
+
import { getAuthData } from '@korioinc/next-core/auth/server';
|
|
110
|
+
|
|
111
|
+
export default async function Layout({ children }: { children: ReactNode }) {
|
|
112
|
+
const authData = await getAuthData();
|
|
113
|
+
|
|
114
|
+
return <AuthContextProvider initialAuthData={authData}>{children}</AuthContextProvider>;
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Client components can read auth state and permission helpers from the provider:
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
'use client';
|
|
122
|
+
|
|
27
123
|
import { useAuthContext } from '@korioinc/next-core/auth/client';
|
|
28
|
-
import { getCurrentUser } from '@korioinc/next-core/auth/server';
|
|
29
124
|
|
|
30
|
-
|
|
31
|
-
const { isLogin, user,
|
|
125
|
+
export function AccountButton() {
|
|
126
|
+
const { isLogin, user, hasPermission, logout } = useAuthContext();
|
|
127
|
+
|
|
128
|
+
if (!isLogin) return null;
|
|
32
129
|
|
|
33
|
-
|
|
34
|
-
|
|
130
|
+
return (
|
|
131
|
+
<button disabled={!hasPermission('update')} onClick={logout}>
|
|
132
|
+
{user?.name}
|
|
133
|
+
</button>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
35
136
|
```
|
|
36
137
|
|
|
37
|
-
|
|
138
|
+
## Routing and i18n
|
|
139
|
+
|
|
140
|
+
Use auth and locale routing together from the Next.js request entrypoint:
|
|
38
141
|
|
|
39
142
|
```typescript
|
|
143
|
+
import type { NextFetchEvent, NextRequest } from 'next/server';
|
|
144
|
+
import { NextResponse } from 'next/server';
|
|
145
|
+
|
|
146
|
+
import { handleAuthRouting } from '@korioinc/next-core/auth/server';
|
|
40
147
|
import { handleLocaleRouting } from '@korioinc/next-core/i18n/routing';
|
|
41
148
|
|
|
42
|
-
|
|
43
|
-
|
|
149
|
+
export default async function proxy(request: NextRequest, _event: NextFetchEvent): Promise<NextResponse> {
|
|
150
|
+
const authResponse = await handleAuthRouting(request);
|
|
151
|
+
if (authResponse) return authResponse;
|
|
152
|
+
|
|
44
153
|
return handleLocaleRouting(request);
|
|
45
154
|
}
|
|
46
155
|
```
|
|
47
156
|
|
|
48
|
-
|
|
157
|
+
Server components can initialize Lingui and pass loaded messages to the client:
|
|
49
158
|
|
|
50
|
-
```
|
|
51
|
-
import {
|
|
52
|
-
|
|
159
|
+
```tsx
|
|
160
|
+
import type { PropsWithChildren } from 'react';
|
|
161
|
+
|
|
162
|
+
import { PageLocaleParam, initLingui } from '@korioinc/next-core/i18n/init-lingui';
|
|
163
|
+
import { allMessages } from '@korioinc/next-core/i18n/lingui.setup';
|
|
164
|
+
import { LinguiClientProvider } from '@korioinc/next-core/i18n/providers/lingui-client-provider';
|
|
165
|
+
|
|
166
|
+
export default async function LocaleLayout({ children, params }: PropsWithChildren<PageLocaleParam>) {
|
|
167
|
+
const locale = (await params).locale;
|
|
168
|
+
initLingui(locale);
|
|
53
169
|
|
|
54
|
-
export function Layout({ children }: { children: React.ReactNode }) {
|
|
55
170
|
return (
|
|
56
|
-
<
|
|
171
|
+
<LinguiClientProvider initialLocale={locale} initialMessages={allMessages[locale] ?? {}}>
|
|
57
172
|
{children}
|
|
58
|
-
</
|
|
173
|
+
</LinguiClientProvider>
|
|
59
174
|
);
|
|
60
175
|
}
|
|
176
|
+
```
|
|
61
177
|
|
|
62
|
-
|
|
178
|
+
Useful routing exports include `getLocales`, `getDefaultLocale`,
|
|
179
|
+
`getPathname`, `getCurrentPathname`, `getCurrentLanguageAlternates`,
|
|
180
|
+
`getFullUrl`, and `getFullUrlByPathname`. Client components can use
|
|
181
|
+
`useToLocalePath` from `@korioinc/next-core/i18n/routing.client`.
|
|
182
|
+
|
|
183
|
+
## Theme and components
|
|
184
|
+
|
|
185
|
+
Use the server theme provider in layouts when theme state may be read from
|
|
186
|
+
cookies:
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
import type { ReactNode } from 'react';
|
|
190
|
+
|
|
191
|
+
import { LocaleSwitcher, ThemeSwitcher } from '@korioinc/next-core/components';
|
|
192
|
+
import { ThemeProvider } from '@korioinc/next-core/theme/server';
|
|
193
|
+
|
|
194
|
+
export default function Layout({ children }: { children: ReactNode }) {
|
|
63
195
|
return (
|
|
64
|
-
<
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
196
|
+
<ThemeProvider attribute='class' enableSystem defaultTheme='system'>
|
|
197
|
+
<header>
|
|
198
|
+
<ThemeSwitcher />
|
|
199
|
+
<LocaleSwitcher />
|
|
200
|
+
</header>
|
|
201
|
+
{children}
|
|
202
|
+
</ThemeProvider>
|
|
68
203
|
);
|
|
69
204
|
}
|
|
70
205
|
```
|
|
71
206
|
|
|
72
|
-
|
|
207
|
+
Import the shared styles from app CSS:
|
|
208
|
+
|
|
209
|
+
```css
|
|
210
|
+
@import '@korioinc/next-core/styles/globals.css';
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## API client
|
|
214
|
+
|
|
215
|
+
`requestApi` is a server-side fetch helper. It uses `api.baseUrl` and the access
|
|
216
|
+
token cookie from `next-kit.config.ts`, forwards the token as `Authorization`,
|
|
217
|
+
updates the cookie from an `x-refreshed-token` response header, and clears the
|
|
218
|
+
cookie on `401`.
|
|
73
219
|
|
|
74
220
|
```typescript
|
|
75
|
-
import {
|
|
221
|
+
import { requestApi } from '@korioinc/next-core/api-client';
|
|
222
|
+
|
|
223
|
+
type SearchResult = {
|
|
224
|
+
id: string;
|
|
225
|
+
title: string;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const results = await requestApi<SearchResult[]>('/search', {
|
|
229
|
+
params: { q: 'korio' },
|
|
230
|
+
next: { revalidate: 60 },
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Ads
|
|
235
|
+
|
|
236
|
+
```tsx
|
|
237
|
+
import type { ReactNode } from 'react';
|
|
238
|
+
|
|
239
|
+
import { getConfig } from '@korioinc/next-conf';
|
|
240
|
+
import { AdContainer, GoogleAdSense } from '@korioinc/next-core/ads';
|
|
241
|
+
|
|
242
|
+
export function RootProviders({ children }: { children: ReactNode }) {
|
|
243
|
+
const publisherId = getConfig().analytics?.adsensePublisherId;
|
|
76
244
|
|
|
77
|
-
export function Page() {
|
|
78
245
|
return (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
246
|
+
<>
|
|
247
|
+
{publisherId && <GoogleAdSense publisherId={publisherId} />}
|
|
248
|
+
{children}
|
|
249
|
+
</>
|
|
83
250
|
);
|
|
84
251
|
}
|
|
252
|
+
|
|
253
|
+
export function PageAd() {
|
|
254
|
+
return <AdContainer adType='leaderboard' className='hidden lg:block' />;
|
|
255
|
+
}
|
|
85
256
|
```
|
|
86
257
|
|
|
87
|
-
|
|
258
|
+
`GoogleAdSense` requires a `publisherId` prop. `AdContainer` reads
|
|
259
|
+
`analytics.adsensePublisherId` from `next-kit.config.ts` when loading production
|
|
260
|
+
ads and renders mock ads for local or development environments. See
|
|
261
|
+
`src/ads/README.md` in this package for available ad types and placement patterns.
|
|
88
262
|
|
|
89
|
-
|
|
90
|
-
- React 19+
|
|
91
|
-
- TypeScript 5.9+
|
|
263
|
+
## Local storage
|
|
92
264
|
|
|
93
|
-
|
|
265
|
+
```typescript
|
|
266
|
+
import { LocalStorageManager, createPersistedStore } from '@korioinc/next-core/local-storage';
|
|
94
267
|
|
|
95
|
-
|
|
268
|
+
type Preferences = {
|
|
269
|
+
compact: boolean;
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const preferences = new LocalStorageManager<Preferences>('preferences');
|
|
273
|
+
await preferences.setItem({ compact: true });
|
|
96
274
|
|
|
97
|
-
|
|
275
|
+
const store = createPersistedStore('todo-store', {
|
|
276
|
+
todos: [] as string[],
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
await store.hydrate();
|
|
280
|
+
```
|
|
98
281
|
|
|
99
|
-
|
|
282
|
+
`LocalStorageManager` uses localforage and reads `storage.name`,
|
|
283
|
+
`storage.storeName`, and `storage.driver` from `next-kit.config.ts`.
|
|
284
|
+
|
|
285
|
+
## Utilities
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import { cn, getBaseUrl, getEntry, getUrl, isBrowser } from '@korioinc/next-core/utils';
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
- `cn` combines `clsx` and `tailwind-merge`
|
|
292
|
+
- `getBaseUrl` uses the app URL environment fallback logic
|
|
293
|
+
- `getEntry` and `getUrl` help build sitemap entries
|
|
294
|
+
- `isBrowser` guards browser-only code paths
|
|
295
|
+
|
|
296
|
+
## License
|
|
297
|
+
|
|
298
|
+
MIT
|
package/dist/i18n/routing.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare function getLocales(): string[];
|
|
|
8
8
|
* Get default locale
|
|
9
9
|
*/
|
|
10
10
|
export declare function getDefaultLocale(): string;
|
|
11
|
+
export declare function getHreflang(locale: string): string;
|
|
11
12
|
export declare function getPathLocale(pathname: string): string | undefined;
|
|
12
13
|
export declare function handleLocaleRouting(request: NextRequest): NextResponse<unknown>;
|
|
13
14
|
export declare function getRequestLocale(requestHeaders: Headers): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/i18n/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAoC7D;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,EAAE,CAErC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AA4BD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAElE;AAiFD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,yBA2EvD;AAED,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,OAAO,GAAG,MAAM,CAShE;AAED,wBAAgB,eAAe,CAAC,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAW9F;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAevG;AAED,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,UAY7E;AAsBD,wBAAgB,qBAAqB,CAAC,QAAQ,GAAE,MAAY,
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/i18n/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAoC7D;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,EAAE,CAErC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIlD;AA4BD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAElE;AAiFD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,yBA2EvD;AAED,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,OAAO,GAAG,MAAM,CAShE;AAED,wBAAgB,eAAe,CAAC,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAW9F;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAevG;AAED,wBAAgB,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,UAY7E;AAsBD,wBAAgB,qBAAqB,CAAC,QAAQ,GAAE,MAAY,0BA0B3D;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAK1D;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAKxE;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAuBpF;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAE3E;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKrE;AAED,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,eAAe,CAAC,CAMvE;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAU1D;AAED,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAIpF;AAED,KAAK,aAAa,GACd,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAC7C,eAAe,GACf,uBAAuB,GACvB,SAAS,CAAC;AAiDd,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,MAAM,CAErF;AAED,wBAAsB,UAAU,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAIxE;AAED,wBAAsB,2BAA2B,IAAI,OAAO,CAAC,MAAM,CAAC,CAKnE"}
|
package/dist/i18n/routing.js
CHANGED
|
@@ -36,6 +36,10 @@ export function getLocales() {
|
|
|
36
36
|
export function getDefaultLocale() {
|
|
37
37
|
return DEFAULT_FALLBACK();
|
|
38
38
|
}
|
|
39
|
+
export function getHreflang(locale) {
|
|
40
|
+
const [language, region] = locale.split('-');
|
|
41
|
+
return region ? `${language.toLowerCase()}-${region.toUpperCase()}` : language.toLowerCase();
|
|
42
|
+
}
|
|
39
43
|
/**
|
|
40
44
|
* 쿠키를 설정하는 헬퍼 함수
|
|
41
45
|
*/
|
|
@@ -245,11 +249,12 @@ export function getLanguageAlternates(pathname = '/') {
|
|
|
245
249
|
locales
|
|
246
250
|
.filter((locale) => locale !== 'pseudo')
|
|
247
251
|
.forEach((locale) => {
|
|
252
|
+
const hreflang = getHreflang(locale);
|
|
248
253
|
if (LOCALE_PREFIX === 'as-needed' && locale === defaultFallback) {
|
|
249
|
-
alternates[
|
|
254
|
+
alternates[hreflang] = basePath;
|
|
250
255
|
}
|
|
251
256
|
else {
|
|
252
|
-
alternates[
|
|
257
|
+
alternates[hreflang] = `/${locale}${basePath === '/' ? '' : basePath}`;
|
|
253
258
|
}
|
|
254
259
|
});
|
|
255
260
|
return alternates;
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/utils/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { cn, isBrowser, getBaseUrl } from './helpers';
|
|
2
|
-
export { getEntry, getUrl } from './sitemap';
|
|
2
|
+
export { getEntry, getLocalizedEntries, getUrl } from './sitemap';
|
package/dist/utils/sitemap.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MetadataRoute } from 'next';
|
|
1
2
|
import { getPathname } from '../i18n/routing';
|
|
2
3
|
type Href = Parameters<typeof getPathname>[0]['href'];
|
|
3
4
|
export declare function getEntry(href: Href, options?: Record<string, string>): {
|
|
@@ -8,6 +9,7 @@ export declare function getEntry(href: Href, options?: Record<string, string>):
|
|
|
8
9
|
};
|
|
9
10
|
};
|
|
10
11
|
};
|
|
12
|
+
export declare function getLocalizedEntries(routes: readonly Href[]): MetadataRoute.Sitemap;
|
|
11
13
|
export declare function getUrl(href: Href, locale: string): string;
|
|
12
14
|
export {};
|
|
13
15
|
//# sourceMappingURL=sitemap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../src/utils/sitemap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../src/utils/sitemap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,EAAe,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAgB9D,KAAK,IAAI,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM;;;;;;;EAQxE;AAMD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,GAAG,aAAa,CAAC,OAAO,CAWlF;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,UAKhD"}
|
package/dist/utils/sitemap.js
CHANGED
|
@@ -1,17 +1,40 @@
|
|
|
1
|
-
import { getPathname } from '../i18n/routing';
|
|
1
|
+
import { getHreflang, getPathname } from '../i18n/routing';
|
|
2
2
|
import { getBaseUrl } from '../utils/helpers';
|
|
3
3
|
import linguiConfig from 'lingui.config';
|
|
4
4
|
const { locales, fallbackLocales } = linguiConfig;
|
|
5
5
|
const defaultLocale = fallbackLocales.default;
|
|
6
|
+
const indexableLocales = [...locales]
|
|
7
|
+
.filter((locale) => locale !== 'pseudo')
|
|
8
|
+
.sort((a, b) => {
|
|
9
|
+
if (a === defaultLocale)
|
|
10
|
+
return -1;
|
|
11
|
+
if (b === defaultLocale)
|
|
12
|
+
return 1;
|
|
13
|
+
return a.localeCompare(b);
|
|
14
|
+
});
|
|
6
15
|
export function getEntry(href, options = {}) {
|
|
7
16
|
return {
|
|
8
17
|
url: getUrl(href, defaultLocale),
|
|
9
18
|
alternates: {
|
|
10
|
-
languages: Object.fromEntries(
|
|
19
|
+
languages: Object.fromEntries(indexableLocales.map((cur) => [getHreflang(cur), getUrl(href, cur)])),
|
|
11
20
|
},
|
|
12
21
|
...options,
|
|
13
22
|
};
|
|
14
23
|
}
|
|
24
|
+
function getAlternateLanguages(href) {
|
|
25
|
+
return Object.fromEntries(indexableLocales.map((locale) => [getHreflang(locale), getUrl(href, locale)]));
|
|
26
|
+
}
|
|
27
|
+
export function getLocalizedEntries(routes) {
|
|
28
|
+
return routes.flatMap((href) => {
|
|
29
|
+
const languages = getAlternateLanguages(href);
|
|
30
|
+
return indexableLocales.map((locale) => ({
|
|
31
|
+
url: getUrl(href, locale),
|
|
32
|
+
alternates: {
|
|
33
|
+
languages,
|
|
34
|
+
},
|
|
35
|
+
}));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
15
38
|
export function getUrl(href, locale) {
|
|
16
39
|
const pathname = getPathname({ locale, href });
|
|
17
40
|
const host = getBaseUrl();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@korioinc/next-core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.45",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./ads": {
|
|
@@ -73,39 +73,39 @@
|
|
|
73
73
|
],
|
|
74
74
|
"devDependencies": {
|
|
75
75
|
"@headlessui/react": "^2.2.10",
|
|
76
|
-
"@lingui/conf": "^
|
|
77
|
-
"@lingui/core": "^
|
|
78
|
-
"@lingui/react": "^
|
|
76
|
+
"@lingui/conf": "^6.0.1",
|
|
77
|
+
"@lingui/core": "^6.0.1",
|
|
78
|
+
"@lingui/react": "^6.0.1",
|
|
79
79
|
"@tailwindcss/typography": "^0.5.19",
|
|
80
80
|
"@types/negotiator": "^0.6.4",
|
|
81
|
-
"@types/node": "^25.
|
|
81
|
+
"@types/node": "^25.8.0",
|
|
82
82
|
"@types/react": "^19.2.14",
|
|
83
83
|
"@types/react-dom": "^19.2.3",
|
|
84
|
-
"eslint": "^10.
|
|
85
|
-
"jsdom": "^29.
|
|
86
|
-
"react": "^19.2.
|
|
87
|
-
"react-dom": "^19.2.
|
|
88
|
-
"tailwindcss": "^4.
|
|
89
|
-
"tsc-alias": "^1.8.
|
|
84
|
+
"eslint": "^10.4.0",
|
|
85
|
+
"jsdom": "^29.1.1",
|
|
86
|
+
"react": "^19.2.6",
|
|
87
|
+
"react-dom": "^19.2.6",
|
|
88
|
+
"tailwindcss": "^4.3.0",
|
|
89
|
+
"tsc-alias": "^1.8.17",
|
|
90
90
|
"tw-animate-css": "^1.4.0",
|
|
91
|
-
"typescript": "^6.0.
|
|
92
|
-
"vitest": "^4.1.
|
|
93
|
-
"@korioinc/next-configs": "2.0.
|
|
91
|
+
"typescript": "^6.0.3",
|
|
92
|
+
"vitest": "^4.1.6",
|
|
93
|
+
"@korioinc/next-configs": "2.0.45"
|
|
94
94
|
},
|
|
95
95
|
"dependencies": {
|
|
96
96
|
"@floating-ui/react": "^0.27.19",
|
|
97
|
-
"@formatjs/intl-localematcher": "^0.8.
|
|
97
|
+
"@formatjs/intl-localematcher": "^0.8.8",
|
|
98
98
|
"clsx": "^2.1.1",
|
|
99
99
|
"cookies-next": "^6.1.1",
|
|
100
100
|
"cosmiconfig": "^9.0.1",
|
|
101
|
-
"jose": "^6.2.
|
|
101
|
+
"jose": "^6.2.3",
|
|
102
102
|
"localforage": "^1.10.0",
|
|
103
103
|
"negotiator": "^1.0.0",
|
|
104
104
|
"pretendard": "^1.3.9",
|
|
105
105
|
"schema-dts": "^2.0.0",
|
|
106
|
-
"tailwind-merge": "^3.
|
|
107
|
-
"valtio": "^2.3.
|
|
108
|
-
"@korioinc/next-conf": "2.0.
|
|
106
|
+
"tailwind-merge": "^3.6.0",
|
|
107
|
+
"valtio": "^2.3.2",
|
|
108
|
+
"@korioinc/next-conf": "2.0.45"
|
|
109
109
|
},
|
|
110
110
|
"publishConfig": {
|
|
111
111
|
"access": "public",
|
|
@@ -119,9 +119,9 @@
|
|
|
119
119
|
"author": "Korio Inc.",
|
|
120
120
|
"peerDependencies": {
|
|
121
121
|
"@headlessui/react": ">=2.2.0",
|
|
122
|
-
"@lingui/core": ">=
|
|
123
|
-
"@lingui/react": ">=
|
|
124
|
-
"next": ">=16.2.
|
|
122
|
+
"@lingui/core": ">=6.0.1",
|
|
123
|
+
"@lingui/react": ">=6.0.1",
|
|
124
|
+
"next": ">=16.2.6",
|
|
125
125
|
"react": ">=19.2.4",
|
|
126
126
|
"react-dom": ">=19.2.4",
|
|
127
127
|
"tailwindcss": ">=4.0.0"
|