最近在写 Nuxt3 的多语言 SEO 元信息工具函数 useSeoMetaForPage() 时,遇到了一个让人非常迷惑的问题:报错指向 useHead(),却无论如何也想不通它为什么不能在组件外使用

我把代码贴给 GPT 分析,它也说“useHead 不能在 setup 外使用”。但我总觉得哪里不对劲——useHead() 是可以在组件外用的啊,Nuxt 官方也给出明确说明。

所以我开始自己动手调试,最终找到了真正的报错源头。

💥 表象:useHead 报错,setup 限制?

出错代码如下:

1
2
3
4
5
6
const { t } = useI18n({ useScope: 'global' }) // ❌ 报错源头
...
useHead({
title: t('meta.global.title'),
...
})

🧠 真相:罪魁祸首是 useI18n()

调试中我发现,真正的报错点是 useI18n()。它只能在组件内调用,不能在 setup() 外或普通函数里调用,而我却把它放进了工具函数内部,组件上下文早已丢失,导致报错。

于是我尝试把 const { t } = useI18n() 移出函数,放在模块顶层,希望复用……结果更严重,模块加载阶段就直接崩了

一番寻找后,我找到了官方推荐的写法:

1
const title = useNuxtApp().$i18n.t('meta.global.title')

这样就不需要上下文了,可以在任何地方调用,成功绕过 setup() 限制。

⏳ 第二个问题:懒加载语言文件未准备好

我的 Nuxt 配置中使用了 lazy: true

1
2
3
4
5
6
7
8
i18n: {
lazy: true,
langDir: 'locales',
locales: [
{ code: 'zh', file: 'zh.json' },
{ code: 'en', file: 'en.json' },
],
}

这意味着语言文件是异步加载的,如果直接调用 t('...'),可能会返回空字符串或触发 undefined 问题。

✅ 终极解决方案

于是我写了一个异步函数 updateSeoMetaWithLocale,用来切换语言、加载语言包,然后再刷新 meta 信息:

1
2
3
4
5
export async function updateSeoMetaWithLocale(locale: 'zh' | 'en') {
await useNuxtApp().$i18n.loadLocaleMessages(locale)
await nextTick()
useSeoMetaForPage()
}

这样确保语言文件已经加载完成,再调用 useHead() 设置 meta 信息才是安全的。

✍️ 小结

现象 误判 真相
useHead() 报错 以为 setup 限制 实际是 useI18n 注入失败
useI18n() 在组件外使用 ❌ 报错 ✅ 改用 useNuxtApp().$i18n
多语言翻译无效 以为失效 ✅ 懒加载未完成,需等待加载