# 单文件组件

# 基本用法

如果使用单文件组件构建 Vue 组件或 Vue 应用程序,则可以管理 i18n 自定义块的语言环境信息。

以下是单文件组件示例 (opens new window):

<i18n>
{
  "en": {
    "hello": "hello world!"
  },
  "ja": {
    "hello": "こんにちは、世界!"
  }
}
</i18n>

<template>
  <div id="app">
    <label for="locale">locale</label>
    <select v-model="locale">
      <option>en</option>
      <option>ja</option>
    </select>
    <p>message: {{ $t('hello') }}</p>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () { return { locale: 'en' } },
  watch: {
    locale (val) {
      this.$i18n.locale = val
    }
  }
}
</script>

# 安装 vue-i18n-loader

为了使用 <i18n> 自定义块,你需要安装 vue-loadervue-i18n-loader。如果你使用了单文件组件,vue-loader (opens new window) 很可能已在项目中使用了,那么 vue-i18n-loader (opens new window) 必须另外安装:

npm i --save-dev @kazupon/vue-i18n-loader

# Webpack

需要对 Webpack 进行以下配置:

对于 vue-loader v15 或更高版本:

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
      },
      {
        resourceQuery: /blockType=i18n/,
        type: 'javascript/auto',
        loader: '@kazupon/vue-i18n-loader'
      }
      // ...
    ]
  },
  // ...
}

对于 vue-loader v14:

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            // 你需要指定 `i18n` 的值为 `vue-i18n-loader`
            i18n: '@kazupon/vue-i18n-loader'
          }
        }
      },
      // ...
    ]
  },
  // ...
}

# Vue CLI 3.0

Vue CLI 3.0 (opens new window) 隐藏了 webpack 配置,因此,如果我们想在单文件组件中添加对 <i18n> 标记的支持,我们需要修改现有配置。

为此,我们必须在项目的根目录下创建一个 vue.config.js。完成后,我们必须包括以下内容:

对于 vue-loader v15 或更高版本:

module.exports = {
  chainWebpack: config => {
    config.module
      .rule("i18n")
      .resourceQuery(/blockType=i18n/)
      .type('javascript/auto')
      .use("i18n")
        .loader("@kazupon/vue-i18n-loader")
        .end();
  }
}

对于 vue-loader v14:

const merge = require('deepmerge')

module.exports = {
  chainWebpack: config => {
    config.module
      .rule('vue')
      .use('vue-loader')
      .tap(options =>
        merge(options, {
          loaders: {
            i18n: '@kazupon/vue-i18n-loader'
          }
        })
      )
  }
}

别忘了安装deepmerge (opens new window)! (npm i deepmerge -Dyarn add deepmerge -D)

如果你想了解有关修改现有配置的更多信息点击这里 (opens new window)

# Laravel-Mix

对于带有 vue-loader v15 或更高版本的 Laravel-mix 4:

// 使用 “i18n” 方法扩展 Mix ,加载 vue-i18n-loader
mix.extend( 'i18n', new class {
        webpackRules() {
            return [
                {
                    resourceQuery: /blockType=i18n/,
                    type:          'javascript/auto',
                    loader:        '@kazupon/vue-i18n-loader',
                },
            ];
        }
    }(),
);

// 确保在 `.js(..., ...)` 之前调用 `.i18n()` (来加载加载器)
mix.i18n()
   .js( 'resources/js/App.js', 'public/js/app.js' )
   ...

对于带有 vue-loader v14 的 Laravel-mix 2:

从 Laravel-mix 的 V2.1 (opens new window) 开始,你可以通过 mix.extend() 添加自定义规则。Laravel mix 已经有了处理 .vue 文件的规则。要添加 vue-i18n-loader,请将以下内容添加到 webpack.mix.js

// 下面的代码将注入 i18n Kazupon/vue-18-loader 作为 .vue 文件的加载器。
mix.extend( 'i18n', function( webpackConfig, ...args ) {
    webpackConfig.module.rules.forEach( ( module ) => {
        // 搜索处理 .vue 文件的 “vue-loader” 组件。
        if( module.loader !== 'vue-loader' ) {
            return;
        }

        // 在此模块中,为 i18n 标记添加 vue-i18n-loader。
        module.options.loaders.i18n = '@kazupon/vue-i18n-loader';
    } );
} );

// 确保在 `.js(...,...)` 之前调用 `.i18n()`
mix.i18n()
   .js( 'resources/assets/js/App.js', 'public/js/app.js' )
   ...

# 加载 YAML

i18n 自定义块需要指定为 JSON 格式,你也可以通过使用 vue-loader 预加载器功能来使用 YAML 格式。

以下是 YAML 格式的 i18n 自定义块:

<i18n>
en:
  hello: "hello world!"
ja:
  hello: "こんにちは、世界!"
</i18n>

Webpack 配置如下:

对于 vue-loader v15 或更高版本:

// Vue CLI 3.0
module.exports = {
  chainWebpack: config => {
    config.module
      .rule("i18n")
      .resourceQuery(/blockType=i18n/)
      .type('javascript/auto')
      .use("i18n")
        .loader("@kazupon/vue-i18n-loader")
        .end()
      .use('yaml')
        .loader('yaml-loader')
        .end()
  }
}

对于 vue-loader v14:

module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          preLoaders: {
            i18n: 'yaml-loader'
          },
          loaders: {
            i18n: '@kazupon/vue-i18n-loader'
          }
        }
      },
      // ...
    ]
  },
  // ...
}

# 多个自定义块

你可以使用具有多个 i18n 自定义块的语言环境信息。

<i18n src="./common/locales.json"></i18n>
<i18n>
  {
    "en": {
      "hello": "hello world!"
    },
    "ja": {
      "hello": "こんにちは、世界!"
    }
  }
</i18n>

如上所见,第一个自定义块使用 src 特性加载常用的语言环境信息,第二个自定义块加载仅在该单文件组件中定义的语言环境信息。这些语言环境信息将合并为组件的语言环境信息。

这样,多个自定义块在想要用作模块时非常有用。

# Scoped 风格

当使用带有 scoped style vue-i18n 时,重要的是要记住使用深度选择器 (opens new window) 来设置嵌套转换的样式。例如:

翻译仅包含文本(不使用深层选择器)

<i18n>
{
  "en": {
    "hello": "hello world!"
  },
  "ja": {
    "hello": "こんにちは、世界"
  }
}
</i18n>

<template>
  <div class="parent">
    <p>message: {{ $t('hello') }}</p>
  </div>
</template>

<!-- 可行 -->
<style scoped>
  .parent p {
    color: #42b883;
  }
</style>

使用 HTML 元素翻译(必须使用深度选择器)

<i18n>
{
  "en": {
    "hello": "hello<span>world!</span>"
  },
  "ja": {
    "hello": "こんにちは、<span>世界!</span>"
  }
}
</i18n>

<template>
  <div class="parent">
    <p v-html="$t('hello')"></p>
  </div>
</template>

<!-- 不可行-->
<style scoped>
  .parent p {
    color: #42b883;
  }

  .parent p span {
    color: red;
  }
</style>

<!-- 可行 >>> -->
<style scoped>
  .parent p {
    color: #42b883;
  }

  .parent p >>> span {
    color: red;
  }
</style>

<!-- 可行 /deep/ -->
<style scoped>
  .parent p {
    color: #42b883;
  }

  .parent p /deep/ span {
    color: red;
  }
</style>

<!-- 可行 ::v-deep -->
<style scoped>
  .parent p {
    color: #42b883;
  }

  ::v-deep .parent p span {
    color: red;
  }
</style>

# 函数式组件中的自定义块

如果单个文件组件具有使用函数式组件的模板,并且你已经定义了 i18n 自定义块,请注意你无法使用语言环境信息进行本地化。

例如,以下代码无法使用 i18n 自定义块的语言环境信息进行本地化。

<i18n>
{
  "en": {
    "hello": "hello world"
  },
  "ja": {
    "hello": "こんにちは、世界"
  }
}
</i18n>

<template functional>
  <!-- 'hello' 的父实例的语言环境信息 -->
  <p>{{ parent.$t('hello') }}</p>
</template>