diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 53b4f28893e1..2b7b6c5ea31b 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1474,66 +1474,68 @@ export interface AstroUserConfig { * * Controls the routing strategy to determine your site URLs. Set this based on your folder/URL path configuration for your default language. */ - routing?: { - /** - * @docs - * @name i18n.routing.prefixDefaultLocale - * @kind h4 - * @type {boolean} - * @default `false` - * @version 3.7.0 - * @description - * - * When `false`, only non-default languages will display a language prefix. - * The `defaultLocale` will not show a language prefix and content files do not exist in a localized folder. - * URLs will be of the form `example.com/[locale]/content/` for all non-default languages, but `example.com/content/` for the default locale. - * - * When `true`, all URLs will display a language prefix. - * URLs will be of the form `example.com/[locale]/content/` for every route, including the default language. - * Localized folders are used for every language, including the default. - */ - prefixDefaultLocale?: boolean; - - /** - * @docs - * @name i18n.routing.redirectToDefaultLocale - * @kind h4 - * @type {boolean} - * @default `true` - * @version 4.2.0 - * @description - * - * Configures whether or not the home URL (`/`) generated by `src/pages/index.astro` - * will redirect to `/[defaultLocale]` when `prefixDefaultLocale: true` is set. - * - * Set `redirectToDefaultLocale: false` to disable this automatic redirection at the root of your site: - * ```js - * // astro.config.mjs - * export default defineConfig({ - * i18n:{ - * defaultLocale: "en", - * locales: ["en", "fr"], - * routing: { - * prefixDefaultLocale: true, - * redirectToDefaultLocale: false - * } - * } - * }) - *``` - * */ - redirectToDefaultLocale?: boolean; - - /** - * @name i18n.routing.strategy - * @type {"pathname"} - * @default `"pathname"` - * @version 3.7.0 - * @description - * - * - `"pathname": The strategy is applied to the pathname of the URLs - */ - strategy?: 'pathname'; - }; + routing?: + | 'manual' + | { + /** + * @docs + * @name i18n.routing.prefixDefaultLocale + * @kind h4 + * @type {boolean} + * @default `false` + * @version 3.7.0 + * @description + * + * When `false`, only non-default languages will display a language prefix. + * The `defaultLocale` will not show a language prefix and content files do not exist in a localized folder. + * URLs will be of the form `example.com/[locale]/content/` for all non-default languages, but `example.com/content/` for the default locale. + * + * When `true`, all URLs will display a language prefix. + * URLs will be of the form `example.com/[locale]/content/` for every route, including the default language. + * Localized folders are used for every language, including the default. + */ + prefixDefaultLocale?: boolean; + + /** + * @docs + * @name i18n.routing.redirectToDefaultLocale + * @kind h4 + * @type {boolean} + * @default `true` + * @version 4.2.0 + * @description + * + * Configures whether or not the home URL (`/`) generated by `src/pages/index.astro` + * will redirect to `/[defaultLocale]` when `prefixDefaultLocale: true` is set. + * + * Set `redirectToDefaultLocale: false` to disable this automatic redirection at the root of your site: + * ```js + * // astro.config.mjs + * export default defineConfig({ + * i18n:{ + * defaultLocale: "en", + * locales: ["en", "fr"], + * routing: { + * prefixDefaultLocale: true, + * redirectToDefaultLocale: false + * } + * } + * }) + *``` + * */ + redirectToDefaultLocale?: boolean; + + /** + * @name i18n.routing.strategy + * @type {"pathname"} + * @default `"pathname"` + * @version 3.7.0 + * @description + * + * - `"pathname": The strategy is applied to the pathname of the URLs + */ + strategy?: 'pathname'; + }; /** * @name i18n.domains diff --git a/packages/astro/src/core/base-pipeline.ts b/packages/astro/src/core/base-pipeline.ts index 139ee9485811..cd4e52cba7a8 100644 --- a/packages/astro/src/core/base-pipeline.ts +++ b/packages/astro/src/core/base-pipeline.ts @@ -47,9 +47,13 @@ export abstract class Pipeline { */ readonly site = manifest.site ) { - this.internalMiddleware = [ - createI18nMiddleware(i18n, manifest.base, manifest.trailingSlash, manifest.buildFormat), - ]; + this.internalMiddleware = []; + // we do use our middleware only if the user isn't using the manual setup + if (i18n?.strategy !== 'manual') { + this.internalMiddleware.push( + createI18nMiddleware(i18n, manifest.base, manifest.trailingSlash, manifest.buildFormat) + ); + } } abstract headElements(routeData: RouteData): Promise | HeadElements; diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 4945afd3ed1a..d1f8665571fc 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -338,21 +338,24 @@ export const AstroConfigSchema = z.object({ .optional(), fallback: z.record(z.string(), z.string()).optional(), routing: z - .object({ - prefixDefaultLocale: z.boolean().default(false), - redirectToDefaultLocale: z.boolean().default(true), - strategy: z.enum(['automatic', 'manual']).default('automatic'), - }) - .default({}) - .refine( - ({ prefixDefaultLocale, redirectToDefaultLocale }) => { - return !(prefixDefaultLocale === false && redirectToDefaultLocale === false); - }, - { - message: - 'The option `i18n.redirectToDefaultLocale` is only useful when the `i18n.prefixDefaultLocale` is set to `true`. Remove the option `i18n.redirectToDefaultLocale`, or change its value to `true`.', - } - ), + .enum(['manual']) + .or( + z + .object({ + prefixDefaultLocale: z.boolean().default(false), + redirectToDefaultLocale: z.boolean().default(true), + }) + .refine( + ({ prefixDefaultLocale, redirectToDefaultLocale }) => { + return !(prefixDefaultLocale === false && redirectToDefaultLocale === false); + }, + { + message: + 'The option `i18n.redirectToDefaultLocale` is only useful when the `i18n.prefixDefaultLocale` is set to `true`. Remove the option `i18n.redirectToDefaultLocale`, or change its value to `true`.', + } + ) + ) + .default({}), }) .optional() .superRefine((i18n, ctx) => { diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts index 83d9751defb3..bfa4efc47195 100644 --- a/packages/astro/src/core/errors/errors-data.ts +++ b/packages/astro/src/core/errors/errors-data.ts @@ -1033,7 +1033,7 @@ export const MissingIndexForInternationalization = { /** * @docs * @description - * + * Some internationalization functions can't be exposed unless the default routing is disabled */ export const IncorrectStrategy = { name: 'IncorrectStrategy', diff --git a/packages/astro/src/i18n/utils.ts b/packages/astro/src/i18n/utils.ts index d3dddba1f8c5..b45c37ee7186 100644 --- a/packages/astro/src/i18n/utils.ts +++ b/packages/astro/src/i18n/utils.ts @@ -191,6 +191,7 @@ export function computeCurrentLocale( } export type RoutingStrategies = + | 'manual' | 'pathname-prefix-always' | 'pathname-prefix-other-locales' | 'pathname-prefix-always-no-redirect' @@ -201,25 +202,29 @@ export function toRoutingStrategy(i18n: NonNullable) { let { routing, domains } = i18n; let strategy: RoutingStrategies; const hasDomains = domains ? Object.keys(domains).length > 0 : false; - if (!hasDomains) { - if (routing?.prefixDefaultLocale === true) { - if (routing.redirectToDefaultLocale) { - strategy = 'pathname-prefix-always'; + if (routing === 'manual') { + strategy = 'manual'; + } else { + if (!hasDomains) { + if (routing?.prefixDefaultLocale === true) { + if (routing.redirectToDefaultLocale) { + strategy = 'pathname-prefix-always'; + } else { + strategy = 'pathname-prefix-always-no-redirect'; + } } else { - strategy = 'pathname-prefix-always-no-redirect'; + strategy = 'pathname-prefix-other-locales'; } } else { - strategy = 'pathname-prefix-other-locales'; - } - } else { - if (routing?.prefixDefaultLocale === true) { - if (routing.redirectToDefaultLocale) { - strategy = 'domains-prefix-always'; + if (routing?.prefixDefaultLocale === true) { + if (routing.redirectToDefaultLocale) { + strategy = 'domains-prefix-always'; + } else { + strategy = 'domains-prefix-always-no-redirect'; + } } else { - strategy = 'domains-prefix-always-no-redirect'; + strategy = 'domains-prefix-other-locales'; } - } else { - strategy = 'domains-prefix-other-locales'; } } diff --git a/packages/astro/src/virtual-modules/i18n.ts b/packages/astro/src/virtual-modules/i18n.ts index 788c0413548c..2e6d92189924 100644 --- a/packages/astro/src/virtual-modules/i18n.ts +++ b/packages/astro/src/virtual-modules/i18n.ts @@ -242,7 +242,7 @@ export const pathHasLocale = (path: string) => I18nInternals.pathHasLocale(path, * @param {ValidRedirectStatus?} statusCode An optional status code for the redirect. */ export const redirectToDefaultLocale = - i18n?.routing?.strategy === 'manual' + i18n?.routing === 'manual' ? I18nInternals.redirectToDefaultLocale({ base, trailingSlash, @@ -268,7 +268,7 @@ export const redirectToDefaultLocale = * */ export const noFoundForNonLocaleRoute = - i18n?.routing?.strategy === 'manual' + i18n?.routing === 'manual' ? I18nInternals.noFoundForNonLocaleRoute({ base, trailingSlash, @@ -289,12 +289,10 @@ export const noFoundForNonLocaleRoute = * */ export const requestHasLocale = - i18n?.routing?.strategy === 'manual' - ? I18nInternals.requestHasLocale(locales) - : noop('requestHasLocale'); + i18n?.routing === 'manual' ? I18nInternals.requestHasLocale(locales) : noop('requestHasLocale'); export const useFallback: UseFallback = - i18n?.routing?.strategy === 'manual' + i18n?.routing === 'manual' ? I18nInternals.useFallback({ base, trailingSlash,