Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat: add localeLocation API (#1142)
The intention of `localeRoute` was that it's used within `$route.push` call. The issue
with that was that `localeRoute` returned `Route` while `push` expects `Location`.

Changing the return type to `Location` while returning the route object would be wrong
so instead added a new API that returns `Location` and left `localeRoute` to return `Route`.

Fixes #776
  • Loading branch information
rchl committed Apr 9, 2021
1 parent 2d83bc8 commit c587d23
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 24 deletions.
21 changes: 18 additions & 3 deletions docs/content/en/api.md
Expand Up @@ -51,11 +51,24 @@ All [Vue I18n properties and methods](http://kazupon.github.io/vue-i18n/api/#vue
<badge>v6.12.0+</badge>

- **Arguments**:
- route (type: `string` | [`Location`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L125))
- route (type: `RawLocation`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L8))
- locale (type: `string`, default: current locale)
- **Returns**: [`Route`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L135-L145) | `undefined`

Returns localized route for passed in `route` parameters. If `locale` is not specified, uses current locale.

See also [Basic usage - nuxt-link](../basic-usage#nuxt-link).

#### localeLocation

<badge>v6.24.0+</badge>

- **Arguments**:
- route (type: `RawLocation`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L8))
- locale (type: `string`, default: current locale)
- **Returns**: [`Location`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L125) | `undefined`
- **Returns**: [`Location`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L125-L133) | `undefined`

Returns localized location for passed in `route`. If `locale` is not specified, uses current locale.
Returns localized location for passed in `route` parameters. If `locale` is not specified, uses current locale.

See also [Basic usage - nuxt-link](../basic-usage#nuxt-link).

Expand Down Expand Up @@ -225,6 +238,7 @@ export default Vue.extend({
### getRouteBaseName
### localePath
### localeRoute
### localeLocation
### switchLocalePath

See more info about those in [methods documentation](#methods).
Expand All @@ -250,6 +264,7 @@ export const actions = {
### getRouteBaseName
### localePath
### localeRoute
### localeLocation
### switchLocalePath

See more info about those in [methods documentation](#methods).
15 changes: 8 additions & 7 deletions docs/content/en/basic-usage.md
Expand Up @@ -77,13 +77,14 @@ export default ({ app }) => {
}
```

* `localeRoute` <badge>v6.12.0+</badge> – Returns the route object for a given page. It works like `localePath` but returns full route resolved by Vue Router rather than just its full path. This can be useful since full path returned from `localePath` might not carry all information from provided input (for example route params that the page doesn't specify).
* `localeRoute` <badge>v6.12.0+</badge> – Returns the `Route` object for a given page. It works like `localePath` but returns route resolved by Vue Router rather than just a full route path. This can be useful since full path returned from `localePath` might not carry all information from provided input (for example the route params that the page doesn't specify).

```vue
<a
href="#"
@click="$router.push(localeRoute({
name: 'index',
params: { foo: '1' }
}))">Navigate</a>
const { fullPath } = localeRoute({ name: 'index', params: { foo: '1' } })
```

* `localeLocation` <badge>v6.24.0+</badge> – Returns the `Location` object for a given page. It works like `localePath` but returns `Location` resolved by Vue Router rather than just a full route path. This can be useful since full path returned from `localePath` might not carry all information from provided input (for example route params that the page doesn't specify).

```vue
<a href="#" @click="$router.push(localeRoute({ name: 'index', params: { foo: '1' } }))">Navigate</a>
```
21 changes: 18 additions & 3 deletions docs/content/es/api.md
Expand Up @@ -51,11 +51,24 @@ Todos los [Vue I18n propiedades y métodos](http://kazupon.github.io/vue-i18n/ap
<badge>v6.12.0+</badge>

- **Arguments**:
- route (type: `string` | [`Location`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L125))
- route (type: `RawLocation`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L8))
- locale (type: `string`, default: current locale)
- **Returns**: [`Route`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L135-L145) | `undefined`

Returns localized route for passed in `route` parameters. If `locale` is not specified, uses current locale.

See also [Basic usage - nuxt-link](../basic-usage#nuxt-link).

#### localeLocation

<badge>v6.24.0+</badge>

- **Arguments**:
- route (type: `RawLocation`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L8))
- locale (type: `string`, default: current locale)
- **Returns**: [`Location`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L125) | `undefined`
- **Returns**: [`Location`](https://github.com/vuejs/vue-router/blob/f40139c27a9736efcbda69ec136cb00d8e00fa97/types/router.d.ts#L125-L133) | `undefined`

Returns localized location for passed in `route`. If `locale` is not specified, uses current locale.
Returns localized location for passed in `route` parameters. If `locale` is not specified, uses current locale.

See also [Basic usage - nuxt-link](../basic-usage#nuxt-link).

Expand Down Expand Up @@ -225,6 +238,7 @@ export default Vue.extend({
### getRouteBaseName
### localePath
### localeRoute
### localeLocation
### switchLocalePath

See more info about those in [methods documentation](#methods).
Expand All @@ -250,6 +264,7 @@ export const actions = {
### getRouteBaseName
### localePath
### localeRoute
### localeLocation
### switchLocalePath
See more info about those in [methods documentation](#methods).
12 changes: 12 additions & 0 deletions docs/content/es/basic-usage.md
Expand Up @@ -77,3 +77,15 @@ export default ({ app }) => {
const switchLocalePath = app.switchLocalePath('fr')
}
```

* `localeRoute` <badge>v6.12.0+</badge> – Returns the `Route` object for a given page. It works like `localePath` but returns route resolved by Vue Router rather than just a full route path. This can be useful since full path returned from `localePath` might not carry all information from provided input (for example the route params that the page doesn't specify).

```vue
const { fullPath } = localeRoute({ name: 'index', params: { foo: '1' } })
```

* `localeLocation` <badge>v6.24.0+</badge> – Returns the `Location` object for a given page. It works like `localePath` but returns `Location` resolved by Vue Router rather than just a full route path. This can be useful since full path returned from `localePath` might not carry all information from provided input (for example route params that the page doesn't specify).

```vue
<a href="#" @click="$router.push(localeRoute({ name: 'index', params: { foo: '1' } }))">Navigate</a>
```
35 changes: 30 additions & 5 deletions src/templates/plugin.routing.js
Expand Up @@ -8,15 +8,35 @@ import { getDomainFromLocale } from './utils-common'
* @type {Vue['localePath']}
*/
function localePath (route, locale) {
const localizedRoute = this.localeRoute(route, locale)
return localizedRoute ? localizedRoute.fullPath : ''
const localizedRoute = resolveRoute.call(this, route, locale)
return localizedRoute ? localizedRoute.route.fullPath : ''
}

/**
* @this {import('../../types/internal').PluginProxy}
* @type {Vue['localeRoute']}
*/
function localeRoute (route, locale) {
const resolved = resolveRoute.call(this, route, locale)
return resolved ? resolved.route : undefined
}

/**
* @this {import('../../types/internal').PluginProxy}
* @type {Vue['localeLocation']}
*/
function localeLocation (route, locale) {
const resolved = resolveRoute.call(this, route, locale)
return resolved ? resolved.location : undefined
}

/**
* @this {import('../../types/internal').PluginProxy}
* @param {import('vue-router').RawLocation} route
* @param {string} [locale]
* @return {ReturnType<import('vue-router').default['resolve']> | undefined}
*/
function resolveRoute (route, locale) {
// Abort if no route or no locale
if (!route) {
return
Expand Down Expand Up @@ -81,12 +101,12 @@ function localeRoute (route, locale) {
}
}

const resolvedRoute = this.router.resolve(localizedRoute).route
if (resolvedRoute.name) {
const resolvedRoute = this.router.resolve(localizedRoute)
if (resolvedRoute.route.name) {
return resolvedRoute
}
// If didn't resolve to an existing route then just return resolved route based on original input.
return this.router.resolve(route).route
return this.router.resolve(route)
}

/**
Expand Down Expand Up @@ -168,6 +188,7 @@ const VueInstanceProxy = function (targetFunction) {
i18n: this.$i18n,
localePath: this.localePath,
localeRoute: this.localeRoute,
localeLocation: this.localeLocation,
req: process.server ? this.$ssrContext.req : null,
route: this.$route,
router: this.$router,
Expand All @@ -192,6 +213,7 @@ const NuxtContextProxy = function (context, targetFunction) {
getRouteBaseName: app.getRouteBaseName,
i18n: app.i18n,
localePath: app.localePath,
localeLocation: app.localeLocation,
localeRoute: app.localeRoute,
req: process.server ? req : null,
route,
Expand All @@ -210,6 +232,7 @@ const plugin = {
methods: {
localePath: VueInstanceProxy(localePath),
localeRoute: VueInstanceProxy(localeRoute),
localeLocation: VueInstanceProxy(localeLocation),
switchLocalePath: VueInstanceProxy(switchLocalePath),
getRouteBaseName: VueInstanceProxy(getRouteBaseName)
}
Expand All @@ -224,12 +247,14 @@ export default (context) => {

app.localePath = context.localePath = NuxtContextProxy(context, localePath)
app.localeRoute = context.localeRoute = NuxtContextProxy(context, localeRoute)
app.localeLocation = context.localeLocation = NuxtContextProxy(context, localeLocation)
app.switchLocalePath = context.switchLocalePath = NuxtContextProxy(context, switchLocalePath)
app.getRouteBaseName = context.getRouteBaseName = NuxtContextProxy(context, getRouteBaseName)

if (store) {
store.localePath = app.localePath
store.localeRoute = app.localeRoute
store.localeLocation = app.localeLocation
store.switchLocalePath = app.switchLocalePath
store.getRouteBaseName = app.getRouteBaseName
}
Expand Down
1 change: 1 addition & 0 deletions test/fixture/basic/middleware/i18n-middleware.js
Expand Up @@ -8,6 +8,7 @@ const middleware = ({ app }) => {
app.allLocalePaths = app.i18n.localeCodes.map(locale => app.switchLocalePath(locale))
app.routeBaseName = app.getRouteBaseName()
app.localizedRoute = app.localeRoute(app.routeBaseName, 'fr')
app.localizedLocation = app.localeLocation(app.routeBaseName, 'fr')
}

export default middleware
13 changes: 11 additions & 2 deletions test/module.test.js
Expand Up @@ -592,8 +592,7 @@ for (const trailingSlash of TRAILING_SLASHES) {
expect(dom.querySelector('#name')?.textContent).toBe('middleware')
const routeObject = dom.querySelector('#localizedRoute')?.textContent || '{}'
expect(JSON.parse(routeObject)).toMatchObject({
name: 'middleware___fr',
fullPath: pathRespectingTrailingSlash('/fr/middleware-fr')
name: 'middleware___fr'
})
})

Expand Down Expand Up @@ -1079,6 +1078,16 @@ describe('prefix_and_default strategy', () => {
})
})

test('localeLocation returns route name for existing route', async () => {
const window = await nuxt.renderAndGetWindow(url('/'))
expect(window.$nuxt.localeLocation('/about-us', 'en')).toMatchObject({ name: 'about___en___default' })
})

test('localeLocation returns route path for non-existing route', async () => {
const window = await nuxt.renderAndGetWindow(url('/'))
expect(window.$nuxt.localeLocation('/abc', 'en')).toMatchObject({ path: '/abc' })
})

test('canonical SEO link is added to prefixed default locale', async () => {
const html = await get('/en')
const dom = getDom(html)
Expand Down
1 change: 1 addition & 0 deletions types/internal.d.ts
Expand Up @@ -21,6 +21,7 @@ export interface PluginProxy {
i18n: Vue['$i18n'],
localePath: Vue['localePath'],
localeRoute: Vue['localeRoute'],
localeLocation: Vue['localeLocation'],
req?: IncomingMessage,
route: Vue['$route'],
router: Vue['$router'],
Expand Down
13 changes: 10 additions & 3 deletions types/test/index.ts
Expand Up @@ -2,14 +2,14 @@
/* eslint-disable no-unused-vars */
import Vue from 'vue'
import Vuex from 'vuex'
import { Route } from 'vue-router'
import { Location, Route } from 'vue-router'
import { Plugin } from '@nuxt/types'
import '../index'

const vm = new Vue()
const locale = 'en'

let path: string | undefined
let path: string

// localePath

Expand All @@ -30,7 +30,14 @@ const routeBaseName: string | undefined = vm.getRouteBaseName(vm.$route)

const localizedRoute: Route | undefined = vm.localeRoute('about', 'fr')
if (localizedRoute) {
vm.$router.push({ path: localizedRoute.path })
const { fullPath } = localizedRoute
}

// localeLocation

const localizedLocation: Location | undefined = vm.localeLocation('about', 'fr')
if (localizedLocation) {
vm.$router.push(localizedLocation)
}

// $i18n
Expand Down
3 changes: 2 additions & 1 deletion types/vue.d.ts
@@ -1,7 +1,7 @@
import 'vue'
import 'vuex'
import '@nuxt/types'
import { RawLocation, Route } from 'vue-router'
import { Location, RawLocation, Route } from 'vue-router'
import VueI18n, { IVueI18n } from 'vue-i18n'
import { MetaInfo } from 'vue-meta'
import { BaseOptions, LocaleObject, Options } from '.'
Expand Down Expand Up @@ -49,6 +49,7 @@ interface NuxtI18nApi {
getRouteBaseName(route?: Route): string | undefined
localePath(route: RawLocation, locale?: string): string
localeRoute(route: RawLocation, locale?: string): Route | undefined
localeLocation(route: RawLocation, locale?: string): Location | undefined
switchLocalePath(locale: string): string
}

Expand Down

0 comments on commit c587d23

Please sign in to comment.