Skip to content

Commit

Permalink
feat: custome route path for component with defineI18nRoute (nuxt-m…
Browse files Browse the repository at this point in the history
  • Loading branch information
kazupon authored Oct 4, 2022
1 parent 5e77ad8 commit c70a8d4
Show file tree
Hide file tree
Showing 34 changed files with 569 additions and 53 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
dist
playground
specs/fixtures
test/fixtures
coverage
docs/components/content/Logo.vue
8 changes: 6 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ This todo is based on [nuxt/i18n](https://i18n.nuxtjs.org/) docs.
- [x] prefix
- [x] prefix_and_default
- [x] Configurations
- [ ] Custom route paths
- [ ] In-component options
- [x] Custom route paths
- [x] In-component options
- [x] Module's configuration
- [ ] Ignoring localized routes
- [ ] Pick localized routes
Expand Down Expand Up @@ -83,6 +83,10 @@ This todo is based on [nuxt/i18n](https://i18n.nuxtjs.org/) docs.
- [x] useLocaleHead (same `$nuxtI18nHead` )
- [x] useBrowserLocale (same `getBrowserLocale`)

### Compiler Macros (NWE!)

- [x] defineI18nRoute (same `nuxtI18n` component options)

### Extension of Vuex

- [ ] $i18n
Expand Down
2 changes: 1 addition & 1 deletion build.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
externals: ['node:fs', '@intlify/vue-i18n-bridge', 'webpack']
externals: ['node:fs', 'node:url', '@intlify/vue-i18n-bridge', 'webpack']
})
48 changes: 31 additions & 17 deletions docs/content/30.guide/4.custom-paths.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,49 @@ title: Custom route paths
description: 'Customize the names of the paths for specific locale.'
---

::alert{type="warning"}
// TODO:
🚧 This feature is not implemented **fully** yet.
::

In some cases, you might want to translate URLs in addition to having them prefixed with the locale code. There are 2 ways of configuring custom paths for your pages: [in-component options](#in-component-options) or via the [module's configuration](#modules-configuration).
In some cases, you might want to translate URLs in addition to having them prefixed with the locale code. There are 2 ways of configuring custom paths for your pages: [Compiler macro](#compiler-macro) or via the [Nuxt configuration](#nuxt-configuration).

::alert{type="warning"}
Custom paths are not supported when using the `no-prefix` [strategy](/strategies).
::

### In-component options
### Compiler macro

::alert{type="warning"}
// TODO:
🚧 This feature is not implemented yet.
You can use the `defineI18nRoute` compiler macro to set some custom paths for each page component.

```html {}[pages/about.vue]
<script setup>
defineI18nRoute({
paths: {
en: '/about-us', // -> accessible at /about-us (no prefix since it's the default locale)
fr: '/a-propos', // -> accessible at /fr/a-propos
es: '/sobre' // -> accessible at /es/sobre
}
})
</script>
```

To configure a custom path for a dynamic route, you need to put the params in the URI similarly to how you would do it in vue-router.

```html {}[pages/articles/[name].vue]
<script setup>
defineI18nRoute({
paths: {
en: '/articles/:name',
es: '/artículo/:name'
}
})
```
::alert{type="info"}
`defineI18nRoute` compiler macro is tree-shaked out at build time and is not included in the dist files.
::
### Module's configuration
### Nuxt configuration
Make sure you set the `parsePages` option to `false` to disable babel parsing and add your custom paths in the `pages` option:
```js {}[nuxt.config.js]
import { defineNuxtConfig } from 'nuxt'

export default defineNuxtConfig({
// ...
Expand Down Expand Up @@ -65,8 +83,6 @@ pages/
Here's how you would configure these particular pages in the configuration:
```js {}[nuxt.config.js]
import { defineNuxtConfig } from 'nuxt'

export default defineNuxtConfig({
// ...
Expand Down Expand Up @@ -108,8 +124,6 @@ pages/
You would need to set up your `pages` property as follows:
```js {}[nuxt.config.js]
import { defineNuxtConfig } from 'nuxt'

export default defineNuxtConfig({
// ...
Expand Down
44 changes: 44 additions & 0 deletions docs/content/50.API/2.compiler-macros.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: Compiler Macros
description: 'Compiler Macros for `@nuxtjs/i18n`'
---

## `defineI18nRoute`

`defineI18nRoute` is a compiler macro that you can use to set custom route paths for your **page** components located in the `pages/` directory (unless [set otherwise](https://v3.nuxtjs.org/api/configuration/nuxt.config#pages)). This way you can set custom route paths for each static or dynamic route of your Nuxt application.

```vue [pages/some-page.vue]
<script setup>
defineI18nRoute({
paths: {
en: '/about-us',
fr: '/a-propos',
ja: '/about-ja'
}
})
</script>
```

## Type

```ts
defineI18nRoute(route: I18nRoute) => void

interface I18nRoute {
paths?: Record<Locale, string>
}
```

## Parameters

### `paths`

- **Type**: `I18nRoute`

An object accepting the following i18n route settings:

**`paths`**

- **Type**: `Record<Locale, string>`

Customize page component routes per locale. You can specify static and dynamic paths for vue-router.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@
"is-https": "^4.0.0",
"js-cookie": "^3.0.1",
"knitwork": "^0.1.2",
"magic-string": "^0.26.5",
"mlly": "^0.5.4",
"pathe": "^0.3.2",
"ufo": "^0.8.5",
"unplugin": "^0.9.6",
"vue-i18n": "^9.3.0-beta.6",
"vue-i18n-routing": "^0.6.0"
},
Expand Down
19 changes: 10 additions & 9 deletions playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,21 @@ export default defineNuxtConfig({
// strategy: 'no_prefix',
// strategy: 'prefix',
// strategy: 'prefix_and_default',
parsePages: true,
pages: {
about: {
ja: '/about-ja'
}
},
differentDomains: true,
// detectBrowserLanguage: false,
detectBrowserLanguage: {
// alwaysRedirect: true,
useCookie: false
// cookieKey: 'i18n_redirected',
// cookieKey: 'my_custom_cookie_name',
// redirectOn: 'root'
},
// differentDomains: true,
detectBrowserLanguage: false,
// detectBrowserLanguage: {
// // alwaysRedirect: true,
// useCookie: false
// // cookieKey: 'i18n_redirected',
// // cookieKey: 'my_custom_cookie_name',
// // redirectOn: 'root'
// },
onBeforeLanguageSwitch: (oldLocale, newLocale, initial, context) => {
console.log('onBeforeLanguageSwitch', oldLocale, newLocale, initial)
},
Expand Down
16 changes: 10 additions & 6 deletions playground/pages/about/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,21 @@ export default defineComponent({
useHead({
meta: [{ property: 'og:title', content: 'this is og title' }]
})
defineI18nRoute({
paths: {
en: '/about-us',
fr: '/a-propos',
ja: '/about-ja'
}
})
definePageMeta({
title: 'pages.title.about'
})
return {}
}
})
</script>

<script setup lang="ts">
definePageMeta({
title: 'pages.title.about'
})
</script>

<template>
<div>
<nav>
Expand Down
15 changes: 15 additions & 0 deletions playground/pages/blog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<template>
<div>
<h1>This is blog page</h1>
</div>
</template>

<script setup>
defineI18nRoute({
paths: {
en: '/blog-us',
fr: '/a-blog',
ja: '/blog-ja'
}
})
</script>
4 changes: 2 additions & 2 deletions playground/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const availableLocales = computed(() => {
<h2>{{ $t('hello', { name: 'nuxt3' }) }}</h2>
<h2>Pages</h2>
<nav>
<NuxtLink :to="localePath('/')">Home</NuxtLink> |
<NuxtLink :to="localePath('/about')">About</NuxtLink>
<NuxtLink :to="localePath('/')">Home</NuxtLink> | <NuxtLink :to="localePath({ name: 'about' })">About</NuxtLink> |
<NuxtLink :to="localePath({ name: 'blog' })">Blog</NuxtLink>
</nav>
<h2>Current Language: {{ getLocaleName(locale) }}</h2>
<h2>Current Strategy: {{ strategy }}</h2>
Expand Down
53 changes: 53 additions & 0 deletions specs/custom_route_paths/compiler_macro.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { test, expect } from 'vitest'
import { fileURLToPath } from 'node:url'
import { setup, url, createPage } from '@nuxt/test-utils'

await setup({
rootDir: fileURLToPath(new URL(`../fixtures/head`, import.meta.url)),
browser: true,
// overrides
nuxtConfig: {
i18n: {
defaultLocale: 'en',
parsePages: true
}
}
})

test('can access to custom route path', async () => {
const home = url('/')
const page = await createPage()
await page.goto(home)

await page.locator('#link-blog').click()
await page.waitForTimeout(1000)

expect(await page.url()).include('/blog-us')

await page.goBack()
await page.locator('#lang-switcher-with-nuxt-link a').click()

await page.locator('#link-blog').click()
await page.waitForTimeout(1000)

expect(await page.url()).include('/fr/a-blog')
})

test('can access to custom dynamic route path', async () => {
const home = url('/')
const page = await createPage()
await page.goto(home)

await page.locator('#link-category').click()
await page.waitForTimeout(1000)

expect(await page.url()).include('/categories/foo')

await page.goBack()
await page.locator('#lang-switcher-with-nuxt-link a').click()

await page.locator('#link-category').click()
await page.waitForTimeout(1000)

expect(await page.url()).include(encodeURI('/fr/catégories/foo'))
})
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ await setup({
nuxtConfig: {
i18n: {
defaultLocale: 'en',
parsePages: false,
pages: {
about: {
fr: '/about-fr'
Expand Down
3 changes: 2 additions & 1 deletion specs/fixtures/head/locales/en-US.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"home": "Homepage",
"about": "About us",
"posts": "Posts"
"posts": "Posts",
"categories": "Categories"
}
3 changes: 2 additions & 1 deletion specs/fixtures/head/locales/fr-FR.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"home": "Accueil",
"about": "À propos",
"posts": "Articles"
"posts": "Articles",
"categories": "Catégories"
}
14 changes: 14 additions & 0 deletions specs/fixtures/head/pages/blog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<template>
<div>
<h1>This is blog page</h1>
</div>
</template>

<script setup>
defineI18nRoute({
paths: {
en: '/blog-us',
fr: '/a-blog'
}
})
</script>
14 changes: 14 additions & 0 deletions specs/fixtures/head/pages/categories.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<template>
<div>
<NuxtPage />
</div>
</template>

<script setup>
defineI18nRoute({
paths: {
en: '/categories/:id',
fr: '/catégories/:id'
}
})
</script>
5 changes: 5 additions & 0 deletions specs/fixtures/head/pages/categories/[id].vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div>
<h1>This is category page</h1>
</div>
</template>
4 changes: 4 additions & 0 deletions specs/fixtures/head/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@ definePageMeta({
<code id="home-use-async-data">{{ data }}</code>
</section>
<NuxtLink id="link-about" exact :to="localePath('about')">{{ $t('about') }}</NuxtLink>
<NuxtLink id="link-blog" :to="localePath({ name: 'blog' })">{{ $t('posts') }}</NuxtLink>
<NuxtLink id="link-category" :to="localePath({ name: 'categories', params: { id: 'foo' } })">{{
$t('categories')
}}</NuxtLink>
</div>
</template>
Loading

0 comments on commit c70a8d4

Please sign in to comment.