diff --git a/pages/blog/[...slug].vue b/pages/blog/[...slug].vue
index 454f5fb..cb3f5e2 100644
--- a/pages/blog/[...slug].vue
+++ b/pages/blog/[...slug].vue
@@ -118,7 +118,9 @@ const currentLocale = ref(locale.value)
// Get the slug from the route
const slug = route.params.slug
-const articlePath = `/${Array.isArray(slug) ? slug.join('/') : slug}`
+const base = `/${Array.isArray(slug) ? slug.join('/') : slug}`
+// Our list links to /blog/{locale}/{slug}, remove /blog prefix to query content file
+const articlePath = base.replace(/^\/blog(?=\/)/, '')
// Fetch the article
const { data: article, pending, error } = await useAsyncData(`article-${articlePath}`, async () => {
@@ -140,9 +142,7 @@ useSeoMeta({
twitterCard: 'summary_large_image'
})
-const availableLocales = computed(() =>
- locales.value.filter(locale => locale.code !== 'en' || locale.code === currentLocale.value)
-)
+const availableLocales = computed(() => locales.value)
const formatDate = (date) => {
return new Date(date).toLocaleDateString('en-US', {
@@ -156,9 +156,10 @@ const switchToTranslation = async (targetLocale) => {
if (targetLocale === currentLocale.value) return
try {
- const translated = await queryContent(`/${targetLocale}${articlePath}`).findOne()
+ const base = articlePath.replace(/^\/(en|zh|zh-hant)/,'')
+ const translated = await queryContent(`/${targetLocale}${base}`).findOne()
if (translated?._path) {
- await navigateTo(translated._path)
+ await navigateTo(`/blog${translated._path}`)
return
}
throw new Error('Not found')
diff --git a/pages/blog/index.vue b/pages/blog/index.vue
index 3b4586d..ef5e5ce 100644
--- a/pages/blog/index.vue
+++ b/pages/blog/index.vue
@@ -47,7 +47,7 @@
-
+
{{ article.title }}
@@ -58,7 +58,7 @@
{{ $t('blog.readMore') }}
@@ -107,11 +107,11 @@ useSeoMeta({
const { locales } = useI18n()
const currentLocale = ref(locale.value)
-// Fetch blog articles
-const { data: articles, pending, error } = await useAsyncData('blog-articles', async () => {
+// Fetch blog articles (filter by current _locale provided by @nuxt/content)
+const { data: articles, pending, error } = await useAsyncData(() => `blog-${locale.value}`, async () => {
try {
- return await queryContent(`/${locale.value}`)
- .where({ _type: 'markdown' })
+ return await queryContent()
+ .where({ _locale: locale.value })
.sort({ date: -1 })
.find()
} catch (err) {
@@ -119,6 +119,15 @@ const { data: articles, pending, error } = await useAsyncData('blog-articles', a
return []
}
})
+// Build localized link for article
+const articleLink = (a) => {
+ if (!a || !a._path) return '/blog'
+ const hasLocale = /^\/(en|zh|zh-hant)(\/|$)/.test(a._path)
+ const localized = hasLocale
+ ? a._path
+ : (locale.value === 'en' ? a._path : `/${locale.value}${a._path}`)
+ return `/blog${localized}`
+}
const availableLocales = computed(() =>
locales.value.filter(locale => locale.code !== 'en' || locale.code === currentLocale.value)
@@ -136,9 +145,10 @@ const switchToTranslation = async (article, targetLocale) => {
if (targetLocale === currentLocale.value) return
try {
- const translated = await queryContent(`/${targetLocale}${article._path}`).findOne()
+ const basePath = article._path.replace(/^\/(en|zh|zh-hant)/, '')
+ const translated = await queryContent(`/${targetLocale}${basePath}`).findOne()
if (translated?._path) {
- await navigateTo(translated._path)
+ await navigateTo(`/blog${translated._path}`)
return
}
throw new Error('Not found')
diff --git a/pages/contact.vue b/pages/contact.vue
index 3b5ce46..67158bf 100644
--- a/pages/contact.vue
+++ b/pages/contact.vue
@@ -209,11 +209,18 @@ const submitForm = async () => {
throw new Error('invalid_email')
}
const fd = new FormData()
+ // 更友好的字段标签(供邮件展示)
+ fd.append('🧑 姓名', form.value.name)
+ fd.append('✉️ 邮箱', form.value.email)
+ fd.append('🧩 主题', form.value.subject)
+ fd.append('💬 消息', form.value.message)
+ // 兼容性保留原始字段(便于自动解析和统计)
fd.append('name', form.value.name)
fd.append('email', form.value.email)
fd.append('subject', form.value.subject)
fd.append('message', form.value.message)
- fd.append('_subject', `Website Contact: ${form.value.subject}`)
+ // 自定义邮件主题/语言/回复地址
+ fd.append('_subject', `📨 ${t('contact.title')} | ${form.value.subject}`)
fd.append('_language', locale.value)
fd.append('_replyto', form.value.email)
diff --git a/pages/index.vue b/pages/index.vue
index fa651df..1da2513 100644
--- a/pages/index.vue
+++ b/pages/index.vue
@@ -46,6 +46,33 @@
+
+
+
+
+
+
加载中...
+
+
+
+
+
{{ a.title || 'Untitled' }}
+
+ {{ a.description || '' }}
+ {{ a.date ? new Date(a.date).toLocaleDateString() : '' }}
+
+
+
+
+
@@ -129,6 +156,27 @@ useSeoMeta({
description: () => t('seo.home.description')
})
+// Latest articles (from @nuxt/content) filtered by _locale
+const { data: articles, pending } = await useAsyncData(() => `home-articles-${locale.value}`,
+ async () => {
+ try {
+ return await queryContent()
+ .where({ _locale: locale.value })
+ .sort({ date: -1 })
+ .limit(3)
+ .find()
+ } catch (err) {
+ console.error('Error fetching home articles:', err)
+ return []
+ }
+ }
+)
+
+const articleLink = (a) => {
+ if (!a || !a._path) return '/blog'
+ return `/blog${a._path}`
+}
+
// Services data
const services = computed(() => [
{