runtime.js 2.39 KB
/**
 * runtime.js —— 只装配 vue-i18n(设 fallback='en')+ setLocale/getLocale。
 * 不读 env、不发网络;locale 初值由调用方注入。
 */
import { createI18n as createVueI18n } from 'vue-i18n'
import { messages } from './messages/index.js'
import { SUPPORTED_LOCALES, DEFAULT_LOCALE, LOCALE_META, isSupportedLocale } from './locales.js'

/**
 * @typedef {import('./locales.js').LocaleCode} LocaleCode
 * @typedef {import('./locales.js').LocaleMeta} LocaleMeta
 */

/**
 * @typedef {object} CreateI18nOptions
 * @property {LocaleCode} [locale] 初值(注入);缺省 `'en'`。非法值回落 `'en'`。
 * @property {LocaleCode} [fallbackLocale] 缺省 `'en'`(英语第一公民)。
 */

/**
 * @typedef {object} I18nRuntime
 * @property {import('vue-i18n').I18n} i18n vue-i18n 实例,`app.use(i18n)`。
 * @property {(code: LocaleCode) => void} setLocale 切换当前 locale(非法值回落 fallback)。
 * @property {() => LocaleCode} getLocale 读当前 locale(供 api-sdk 取 `x-locale`)。
 * @property {LocaleMeta[]} locales 语言元数据数组(供渲染切换器)。
 */

/**
 * 唯一入口工厂:装配 vue-i18n 运行时。
 * @param {CreateI18nOptions} [opts]
 * @returns {I18nRuntime}
 */
export function createI18n(opts = {}) {
  const fallbackLocale = isSupportedLocale(opts.fallbackLocale)
    ? opts.fallbackLocale
    : DEFAULT_LOCALE
  const initialLocale = isSupportedLocale(opts.locale) ? opts.locale : fallbackLocale

  const i18n = createVueI18n(
    /** @type {any} */ ({
      legacy: false, // Composition API 模式
      locale: initialLocale,
      fallbackLocale, // 缺失 key 自动回落 en,不显示原始 key、不抛错
      fallbackWarn: false,
      missingWarn: false,
      messages,
      availableLocales: SUPPORTED_LOCALES,
    }),
  )

  // legacy:false 下 `i18n.global.locale` 是一个 ref;vue-i18n 重载类型在
  // checkJs 下无法精确推断该分支,故对 global 取一次窄化引用集中处理。
  const composer = /** @type {{ locale: { value: LocaleCode } }} */ (
    /** @type {unknown} */ (i18n.global)
  )

  /** @param {LocaleCode} code */
  function setLocale(code) {
    const next = isSupportedLocale(code) ? code : fallbackLocale
    composer.locale.value = next
  }

  /** @returns {LocaleCode} */
  function getLocale() {
    return composer.locale.value
  }

  return { i18n, setLocale, getLocale, locales: LOCALE_META }
}