Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add possibility to disable default redirect for prefix_and_default strategy #1437

Open
wants to merge 9 commits into
base: v7
Choose a base branch
from
1 change: 1 addition & 0 deletions src/helpers/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const DEFAULT_OPTIONS = {
vueI18nLoader: false,
locales: [],
defaultLocale: '',
disableDefaultRedirect: false,
defaultDirection: 'ltr',
routesNameSeparator: '___',
defaultLocaleRouteNameSuffix: 'default',
Expand Down
12 changes: 9 additions & 3 deletions src/templates/plugin.main.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
loadLanguageAsync,
resolveBaseUrl,
registerStore,
mergeAdditionalMessages
mergeAdditionalMessages, isEnabledRedirectForPath
} from './plugin.utils'
// @ts-ignore
import { joinURL } from '~i18n-ufo'
Expand Down Expand Up @@ -153,14 +153,20 @@ export default async (context) => {
let redirectPath = ''

const isStaticGenerate = process.static && process.server
const isSameLocale = getLocaleFromRoute(route) !== newLocale
Renhor marked this conversation as resolved.
Show resolved Hide resolved
const isPrefixAndDefaultStrategy = options.strategy === Constants.STRATEGIES.PREFIX_AND_DEFAULT
const isDefaultLocale = newLocale === options.defaultLocale
const isEnabledRedirectForRoute = isEnabledRedirectForPath(route.fullPath, app.i18n.localeCodes, options.disableDefaultRedirect)

// Decide whether we should redirect to a different route.
if (
!isStaticGenerate &&
!app.i18n.differentDomains &&
options.strategy !== Constants.STRATEGIES.NO_PREFIX &&
// Skip if already on the new locale unless the strategy is "prefix_and_default" and this is the default
// locale, in which case we might still redirect as we prefer unprefixed route in this case.
(getLocaleFromRoute(route) !== newLocale || (options.strategy === Constants.STRATEGIES.PREFIX_AND_DEFAULT && newLocale === options.defaultLocale))
// locale, in which case we might still redirect as we prefer unprefixed route in this case, but let user a
// possibility to disable this behavior by switching disableDefaultRedirect option to true.
(isSameLocale || (isPrefixAndDefaultStrategy && isDefaultLocale && isEnabledRedirectForRoute))
rchl marked this conversation as resolved.
Show resolved Hide resolved
) {
// The current route could be 404 in which case attempt to find matching route using the full path since
// "switchLocalePath" can only find routes if the current route exists.
Expand Down
36 changes: 35 additions & 1 deletion src/templates/plugin.utils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import isHTTPS from 'is-https'
import { localeMessages, options } from './options'
import { formatMessage } from './utils-common'
import { addSlashToPath, clearPathFromLocale, formatMessage } from './utils-common'
// @ts-ignore
import { hasProtocol } from '~i18n-ufo'

Expand Down Expand Up @@ -216,6 +216,40 @@ export function mergeAdditionalMessages (i18n, additionalMessages, localeCodes,
}
}

/**
* @param {string} pathString
* @param {readonly string[]} localeCodes
* @param {import('../../types').DisableDefaultRedirect} disableDefaultRedirect
* @return {boolean}
*/
export function isEnabledRedirectForPath (pathString, localeCodes, disableDefaultRedirect) {
if (!disableDefaultRedirect) {
return true
}

if (typeof disableDefaultRedirect === 'boolean') {
return false
}

const clearPath = clearPathFromLocale(pathString, localeCodes)
const clearPathWithSlash = addSlashToPath(clearPath)

return !disableDefaultRedirect
.map((patternString) => {
const isPattern = patternString.includes('*')
rchl marked this conversation as resolved.
Show resolved Hide resolved
const pathPattern = patternString.replace('*', '')
const normalizedPathPattern = addSlashToPath(pathPattern)

return {
isPattern,
path: normalizedPathPattern
}
})
.some(({ isPattern, path }) => {
return isPattern ? clearPathWithSlash.startsWith(path) : clearPathWithSlash === path
})
}

/**
* @param {any} value
* @return {boolean}
Expand Down
19 changes: 19 additions & 0 deletions src/templates/utils-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,22 @@ export function setLocaleCookie (locale, res, { useCookie, cookieDomain, cookieK
res.setHeader('Set-Cookie', headers)
}
}

/**
* @param {string} pathString
* @param {readonly string[]} localeCodes
* @return {string}
*/
export function clearPathFromLocale (pathString, localeCodes) {
Renhor marked this conversation as resolved.
Show resolved Hide resolved
const regexp = new RegExp(`^(\\/${localeCodes.join('|\\/')})(?=\\/|$)`)

return pathString.replace(regexp, '') || '/'
}

/**
* @param {string} pathString
* @return {string}
*/
export function addSlashToPath (pathString) {
return pathString.endsWith('/') ? pathString : `${pathString}/`
Renhor marked this conversation as resolved.
Show resolved Hide resolved
}
3 changes: 3 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,12 @@ export interface BaseOptions {
onLanguageSwitched?: (oldLocale: string, newLocale: string) => void
}

export type DisableDefaultRedirect = boolean | string[]

export interface Options extends BaseOptions {
baseUrl?: string | ((context: NuxtContext) => string)
detectBrowserLanguage?: DetectBrowserLanguageOptions | false
disableDefaultRedirect?: DisableDefaultRedirect;
rchl marked this conversation as resolved.
Show resolved Hide resolved
langDir?: string | null
lazy?: boolean | LazyOptions
pages?: {
Expand Down