Skip to content
Go back

Directus 开放数据平台(二)多语言模型结构的设计与实现

| 0 Views Edit page

前言

Steam.CASH 导航站在构思初期,多语言支持就是一个重要的需求,因此后续在对 CMS 进行调研的时候,也着重考虑了“是否支持多语言内容”这一点。
最终 StrapiDirectus 进入了决赛圈,但是由于 Strapi 从 v4 到 v5 的破坏性更新让社区颇有不满,于是我选择了 Directus
中文互联网上似乎没有太多关于 Directus 多语言实现的资料,这里就分享一下我的设计思路和实现方法,希望能对有你有所帮助。


关于 Directus 的多语言支持

官方有专门的文档:Translations | Directus Docs
其中介绍了 Directus 支持的两种翻译:

  • Data Studio 界面翻译:指的是翻译 Directus 管理后台的用户界面。
    可以看到在配置中,每个页面上会出现的单词和短语都对应着一个翻译值。
    Data Studio 界面翻译

  • 内容翻译 (Content Translations):翻译数据库中的实际内容,可通过 API 提供给外部应用。
    内容翻译

显然 Directus 本身是支持多语言内容管理的,并且由于我们只把它作为数据管理后台使用,没有用到它的前端(我的前端是使用 Astro 静态站点生成器来构建的),因此只需关注第二种 内容翻译 的实现即可


Directus 的数据结构以及多语言设计

过一下 Directus 基础的数据结构设计概念:

  • Collection(集合):本质就是一张表(或一个数据实体)。需要注意的是分类和语言也算是 Collection
    例如 articles、categories、languages。
  • Field(字段):表里的列。
    比如 articles.title、articles.status、articles.published_at。
  • Item(条目):表里的一行数据。
    一篇文章就是 articles 的一个 item。
  • Relation(关系):表与表的关联,Directus 会帮你生成“可视化的关系字段”和 API 的嵌套读取能力。
    常见 3 类:
    • M2O / O2M(一对多 / 多对一):最常用。比如“文章属于一个分类”(articles → categories 是 M2O)。
    • M2M(多对多):通常会有一张“中间表 / junction”。比如“文章有多个标签、标签也属于多篇文章”。
    • O2O(一对一):例如文章和 SEO 扩展表一对一。

考虑到我的以下需求:

  1. 文章 (articles) 需要支持多语言
  2. 分类 (categories) 需要支持多语言
  3. 标签 (tags) 需要支持多语言
  4. 存在多层级分类
  5. 一篇文章可以属于多个分类

最终,我的数据结构为:

  • languages:语言表(包含 code 字段值为 zh-CNen-US 等,name 字段为语言名称)
  • articles:文章主表(只存储不随语言变化的字段由于我的博文路径是 /<lang>/<slug>,因此 slug 字段也放在这里
  • articles_translations:文章翻译表(随语言变化的字段,如 titlecontent 等)
    • articles_translations.article_id -> articles.id (M2O)
    • articles_translations.language_code -> languages.code (M2O)
  • categories:分类主表(只存储不随语言变化的字段,如 slug
    • categories.parent_id -> categories.id (M2O,自关联,用于多级分类)
  • categories_translations:分类翻译表(namedescription 等)
    • categories_translations.category_id -> categories.id (M2O)
    • categories_translations.language_code -> languages.code (M2O)
  • articles_categories:文章与分类的多对多中间表
    • articles_categories.article_id -> articles.id
    • articles_categories.category_id -> categories.id
  • tags:标签主表(只存储不随语言变化的字段,如 slug
  • tags_translations:标签翻译表(namedescription 等)
    • tags_translations.tag_id -> tags.id (M2O)
    • tags_translations.language_code -> languages.code (M2O)
  • articles_tags:文章与标签的多对多中间表
    • articles_tags.article_id -> articles.id
    • articles_tags.tag_id -> tags.id

约束条件如下:

  • articles_translations(article_id, language_code) 联合唯一(同文章同语言只允许一条翻译)
  • categories_translations(category_id, language_code) 联合唯一
  • tags_translations(tag_id, language_code) 联合唯一
  • articles_categories(article_id, category_id) 联合唯一(避免重复绑定)
  • articles_tags(article_id, tag_id) 联合唯一(避免重复绑定)

操作概述

  1. 创建文章集合 (Collection)
  2. 创建文章翻译集合
  3. 将语言集合关联到文章翻译集合
  4. 创建一篇文章
  5. 添加翻译内容
  6. 通过 API 获取多语言内容

实际步骤

一、创建文章集合 (Collection)

主键 id 修改为使用 UUID:
表名和主键
可选字段全部勾选:
可选字段
添加字段 slug,设置为必须项目:
slug 字段

二、创建文章翻译集合

虽然官方文档中提到可以通过新增翻译字段来自动创建翻译集合,但我这里选择手动创建 test_articles_translations 集合,以便更好地控制字段和关系。

The languages collection will be automatically created when you add your first translations field. It contains each language you support, with a code and direction field (some languages are written right-to-left).

The field will also create a new collection-specific collection for translated content, for example articles_translations. Add fields you wish to translate to this collection, and they will be displayed in the translations interface

一样选择使用 UUID 作为主键,添加字段 titlecontentlanguage_codearticle_id
翻译表字段

三、将语言集合关联到文章翻译集合

编辑 test_articles 文章集合,添加 translations 关系字段,类型选择 M2M,关联到 test_articles_translationsimage.png


Edit page