Skip to content

Commit

Permalink
fix: locale prefixes are not added to route aliases (#2962)
Browse files Browse the repository at this point in the history
* fix: locale prefixes are not added to route aliases

* refactor: simplify `analyzeNuxtPages`

* test: add tests for prefixed alias

* refactor: revert unrelated refactor

* fix: add warning if `scanPageMeta` is disabled
  • Loading branch information
BobbieGoede committed May 30, 2024
1 parent d00d368 commit 6223696
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 28 deletions.
28 changes: 28 additions & 0 deletions specs/experimental/scan_page_meta.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { test, expect } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup, url } from '../utils'
import { getText, renderPage } from '../helper'

await setup({
rootDir: fileURLToPath(new URL(`../fixtures/basic_usage`, import.meta.url)),
browser: true,
// overrides
nuxtConfig: {
experimental: {
scanPageMeta: true
}
}
})

describe('Using Nuxt experimental feature `scanPageMeta`', async () => {
test('can access localized alias', async () => {
const { page } = await renderPage('/')

// Aliases path renders home
await page.goto(url('/aliased-home-path'))
expect(await getText(page, 'title')).toEqual('Page - Homepage')

await page.goto(url('/fr/aliased-home-path'))
expect(await getText(page, 'title')).toEqual('Page - Accueil')
})
})
3 changes: 2 additions & 1 deletion specs/fixtures/basic_usage/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ route.meta.pageTransition = {
}
// @ts-ignore
definePageMeta({
title: 'home'
title: 'home',
alias: ['/aliased-home-path']
})
const i18nHead = useLocaleHead({
Expand Down
6 changes: 6 additions & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ export default defineNuxtModule<NuxtI18nOptions>({
)
}

if (nuxt.options.experimental.scanPageMeta === false) {
logger.warn(
"Route localization features (e.g. custom name, prefixed aliases) require Nuxt's `experimental.scanPageMeta` to be enabled.\nThis feature will be enabled in future Nuxt versions (https://github.com/nuxt/nuxt/pull/27134), check out the docs for more details: https://nuxt.com/docs/guide/going-further/experimental-features#scanpagemeta"
)
}

/**
* nuxt layers handling ...
*/
Expand Down
72 changes: 46 additions & 26 deletions src/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,16 @@ const debug = createDebug('@nuxtjs/i18n:pages')

export type AnalyzedNuxtPageMeta = {
inRoot: boolean
/**
* Analyzed path used to retrieve configured custom paths
*/
path: string
}

export type NuxtPageAnalyzeContext = {
/**
* Array of paths to track current route depth
*/
stack: string[]
srcDir: string
pagesDir: string
Expand Down Expand Up @@ -70,43 +76,48 @@ export function setupPages(options: Required<NuxtI18nOptions>, nuxt: Nuxt) {
})
}

/**
* Analyze page path
*/
function analyzePagePath(pagePath: string, parents = 0) {
const { dir, name } = parsePath(pagePath)

if (parents > 0 || dir !== '/') {
return `${dir.slice(1, dir.length)}/${name}`
}

return name
}

/**
* Construct the map of full paths from NuxtPage to support custom routes.
* `NuxtPage` of the nested route doesn't have a slash (`/`) and isn’t the full path.
*/
export function analyzeNuxtPages(ctx: NuxtPageAnalyzeContext, pages: NuxtPage[], pageDirOverride?: string): void {
export function analyzeNuxtPages(ctx: NuxtPageAnalyzeContext, pages?: NuxtPage[], pageDirOverride?: string): void {
if (pages == null || pages.length === 0) return

const pagesPath = resolve(ctx.srcDir, pageDirOverride ?? ctx.pagesDir)
for (const page of pages) {
if (page.file == null) {
continue
}
if (page.file == null) continue

const splits = page.file.split(pagesPath)
if (splits.length === 2 && splits[1]) {
const { dir, name } = parsePath(splits[1])
let path = ''
if (ctx.stack.length > 0) {
path += `${dir.slice(1, dir.length)}/${name}`
} else {
if (dir !== '/') {
path += `${dir.slice(1, dir.length)}/`
}
path += name
}
const p: AnalyzedNuxtPageMeta = {
inRoot: ctx.stack.length === 0,
path
}
ctx.pages.set(page, p)
const filePath = splits.at(1)
if (filePath == null) continue

if (page.children && page.children.length > 0) {
ctx.stack.push(page.path)
analyzeNuxtPages(ctx, page.children, pageDirOverride)
ctx.stack.pop()
}
}
ctx.pages.set(page, {
path: analyzePagePath(filePath, ctx.stack.length),
inRoot: ctx.stack.length === 0
})

ctx.stack.push(page.path)
analyzeNuxtPages(ctx, page.children, pageDirOverride)
ctx.stack.pop()
}
}

/**
* Function factory, returns a function based on the `customRoutes` option property
*/
export function getRouteOptionsResolver(
ctx: NuxtPageAnalyzeContext,
options: Pick<Required<NuxtI18nOptions>, 'pages' | 'defaultLocale' | 'customRoutes'>
Expand All @@ -132,6 +143,9 @@ function resolveRoutePath(path: string): string {
return routePath
}

/**
* Retrieve custom routes from i18n config `pages` property
*/
function getRouteOptionsFromPages(
ctx: NuxtPageAnalyzeContext,
route: NuxtPage,
Expand Down Expand Up @@ -189,6 +203,9 @@ function getRouteOptionsFromPages(
return options
}

/**
* Retrieve custom routes by parsing page components and extracting argument passed to `defineI18nRoute()`
*/
function getRouteOptionsFromComponent(route: NuxtPage, localeCodes: string[]) {
debug('getRouteOptionsFromComponent', route)
const file = route.file
Expand Down Expand Up @@ -227,6 +244,9 @@ function getRouteOptionsFromComponent(route: NuxtPage, localeCodes: string[]) {
return options
}

/**
* Parse page component at `target` and extract argument passed to `defineI18nRoute()`
*/
function readComponent(target: string) {
let options: ComputedRouteOptions | false | undefined = undefined

Expand Down
31 changes: 30 additions & 1 deletion src/routing.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getNormalizedLocales } from './utils'
import { getNormalizedLocales, toArray } from './utils'
import { isObject } from '@intlify/shared'

import type { Locale } from 'vue-i18n'
Expand Down Expand Up @@ -152,6 +152,35 @@ export function localizeRoutes(routes: NuxtPage[], options: LocalizeRoutesParams
}
}

// TODO: alias custom paths?
// add prefixes to aliases where applicable
if (localized.alias) {
const aliases = toArray(localized.alias)
const localizedAliases: string | string[] | undefined = []

for (const alias of aliases) {
const aliasPrefixable = prefixLocalizedRoute(
{ defaultLocale: isDefaultLocale ? locale : options.defaultLocale, ...localized, path: alias },
options,
extra
)

let localizedAlias = alias
if (aliasPrefixable) {
localizedAlias = join('/', locale, localizedAlias)
}

localizedAlias &&= adjustRoutePathForTrailingSlash(
{ ...localized, path: localizedAlias },
options.trailingSlash
)

localizedAliases.push(localizedAlias)
}

localized.alias = localizedAliases
}

localized.path &&= adjustRoutePathForTrailingSlash(localized, options.trailingSlash)

// remove parent path from child route
Expand Down
4 changes: 4 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -621,3 +621,7 @@ export const applyOptionOverrides = (options: NuxtI18nOptions, nuxt: Nuxt) => {
Object.assign(options, defu(overrides, mergedOptions))
}
}

export function toArray<T>(value: T | T[]): T[] {
return Array.isArray(value) ? value : [value]
}

0 comments on commit 6223696

Please sign in to comment.