diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8771c64b9..b1dc0afab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,10 +9,10 @@ env: on: push: branches: - - main + - v8 pull_request: branches: - - main + - v8 jobs: lint: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bb002b48b..d85e769dc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,7 +52,7 @@ jobs: - name: Commit changelog uses: stefanzweifel/git-auto-commit-action@v5 with: - branch: main + branch: v8 file_pattern: 'CHANGELOG.md' commit_message: 'chore: generate changelog' diff --git a/CHANGELOG.md b/CHANGELOG.md index 346326867..ed979d7cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +# v8.3.3 (2024-07-28T09:51:21Z) + +This changelog is generated by [GitHub Releases](https://github.com/nuxt-modules/i18n/releases/tag/v8.3.3) + +###    🐞 Bug Fixes + +- Encode `switchLocalePath` during SSR replacement  -  by @BobbieGoede in https://github.com/nuxt-modules/i18n/issues/3043 [(28d22)](https://github.com/nuxt-modules/i18n/commit/28d22aa6) + +#####     [View changes on GitHub](https://github.com/nuxt-modules/i18n/compare/v8.3.2...v8.3.3) + +# v8.3.2 (2024-07-27T04:42:45Z) + +This changelog is generated by [GitHub Releases](https://github.com/nuxt-modules/i18n/releases/tag/v8.3.2) + +###    🐞 Bug Fixes + +- Update `@nuxt/module-builder`  -  by @BobbieGoede in https://github.com/nuxt-modules/i18n/issues/2960 [(fe300)](https://github.com/nuxt-modules/i18n/commit/fe300294) +- Locale prefixes are not added to route aliases  -  by @BobbieGoede in https://github.com/nuxt-modules/i18n/issues/2962 [(62236)](https://github.com/nuxt-modules/i18n/commit/62236964) +- Unable to configure server integration using inline options  -  by @BobbieGoede in https://github.com/nuxt-modules/i18n/issues/3020 [(856ba)](https://github.com/nuxt-modules/i18n/commit/856ba4fc) + +#####     [View changes on GitHub](https://github.com/nuxt-modules/i18n/compare/v8.3.1...v8.3.2) + # v8.3.1 (2024-04-24T10:05:08Z) This changelog is generated by [GitHub Releases](https://github.com/nuxt-modules/i18n/releases/tag/v8.3.1) diff --git a/package.json b/package.json index 2b2d411b5..ca590cce5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@nuxtjs/i18n", "description": "i18n for Nuxt", - "version": "8.3.1", + "version": "8.3.3", "homepage": "https://i18n.nuxtjs.org", "bugs": { "url": "https://github.com/nuxt-community/i18n-module/issues" diff --git a/playground/pages/index.vue b/playground/pages/index.vue index 45f6898eb..9d1e03fd7 100644 --- a/playground/pages/index.vue +++ b/playground/pages/index.vue @@ -1,5 +1,6 @@ <` + + const html = await $fetch(url) + const dom = getDom(html) + + // the localized should be the same as encoded + expect(dom.querySelector('#slp-xss a').href).toEqual(encodeURI('/nl' + url)) + }) }) diff --git a/specs/fixtures/basic_usage/app.vue b/specs/fixtures/basic_usage/app.vue index c0937df0c..fcb7faf7f 100644 --- a/specs/fixtures/basic_usage/app.vue +++ b/specs/fixtures/basic_usage/app.vue @@ -1,6 +1,6 @@ + + diff --git a/specs/fixtures/inline_options/locale-detector.ts b/specs/fixtures/inline_options/locale-detector.ts new file mode 100644 index 000000000..4cce000e8 --- /dev/null +++ b/specs/fixtures/inline_options/locale-detector.ts @@ -0,0 +1,23 @@ +// Detect based on query, cookie, header +export default defineI18nLocaleDetector((event, config) => { + // try to get locale from query + const query = tryQueryLocale(event, { lang: '' }) // disable locale default value with `lang` option + if (query) { + return query.toString() + } + + // try to get locale from cookie + const cookie = tryCookieLocale(event, { lang: '', name: 'i18n_locale' }) // disable locale default value with `lang` option + if (cookie) { + return cookie.toString() + } + + // try to get locale from header (`accept-header`) + const header = tryHeaderLocale(event, { lang: '' }) // disable locale default value with `lang` option + if (header) { + return header.toString() + } + + // If the locale cannot be resolved up to this point, it is resolved with the value `defaultLocale` of the locale config passed to the function + return config.defaultLocale +}) diff --git a/specs/fixtures/inline_options/nuxt.config.ts b/specs/fixtures/inline_options/nuxt.config.ts index 9712bcec9..5b955a318 100644 --- a/specs/fixtures/inline_options/nuxt.config.ts +++ b/specs/fixtures/inline_options/nuxt.config.ts @@ -19,7 +19,10 @@ export default defineNuxtConfig({ file: 'locale-file-en.json', name: 'English' } - ] + ], + experimental: { + localeDetector: './locale-detector.ts' + } } ] ], diff --git a/specs/fixtures/inline_options/server/api/translate.ts b/specs/fixtures/inline_options/server/api/translate.ts new file mode 100644 index 000000000..1eae6c186 --- /dev/null +++ b/specs/fixtures/inline_options/server/api/translate.ts @@ -0,0 +1,7 @@ +import { useTranslation } from '@intlify/h3' + +export default defineEventHandler(async event => { + const t = await useTranslation(event) + + return t('home') +}) diff --git a/specs/inline_options.spec.ts b/specs/inline_options.spec.ts index 4c7717d69..2cbb66080 100644 --- a/specs/inline_options.spec.ts +++ b/specs/inline_options.spec.ts @@ -1,6 +1,6 @@ import { test, expect, describe } from 'vitest' import { fileURLToPath } from 'node:url' -import { setup } from './utils' +import { setup, url, $fetch } from './utils' import { renderPage } from './helper' await setup({ @@ -34,4 +34,9 @@ describe('inline options are handled correctly', async () => { ) ).toBe(false) }) + + test('(#2721) server integration from inline configuration', async () => { + const res = await $fetch(url('/api/translate')) + expect(res).toEqual('Homepage') + }) }) diff --git a/src/constants.ts b/src/constants.ts index ba59587c5..83697b1ab 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -66,7 +66,8 @@ export const DEFAULT_OPTIONS = { cookieSecure: false, fallbackLocale: '', redirectOn: 'root', - useCookie: true + useCookie: true, + httpOnly: false, }, differentDomains: false, baseUrl: '', diff --git a/src/module.ts b/src/module.ts index 7e9c3a21f..295905a0a 100644 --- a/src/module.ts +++ b/src/module.ts @@ -234,6 +234,7 @@ export default defineNuxtModule({ // for core plugin addPlugin(resolve(runtimeDir, 'plugins/i18n')) + addPlugin(resolve(runtimeDir, 'plugins/switch-locale-path-ssr')) // for composables nuxt.options.alias['#i18n'] = resolve(distDir, 'runtime/composables/index.mjs') diff --git a/src/nitro.ts b/src/nitro.ts index a1100d725..25dd14938 100644 --- a/src/nitro.ts +++ b/src/nitro.ts @@ -7,7 +7,7 @@ import { addServerPlugin, createResolver, resolvePath, useLogger } from '@nuxt/k import yamlPlugin from '@rollup/plugin-yaml' import json5Plugin from '@miyaneee/rollup-plugin-json5' import { getFeatureFlags } from './bundler' -import { isExists } from './utils' +import { getLayerI18n, isExists } from './utils' import { H3_PKG, UTILS_H3_PKG, @@ -131,13 +131,16 @@ export { localeDetector } } async function resolveLocaleDetectorPath(nuxt: Nuxt) { - const serverI18nLayer = nuxt.options._layers.find( - l => l.config.i18n?.experimental?.localeDetector != null && l.config.i18n?.experimental?.localeDetector !== '' - ) + const serverI18nLayer = nuxt.options._layers.find(l => { + const layerI18n = getLayerI18n(l) + return layerI18n?.experimental?.localeDetector != null && layerI18n?.experimental?.localeDetector !== '' + }) + let enableServerIntegration = serverI18nLayer != null if (serverI18nLayer != null) { - const pathTo = resolve(serverI18nLayer.config.rootDir, serverI18nLayer.config.i18n!.experimental!.localeDetector!) + const serverI18nLayerConfig = getLayerI18n(serverI18nLayer) + const pathTo = resolve(serverI18nLayer.config.rootDir, serverI18nLayerConfig!.experimental!.localeDetector!) const localeDetectorPath = await resolvePath(pathTo, { cwd: nuxt.options.rootDir, extensions: EXECUTABLE_EXTENSIONS diff --git a/src/runtime/components/SwitchLocalePathLink.ts b/src/runtime/components/SwitchLocalePathLink.ts index 906a04fbd..3166d0cce 100644 --- a/src/runtime/components/SwitchLocalePathLink.ts +++ b/src/runtime/components/SwitchLocalePathLink.ts @@ -21,7 +21,7 @@ export default defineComponent({ return () => [ h(Comment, `${SWITCH_LOCALE_PATH_LINK_IDENTIFIER}-[${props.locale}]`), - h(NuxtLink, { ...attrs, to: switchLocalePath(props.locale) }, slots.default), + h(NuxtLink, { ...attrs, to: encodeURI(switchLocalePath(props.locale)) }, slots.default), h(Comment, `/${SWITCH_LOCALE_PATH_LINK_IDENTIFIER}`) ] } diff --git a/src/runtime/internal.ts b/src/runtime/internal.ts index c2d8eaa37..83290ba51 100644 --- a/src/runtime/internal.ts +++ b/src/runtime/internal.ts @@ -99,7 +99,8 @@ export function getI18nCookie() { expires: new Date(date.setDate(date.getDate() + 365)), path: '/', sameSite: detect && detect.cookieCrossOrigin ? 'none' : 'lax', - secure: (detect && detect.cookieCrossOrigin) || (detect && detect.cookieSecure) + secure: (detect && detect.cookieCrossOrigin) || (detect && detect.cookieSecure), + httpOnly: detect && detect.httpOnly ? true : false } if (detect && detect.cookieDomain) { diff --git a/src/runtime/plugins/i18n.ts b/src/runtime/plugins/i18n.ts index dcc80e995..18d968e2e 100644 --- a/src/runtime/plugins/i18n.ts +++ b/src/runtime/plugins/i18n.ts @@ -7,11 +7,9 @@ import { isSSG, localeLoaders, parallelPlugin, - normalizedLocales, - SWITCH_LOCALE_PATH_LINK_IDENTIFIER + normalizedLocales } from '#build/i18n.options.mjs' import { loadVueI18nOptions, loadInitialMessages, loadLocale } from '../messages' -import { useSwitchLocalePath } from '../composables' import { loadAndSetLocale, detectLocale, @@ -401,29 +399,6 @@ export default defineNuxtPlugin({ // inject for nuxt helpers injectNuxtHelpers(nuxtContext, i18n) - // Replace `SwitchLocalePathLink` href in rendered html for SSR support - if (runtimeI18n.experimental.switchLocalePathLinkSSR === true) { - const switchLocalePath = useSwitchLocalePath() - - const switchLocalePathLinkWrapperExpr = new RegExp( - [ - ``, - `.+?`, - `` - ].join(''), - 'g' - ) - - nuxt.hook('app:rendered', ctx => { - if (ctx.renderResult?.html == null) return - - ctx.renderResult.html = ctx.renderResult.html.replaceAll( - switchLocalePathLinkWrapperExpr, - (match: string, p1: string) => match.replace(/href="([^"]+)"/, `href="${switchLocalePath(p1 ?? '')}"`) - ) - }) - } - let routeChangeCount = 0 addRouteMiddleware( diff --git a/src/runtime/plugins/switch-locale-path-ssr.ts b/src/runtime/plugins/switch-locale-path-ssr.ts new file mode 100644 index 000000000..598665889 --- /dev/null +++ b/src/runtime/plugins/switch-locale-path-ssr.ts @@ -0,0 +1,33 @@ +import { defineNuxtPlugin } from '#imports' +import { useSwitchLocalePath } from '#i18n' +import { SWITCH_LOCALE_PATH_LINK_IDENTIFIER } from '#build/i18n.options.mjs' + +// Replace `SwitchLocalePathLink` href in rendered html for SSR support +export default defineNuxtPlugin({ + name: 'i18n:plugin:switch-locale-path-ssr', + dependsOn: ['i18n:plugin'], + setup(nuxt) { + if (nuxt.$config.public.i18n.experimental.switchLocalePathLinkSSR !== true) return + + const switchLocalePath = useSwitchLocalePath() + + const switchLocalePathLinkWrapperExpr = new RegExp( + [ + ``, + `.+?`, + `` + ].join(''), + 'g' + ) + + nuxt.hook('app:rendered', ctx => { + if (ctx.renderResult?.html == null) return + + ctx.renderResult.html = ctx.renderResult.html.replaceAll( + switchLocalePathLinkWrapperExpr, + (match: string, p1: string) => + match.replace(/href="([^"]+)"/, `href="${encodeURI(switchLocalePath(p1 ?? ''))}"`) + ) + }) + } +}) diff --git a/src/runtime/routing/extends/router.ts b/src/runtime/routing/extends/router.ts index 3f90a4b90..17c6e331d 100644 --- a/src/runtime/routing/extends/router.ts +++ b/src/runtime/routing/extends/router.ts @@ -3,7 +3,7 @@ import { getLocalesRegex } from '../utils' import { localeCodes } from '#build/i18n.options.mjs' import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from 'vue-router' -import { useRuntimeConfig } from 'nuxt/app' +import { useRuntimeConfig } from '#imports' export function createLocaleFromRouteGetter() { const { routesNameSeparator, defaultLocaleRouteNameSuffix } = useRuntimeConfig().public.i18n diff --git a/src/types.ts b/src/types.ts index d7b479d48..092e6bf63 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,7 +14,8 @@ export interface DetectBrowserLanguageOptions { cookieSecure?: boolean fallbackLocale?: Locale | null redirectOn?: RedirectOnOptions - useCookie?: boolean + useCookie?: boolean, + httpOnly?: boolean } export type LocaleType = 'static' | 'dynamic' | 'unknown'