国际化

未匹配的标注

@adonisjs/i18n 官方软件包为你的 AdonisJS 应用程序添加了对 国际化和本地化 的支持。

  • 国际化助手允许你对特定值(例如日期、货币和名称)执行语言敏感的格式化。
  • 本地化层允许你存储翻译并在 Edge 模板、验证错误、身份验证异常等中引用它们。

I18n(国际化的简写)包必须单独安装和配置。

# title: 安装
npm i @adonisjs/i18n
# title: 配置
node ace configure @adonisjs/i18n

# CREATE: app/Middleware/DetectUserLocale.ts
# CREATE: ./resources/lang
# CREATE: config/i18n.ts
# UPDATE: .adonisrc.json { providers += "@adonisjs/i18n" }

用法

以下是导入已安装包和格式化值的基本示例。

注意:I18n.locale 方法返回一个特定的 I18n 类的实例语言环境。区域设置代码必须是有效的 ISO 639-1 标准语言代码。

import I18n from '@ioc:Adonis/Addons/I18n'

I18n.locale('en-US').formatDate(new Date())
// 10/8/2021

I18n.locale('fr').formatCurrency(100, { currency: 'EUR' })
// 100,00 €

const luxonDate = DateTime.local().minus({ minutes: 10 })
I18n.locale('pt').formatRelativeTime(luxonDate, 'auto')
// há 10 minutos

你可以使用 formatMessage 方法来格式化存储的翻译。该方法接受消息键作为第一个参数,数据作为第二个参数。

import I18n from '@ioc:Adonis/Addons/I18n'

I18n
  .locale('en-US')
  .formatMessage('messages.greeting', { name: 'Virk' })

详细了解 [格式化翻译 →](https://docs.adonisjs.com/guides/i18n#formatting-translations)


HTTP 请求期间的使用情况

建议在 HTTP 请求期间使用 ctx.i18n 对象。它是当前请求的 I18n 类的孤立实例。

Route.get('/', async ({ i18n }) => {
  return i18n.formatCurrency(100, { currency: 'EUR' })
})

默认情况下,ctx.i18n 的语言环境设置为应用程序默认语言环境。因此,建议使用 DetectUserLocale 中间件来查找用户区域设置并为其余的请求更新它。

配置

配置存储在 config/i18n.ts 文件中。你总能在 GitHub 上找到最新的 config stub

import Application from '@ioc:Adonis/Core/Application'
import { I18nConfig } from '@ioc:Adonis/Addons/I18n'

const i18nConfig: I18nConfig = {
  translationsFormat: 'icu',
  defaultLocale: 'en',

  // 可选的
  supportedLocales: [],
  fallbackLocales: {},

  provideValidatorMessages: true,
  loaders: {
    fs: {
      enabled: true,
      location: Application.resourcesPath('lang'),
    },
  },
}

export default i18nConfig

翻译格式

用于格式化翻译的格式。官方仅支持 ICU 消息格式


defaultLocale

defaultLocale 是应用程序的默认语言。它始终是静态的,不能在运行时更改。当当前用户语言不受支持时,我们会从默认语言环境中查找翻译,并且没有可用的回退。

const i18nConfig: I18nConfig = {
  defaultLocale: 'en'
}

supportedLocales

它是你的应用程序支持的 ISO 639-1 格式语言代码数组。如果此数组中未提及用户语言,我们将使用 defaultLocale 来查找翻译。

你可以选择在配置文件中定义 supportedLocales。否则,我们将从你在 resources/lang 目录中创建的语言目录推断支持的语言环境。

const i18nConfig: I18nConfig = {
  supportedLocales: ['fr', 'en', 'it']
}

fallbackLocales

fallbackLocales 是你的应用程序支持的语言环境及其后备语言环境的键值对。

例如:使用西班牙语作为加泰罗尼亚语的后备语言比使用英语更有意义。因此,你可以自己定义后备语言环境。

注:你定义了回退的语言环境应该是 supportedLocales 数组的一部分。

const i18nConfig: I18nConfig = {
  fallbackLocales: {
    ca: 'es'
  }
}

provideValidatorMessages

启用/禁用通过翻译文件提供验证器消息的支持。当标志设置为 true 时提供消息。

了解有关翻译验证消息 的更多信息。


loaders

loaders 用于从某种存储中加载消息。我们正式发布了 fs 加载器的实现,它从文件系统加载 .json.yaml 文件。

区域匹配

我们允许你为特定区域定义翻译,或使用两位数的语言代码进行通用支持。

例如:如果你将法语的翻译存储在 fr 目录中,那么法语的所有变体都会看到相同的消息。

但是,如果你创建特定于区域的目录,例如 fr-cafr-ch,则将提供来自最佳匹配语言环境的翻译。

区域设置匹配的风格称为内容协商。我们不是寻找精确匹配,而是协商最接近的匹配。

寻找最匹配的语言环境

你应该使用 I18n.getSupportedLocale 方法来找到用户语言的最佳区域设置。

该方法接受一个字符串或一个用户语言数组,并返回你的应用程序支持的匹配语言环境。null 未找到匹配项时返回。

import I18n from '@ioc:Adonis/Addons/I18n'

const userLanguage = 'en-US'
const bestMatch = I18n.getSupportedLocale(userLanguage)

if (bestMatch) {
  I18n.locale(bestMatch).formatMessage()
} else {
  I18n.locale(I18n.defaultLocale).formatMessage()
}

检测用户区域设置

你应该使用存储在 app/Middleware 目录中的 DetectUserLocale 中间件来查找传入 HTTP 请求的语言环境。

默认情况下,中间件使用 Accept-language HTTP 标头来查找用户浏览器的语言。

但是,你可以更改此中间件的实现并使用适合你的用例和应用程序需求的任何策略。请记住以下几点。

  • 确保始终将用户选择的区域设置传递给 I18n.getSupportedLocale(userLocale) 方法,以找到你的应用程序支持的最佳区域设置。
  • 如果找到匹配项,则调用 ctx.i18n.switchLocale(locale) 方法为请求的其余部分切换区域设置。

此外,请确保在 start/kernel.ts 文件中注册中间件。

// 文件名: start/kernel.ts
Server.middleware.register([
  // ... 其他中间件
  () => import('App/Middleware/DetectUserLocale')
])

查看此 示例项目,它使用应用程序内语言切换器和会话来管理用户首选语言。

翻译存储

fs (默认)加载器在 resources/lang 目录中查找翻译。你必须为应用程序支持的每个语言环境创建一个子目录。例如:

注:语言目录必须以有效的 ISO 639-1 语言代码命名

resources/lang
├── en
└── fr

加载器将读取所有 .json.yaml 文件。此外,你可以随意在语言目录中创建多个子目录或文件。

resources/lang
├── en
│   ├── emails.yaml
│   └── validator.json
└── fr
    └── validator.json
// 文件名: resources/lang/fr/validator.json
{
  "shared": {
    "required": "Ce champ est requis"
  }
}
# 文件名: resources/lang/en/emails.yaml
welcome:
  content: >-
    <h2> Welcome to AdonisJS </h2>
    <p> Click <a href="{ url }"> here </a> to verify your account </p>

格式化翻译

icu 格式化程序允许你使用 ICU 消息格式 编写翻译。它是一种用于编写翻译的行业标准格式,并受到 Crowdin 和 Lokalise 等许多翻译服务的支持。

en/messages.json 文件中给出以下消息。

// 文件名: resources/lang/en/messages.json
{
  "title": "A fully featured web framework for Node.js."
}

你可以按如下方式渲染它。

import I18n from '@ioc:Adonis/Addons/I18n'
I18n.locale('en').formatMessage('messages.title')

并使用 t 辅助方法在模板中渲染它。

<h1> {{ t('messages.title') }} </h1>

插值

ICU 消息语法使用单个花括号来引用动态值。例如:

注:ICU 消息语法不支持嵌套数据集,因此你只能在插值期间访问平面对象的属性。

{
  "greeting": "Hello { username }"
}
{{ t('messages.greeting', { username: 'Virk' }) }}

你还可以在消息中编写 HTML。但是,请确保在 Edge 模板中使用三个 花括号 来呈现 HTML 而不会转义它。

数字格式

你可以使用 {key, type, format} 语法来格式化翻译消息中的数值。在以下示例中:

{
  "bagel_price": "The price of this bagel is {amount, number, ::currency/USD}"
}
{{ t('bagel_price', { amount: 2.49 }) }}
The price of this bagel is $2.49

以下是使用具有不同格式样式和数字骨架的 number 格式的一些示例。

Length of the pole: {price, number, ::measure-unit/length-meter}
Account balance: {price, number, ::currency/USD compact-long}

日期/时间格式

你可以使用 {key, type, format} 语法格式化 Date 实例或 luxon DateTime 实例。在以下示例中:

  • expectedDate 是运行时值。
  • date 是格式化类型。
  • medium 是日期格式。
{
  "shipment_update": "Your package will arrive on {expectedDate, date, medium}"
}
{{ t('shipment_update', { expectedDate: luxonDateTime }) }}
Your package will arrive on Oct 16, 2021

同样,你可以使用时间格式来格式化当前语言环境的时间。

{
  "appointment": "You have an appointment today at {appointmentAt, time, ::h:m a}"
}
You have an appointment today at 2:48 PM

可用的日期/时间框架

ICU 提供了大量的模式来自定义日期时间格式。但是,并非所有这些都可以通过 ECMA402 的 Intl API 获得。因此,我们仅支持以下模式。

符号 描述
G 时代代号
y
M
L 一年中的独立月份
d
E 星期几
e 不支持本地星期 e..eee
c 不支持独立的本地星期 c..ccc
a 上午/下午标记
h 小时 [1-12]
H 小时 [0-23]
K 小时 [0-11]
k 小时 [1-24]
m 分钟
s
z 时区

复数规则

ICU 消息语法对在消息中定义复数规则具有一流的支持。例如:

注:
在以下示例中,我们使用 YAML 而不是 JSON,因为在 YAML 中编写多行文本更容易。

cart_summary:
  "You have {itemsCount, plural,
    =0 {no items}
    one {1 item}
    other {# items}
  } in your cart"
{{ t('messages.cart_summary', { itemsCount: 1 }) }}
You have 1 item in your cart.

# 是一个特殊的标记,用作数值的占位符。它将被格式化为 {key, number}

{{ t('messages.cart_summary', { itemsCount: 1000 }) }}

<!-- Output -->
<!-- You have 1,000 items in your cart -->

可用的复数类别

复数规则使用 {key,plural,matches} 语法。matches 是一个字面值,并匹配以下复数类别之一。

类别 描述
zero 此类别用于具有专门针对零个项目的语法的语言。 (例如阿拉伯语和拉脱维亚语)
one 此类别用于语法明确专门用于一项的语言。许多语言,但不是全部,都使用这个复数类别。 (许多流行的亚洲语言,如中文和日文,不使用此类别。)
two 此类别用于具有明确专门用于两个项目的语法的语言。 (例如阿拉伯语和威尔士语。)
few 此类别用于语法明确专门用于少量项目的语言。对于某些语言,这用于 2-4 项,用于某些 3-10 项,而其他语言则有更复杂的规则。
many 此类别用于对大量项目具有专门语法的语言。 (例如阿拉伯语、波兰语和俄语。)
other 如果值与其他复数类别之一不匹配,则使用此类别。请注意,这用于具有简单“单数”与“复数”二分法的语言(例如英语)的“复数”。
=value 这用于匹配特定值,而与当前语言环境的多个类别无关。

注:表格内容引用自formatjs.io

Select

select 格式允许你通过将值与众多选项之一进行匹配来选择输出。编写特定性别的文本是 select 格式的一个很好的例子。

# title: Yaml
auto_reply:
  "{gender, select,
    male {He}
    female {She}
    other {They}
  } will respond shortly."
{{ t('messages.auto_reply', { gender: 'female' }) }}
She will respond shortly.

选择序数

select ordinal 格式允许你根据序数复数规则选择输出。该格式类似于 plural格式。但是,该值映射到序数复数类别。

anniversary_greeting:
  "It's my {years, selectordinal,
    one {#st}
    two {#nd}
    few {#rd}
    other {#th}
  } anniversary"
{{ t('messages.anniversary_greeting', { years: 2 }) }}
It's my 2nd anniversary

可用的选择序数类别

选择序数格式使用 {key, selectordinal, matches} 语法。匹配是文字值,并与以下复数类别之一匹配。

类别 描述
zero 此类别用于具有专门针对零个项目的语法的语言。 (例如阿拉伯语和拉脱维亚语。)
one 此类别用于语法明确专门用于一项的语言。许多语言,但不是全部,都使用这个复数类别。 (许多流行的亚洲语言,如中文和日文,不使用此类别。)
two 此类别用于具有明确专门用于两个项目的语法的语言。 (例如阿拉伯语和威尔士语。)
few 此类别用于语法明确专门用于少量项目的语言。对于某些语言,这用于 2-4 项,用于某些 3-10 项,而其他语言则有更复杂的规则。
many 此类别用于具有大量项目的专门语法的语言。 (例如阿拉伯语、波兰语和俄语。)
other 如果值与其他复数类别之一不匹配,则使用此类别。请注意,这用于具有简单“单数”与“复数”二分法的语言(例如英语)的“复数”。
=value 这用于匹配特定值,而与当前语言环境的多个类别无关。

表格:表格内容引用自 formatjs.io

国际格式化程序

Intl 格式化程序是 Node.js Intl API 的薄包装器。创建 Intl 类的新实例很慢,因此我们记住构造函数以加快速度。 查看基准

formatNumber

formatNumber 使用 Intl.NumberFormat 类来格式化数值。

  • 第一个参数是要格式化的值。它必须是数字、bigint 或数字的字符串表示形式。

  • 第二个参数是选项。它们与 Intl.NumberFormat 类接受的选项相同。

import I18n from '@ioc:Adonis/Addons/I18n'

I18n
  .locale('en')
  .formatNumber(123456.789, {
    maximumSignificantDigits: 3
  })

formatCurrency

formatCurrency 方法使用 Intl.NumberFormat 类,但将 style 隐式设置为货币。

import I18n from '@ioc:Adonis/Addons/I18n'

I18n
  .locale('en')
  .formatCurrency(200, {
    currency: 'USD'
  })

formatDate

formatDate 方法使用 Intl.DateTimeFormat 类来格式化一个日期。

  • 第一个参数是要格式化的日期。它可以是 ISO 日期字符串timestamp、JavaScriptDate 类的实例或 luxonDateTime

  • 第二个参数是选项。它们与 Intl.DateTimeFormat 类接受的选项相同。

import I18n from '@ioc:Adonis/Addons/I18n'

I18n
  .locale('en')
  .formatDate(new Date(), {
    dateStyle: 'long'
  })

formatTime

formatTime 方法使用 Intl.DateTimeFormat 类,但将 timeStyle 隐式设置为 medium。

import I18n from '@ioc:Adonis/Addons/I18n'

I18n
  .locale('en')
  .formatTime(new Date(), {
    timeStyle: 'long'
  })

formatRelativeTime

formatRelativeTime 方法使用 Intl.RelativeTimeFormat 类来格式化相对时间表示字符串的值。

  • 第一个参数是相对时间的值。它可以是 ISO 日期字符串、绝对数字差异、JavaScript Date 类的实例或 luxon DateTime 的实例。

  • 第二个参数是格式化单位。除了官方支持的单位,我们还支持一个额外的 auto 单位。

  • 第三个参数是选项。它们与 Intl.RelativeTimeFormat 类接受的选项相同。

import { DateTime } from 'luxon'
import I18n from '@ioc:Adonis/Addons/I18n'

const luxonDate = DateTime.local().plus({ hours: 2 })
I18n
  .locale('en')
  .formatRelativeTime(luxonDate, 'hours')

当使用格式化单位设置为 auto 时,我们会找到最佳单位。例如:

const luxonDate = DateTime.local().plus({ hours: 2 })
I18n
  .locale('en')
  .formatRelativeTime(luxonDate, 'auto')

// In 2 hours 👈
const luxonDate = DateTime.local().plus({ hours: 200 })
I18n
  .locale('en')
  .formatRelativeTime(luxonDate, 'auto')

// In 8 days 👈

formatPlural

formatPlural 方法使用 Intl.PluralRules 并返回一个给定数值的复数类别。

  • 第一个参数是值。它必须是数字或数字的字符串表示形式。

  • 第二个参数是选项。它们与 Intl.PluralRules 类接受的选项相同。

import I18n from '@ioc:Adonis/Addons/I18n'

I18n.locale('en').formatPlural(0)
// 其他

I18n.locale('en').formatPlural(1)
// one

I18n.locale('en').formatPlural(2)
// 其他

验证器消息

以下是配置 i18n 包以提供来自翻译文件的验证消息的步骤。

  1. 在配置文件中设置 provideValidatorMessages = true 的值。
  2. 在每个语言目录中创建一个 validator.json 文件。
  3. shared 对象内的验证规则定义消息。
// 文件名: resources/lang/en/validator.json
{
  "shared": {
    "required": "The value for the field is required",
    "unique": "Email is already in use",
    "minLength": "The field must have { minLength } items"
  }
}

shared 键中的消息会自动提供给验证器。你还可以具体并为 field + rule 组合定义消息。例如:

{
  "shared": {
    "required": "The value for the field is required",
    "username.required": "Username is required to create an account"
  }
}

自定义消息包

如果你的应用程序的某些部分需要特定的验证消息,你可以在 validator.json 文件中的不同顶级键下定义它们,然后使用 i18n.validatorMessages() 方法。

// 文件名: resources/lang/en/validator.json
{
  "shared": {},
  "contact": {
    "email.required": "Enter the email so that we can contact you",
    "message.required": "Describe your project in a few words."
  }
}

现在,你可以在验证器上引用来自 contact 对象的消息,如下所示。

import { schema } from '@ioc:Adonis/Core/Validator'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class ContactValidator {
  constructor(protected ctx: HttpContextContract) {}

  public schema = schema.create({})

  public messages = this.ctx.i18n.validatorMessages('validator.contact')
}

验证消息

你还可以为 auth 包引发的异常提供翻译。翻译必须在 auth.json 文件中使用异常代码作为翻译键来定义。

备注:
翻译用于响应文本,而不是 error.message 属性。它们仍然是英文和硬编码的。

{
  "E_INVALID_AUTH_SESSION": "Your session has expired",
  "E_INVALID_API_TOKEN": "Invalid or expired API token",
  "E_INVALID_BASIC_CREDENTIALS": "Invalid credentials",
  "E_INVALID_AUTH_UID": "Invalid credentials",
  "E_INVALID_AUTH_PASSWORD": "Invalid credentials"
}

翻译电子邮件

由于电子邮件通常在后台发送(在 HTTP 请求生命周期之外),因此你必须将 i18n 实例显式传递给电子邮件模板。

t 辅助方法是 i18n.formatMessage 的别名,它将以与你创建 i18n 类实例并传递它的语言相同的语言格式化消息到模板状态。

import Mail from '@ioc:Adonis/Addons/Mail'
import I18n from '@ioc:Adonis/Addons/I18n'

const i18n = I18n.locale(customerLocale)

await Mail.send((message) => {
  message
    .subject(i18n.formatMessage('emails.welcome_subject'))
    .htmlView('emails/welcome', { i18n })
})

重新加载翻译

翻译在应用程序启动时被加载并缓存在内存中。因此,在你重新启动该过程之前,对翻译文件所做的任何更改都不会反映出来。

在开发过程中,开发服务器将在文件更改时自行重启。但是,在生产中,你必须手动重新启动服务器(如新部署)。

如果出于某种原因,你想在正在运行的进程中重新加载翻译,那么可以使用 I18n.reloadTranslations() 方法来做到这一点。

import I18n from '@ioc:Adonis/Addons/I18n'

await I18n.reloadTranslations()

报告缺失的翻译

为了帮助你逐步添加新语言的翻译,我们通过发出 i18n:missing:translation 事件来报告缺失的翻译。

通过运行以下 Ace 命令创建一个新的预加载文件 start/i18n.ts。选择所有环境。

node ace make:prldfile i18n

打开新创建的文件并将以下内容粘贴到其中。目前,我们正在使用 I18n.prettyPrint 方法将消息记录到控制台。但是,你也可以使用记录器来记录消息。

// title: start/i18n.ts
import Event from '@ioc:Adonis/Core/Event'
import I18n from '@ioc:Adonis/Addons/I18n'

Event.on('i18n:missing:translation', I18n.prettyPrint)

添加自定义消息格式化程序

消息格式化程序定义了存储翻译的语法和功能。该软件包附带一个 icu 格式化程序,它使用 ICU 消息语法来编写翻译。

但是,你也可以使用 I18n.extend 方法注册自定义消息格式化程序。格式化程序实现必须遵守 TranslationsFormatterContract 接口。

interface TranslationsFormatterContract {
  readonly name: string
  format(message: string, locale: string, data?: Record<string, any>): string
}

name

格式化程序的唯一名称。这将是一个静态字符串值。


format

format 方法接收以下参数,并且必须返回格式化的字符串。

  • 第一个参数是消息文本。
  • 第二个参数是应该进行格式化的 locale
  • 最后,动态值的数据对象。

虚拟实现

以下是一个非常简单的实现,它使用 Edge 模板引擎来格式化翻译。

步骤 1. 创建格式化程序类。

providers 目录中创建一个新文件 MustacheFormatter.ts 并将以下内容粘贴到其中。

import type { ViewContract } from '@ioc:Adonis/Core/View'
import type { TranslationsFormatterContract } from '@ioc:Adonis/Addons/I18n'

export class MustacheFormatter implements TranslationsFormatterContract {
  public readonly name = 'mustache'
  constructor(private view: ViewContract) {}

  public format(message: string, _: string, data?: Record<string, any>) {
    return this.view.renderRawSync(message, data)
  }
}

步骤 2. 扩展 I18n 并注册格式化程序

打开 providers/AppProvider.ts 文件并在 boot 方法中注册格式化程序。

// 文件名: providers/AppProvider.ts
import { ApplicationContract } from '@ioc:Adonis/Core/Application'
import { MustacheFormatter } from './MustacheFormatter'

export default class AppProvider {
  constructor(protected app: ApplicationContract) {}

  public register() {
    // 注册你自己的绑定
  }

  public async boot() {
    const I18n = this.app.container.resolveBinding('Adonis/Addons/I18n')
    const View = this.app.container.resolveBinding('Adonis/Core/View')

    I18n.extend('mustache', 'formatter', () => new MustacheFormatter(View))
  }

  public async ready() {
    // 应用准备就绪
  }

  public async shutdown() {
    // 清理,因为应用程序正在关闭
  }
}

步骤 3. 使用 mustache 格式化程序

更新配置文件并将 translationsFormat 设置为 mustache。

{
  translationsFormat: 'mustache'
}

添加自定义消息加载器

消息加载器负责从永久源加载消息。该软件包附带一个 fs 格式化程序,它从文件系统读取 .json.yaml 文件。

但是,你也可以使用 I18n.extend 方法注册自定义加载程序。加载器实现必须遵守 LoaderContract 接口。

type Translations = {
  [lang: string]: Record<string, string>
}

interface LoaderContract {
  load(): Promise<Translations>
}

加载器只需要实现一个名为 load 的方法,它将所有翻译作为一个对象返回。

对象的顶级键是语言代码,值是消息的另一个对象。

{
  en: {},
  fr: {},
  it: {}
}

此外,请确保将语言对象内的嵌套消息转换为平面对象。例如:

{
  en: {
    'messages.title': '',
    'messages.subtitle': ''
  }
}

虚拟实现

下面是一个非常简单的实现,它使用 Lucid 从数据库中读取消息。

步骤 1. 创建加载器类。

providers 目录中创建一个新文件 DbLoader.ts 并将以下内容粘贴到其中。

import type { DatabaseContract } from '@ioc:Adonis/Lucid/Database'
import type {
  Translations,
  LoaderContract
} from '@ioc:Adonis/Addons/I18n'

export type DbLoaderConfig = {
  enabled: boolean
  table: string
}

export class DbLoader implements LoaderContract {
  constructor(private db: DatabaseContract, private config: DbLoaderConfig) {}

  public async load() {
    const rows = await this.db.from(this.config.table)

    return rows.reduce<Translations>((result, row) => {
      result[row.locale] = result[row.locale] || {}
      result[row.locale][row.key] = row.message
      return result
    }, {})
  }
}

步骤 2. 扩展 I18n 并注册加载程序

打开 providers/AppProvider.ts 文件并在 boot 方法中注册加载程序。

// 文件名: providers/AppProvider.ts
import { ApplicationContract } from '@ioc:Adonis/Core/Application'
import { DbLoader } from './DbLoader'

export default class AppProvider {
  constructor(protected app: ApplicationContract) {}

  public register() {
    // 注册你自己的绑定
  }

  public async boot() {
    const I18n = this.app.container.resolveBinding('Adonis/Addons/I18n')
    const Db = this.app.container.resolveBinding('Adonis/Lucid/Database')

    I18n.extend('db', 'loader', (_, config) => {
      return new DbLoader(Db, config)
    })
  }

  public async ready() {
    // 应用准备就绪
  }

  public async shutdown() {
    // 清理,因为应用程序正在关闭
  }
}

步骤 3. 使用 db 加载程序

更新配置文件并将 db 加载器键添加到 loaders 对象。

{
  loaders: {
    fs: {},
    db: {
      enabled: true,
      table: 'translations'
    }
  }
}

步骤 4. 创建翻译表

使用以下迁移来创建翻译表。

注:运行迁移时,你必须在配置文件中禁用 db 加载器。否则,加载程序将尝试从不存在的表中读取消息。

import BaseSchema from '@ioc:Adonis/Lucid/Schema'

export default class Translations extends BaseSchema {
  protected tableName = 'translations'

  public async up() {
    this.schema.createTable(this.tableName, (table) => {
      table.increments('id')
      table.string('locale', 8).notNullable()
      table.string('key').notNullable()
      table.text('message', 'longtext').notNullable()

      table.timestamp('created_at', { useTz: true })
      table.timestamp('updated_at', { useTz: true })

      table.unique(['locale', 'key'])
    })
  }

  public async down() {
    this.schema.dropTable(this.tableName)
  }
}

扩展阅读

请务必阅读 API 参考指南 以查看所有可用的属性和方法。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/adonisjs/5.x/di...

译文地址:https://learnku.com/docs/adonisjs/5.x/di...

上一篇 下一篇
贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~