• 亮色
  • 深色
  • 自动
  • RSS 订阅

    为 Nuxt 3 项目配置 lazy i18n

    2024-06-15

    开始一个 Nuxt 3 项目

    首先,启动一个 Nuxt 项目:

    pnpm dlx nuxi@latest init nuxt3-lazy-i18n-demo
    cd nuxt3-lazy-i18n-demo
    pnpm install
    pnpm run dev
    

    添加 nuxt/i18n 模块

    然后将 nuxt/i18n 模块添加到项目中:

    pnpm dlx nuxi@latest module add i18n
    

    执行完毕后,打开 nuxt.config.ts 文件,确保 "@nuxtjs/i18n" 添加到 modules 中(如果没有的话就手动添加),如下图所示:

    示例

    本地化语言

    添加本地化语言

    新建一个 lang 目录,也可以是其他的,用来存放需要支持的语言。其中的文件名便是想要支持的语言,假设要支持中文,可以创建一个 zh.js 或者 zh.ts 文件。

    mkdir lang
    touch lang/zh.js
    

    Tip

    其实文件名可以随意命名,但是为了更好地开发以及后期维护,建议以 bcp47 标准的命名。例如中文为 zh-CNzh-cnzh 这样。

    然后在刚刚新建的 zh.js(或者 zh.ts) 文件里添加一个默认导出:

    export default defineI18nLocale(() => {
      return {}
    })
    

    然后回到 nuxt.config.ts 文件,添加 zh.js,看起来下面这样:

    // https://nuxt.com/docs/api/configuration/nuxt-config
    export default defineNuxtConfig({
      devtools: { enabled: true },
      modules: ['@nuxtjs/i18n'],
    
      i18n: {
        lazy: true,
        // langDir 的值是刚刚创建 lang 文件夹名称
        langDir: 'lang',
    
        // // 因为默认会去读取浏览器语言,所以如果你的浏览器语言不是 zh,
        // // 那么你可能需要添加下面这一行才能在当前浏览器看到效果
        // defaultLocale: 'zh',
    
        locales: [
          // zh.js 是 lang 目录下的 zh.js 文件
          { code: 'zh', file: 'zh.js', name: '中文' },
        ],
      },
    })
    

    本地化语言内容

    添加本地化语言内容

    需要注意的是,目前 nuxt/i18n 会把 nuxt.config.tsi18n 配置里 locales 选项中没有指定的文件转换到 langDir 选项中指定的目录内。参考:https://github.com/nuxt-modules/i18n/issues/2145

    因此如果要在 lang 目录下定义语言内容,在 zh.js 中导入这些语言内容的话,是行不通的。为此,需要将语言内容的文件放在其他地方,不能放在 langDir 选项指定的目录里。

    这里可以新建一个 locales 目录,将语言内容放在这个目录下。这里假设 zh 语言有很多内容,以至于我们想要将它们拆分到不同文件中:

    mkdir locales
    mkdir locales/zh
    touch locales/zh/hello.json
    

    然后编辑 locales/zh/hello.json 文件,在其中添加如下内容(仅作为示例):

    { "message": "你好" }
    

    导入本地化语言内容

    然后编辑 lang/zh.js 文件,修改为如下内容:

    import hello from '~/locales/zh/hello.json'
    
    export default defineI18nLocale(() => {
      return { hello }
    })
    

    使用本地化语言内容

    这里为了方便演示,可以在 app.vuetemplate 块里添加:

    <template>
      <div>{{ $t('hello.message') }}</div>
    </template>
    

    然后访问界面 http://localhost:3000,可以看到如下界面:

    成功示例

    VSCode 配置

    VSCode 可以安装 lokalise.i18n-ally 扩展来达到更好的开发体验。

    安装完成扩展后,在项目下新建 .vscode/settings.json 文件:

    mkdir .vscode
    touch .vscode/settings.json
    

    .vscode/settings.json 文件中添加如下内容:

    {
      "i18n-ally.namespace": true,
      "i18n-ally.localesPaths": ["locales"],
      "i18n-ally.pathMatcher": "{locale}/{namespaces}.json",
    
      "i18n-ally.keystyle": "nested",
      "i18n-ally.keepFulfilled": true
    }
    

    主要是前三行配置:

    1. 第一行是表示启用命名空间
    2. 第二行是本地化语言内容的存放路径,是一个相对路径
    3. 第三行是本地化语言内容匹配器,这里使用本地化语言标签加命名空间匹配器,所以第一行需要启用命名空间

    添加完成后,扩展会去读取 locales 目录下的本地化语言标签(使用 bcp47 标准进行匹配)里的本地化语言内容,且以命名空间的形式去解析。

    已经知道我们的 locales/ 目录下有个 zh 语言,且该语言内有个 hello.json 文件,文件里有个 message 本地化信息。

    Info

    message 叫本地化信息不知道合不合适,vue i18n 文档是英文的,中文语境下也不知道有什么好的形容词。

    此时就相当于 hello 这个命名空间里有个 message 本地化信息,即 hello.message 是能够被扩展正确识别的。

    如果有个 locales/zh/form/label/item.json 文件,且此文件有个 id 本地化信息内容是 项编号,那么就相当于有一个 form.label.item.id 本地化信息。

    但是需要注意这只是扩展的行为,如果要让 Nuxt 中有相同的行为,需要在 lang/zh.js 中以相同的方式导入 locales/zh/form/label/item.json 才行,例如:

    import hello from '~/locales/zh/hello.json'
    import item from '~/locales/zh/form/label/item.json'
    
    export default defineI18nLocale(() => {
      return { hello, form: { label: { item } } }
    })
    

    此时可以在 template 里通过 {{ $t('form.label.item.id') }} 使用。

    可以通过 VSCode 窗口在右下角来选择要在 VSCode 里直接显示的本地化信息内容:

    显示本地化信息

    其他

    如果不生效的话,可以看看目前可以使用的本地化信息有哪些,可以在 app.vuescript setup 里使用下面这个来查看:

    const i18n = useI18n()
    
    console.log(i18n.messages.value)
    

    最近睡眠质量不太好,所以可能写得有些混乱。也可以直接看 github 上的仓库:https://github.com/nafnix/nuxt-app

    参考