# Vue I18n 动态渲染问题：v-for 与复杂数据结构

URL: https://caijiao.org/posts/18
Source: docs/posts/18.md
Description: 本文探讨了在使用 Vue I18n 时，如何通过 v-for 正确渲染翻译文件中的复杂数据结构，提供了结构调整和最佳实践解决方案。

在使用 Vue I18n 时，许多开发者遇到一个常见问题：如何通过 `v-for` 循环动态渲染翻译文件中的内容，特别是当翻译文件中包含复杂的数组或对象时。Vue I18n 主要设计用于翻译字符串，因此当尝试直接迭代翻译文件中的数据结构时，会出现无法渲染的情况。本文将探讨这个问题，并提供解决方案。

## 问题说明

### Vue I18n 如何工作

Vue I18n 的 `t()` 方法是为字符串翻译设计的。它不会返回复杂的数据结构（如数组或对象），而是期望返回单一的翻译文本。因此，当你尝试直接使用 `t()` 来获取一个数组或对象时，它会返回一个字符串，而不是数组或对象本身，这就导致无法通过 `v-for` 渲染。

### 示例：错误的做法

考虑以下翻译文件和组件代码：

#### 1. 翻译文件（JSON 格式）

```json
{
  "faq": {
    "title": "常见问题",
    "list": [
      { "question": "q1", "answer": "a1" },
      { "question": "q2", "answer": "a2" }
    ]
  }
}
````

#### 2. 错误的 `v-for` 使用方法

在模板中使用 `v-for` 循环渲染 `faq.list` 时，试图直接迭代翻译文件中的数组：

```vue
<div v-for="(item,index) in t('faq.list')" :key="index">
  <p>{{ t(item.question) }}</p>
  <p>{{ t(item.answer) }}</p>
</div>
```

这种做法会导致问题，因为 `t('faq.list')` 返回的是字符串，而不是一个可以迭代的数组或对象。因此，无法正确渲染 `question` 和 `answer`。

## 解决方案

为了正确渲染翻译文件中的复杂结构，最佳做法是将翻译文件中的数组或对象结构调整为键值对，并通过 `t()` 获取具体翻译内容。这里我们提供两种方法来解决该问题。

### 方法 1：使用对象而非数组

将 `faq.list` 从数组转换为对象，使用唯一的键来标识每一项。这样，`v-for` 可以按需迭代。

#### 1. 调整翻译文件结构

将 `list` 从数组改为对象：

```json
{
  "faq": {
    "title": "常见问题",
    "list": {
      "1": { "question": "q1", "answer": "a1" },
      "2": { "question": "q2", "answer": "a2" }
    }
  }
}
```

#### 2. 模板中使用动态键值渲染

通过 `v-for` 循环迭代 `faq.list` 中的对象，动态访问每一项：

```vue
<div v-for="i in 2" :key="i">
  <h5 class="text-dark">{{ t(`faq.list.${i}.question`) }}</h5>
  <p class="text-muted" v-html="t(`faq.list.${i}.answer`)"></p>
</div>
```

这种方式通过动态生成的索引 `i`，直接访问翻译文件中的每一项，正确渲染 `faq.list` 中的每个问题和答案。

## 总结

1. **结构调整：** 将翻译数据结构进行适当调整，避免在翻译文件中使用数组。可以使用对象并通过键值访问。
2. **翻译函数使用：** 使用 `t()` 函数来翻译每个具体的字段，而不是试图直接迭代复杂的对象或数组。
3. **推荐实践：** 在翻译文件中使用键值对，以便通过 `v-for` 和 `t()` 结合使用，确保内容能正确渲染。
