在我的带有静态目标的多语言 nuxt 应用程序中,我遇到了与生成的静态页面相关的问题:
需要通过 asyncData 和 ciryllic endocoedURI 生成动态数据的页面,它们可以在最终 dist 中以 2 种方式访问:
http://localhost:3000/bg/%D0%B2%D0%B8%D0%BB%D0%B8-%D1%85%D0%B0%D0%BB%D0%BA%D0%B8%D0% B4%D0%B8%D0%BA%D0%B8 此 URL 回退到 SPA 页面(问题)
http://localhost:3000/bg/%D0%B2%D0%B8%D0%BB%D0%B8-%D1%85%D0%B0%D0%BB%D0%BA%D0%B8%D0% B4%D0%B8%D0%BA%D0%B8/ 这是完整的静态页面
问题是第二个链接末尾的“/”,我不知道为什么会这样。
我在我的项目(最新版本)上使用了 nuxt-i18n 我的组件内部的路径配置如下:
nuxtI18n: {
paths: {
en: encodeURI(`/${process.env.VILLAS_EN}`),
bg: encodeURI(`/${process.env.VILLAS_BG}`),
ru: encodeURI(`/${process.env.VILLAS_RU}`)
}
},
在 .env 文件中,我有这些值:
VILLAS_EN = 'villas'
VILLAS_BG = 'вили-халкидики'
VILLAS_RU = 'халкидики-виллы'
在 nuxt.config.js 内部:
modules: [
'@nuxtjs/axios'
,['nuxt-i18n', {
strategy: 'prefix_except_default',
locales: [
//{ name: 'Italiano', code: 'it', iso: 'it-IT', file: 'it-IT.js' },
{ name: 'Bulgarian', code: 'bg', iso: 'bg-BG', file: 'bg-BG.js' },
{ name: 'Russian', code: 'ru', iso: 'ru-RU', file: 'ru-RU.js' },
{ name: 'English', code: 'en', iso: 'en-US', file: 'en-US.js' },
]
, lazy: true
, langDir: 'locales/'
, defaultLocale: 'en'
//, encodePaths: false
, seo: true
//, parsePages: false
//, pages: i18nConfig.pages
/*
, detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected',
onlyOnRoot: true
}*/
}]
老实说,我不知道如何解决这个问题。我做了一个测试,在所有路径上添加了最后一个斜杠,但它不起作用。在此先感谢您的帮助。
下面是完整的 nuxt.config.js
/*
** Load .env configuration base on profile ( development | staging | production )
*/
/*
** Vuetify local settings
*/
import colors from 'vuetify/es5/util/colors'
import axios from 'axios'
require('dotenv').config()
// import i18nConfig from './i18n.config'
export default {
ssr: true,
target: 'static',
publicRuntimeConfig: {
apiBaseUrl: process.env.API_BASE_URL,
apiBasePath: process.env.API_BASE_PATH,
baseTitle: process.env.BASE_TITLE || 'SiteTitle',
pathVillasEn: 'villas',
pathVillasBg: 'вили-халкидики',
pathVillasRu: 'халкидики-виллы',
sendGridApiKey: process.env.SENDGRID_API_KEY,
recaptcha: {
siteKey: process.env.RECAPTCHA_SITE_KEY,
},
contactFormApi: process.env.CONTACT_FORM_API,
},
/*
** Headers of the page
*/
head: {
// titleTemplate: '%s - ' + process.env.npm_package_name,
// title: process.env.npm_package_name || '',
titleTemplate: '%s - SiteTitle',
title: process.env.BASE_TITLE || '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: process.env.npm_package_description || '' },
{ 'http-equiv': 'X-UA-Compatible', content: 'IE=edge' },
],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
},
/*
** Customize the progress-bar color
*/
loading: { color: '#f00' },
/*
** Plugins to load before mounting the App
*/
plugins: [
'~/plugins/axios',
'~/plugins/helper',
'~/plugins/calculator',
//, '~/plugins/composition-api'
],
/*
** Nuxt.js dev-modules
*/
buildModules: [
['@nuxtjs/dotenv', { filename: '.env.' + process.env.NODE_ENV }],
'@nuxtjs/axios',
['@nuxtjs/vuetify', { treeShake: true }],
['@nuxtjs/google-analytics', { id: process.env.GOOGLE_ANALYTICS }],
],
/*
** Nuxt.js modules
*/
modules: [
'@nuxtjs/axios',
[
'nuxt-i18n',
{
strategy: 'prefix_except_default',
locales: [
{ name: 'Bulgarian', code: 'bg', iso: 'bg-BG', file: 'bg-BG.js' },
{ name: 'Russian', code: 'ru', iso: 'ru-RU', file: 'ru-RU.js' },
{ name: 'English', code: 'en', iso: 'en-US', file: 'en-US.js' },
],
lazy: true,
langDir: 'locales/',
defaultLocale: 'en',
//, encodePaths: false
seo: true,
//, parsePages: false
//, pages: i18nConfig.pages
/*
, detectBrowserLanguage: {
useCookie: true,
cookieKey: 'i18n_redirected',
onlyOnRoot: true
} */
},
],
//, '@nuxtjs/sitemap'
'nuxt-lazy-load',
'@nuxtjs/robots',
[
'@nuxtjs/recaptcha',
{
hideBadge: true,
siteKey: process.env.RECAPTCHA_SITE_KEY,
version: 3,
},
],
//, '@nuxtjs/auth'
//, '@nuxtjs/proxy'
],
/*
** Robots.txt
*/
robots: {
UserAgent: '*',
Disallow: '/',
},
/*
** Purge CSS
*/
purgeCSS: {
whitelistPatterns: [/^v-*/, /^theme-*/, /^application--*/],
whitelistPatternsChildren: [/^v-*/, /^theme-*/, /^application--*/],
whitelist: ['spacer', 'primary', 'secondary', 'accent', 'error', 'warning', 'info', 'success'],
},
/*
** Axios configurations
*/
axios: {
baseURL: `${process.env.API_BASE_URL}${process.env.API_BASE_PATH}`,
https: true,
// //debug: true,
// //proxyHeadersIgnore: ['host', 'accept', 'cf-ray', 'cf-connecting-ip'],
// proxyHeaders: false,
// https:false,
// credentials: false,
// proxy: true
},
/*
** Static HTML generator
*/
generate: {
interval: 100,
crawler: false,
fallback: '404.html',
gzip: true,
async routes() {
const slugs = []
async function postRoutes(type, lang = '') {
const _lang = `/${lang}` || ''
return await axios
.post(`${process.env.API_BASE_URL}${_lang}${process.env.API_BASE_PATH}/post-type-list`, {
postType: type,
})
.then((r) => {
if (r.data.data.type == 'villas') {
r.data.data.items.map((item) => {
let slug = ''
switch (lang) {
case 'bg':
slug = encodeURI(
`${_lang}/${process.env.VILLAS_BG}/${decodeURI(item.slug).toString()}`,
).toString()
break
case 'ru':
slug = encodeURI(
`${_lang}/${process.env.VILLAS_RU}/${decodeURI(item.slug).toString()}`,
).toString()
break
default:
slug = encodeURI(
`/${process.env.VILLAS_EN}/${decodeURI(item.slug).toString()}`,
).toString()
break
}
if (slug !== undefined) slugs.push({ route: slug, payload: item })
})
}
})
}
await axios
.all([postRoutes('villas'), postRoutes('villas', 'bg'), postRoutes('villas', 'ru')])
.then((results) => { })
return slugs
},
},
/*
** Sitemap
*/
sitemap: {
hostname: process.env.API_BASE_URL,
path: '/sitemapindex.xml',
defaults: {
changefreq: 'daily',
priority: 1,
lastmod: new Date(),
},
// notation (basic)
//, i18n: true
// nuxt-i18n notation (advanced)
i18n: {
locales: ['en', 'bg', 'ru'],
routesNameSeparator: '___',
},
},
/*
** vuetify module configuration
** https://github.com/nuxt-community/vuetify-module
*/
vuetify: {
customVariables: ['~/assets/variables.scss'],
treeShake: true,
defaultAssets: false,
icons: {
iconfont: 'mdi',
},
theme: {
dark: false,
themes: {
dark: {
primary: colors.blue.darken2,
accent: colors.grey.darken3,
secondary: colors.amber.darken3,
info: colors.teal.lighten1,
warning: colors.amber.base,
error: colors.deepOrange.accent4,
success: colors.green.accent3,
},
light: {
primary: colors.blue.darken2,
accent: colors.grey.darken3,
secondary: colors.amber.darken3,
info: colors.teal.lighten1,
warning: colors.amber.base,
error: colors.deepOrange.accent4,
success: colors.green.accent3,
},
},
},
},
/*
** Build configuration
*/
build: {
html: {
minify: {
collapseBooleanAttributes: true,
decodeEntities: true,
minifyCSS: true,
minifyJS: true,
processConditionalComments: true,
removeEmptyAttributes: true,
removeRedundantAttributes: true,
trimCustomFragments: true,
useShortDoctype: true,
preserveLineBreaks: false,
collapseWhitespace: true,
},
},
extractCSS: true,
/*
** You can extend webpack config here
*/
extend(config, ctx) {
config.node = {
console: true,
fs: 'empty',
net: 'empty',
tls: 'empty',
}
},
//, analyze: true
},
}