@analogjs/router 3.0.0-alpha.7 → 3.0.0-alpha.70
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/content/package.json +4 -0
- package/fesm2022/analogjs-router-content.mjs +63 -0
- package/fesm2022/analogjs-router-content.mjs.map +1 -0
- package/fesm2022/analogjs-router-i18n.mjs +156 -0
- package/fesm2022/analogjs-router-i18n.mjs.map +1 -0
- package/fesm2022/analogjs-router-server-actions.mjs +2 -27
- package/fesm2022/analogjs-router-server.mjs +734 -105
- package/fesm2022/analogjs-router-server.mjs.map +1 -0
- package/fesm2022/analogjs-router-tanstack-query-server.mjs +71 -0
- package/fesm2022/analogjs-router-tanstack-query-server.mjs.map +1 -0
- package/fesm2022/analogjs-router-tanstack-query.mjs +39 -0
- package/fesm2022/analogjs-router-tanstack-query.mjs.map +1 -0
- package/fesm2022/analogjs-router-tokens.mjs +7 -2
- package/fesm2022/analogjs-router-tokens.mjs.map +1 -0
- package/fesm2022/analogjs-router.mjs +670 -170
- package/fesm2022/analogjs-router.mjs.map +1 -0
- package/fesm2022/debug.page.mjs +53 -31
- package/fesm2022/debug.page.mjs.map +1 -0
- package/fesm2022/provide-analog-query.mjs +72 -0
- package/fesm2022/provide-analog-query.mjs.map +1 -0
- package/fesm2022/route-files.mjs +361 -0
- package/fesm2022/route-files.mjs.map +1 -0
- package/fesm2022/routes.mjs +5 -278
- package/fesm2022/routes.mjs.map +1 -0
- package/fesm2022/src.mjs +335 -0
- package/fesm2022/src.mjs.map +1 -0
- package/i18n/package.json +4 -0
- package/package.json +52 -5
- package/tanstack-query/package.json +4 -0
- package/tanstack-query/server/package.json +4 -0
- package/types/content/src/index.d.ts +4 -0
- package/types/content/src/lib/debug/routes.d.ts +10 -0
- package/types/{src → content/src}/lib/markdown-helpers.d.ts +1 -1
- package/types/content/src/lib/routes.d.ts +8 -0
- package/types/content/src/lib/with-content-routes.d.ts +2 -0
- package/types/i18n/src/index.d.ts +1 -0
- package/types/i18n/src/provide-i18n.d.ts +92 -0
- package/types/server/actions/src/define-action.d.ts +54 -0
- package/types/server/actions/src/define-api-route.d.ts +57 -0
- package/types/server/actions/src/define-page-load.d.ts +55 -0
- package/types/server/actions/src/define-server-route.d.ts +68 -0
- package/types/server/actions/src/index.d.ts +9 -1
- package/types/server/actions/src/parse-request-data.d.ts +9 -0
- package/types/server/actions/src/validate.d.ts +8 -0
- package/types/server/src/defer-reconcile-runtime.d.ts +23 -0
- package/types/server/src/index.d.ts +9 -2
- package/types/server/src/provide-server-context.d.ts +15 -1
- package/types/server/src/render-stream.d.ts +40 -0
- package/types/server/src/render.d.ts +3 -3
- package/types/server/src/server-fn/app-injector.d.ts +30 -0
- package/types/server/src/server-fn/dispatch.d.ts +56 -0
- package/types/server/src/server-fn/event-handler.d.ts +22 -0
- package/types/server/src/server-fn/interceptors.d.ts +30 -0
- package/types/server/src/server-fn/node-context.d.ts +14 -0
- package/types/server/src/server-fn/registry.d.ts +7 -0
- package/types/server/src/server-fn/same-origin.d.ts +46 -0
- package/types/server/src/server-fn/server-fn.d.ts +21 -0
- package/types/server/src/server-fn/ssr-dispatcher.d.ts +17 -0
- package/types/server/src/utils/reset-component-def-tviews.d.ts +14 -0
- package/types/server/src/utils/stream-html.d.ts +13 -0
- package/types/server/src/utils/stream-request.d.ts +24 -0
- package/types/src/index.d.ts +20 -6
- package/types/src/lib/cache-key.d.ts +1 -1
- package/types/src/lib/cookie-interceptor.d.ts +1 -1
- package/types/src/lib/debug/debug.page.d.ts +4 -2
- package/types/src/lib/define-route.d.ts +6 -1
- package/types/src/lib/endpoints.d.ts +1 -1
- package/types/src/lib/experimental.d.ts +140 -0
- package/types/src/lib/form-action.directive.d.ts +12 -5
- package/types/src/lib/inject-load.d.ts +5 -2
- package/types/src/lib/inject-navigate.d.ts +23 -0
- package/types/src/lib/inject-route-context.d.ts +32 -0
- package/types/src/lib/inject-typed-params.d.ts +63 -0
- package/types/src/lib/json-ld.d.ts +32 -0
- package/types/src/lib/meta-tags.d.ts +3 -1
- package/types/src/lib/models.d.ts +3 -0
- package/types/src/lib/provide-file-router-base.d.ts +4 -0
- package/types/src/lib/provide-file-router.d.ts +2 -8
- package/types/src/lib/route-builder.d.ts +5 -0
- package/types/src/lib/route-files.d.ts +18 -0
- package/types/src/lib/route-path.d.ts +124 -0
- package/types/src/lib/route-types.d.ts +2 -1
- package/types/src/lib/routes.d.ts +2 -10
- package/types/src/lib/server-fn/dispatcher.d.ts +23 -0
- package/types/src/lib/server-fn/inject-server-fn.d.ts +44 -0
- package/types/src/lib/server-fn/server-fn-ref.d.ts +24 -0
- package/types/src/lib/server-fn/types.d.ts +55 -0
- package/types/src/lib/validation-errors.d.ts +7 -0
- package/types/tanstack-query/server/src/define-page-load-queries.d.ts +66 -0
- package/types/tanstack-query/server/src/index.d.ts +3 -0
- package/types/tanstack-query/src/constants.d.ts +9 -0
- package/types/tanstack-query/src/index.d.ts +2 -0
- package/types/tanstack-query/src/provide-analog-query.d.ts +4 -0
- package/types/tanstack-query/src/provide-server-analog-query.d.ts +2 -0
- package/types/tanstack-query/src/server-query.d.ts +16 -0
- package/types/tokens/src/index.d.ts +2 -0
- package/types/server/src/server-component-render.d.ts +0 -4
- package/types/server/src/tokens.d.ts +0 -7
- package/types/src/lib/server.component.d.ts +0 -33
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { r as createRoutes, t as ANALOG_EXTRA_ROUTE_FILE_SOURCES } from "./route-files.mjs";
|
|
2
|
+
import { InjectionToken, inject } from "@angular/core";
|
|
3
|
+
import { ContentRenderer, MarkdownRouteComponent, parseRawContentFile } from "@analogjs/content";
|
|
4
|
+
//#region packages/router/content/src/lib/markdown-helpers.ts
|
|
5
|
+
var isNgZoneEnabled = typeof Zone !== "undefined" && !!Zone.root;
|
|
6
|
+
function toMarkdownModule(markdownFileFactory) {
|
|
7
|
+
return async () => {
|
|
8
|
+
const { content, attributes } = parseRawContentFile(await (isNgZoneEnabled ? Zone.root.run(markdownFileFactory) : markdownFileFactory()));
|
|
9
|
+
const { title, meta, jsonLd } = attributes;
|
|
10
|
+
return {
|
|
11
|
+
default: MarkdownRouteComponent,
|
|
12
|
+
routeMeta: {
|
|
13
|
+
data: { _analogContent: content },
|
|
14
|
+
title,
|
|
15
|
+
meta,
|
|
16
|
+
jsonLd,
|
|
17
|
+
resolve: { renderedAnalogContent: async () => {
|
|
18
|
+
const rendered = await inject(ContentRenderer).render(content);
|
|
19
|
+
return typeof rendered === "string" ? rendered : rendered.content;
|
|
20
|
+
} }
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region packages/router/content/src/lib/routes.ts
|
|
27
|
+
/**
|
|
28
|
+
* This variable reference is replaced with a glob of all content routes.
|
|
29
|
+
*/
|
|
30
|
+
var ANALOG_CONTENT_ROUTE_FILES = {};
|
|
31
|
+
function createContentRoutes(files, debug = false) {
|
|
32
|
+
return createRoutes(files, (filename, fileLoader) => filename.endsWith(".md") ? toMarkdownModule(fileLoader) : fileLoader, debug);
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region packages/router/content/src/lib/with-content-routes.ts
|
|
36
|
+
function withContentRoutes() {
|
|
37
|
+
return {
|
|
38
|
+
ɵkind: 101,
|
|
39
|
+
ɵproviders: [{
|
|
40
|
+
provide: ANALOG_EXTRA_ROUTE_FILE_SOURCES,
|
|
41
|
+
multi: true,
|
|
42
|
+
useValue: {
|
|
43
|
+
files: ANALOG_CONTENT_ROUTE_FILES,
|
|
44
|
+
resolveModule: (filename, fileLoader) => filename.endsWith(".md") ? toMarkdownModule(fileLoader) : fileLoader
|
|
45
|
+
}
|
|
46
|
+
}]
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region packages/router/content/src/lib/debug/routes.ts
|
|
51
|
+
var DEBUG_CONTENT_ROUTES = new InjectionToken("@analogjs/router/content debug routes", {
|
|
52
|
+
providedIn: "root",
|
|
53
|
+
factory() {
|
|
54
|
+
return createContentRoutes(ANALOG_CONTENT_ROUTE_FILES, true);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
function injectDebugContentRoutes() {
|
|
58
|
+
return inject(DEBUG_CONTENT_ROUTES);
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { ANALOG_CONTENT_ROUTE_FILES, createContentRoutes, injectDebugContentRoutes, withContentRoutes };
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=analogjs-router-content.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analogjs-router-content.mjs","names":[],"sources":["../../content/src/lib/markdown-helpers.ts","../../content/src/lib/routes.ts","../../content/src/lib/with-content-routes.ts","../../content/src/lib/debug/routes.ts"],"sourcesContent":["import { inject } from '@angular/core';\nimport {\n ContentRenderer,\n MarkdownRouteComponent,\n parseRawContentFile,\n} from '@analogjs/content';\n\nimport type { RouteExport } from '../../../src/lib/models';\n\ndeclare const Zone: any;\n\ntype RenderResult = string | { content: string };\ntype ContentRendererLike = {\n render: (content: string) => Promise<RenderResult>;\n};\n\nconst isNgZoneEnabled = typeof Zone !== 'undefined' && !!Zone.root;\n\nexport function toMarkdownModule(\n markdownFileFactory: () => Promise<string>,\n): () => Promise<RouteExport> {\n return async () => {\n const markdownFile = await (isNgZoneEnabled\n ? Zone.root.run(markdownFileFactory)\n : markdownFileFactory());\n\n const { content, attributes } = parseRawContentFile(markdownFile);\n const { title, meta, jsonLd } = attributes;\n\n return {\n default: MarkdownRouteComponent,\n routeMeta: {\n data: { _analogContent: content },\n title,\n meta,\n jsonLd,\n resolve: {\n renderedAnalogContent: async () => {\n const contentRenderer = inject<any>(\n ContentRenderer as any,\n ) as ContentRendererLike;\n const rendered = await contentRenderer.render(content);\n return typeof rendered === 'string' ? rendered : rendered.content;\n },\n },\n },\n };\n };\n}\n","import type { Route } from '@angular/router';\n\nimport type { RouteExport } from '../../../src/lib/models';\nimport { createRoutes as createBaseRoutes } from '../../../src/lib/route-builder';\nimport { toMarkdownModule } from './markdown-helpers';\n\n/**\n * This variable reference is replaced with a glob of all content routes.\n */\nexport const ANALOG_CONTENT_ROUTE_FILES = {};\n\nexport type Files = Record<string, () => Promise<RouteExport | string>>;\n\nexport function createContentRoutes(files: Files, debug = false): Route[] {\n return createBaseRoutes(\n files,\n (filename, fileLoader) =>\n filename.endsWith('.md')\n ? toMarkdownModule(fileLoader as () => Promise<string>)\n : (fileLoader as () => Promise<RouteExport>),\n debug,\n );\n}\n","import { type RouterFeatures } from '@angular/router';\n\nimport { ANALOG_CONTENT_ROUTE_FILES } from './routes';\nimport { toMarkdownModule } from './markdown-helpers';\nimport type { RouteExport } from '../../../src/lib/models';\nimport {\n ANALOG_EXTRA_ROUTE_FILE_SOURCES,\n type ExtraRouteFileSource,\n} from '../../../src/lib/route-files';\n\nexport function withContentRoutes(): RouterFeatures {\n return {\n ɵkind: 101 as number,\n ɵproviders: [\n {\n provide: ANALOG_EXTRA_ROUTE_FILE_SOURCES,\n multi: true,\n useValue: {\n files: ANALOG_CONTENT_ROUTE_FILES,\n resolveModule: (\n filename: string,\n fileLoader: () => Promise<unknown>,\n ) =>\n filename.endsWith('.md')\n ? toMarkdownModule(fileLoader as () => Promise<string>)\n : (fileLoader as () => Promise<RouteExport>),\n } satisfies ExtraRouteFileSource,\n },\n ],\n };\n}\n","import { inject, InjectionToken } from '@angular/core';\nimport { Route } from '@angular/router';\n\nimport { ANALOG_CONTENT_ROUTE_FILES, createContentRoutes } from '../routes';\n\nexport const DEBUG_CONTENT_ROUTES: InjectionToken<(Route & DebugRoute)[]> =\n new InjectionToken<(Route & DebugRoute)[]>(\n '@analogjs/router/content debug routes',\n {\n providedIn: 'root',\n factory() {\n const debugRoutes = createContentRoutes(\n ANALOG_CONTENT_ROUTE_FILES as Record<string, () => Promise<string>>,\n true,\n );\n\n return debugRoutes as (Route & DebugRoute)[];\n },\n },\n );\n\nexport type DebugRoute = {\n path: string;\n filename: string;\n isLayout: boolean;\n children?: DebugRoute[];\n};\n\nexport function injectDebugContentRoutes(): (Route & DebugRoute)[] {\n return inject(DEBUG_CONTENT_ROUTES);\n}\n"],"mappings":";;;;AAgBA,IAAM,kBAAkB,OAAO,SAAS,eAAe,CAAC,CAAC,KAAK;AAE9D,SAAgB,iBACd,qBAC4B;AAC5B,QAAO,YAAY;EAQjB,MAAO,EAAA,SAAA,eAAA,oBAPc,OAAO,kBAIpB,KAAS,KAAA,IAAA,oBAAe,GACxB,qBAAwB,EAEzB;EACL,MAAS,EAAA,OAAA,MAAA,WAAA;AACT,SAAW;GACD,SAAA;GACR,WAAA;IACA,MAAA,EAAA,gBAAA,SAAA;IACA;IAEE;IACQ;IAGA,SAAW,EACH,uBAAwB,YAAW;;AAIxD,YAAA,OAAA,aAAA,WAAA,WAAA,SAAA;;;;;;;;;;;ACrCL,IAAa,6BAA6B,EAAE;AAI5C,SAAgB,oBAAoB,OAAc,QAAQ,OAAgB;AACxE,QAAO,aACL,QACC,UAAU,eACT,SAAS,SAAS,MACd,GAAA,iBAAA,WAAA,GAAA,YAAA,MAAA;;;;ACRV,SAAgB,oBAAoC;AAClD,QAAO;EACL,OAAO;EACP,YACE,CACW;GACF,SAAA;GACG,OAAA;GACD,UAAA;IAEL,OAAA;wEAOL,iBAAA,WAAA,GAEJ;;;;;;;ACxBH,IAAa,uBACX,IAAI,eACF,yCACA;CACE,YAAY;CACZ,UAAU;AAMR,SALoB,oBAClB,4BAED,KAAA;;CAIJ,CACF;AASH,SAAgB,2BAAmD;AACjE,QAAO,OAAO,qBAAqB"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { InjectionToken, assertInInjectionContext, inject, makeEnvironmentProviders, provideAppInitializer } from "@angular/core";
|
|
2
|
+
import { LOCALE, REQUEST } from "@analogjs/router/tokens";
|
|
3
|
+
//#region packages/router/i18n/src/provide-i18n.ts
|
|
4
|
+
/**
|
|
5
|
+
* Injection token for the resolved i18n configuration.
|
|
6
|
+
* Provided by `provideI18n()` and consumed by `injectSwitchLocale()`.
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
var I18N_CONFIG = new InjectionToken("@analogjs/router I18n Config");
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the full i18n config by merging explicit values with
|
|
12
|
+
* build-time globals injected by the platform plugin.
|
|
13
|
+
*/
|
|
14
|
+
function resolveI18nConfig(config) {
|
|
15
|
+
const defaultLocale = config.defaultLocale ?? (typeof ANALOG_I18N_DEFAULT_LOCALE !== "undefined" ? ANALOG_I18N_DEFAULT_LOCALE : void 0);
|
|
16
|
+
const locales = config.locales ?? (typeof ANALOG_I18N_LOCALES !== "undefined" ? ANALOG_I18N_LOCALES : void 0);
|
|
17
|
+
if (!defaultLocale || !locales) throw new Error("[@analogjs/router] provideI18n() requires defaultLocale and locales. Either pass them explicitly or configure i18n in the analog() plugin in vite.config.ts.");
|
|
18
|
+
return {
|
|
19
|
+
defaultLocale,
|
|
20
|
+
locales,
|
|
21
|
+
loader: config.loader
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Provides runtime i18n support using Angular's $localize.
|
|
26
|
+
*
|
|
27
|
+
* This provider:
|
|
28
|
+
* 1. Detects the active locale from the URL or falls back to the default.
|
|
29
|
+
* 2. Makes the current locale available via the LOCALE injection token.
|
|
30
|
+
* 3. Loads translations for the active locale at startup using $localize.
|
|
31
|
+
*
|
|
32
|
+
* Works in both SSR and client-only modes. On the client, locale is detected
|
|
33
|
+
* from `window.location.pathname`. On the server, locale is detected from
|
|
34
|
+
* the request in `provideServerContext()` and provided at the platform level;
|
|
35
|
+
* this function does not shadow it.
|
|
36
|
+
*
|
|
37
|
+
* When the platform plugin is configured with `i18n` in `vite.config.ts`,
|
|
38
|
+
* `defaultLocale` and `locales` are injected automatically — only
|
|
39
|
+
* `loader` is required:
|
|
40
|
+
*
|
|
41
|
+
* ```typescript
|
|
42
|
+
* provideI18n({
|
|
43
|
+
* loader: (locale) => import(`./i18n/${locale}.json`),
|
|
44
|
+
* })
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
function provideI18n(config) {
|
|
48
|
+
const resolved = resolveI18nConfig(config);
|
|
49
|
+
const localeProviders = typeof window !== "undefined" ? [{
|
|
50
|
+
provide: LOCALE,
|
|
51
|
+
useValue: detectClientLocale(resolved)
|
|
52
|
+
}] : [];
|
|
53
|
+
return makeEnvironmentProviders([
|
|
54
|
+
{
|
|
55
|
+
provide: I18N_CONFIG,
|
|
56
|
+
useValue: resolved
|
|
57
|
+
},
|
|
58
|
+
...localeProviders,
|
|
59
|
+
provideAppInitializer(async () => {
|
|
60
|
+
await initI18n(resolved, resolveActiveLocale(resolved));
|
|
61
|
+
})
|
|
62
|
+
]);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resolves the active locale, preferring the injected `LOCALE` token
|
|
66
|
+
* (which on the server reads from the platform-level provider set by
|
|
67
|
+
* `provideServerContext()`) and falling back to the request URL,
|
|
68
|
+
* `window.location.pathname`, or `defaultLocale`.
|
|
69
|
+
*/
|
|
70
|
+
function resolveActiveLocale(config) {
|
|
71
|
+
const injected = inject(LOCALE, { optional: true });
|
|
72
|
+
if (injected && config.locales.includes(injected)) return injected;
|
|
73
|
+
const req = inject(REQUEST, { optional: true });
|
|
74
|
+
const first = (req?.originalUrl ?? req?.url ?? (typeof window !== "undefined" ? window.location.pathname : "/")).split("?")[0].split("/").filter(Boolean)[0];
|
|
75
|
+
if (first && config.locales.includes(first)) return first;
|
|
76
|
+
return config.defaultLocale;
|
|
77
|
+
}
|
|
78
|
+
function detectClientLocale(config) {
|
|
79
|
+
if (typeof window === "undefined") return config.defaultLocale;
|
|
80
|
+
const firstSegment = window.location.pathname.split("/").filter(Boolean)[0];
|
|
81
|
+
if (firstSegment && config.locales.includes(firstSegment)) return firstSegment;
|
|
82
|
+
return config.defaultLocale;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Loads translations for the given locale and registers them with $localize.
|
|
86
|
+
*
|
|
87
|
+
* Always clears any previously loaded translations first so that switching
|
|
88
|
+
* between locales in a single SSR process does not mix translation maps.
|
|
89
|
+
*/
|
|
90
|
+
async function initI18n(config, locale) {
|
|
91
|
+
const activeLocale = locale ?? config.defaultLocale;
|
|
92
|
+
await clearTranslationsRuntime();
|
|
93
|
+
if (activeLocale === config.locales[0]) return;
|
|
94
|
+
const translations = await config.loader(activeLocale);
|
|
95
|
+
if (translations && Object.keys(translations).length > 0) await loadTranslationsRuntime(translations);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Loads translations into the global $localize translation map.
|
|
99
|
+
*
|
|
100
|
+
* Uses `@angular/localize`'s `loadTranslations` when available so that
|
|
101
|
+
* each translation string is parsed into the `{text, messageParts,
|
|
102
|
+
* placeholderNames}` shape that `$localize.translate` expects. Falls back
|
|
103
|
+
* to writing raw strings only as a last resort (in which case lookups
|
|
104
|
+
* will not succeed — the fallback exists to keep error messages useful
|
|
105
|
+
* for users who have not installed `@angular/localize`).
|
|
106
|
+
*
|
|
107
|
+
* Requires `@angular/localize/init` to be imported in the application
|
|
108
|
+
* entry point so that `globalThis.$localize` is defined.
|
|
109
|
+
*/
|
|
110
|
+
async function loadTranslationsRuntime(translations) {
|
|
111
|
+
const $localize = globalThis.$localize;
|
|
112
|
+
if (!$localize) {
|
|
113
|
+
console.warn("[@analogjs/router] $localize is not available. Make sure to import @angular/localize/init in your application entry point.");
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
const { loadTranslations } = await import("@angular/localize");
|
|
118
|
+
loadTranslations(translations);
|
|
119
|
+
} catch {
|
|
120
|
+
console.warn("[@analogjs/router] Unable to import @angular/localize. Install it as a dependency to enable runtime translation loading.");
|
|
121
|
+
$localize.TRANSLATIONS ??= {};
|
|
122
|
+
for (const [id, message] of Object.entries(translations)) $localize.TRANSLATIONS[id] = message;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/** @internal — exported for tests; not re-exported from the package entry. */
|
|
126
|
+
async function clearTranslationsRuntime() {
|
|
127
|
+
const $localize = globalThis.$localize;
|
|
128
|
+
if (!$localize) return;
|
|
129
|
+
try {
|
|
130
|
+
const { clearTranslations } = await import("@angular/localize");
|
|
131
|
+
clearTranslations();
|
|
132
|
+
} catch {
|
|
133
|
+
$localize.translate = void 0;
|
|
134
|
+
$localize.TRANSLATIONS = {};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function injectSwitchLocale() {
|
|
138
|
+
assertInInjectionContext(injectSwitchLocale);
|
|
139
|
+
const config = inject(I18N_CONFIG);
|
|
140
|
+
return (targetLocale) => {
|
|
141
|
+
if (typeof window === "undefined") return;
|
|
142
|
+
const { pathname, search, hash } = window.location;
|
|
143
|
+
const newPath = replaceLocaleInPath(pathname, targetLocale, config.locales);
|
|
144
|
+
window.location.href = `${newPath}${search}${hash}`;
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function replaceLocaleInPath(pathname, targetLocale, locales) {
|
|
148
|
+
const segments = pathname.split("/").filter(Boolean);
|
|
149
|
+
if (segments.length > 0 && locales.includes(segments[0])) segments[0] = targetLocale;
|
|
150
|
+
else segments.unshift(targetLocale);
|
|
151
|
+
return "/" + segments.join("/");
|
|
152
|
+
}
|
|
153
|
+
//#endregion
|
|
154
|
+
export { injectSwitchLocale, loadTranslationsRuntime, provideI18n };
|
|
155
|
+
|
|
156
|
+
//# sourceMappingURL=analogjs-router-i18n.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analogjs-router-i18n.mjs","names":[],"sources":["../../i18n/src/provide-i18n.ts"],"sourcesContent":["import {\n EnvironmentProviders,\n InjectionToken,\n Type,\n assertInInjectionContext,\n inject,\n makeEnvironmentProviders,\n provideAppInitializer,\n} from '@angular/core';\nimport { LOCALE, REQUEST, ServerRequest } from '@analogjs/router/tokens';\n\ndeclare const ANALOG_I18N_DEFAULT_LOCALE: string;\ndeclare const ANALOG_I18N_LOCALES: string[];\n\n/**\n * Configuration for runtime i18n support.\n *\n * `defaultLocale` and `locales` are optional when the platform plugin\n * is configured with `i18n` in `vite.config.ts` — the values are\n * injected as build-time globals automatically.\n */\nexport interface I18nConfig {\n /**\n * The default locale to use when no locale is detected.\n * If omitted, reads from the platform plugin's `i18n.defaultLocale`.\n */\n defaultLocale?: string;\n\n /**\n * List of supported locale identifiers.\n * If omitted, reads from the platform plugin's `i18n.locales`.\n */\n locales?: string[];\n\n /**\n * A function that returns translations for a given locale.\n * The returned record maps message IDs to translated strings.\n */\n loader: (\n locale: string,\n ) => Promise<Record<string, string>> | Record<string, string>;\n}\n\n/**\n * Fully resolved i18n config with all required fields.\n */\nexport type ResolvedI18nConfig = Required<I18nConfig>;\n\n/**\n * Injection token for the resolved i18n configuration.\n * Provided by `provideI18n()` and consumed by `injectSwitchLocale()`.\n * @internal\n */\nconst I18N_CONFIG = new InjectionToken<ResolvedI18nConfig>(\n '@analogjs/router I18n Config',\n);\n\n/**\n * Resolves the full i18n config by merging explicit values with\n * build-time globals injected by the platform plugin.\n */\nexport function resolveI18nConfig(config: I18nConfig): Required<I18nConfig> {\n const defaultLocale =\n config.defaultLocale ??\n (typeof ANALOG_I18N_DEFAULT_LOCALE !== 'undefined'\n ? ANALOG_I18N_DEFAULT_LOCALE\n : undefined);\n\n const locales =\n config.locales ??\n (typeof ANALOG_I18N_LOCALES !== 'undefined'\n ? ANALOG_I18N_LOCALES\n : undefined);\n\n if (!defaultLocale || !locales) {\n throw new Error(\n '[@analogjs/router] provideI18n() requires defaultLocale and locales. ' +\n 'Either pass them explicitly or configure i18n in the analog() plugin in vite.config.ts.',\n );\n }\n\n return { defaultLocale, locales, loader: config.loader };\n}\n\n/**\n * Provides runtime i18n support using Angular's $localize.\n *\n * This provider:\n * 1. Detects the active locale from the URL or falls back to the default.\n * 2. Makes the current locale available via the LOCALE injection token.\n * 3. Loads translations for the active locale at startup using $localize.\n *\n * Works in both SSR and client-only modes. On the client, locale is detected\n * from `window.location.pathname`. On the server, locale is detected from\n * the request in `provideServerContext()` and provided at the platform level;\n * this function does not shadow it.\n *\n * When the platform plugin is configured with `i18n` in `vite.config.ts`,\n * `defaultLocale` and `locales` are injected automatically — only\n * `loader` is required:\n *\n * ```typescript\n * provideI18n({\n * loader: (locale) => import(`./i18n/${locale}.json`),\n * })\n * ```\n */\nexport function provideI18n(config: I18nConfig): EnvironmentProviders {\n const resolved = resolveI18nConfig(config);\n\n // Only provide LOCALE at the environment level on the client. On the\n // server, the platform-level LOCALE set by `provideServerContext()` is\n // authoritative and must not be shadowed by an environment-level provider.\n const localeProviders =\n typeof window !== 'undefined'\n ? [{ provide: LOCALE, useValue: detectClientLocale(resolved) }]\n : [];\n\n return makeEnvironmentProviders([\n { provide: I18N_CONFIG, useValue: resolved },\n ...localeProviders,\n provideAppInitializer(async () => {\n const locale = resolveActiveLocale(resolved);\n await initI18n(resolved, locale);\n }),\n ]);\n}\n\n/**\n * Resolves the active locale, preferring the injected `LOCALE` token\n * (which on the server reads from the platform-level provider set by\n * `provideServerContext()`) and falling back to the request URL,\n * `window.location.pathname`, or `defaultLocale`.\n */\nfunction resolveActiveLocale(config: ResolvedI18nConfig): string {\n const injected = inject(LOCALE, { optional: true });\n if (injected && config.locales.includes(injected)) {\n return injected;\n }\n\n // Fallback: read the path directly from the request on the server or\n // from the browser URL on the client. This covers cases where a locale\n // prefix is present in the URL but no token provider set it explicitly.\n const req = inject(REQUEST, { optional: true }) as ServerRequest | null;\n const pathname =\n req?.originalUrl ??\n req?.url ??\n (typeof window !== 'undefined' ? window.location.pathname : '/');\n const first = pathname.split('?')[0].split('/').filter(Boolean)[0];\n if (first && config.locales.includes(first)) {\n return first;\n }\n\n return config.defaultLocale;\n}\n\nexport function detectClientLocale(config: ResolvedI18nConfig): string {\n if (typeof window === 'undefined') {\n return config.defaultLocale;\n }\n\n const pathname = window.location.pathname;\n const segments = pathname.split('/').filter(Boolean);\n const firstSegment = segments[0];\n\n if (firstSegment && config.locales.includes(firstSegment)) {\n return firstSegment;\n }\n\n return config.defaultLocale;\n}\n\n/**\n * Loads translations for the given locale and registers them with $localize.\n *\n * Always clears any previously loaded translations first so that switching\n * between locales in a single SSR process does not mix translation maps.\n */\nexport async function initI18n(\n config: ResolvedI18nConfig,\n locale?: string,\n): Promise<void> {\n const activeLocale = locale ?? config.defaultLocale;\n await clearTranslationsRuntime();\n\n // The source locale (first entry in `locales`) has its messages baked\n // directly into the template source, so there is nothing to load.\n if (activeLocale === config.locales[0]) {\n return;\n }\n\n const translations = await config.loader(activeLocale);\n if (translations && Object.keys(translations).length > 0) {\n await loadTranslationsRuntime(translations);\n }\n}\n\n/**\n * Loads translations into the global $localize translation map.\n *\n * Uses `@angular/localize`'s `loadTranslations` when available so that\n * each translation string is parsed into the `{text, messageParts,\n * placeholderNames}` shape that `$localize.translate` expects. Falls back\n * to writing raw strings only as a last resort (in which case lookups\n * will not succeed — the fallback exists to keep error messages useful\n * for users who have not installed `@angular/localize`).\n *\n * Requires `@angular/localize/init` to be imported in the application\n * entry point so that `globalThis.$localize` is defined.\n */\nexport async function loadTranslationsRuntime(\n translations: Record<string, string>,\n): Promise<void> {\n const $localize = (globalThis as any).$localize;\n if (!$localize) {\n console.warn(\n '[@analogjs/router] $localize is not available. ' +\n 'Make sure to import @angular/localize/init in your application entry point.',\n );\n return;\n }\n\n try {\n const localizePkg = '@angular/localize';\n const { loadTranslations } = (await import(\n /* @vite-ignore */ localizePkg\n )) as {\n loadTranslations: (t: Record<string, string>) => void;\n };\n loadTranslations(translations);\n } catch {\n console.warn(\n '[@analogjs/router] Unable to import @angular/localize. ' +\n 'Install it as a dependency to enable runtime translation loading.',\n );\n $localize.TRANSLATIONS ??= {};\n for (const [id, message] of Object.entries(translations)) {\n $localize.TRANSLATIONS[id] = message;\n }\n }\n}\n\n/** @internal — exported for tests; not re-exported from the package entry. */\nexport async function clearTranslationsRuntime(): Promise<void> {\n const $localize = (globalThis as any).$localize;\n if (!$localize) {\n return;\n }\n try {\n const localizePkg = '@angular/localize';\n const { clearTranslations } = (await import(\n /* @vite-ignore */ localizePkg\n )) as {\n clearTranslations: () => void;\n };\n clearTranslations();\n } catch {\n $localize.translate = undefined;\n $localize.TRANSLATIONS = {};\n }\n}\n\n// ---------------------------------------------------------------------------\n// Component definition registry\n// ---------------------------------------------------------------------------\n\nconst componentDefRegistry = new Set<any>();\n\n/** @internal */\nexport function ɵregisterI18nComponentDef(typeOrDef: Type<any> | any): void {\n if (!typeOrDef) return;\n const def = (typeOrDef as any).ɵcmp ?? typeOrDef;\n if (def && typeof def === 'object' && 'template' in def) {\n componentDefRegistry.add(def);\n }\n}\n\n/** @internal */\nexport function ɵresetI18nComponentDefCache(): void {\n for (const def of componentDefRegistry) {\n def.tView = null;\n }\n}\n\n/** @internal */\nexport function getI18nComponentDefRegistrySize(): number {\n return componentDefRegistry.size;\n}\n\n/** @internal */\nexport function clearI18nComponentDefRegistry(): void {\n componentDefRegistry.clear();\n}\n\nexport function injectSwitchLocale(): (targetLocale: string) => void {\n assertInInjectionContext(injectSwitchLocale);\n const config = inject(I18N_CONFIG);\n\n return (targetLocale: string) => {\n if (typeof window === 'undefined') {\n return;\n }\n\n const { pathname, search, hash } = window.location;\n const newPath = replaceLocaleInPath(pathname, targetLocale, config.locales);\n window.location.href = `${newPath}${search}${hash}`;\n };\n}\n\nexport function replaceLocaleInPath(\n pathname: string,\n targetLocale: string,\n locales: string[],\n): string {\n const segments = pathname.split('/').filter(Boolean);\n\n if (segments.length > 0 && locales.includes(segments[0])) {\n segments[0] = targetLocale;\n } else {\n segments.unshift(targetLocale);\n }\n\n return '/' + segments.join('/');\n}\n"],"mappings":";;;;;;;;AAqDA,IAAM,cAAc,IAAI,eACtB,+BACD;;;;;AAMD,SAAgB,kBAAkB,QAA0C;CAC1E,MAAM,gBACJ,OAAO,kBAKH,OAAA,+BAEI,cAIL,6BACO,KAAA;oCAML,OAAA,wBAAA,cAAE,sBAAe,KAAA;AAAS,KAAA,CAAA,iBAAe,CAAA,QAAQ,OAAA,IAAA,MAAA,+JAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAkCtC,YAAA,QAAA;CAAQ,MAAA,WAAU,kBAAmB,OAAA;CAInD,MAAA,kBAAS,OAAA,WAAA,cAAa,CAAA;EAAU,SAAA;EAAA,UAAA,mBAAA,SAAA;EAAA,CAAA,GAAU,EAAA;AAC5C,QAAG,yBAAA;EACH;GAAA,SAAA;GAAsB,UAAY;GAAA;EAChC,GAAM;EACN,sBAAyB,YAAO;AAElC,SAAA,SAAA,UAAA,oBAAA,SAAA,CAAA;;;;;;;;;;AAWF,SAAI,oBAAmB,QAAQ;CAC7B,MAAO,WAAA,OAAA,QAAA,EAAA,UAAA,MAAA,CAAA;mDAMH,QAAM;;CAcZ,MAAI,SAJU,KAAA,eAAA,KAAA,QAGT,OAAS,WAAA,cAAmB,OAAoC,SAAA,WAAA,MAC/C,MAAA,IAAa,CAAA,GAAA,MAAA,IAAA,CAAA,OAAA,QAAA,CAAA;AACjC,KAAA,SAAc,OAAA,QAAA,SAAA,MAAA,CAAA,QAAA;AAIhB,QAAM,OAAW;;AAGjB,SAAI,mBAAuB,QAAQ;AACjC,KAAA,OAAO,WAAA,YAAA,QAAA,OAAA;;;;;;;;;;;AA0BT,eAAoB,SAAO,QAAK,QAAc;CAC5C,MAAM,eAAA,UAAwB,OAAA;;;;;;;;;;;;;;;;;;;;CAgCT,MAAA,YAAA,WAAA;;AAIrB,UAAA,KAAiB,6HACX;AACN;;AAKA,KAAK;4CACoB;;SAMtB;AACC,UAAA,KAAa,2HACH;AACd,YAAA,iBAAA,EAAA;2DAEE,WAAA,aAAA,MAAA;;;;;CAOF,MAAA,YAAmB,WAAA;MACb,UACN;;EASE,MAAA,EAAA,sBAAqC,MAAA,OAAA;AAGpC,qBAAS;SAER;AACF,YAAO,YAAe,KAAA;AACxB,YAAA,eAA6B,EAAA;;;SAyCzB,qBAA8B;AAEpC,0BAA2B,mBAAiB;CAC1C,MAAA,SAAc,OAAA,YAAA;SACT,iBAAA;AACL,MAAS,OAAQ,WAAA,YAAA"}
|
|
@@ -1,27 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return new Response(JSON.stringify(errors), {
|
|
4
|
-
status,
|
|
5
|
-
headers: { "X-Analog-Errors": "true" }
|
|
6
|
-
});
|
|
7
|
-
}
|
|
8
|
-
function json(data, config) {
|
|
9
|
-
return new Response(JSON.stringify(data), {
|
|
10
|
-
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
11
|
-
...config
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
function redirect(url, config = 302) {
|
|
15
|
-
if (typeof config === "number") return new Response(null, {
|
|
16
|
-
status: config,
|
|
17
|
-
headers: { Location: `${url}` }
|
|
18
|
-
});
|
|
19
|
-
return new Response(null, {
|
|
20
|
-
headers: { Location: `${url}` },
|
|
21
|
-
...config
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
//#endregion
|
|
25
|
-
export { fail, json, redirect };
|
|
26
|
-
|
|
27
|
-
//# sourceMappingURL=analogjs-router-server-actions.mjs.map
|
|
1
|
+
import { a as fail, i as validateWithSchema, n as defineServerRoute, o as json, r as defineAction, s as redirect, t as definePageLoad } from "./src.mjs";
|
|
2
|
+
export { defineAction, definePageLoad, defineServerRoute, fail, json, redirect, validateWithSchema };
|