next-tongue 0.9.9 → 0.9.10
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/cli/init.js
CHANGED
|
@@ -83,14 +83,12 @@ export default defineConfig({
|
|
|
83
83
|
path: `${appRoot}/[locale]/page.tsx`,
|
|
84
84
|
kind: 'create',
|
|
85
85
|
content: `import { getT } from 'next-tongue/server';
|
|
86
|
-
import { ensureTongue } from '#tongue/runtime';
|
|
87
86
|
|
|
88
87
|
export default async function Page({
|
|
89
88
|
params,
|
|
90
89
|
}: {
|
|
91
90
|
params: Promise<{ locale: string }>;
|
|
92
91
|
}) {
|
|
93
|
-
ensureTongue();
|
|
94
92
|
const { locale } = await params;
|
|
95
93
|
const t = await getT(locale, 'home');
|
|
96
94
|
return (
|
|
@@ -246,10 +244,10 @@ export const config = {
|
|
|
246
244
|
function rootLocaleLayout() {
|
|
247
245
|
return `import { notFound } from 'next/navigation';
|
|
248
246
|
import { TongueProvider } from 'next-tongue/client';
|
|
249
|
-
import { getDir, isLocale
|
|
250
|
-
import {
|
|
247
|
+
import { getDir, isLocale } from 'next-tongue/server';
|
|
248
|
+
import { localeParams } from '#tongue/runtime';
|
|
251
249
|
|
|
252
|
-
ensureTongue()
|
|
250
|
+
// Importing #tongue/runtime auto-runs ensureTongue() (withTongue apps).
|
|
253
251
|
export const generateStaticParams = localeParams;
|
|
254
252
|
|
|
255
253
|
export default async function LocaleLayout({
|
|
@@ -278,10 +276,10 @@ export default async function LocaleLayout({
|
|
|
278
276
|
function nestedLocaleLayout() {
|
|
279
277
|
return `import { notFound } from 'next/navigation';
|
|
280
278
|
import { TongueProvider } from 'next-tongue/client';
|
|
281
|
-
import { isLocale
|
|
282
|
-
import {
|
|
279
|
+
import { isLocale } from 'next-tongue/server';
|
|
280
|
+
import { localeParams } from '#tongue/runtime';
|
|
283
281
|
|
|
284
|
-
ensureTongue()
|
|
282
|
+
// Importing #tongue/runtime auto-runs ensureTongue() (withTongue apps).
|
|
285
283
|
export const generateStaticParams = localeParams;
|
|
286
284
|
|
|
287
285
|
export default async function LocaleLayout({
|
package/dist/compiler/build.js
CHANGED
|
@@ -113,8 +113,8 @@ export async function buildMessages(options) {
|
|
|
113
113
|
const defaultMsgRel = config.messages.replaceAll('{locale}', config.defaultLocale);
|
|
114
114
|
const emitLocales = localesForEmit(config);
|
|
115
115
|
// Content hash for idempotency (bump CODEGEN_VERSION when emit format changes)
|
|
116
|
-
// Bump when emit shape changes (
|
|
117
|
-
const CODEGEN_VERSION =
|
|
116
|
+
// Bump when emit shape changes (reserved idents, auto ensureTongue side-effect).
|
|
117
|
+
const CODEGEN_VERSION = 9;
|
|
118
118
|
const hash = createHash('sha256')
|
|
119
119
|
.update(JSON.stringify({
|
|
120
120
|
codegen: CODEGEN_VERSION,
|
|
@@ -337,7 +337,10 @@ export async function buildMessages(options) {
|
|
|
337
337
|
? `export const pseudoLocale = ${JSON.stringify(config.pseudo.locale)};`
|
|
338
338
|
: `export const pseudoLocale = undefined;`, `export function localeParams() {`, ` return locales.map((locale) => ({ locale }));`, `}`, `let ready = false;`, `export function ensureTongue() {`, ` if (ready) return;`, ` __setServerRuntime({`, ` locales: allLocales,`, ` defaultLocale,`, ` timeZone,`, ` rootParams: ${config.routing.rootParams ? 'true' : 'false'},`, ` loadNamespace: async (namespace) => {`, ` const messages = namespaces[namespace];`, ` if (!messages) throw new Error('[next-tongue] Unknown namespace: ' + namespace);`, ` return messages;`, ` },`, ` });`, config.pseudo && config.pseudo.enabled !== false
|
|
339
339
|
? ` configureFormatMessage({ timeZone, pseudo: { locale: ${JSON.stringify(config.pseudo.locale)}, expand: ${config.pseudo.expand} } });`
|
|
340
|
-
: ` configureFormatMessage({ timeZone });`, ` ready = true;`, `}`,
|
|
340
|
+
: ` configureFormatMessage({ timeZone });`, ` ready = true;`, `}`,
|
|
341
|
+
// Side-effect: importing `#tongue/runtime` (or getT's lazy import) wires the
|
|
342
|
+
// server without a per-page ensureTongue() call when using withTongue().
|
|
343
|
+
`ensureTongue();`, ``);
|
|
341
344
|
await writeFile(join(outDir, 'runtime.js'), runtimeLines.join('\n'), 'utf8');
|
|
342
345
|
await writeFile(join(outDir, 'runtime.d.ts'), [
|
|
343
346
|
`/** Generated by next-tongue — do not edit. */`,
|
|
@@ -407,7 +410,7 @@ export async function buildMessages(options) {
|
|
|
407
410
|
await writeFile(join(outDir, 'manifest.json'), JSON.stringify(manifest, null, 2), 'utf8');
|
|
408
411
|
await writeFile(join(outDir, '.hash'), hash, 'utf8');
|
|
409
412
|
// package.json imports helper note — apps map "#tongue/*" themselves / via withTongue
|
|
410
|
-
await writeFile(join(outDir, 'README.md'), 'Generated by next-tongue. Do not edit. Map `#tongue/*` → this directory.\
|
|
413
|
+
await writeFile(join(outDir, 'README.md'), 'Generated by next-tongue. Do not edit. Map `#tongue/*` → this directory.\nImporting `#tongue/runtime` (or calling getT) auto-runs ensureTongue(); an explicit call is optional.\n', 'utf8');
|
|
411
414
|
await clearOutputDir(publishedOutDir);
|
|
412
415
|
try {
|
|
413
416
|
await rename(outDir, publishedOutDir);
|
|
@@ -6,5 +6,8 @@ export type WithTongueOptions = {
|
|
|
6
6
|
/**
|
|
7
7
|
* Config wrapper (not a bundler plugin): runs codegen when Next loads config,
|
|
8
8
|
* maps `#tongue/*` → outDir, registers the call-site loader for Turbopack + webpack.
|
|
9
|
+
*
|
|
10
|
+
* Codegen emits `#tongue/runtime` that auto-calls `ensureTongue()` on import;
|
|
11
|
+
* `getT` / `getFormat` also lazy-import that module — no per-page ensureTongue().
|
|
9
12
|
*/
|
|
10
13
|
export declare function withTongue<T extends object>(nextConfig?: T, options?: WithTongueOptions): T;
|
package/dist/next/with-tongue.js
CHANGED
|
@@ -7,6 +7,9 @@ import { startDevWatcher } from './watcher.js';
|
|
|
7
7
|
/**
|
|
8
8
|
* Config wrapper (not a bundler plugin): runs codegen when Next loads config,
|
|
9
9
|
* maps `#tongue/*` → outDir, registers the call-site loader for Turbopack + webpack.
|
|
10
|
+
*
|
|
11
|
+
* Codegen emits `#tongue/runtime` that auto-calls `ensureTongue()` on import;
|
|
12
|
+
* `getT` / `getFormat` also lazy-import that module — no per-page ensureTongue().
|
|
10
13
|
*/
|
|
11
14
|
export function withTongue(nextConfig = {}, options = {}) {
|
|
12
15
|
const cwd = process.cwd();
|
|
@@ -14,8 +14,12 @@ export type TFunction<N extends Namespace = Namespace> = {
|
|
|
14
14
|
<K extends MessageKey<N>>(key: K, ...args: [ArgsFor<N, K>] extends [never] ? [values?: Record<string, never>] : Record<string, never> extends ArgsFor<N, K> ? [values?: ArgsFor<N, K>] : [values: ArgsFor<N, K>]): string;
|
|
15
15
|
rich: <K extends MessageKey<N>>(key: K, ...args: [ArgsFor<N, K>] extends [never] ? [values?: Record<string, never>] : Record<string, never> extends ArgsFor<N, K> ? [values?: ArgsFor<N, K>] : [values: ArgsFor<N, K>]) => ReactNode;
|
|
16
16
|
has: (key: string) => boolean;
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Non-literal key from a declared set. `key` is narrowed to `From[number]`
|
|
19
|
+
* when `from` is a `as const` / readonly tuple of known keys.
|
|
20
|
+
*/
|
|
21
|
+
dynamic: <const From extends readonly MessageKey<N>[]>(key: From[number], opts: {
|
|
22
|
+
from: From;
|
|
19
23
|
}, values?: Record<string, unknown>) => string;
|
|
20
24
|
ns: <N2 extends Namespace>(namespace: N2) => TFunction<N2>;
|
|
21
25
|
};
|
package/dist/server/index.d.ts
CHANGED
|
@@ -29,11 +29,20 @@ export declare const defaultLocale: {
|
|
|
29
29
|
export type LocaleProps = {
|
|
30
30
|
locale: string;
|
|
31
31
|
};
|
|
32
|
+
/** Map of translators when loading several namespaces in one call. */
|
|
33
|
+
export type MultiT<Ns extends readonly Namespace[]> = {
|
|
34
|
+
[K in Ns[number]]: TFunction<K>;
|
|
35
|
+
};
|
|
32
36
|
/**
|
|
33
37
|
* Explicit locale (always available): `getT(locale, ns)` or `getT(locale)` for `_root`.
|
|
38
|
+
* Multi-ns: `getT(locale, ['home', 'common'])` → `{ home, common }` translators.
|
|
34
39
|
* With `routing.rootParams: true`, `getT(ns)` resolves locale from `next/root-params`
|
|
35
40
|
* when the single argument is a configured namespace (not a locale tag).
|
|
41
|
+
*
|
|
42
|
+
* `withTongue()` + generated `#tongue/runtime` auto-wires messages; an explicit
|
|
43
|
+
* `ensureTongue()` call is optional.
|
|
36
44
|
*/
|
|
45
|
+
export declare function getT<const Ns extends readonly [Namespace, ...Namespace[]]>(locale: Locale | string, namespaces: Ns): Promise<MultiT<Ns>>;
|
|
37
46
|
export declare function getT<N extends Namespace>(locale: Locale | string, namespace: N): Promise<TFunction<N>>;
|
|
38
47
|
export declare function getT(locale: Locale | string): Promise<TFunction<'_root'>>;
|
|
39
48
|
export declare function getFormat(locale?: string, options?: {
|
package/dist/server/index.js
CHANGED
|
@@ -42,6 +42,18 @@ export const defaultLocale = {
|
|
|
42
42
|
};
|
|
43
43
|
export async function getT(localeOrNs, namespace) {
|
|
44
44
|
if (namespace !== undefined) {
|
|
45
|
+
if (Array.isArray(namespace)) {
|
|
46
|
+
if (namespace.length === 0) {
|
|
47
|
+
throw new TongueError('TONGUE_E_CONFIG', 'getT(locale, namespaces) requires a non-empty namespace array');
|
|
48
|
+
}
|
|
49
|
+
const locale = String(localeOrNs);
|
|
50
|
+
const out = {};
|
|
51
|
+
// Load sequentially so a single ensureRuntime runs first; namespaces share locale.
|
|
52
|
+
for (const ns of namespace) {
|
|
53
|
+
out[ns] = await getTWithLocale(locale, ns);
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
45
57
|
return getTWithLocale(String(localeOrNs), namespace);
|
|
46
58
|
}
|
|
47
59
|
const single = String(localeOrNs);
|
|
@@ -54,9 +66,10 @@ export async function getT(localeOrNs, namespace) {
|
|
|
54
66
|
return getTWithLocale(single, '_root');
|
|
55
67
|
}
|
|
56
68
|
async function getTWithLocale(locale, ns) {
|
|
69
|
+
await ensureRuntime();
|
|
57
70
|
assertLocale(locale);
|
|
58
71
|
if (!namespaceLoader) {
|
|
59
|
-
throw new TongueError('TONGUE_E_TYPES_MISSING', 'Message modules not loaded.
|
|
72
|
+
throw new TongueError('TONGUE_E_TYPES_MISSING', 'Message modules not loaded. Wrap next.config with withTongue() and run `tongue build && next build` so `#tongue/runtime` exists. (ensureTongue() is optional — getT loads it automatically.)');
|
|
60
73
|
}
|
|
61
74
|
const messages = await namespaceLoader(ns);
|
|
62
75
|
return createT({
|
|
@@ -67,7 +80,24 @@ async function getTWithLocale(locale, ns) {
|
|
|
67
80
|
},
|
|
68
81
|
});
|
|
69
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Load `#tongue/runtime` and call `ensureTongue()` once when the server runtime
|
|
85
|
+
* is not yet wired (withTongue apps — no per-page ensureTongue boilerplate).
|
|
86
|
+
*/
|
|
87
|
+
async function ensureRuntime() {
|
|
88
|
+
if (namespaceLoader)
|
|
89
|
+
return;
|
|
90
|
+
try {
|
|
91
|
+
const importer = new Function('s', 'return import(s)');
|
|
92
|
+
const mod = await importer('#tongue/runtime');
|
|
93
|
+
mod.ensureTongue?.();
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
/* fall through — getTWithLocale throws a clear error */
|
|
97
|
+
}
|
|
98
|
+
}
|
|
70
99
|
export async function getFormat(locale, options) {
|
|
100
|
+
await ensureRuntime();
|
|
71
101
|
const resolved = locale ?? (runtimeRootParams ? await resolveRootLocale() : undefined);
|
|
72
102
|
if (resolved == null) {
|
|
73
103
|
throw new TongueError('TONGUE_E_LOCALE', 'getFormat(locale) requires a locale, or routing.rootParams: true');
|