Skip to content
本页导读

国际化 i18n

参考 vue-i18n 实现的 UTS 国际化插件

插件安装

先在项目根目录下创建locales文件夹,然后在此文件夹下新增4国语言配置文件,为空即可

  • locales/zh_CN.uts
  • locales/en_US.uts
  • locales/ja_JP.uts
  • locales/ko_KR.uts'

main.uts 安装插件

ts
import App from './App.uvue'
import { createSSRApp } from 'vue'

import { i18n } from '@/uni_modules/ux-frame'

import zhCN from './locales/zh_CN.uts'
import enUS from './locales/en_US.uts'
import jaJP from './locales/ja_JP.uts'
import koKR from './locales/ko_KR.uts'

export function createApp() {
  const app = createSSRApp(App)
 
  // 安装i18n
  app.use(i18n({
  	locale: 'zh-CN',
  	messages: {
  		'zh-CN': zhCN,
  		'en-US': enUS,
  		'ja-JP': jaJP,
  		'ko-KR': koKR
  	}
  }))
  
  return {
    app,
  }
}
import App from './App.uvue'
import { createSSRApp } from 'vue'

import { i18n } from '@/uni_modules/ux-frame'

import zhCN from './locales/zh_CN.uts'
import enUS from './locales/en_US.uts'
import jaJP from './locales/ja_JP.uts'
import koKR from './locales/ko_KR.uts'

export function createApp() {
  const app = createSSRApp(App)
 
  // 安装i18n
  app.use(i18n({
  	locale: 'zh-CN',
  	messages: {
  		'zh-CN': zhCN,
  		'en-US': enUS,
  		'ja-JP': jaJP,
  		'ko-KR': koKR
  	}
  }))
  
  return {
    app,
  }
}

切换语言

组合式API

js
import{ $ux} from '@/uni_modules/ux-frame'

$ux.Locale.i18n().locale.value = 'zh-CN'
import{ $ux} from '@/uni_modules/ux-frame'

$ux.Locale.i18n().locale.value = 'zh-CN'

选项式API

js
this.$ux.Locale.i18n().locale.value = 'zh-CN'
this.$ux.Locale.i18n().locale.value = 'zh-CN'

动态设置

js
// 模拟请求后端接口返回
getData((zhCN) => {
	this.$ux.Locale.i18n().setLocaleMessage('zh-CN', zhCN)
})
// 模拟请求后端接口返回
getData((zhCN) => {
	this.$ux.Locale.i18n().setLocaleMessage('zh-CN', zhCN)
})

格式化

具名插值

语言环境信息如下:

js
const messages = {
  en: {
    message: {
      hello: '{msg} world'
    }
  }
}
const messages = {
  en: {
    message: {
      hello: '{msg} world'
    }
  }
}

模板如下:

html
<text>{{ $t('message.hello', { msg: 'hello' }) }}</text>
<text>{{ $t('message.hello', { msg: 'hello' }) }}</text>

输出如下:

html
<text>hello world</text>
<text>hello world</text>

列表插值

语言环境信息如下:

js
const messages = {
  en: {
    message: {
      hello: '{0} world'
    }
  }
}
const messages = {
  en: {
    message: {
      hello: '{0} world'
    }
  }
}

模板如下:

html
<text>{{ $t('message.hello', ['hello']) }}</text>
<text>{{ $t('message.hello', ['hello']) }}</text>

输出如下:

html
<text>hello world</text>
<text>hello world</text>

链接插值

如果有一个翻译关键字总是与另一个具有相同的具体文本,你可以链接到它。要链接到另一个翻译关键字,你所要做的就是在其内容前加上一个@:符号后跟完整的翻译键名,包括你要链接到的命名空间。
语言环境信息如下:

js
const messages = {
  en: {
    message: {
      the_world: 'the world',
      dio: 'DIO:',
      linked: '@:message.dio @:message.the_world !!!!'
    }
  }
}
const messages = {
  en: {
    message: {
      the_world: 'the world',
      dio: 'DIO:',
      linked: '@:message.dio @:message.the_world !!!!'
    }
  }
}

模板如下:

html
<text>{{ $t('message.linked') }}</text>
<text>{{ $t('message.linked') }}</text>

输出如下:

html
<text>DIO: the world !!!!</text>
<text>DIO: the world !!!!</text>

内置修饰符

如果语言区分字符大小写,则可能需要控制链接的区域设置消息的大小写。链接邮件可以使用修饰符 @.modifier:key 进行格式化

以下修饰符当前可用

  • upper: 链接消息中的所有字符均大写
  • lower: 小写链接消息中的所有字符
  • capitalize: 大写链接消息中的第一个字符

语言环境信息如下:

js
const messages = {
  en: {
    message: {
      homeAddress: 'Home address',
      missingHomeAddress: 'Please provide @.lower:message.homeAddress'
    }
  }
}
const messages = {
  en: {
    message: {
      homeAddress: 'Home address',
      missingHomeAddress: 'Please provide @.lower:message.homeAddress'
    }
  }
}

模板如下:

html
<text>{{ $t('message.homeAddress') }}</text>
<text class="error">{{ $t('message.missingHomeAddress') }}</text
<text>{{ $t('message.homeAddress') }}</text>
<text class="error">{{ $t('message.missingHomeAddress') }}</text

输出如下:

html
<text>Home address</text>
<text class="error">Please provide home address</text>
<text>Home address</text>
<text class="error">Please provide home address</text>

自定义修饰符

如果要使用非内置修饰符,则可以使用自定义修饰符。

js
const i18n = createI18n({
  locale: 'en',
  messages: {
    // set something locale messages ...
  },
  // set custom modifiers at `modifiers` option
  modifiers: {
    snakeCase: (str:string):string => str.split(' ').join('_')
  }
})
const i18n = createI18n({
  locale: 'en',
  messages: {
    // set something locale messages ...
  },
  // set custom modifiers at `modifiers` option
  modifiers: {
    snakeCase: (str:string):string => str.split(' ').join('_')
  }
})

区域设置消息如下:

js
const messages = {
  en: {
    message: {
      snake: 'snake case',
      custom_modifier: "custom modifiers example: @.snakeCase:{'message.snake'}"
    }
  }
}
const messages = {
  en: {
    message: {
      snake: 'snake case',
      custom_modifier: "custom modifiers example: @.snakeCase:{'message.snake'}"
    }
  }
}

复数

你可以使用复数进行翻译。你必须定义具有管道 | 分隔符的语言环境,并在管道分隔符中定义复数。

*您的模板将需要使用 $tc() 而不是 $t()
语言环境信息如下:

js
const messages = {
  en: {
    car: 'car | cars',
    apple: 'no apples | one apple | {count} apples'
  }
}
const messages = {
  en: {
    car: 'car | cars',
    apple: 'no apples | one apple | {count} apples'
  }
}

模板如下:

html
<text>{{ $tc('car', 1) }}</text>
<text>{{ $tc('car', 2) }}</text>

<text>{{ $tc('apple', 0) }}</text>
<text>{{ $tc('apple', 1) }}</text>
<text>{{ $tc('apple', 10, { count: 10 }) }}</text>
<text>{{ $tc('car', 1) }}</text>
<text>{{ $tc('car', 2) }}</text>

<text>{{ $tc('apple', 0) }}</text>
<text>{{ $tc('apple', 1) }}</text>
<text>{{ $tc('apple', 10, { count: 10 }) }}</text>

输出如下:

html
<text>car</text>
<text>cars</text>

<text>no apples</text>
<text>one apple</text>
<text>10 apples</text>
<text>car</text>
<text>cars</text>

<text>no apples</text>
<text>one apple</text>
<text>10 apples</text>

通过预定义的参数访问该数字

你无需明确指定复数的数字。可以通过预定义的命名参数 {count} 和/或 {n} 在语言环境信息中访问该数字。如有必要,你可以覆盖这些预定义的命名参数。
语言环境信息如下:

js
const messages = {
  en: {
    apple: 'no apples | one apple | {count} apples',
    banana: 'no bananas | {n} banana | {n} bananas'
  }
}
const messages = {
  en: {
    apple: 'no apples | one apple | {count} apples',
    banana: 'no bananas | {n} banana | {n} bananas'
  }
}

模板如下:

html
<text>{{ $tc('apple', 10, { count: 10 }) }}</text>
<text>{{ $tc('apple', 10) }}</text>

<text>{{ $tc('banana', 1, { n: 1 }) }}</text>
<text>{{ $tc('banana', 1) }}</text>
<text>{{ $tc('banana', 100, { n: 'too many' }) }}</text>
<text>{{ $tc('apple', 10, { count: 10 }) }}</text>
<text>{{ $tc('apple', 10) }}</text>

<text>{{ $tc('banana', 1, { n: 1 }) }}</text>
<text>{{ $tc('banana', 1) }}</text>
<text>{{ $tc('banana', 100, { n: 'too many' }) }}</text>

输出如下:

html
<text>10 apples</text>
<text>10 apples</text>

<text>1 banana</text>
<text>1 banana</text>
<text>too many bananas</text>
<text>10 apples</text>
<text>10 apples</text>

<text>1 banana</text>
<text>1 banana</text>
<text>too many bananas</text>

自定义复数

但是,这种多元化并不适用于所有语言(例如,斯拉夫语言具有不同的多元化规则)。

为了实现这些规则,您可以将可选的 pluralizationRules 对象传递给 UvueI18n 构造函数选项。

使用针对斯拉夫语言(俄语,乌克兰语等)的规则的非常简化的示例:

js
function customRule(choice:number, choicesLength:number):number {
  if (choice == 0) {
    return 0
  }

  const teen = choice > 10 && choice < 20
  const endsWithOne = choice % 10 == 1
  if (!teen && endsWithOne) {
    return 1
  }
  if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
    return 2
  }

  return choicesLength < 4 ? 2 : 3
}


const i18n = createI18n({
  locale: 'ru',
  // the custom rules here ...
  pluralizationRules: {
    ru: customRule
  },
  messages: {
    ru: {
      car: '0 машин | {n} машина | {n} машины | {n} машин',
      banana: 'нет бананов | {n} банан | {n} банана | {n} бананов'
    }
  }
})
function customRule(choice:number, choicesLength:number):number {
  if (choice == 0) {
    return 0
  }

  const teen = choice > 10 && choice < 20
  const endsWithOne = choice % 10 == 1
  if (!teen && endsWithOne) {
    return 1
  }
  if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
    return 2
  }

  return choicesLength < 4 ? 2 : 3
}


const i18n = createI18n({
  locale: 'ru',
  // the custom rules here ...
  pluralizationRules: {
    ru: customRule
  },
  messages: {
    ru: {
      car: '0 машин | {n} машина | {n} машины | {n} машин',
      banana: 'нет бананов | {n} банан | {n} банана | {n} бананов'
    }
  }
})

这将有效地实现以下目的:

html
<view>Car:</view>
<text>{{ $tc('car', 1) }}</text>
<text>{{ $tc('car', 2) }}</text>
<text>{{ $tc('car', 4) }}</text>
<text>{{ $tc('car', 12) }}</text>
<text>{{ $tc('car', 21) }}</text>

<view>Banana:</view>
<text>{{ $tc('banana', 0) }}</text>
<text>{{ $tc('banana', 4) }}</text>
<text>{{ $tc('banana', 11) }}</text>
<text>{{ $tc('banana', 31) }}</text>
<view>Car:</view>
<text>{{ $tc('car', 1) }}</text>
<text>{{ $tc('car', 2) }}</text>
<text>{{ $tc('car', 4) }}</text>
<text>{{ $tc('car', 12) }}</text>
<text>{{ $tc('car', 21) }}</text>

<view>Banana:</view>
<text>{{ $tc('banana', 0) }}</text>
<text>{{ $tc('banana', 4) }}</text>
<text>{{ $tc('banana', 11) }}</text>
<text>{{ $tc('banana', 31) }}</text>

结果如下:

html
<view>Car:</view>
<text>1 машина</text>
<text>2 машины</text>
<text>4 машины</text>
<text>12 машин</text>
<text>21 машина</text>

<view>Banana:</view>
<text>нет бананов</text>
<text>4 банана</text>
<text>11 бананов</text>
<text>31 банан</text>
<view>Car:</view>
<text>1 машина</text>
<text>2 машины</text>
<text>4 машины</text>
<text>12 машин</text>
<text>21 машина</text>

<view>Banana:</view>
<text>нет бананов</text>
<text>4 банана</text>
<text>11 бананов</text>
<text>31 банан</text>

切换tabBar文本

这是UvueI18n独有的功能,方便切换tabBar上的文本,暂定这个规则

js
const i18n = createI18n({
	tabBars: {
		'en-US': ['home','User Center'],
		'zh-CN': ['首页','用户中心'],
	}
})
const i18n = createI18n({
	tabBars: {
		'en-US': ['home','User Center'],
		'zh-CN': ['首页','用户中心'],
	}
})

日期时间本地化

由于APP不支持Intl.DateTimeFormat,故这功能无法在APP上使用。

日期时间格式如下:

js
const datetimeFormats = {
  'en-US': {
    short: {
      year: 'numeric', month: 'short', day: 'numeric'
    },
    long: {
      year: 'numeric', month: 'short', day: 'numeric',
      weekday: 'short', hour: 'numeric', minute: 'numeric'
    }
  },
  'zh-CN': {
    short: {
      year: 'numeric', month: 'short', day: 'numeric'
    },
    long: {
      year: 'numeric', month: 'short', day: 'numeric',
      weekday: 'short', hour: 'numeric', minute: 'numeric', hour12: true
    }
  }
}
const datetimeFormats = {
  'en-US': {
    short: {
      year: 'numeric', month: 'short', day: 'numeric'
    },
    long: {
      year: 'numeric', month: 'short', day: 'numeric',
      weekday: 'short', hour: 'numeric', minute: 'numeric'
    }
  },
  'zh-CN': {
    short: {
      year: 'numeric', month: 'short', day: 'numeric'
    },
    long: {
      year: 'numeric', month: 'short', day: 'numeric',
      weekday: 'short', hour: 'numeric', minute: 'numeric', hour12: true
    }
  }
}

如上,你可以定义具名的 (例如:short、long 等) 日期时间格式,并需要使用 ECMA-402 Intl.DateTimeFormat 的选项

之后就像语言环境信息一样,你需要指定 UvueI18n 构造函数的 dateTimeFormats 选项:

js
const i18n = createI18n({
  datetimeFormats
})
const i18n = createI18n({
  datetimeFormats
})

模板如下:

html
<text>{{ $d(new Date(), 'short') }}</text>
<text>{{ $d(new Date(), 'long', 'zh-CN') }}</text>
<text>{{ $d(new Date(), 'short') }}</text>
<text>{{ $d(new Date(), 'long', 'zh-CN') }}</text>

第一个参数是日期时间可用值(例如,timestamp)作为参数,第二个参数是日期时间格式名称作为参数。最后一个参数 locale 值作为参数。Date

html
<text>Jun 30, 2024</text>
<text>2024年6月30日周日 下午6:35</text>
<text>Jun 30, 2024</text>
<text>2024年6月30日周日 下午6:35</text>

数字格式

由于APP不支持Intl.NumberFormat,故这功能无法在APP上使用。

你可以使用你定义的格式来本地化数字。

js
const numberFormats = {
  'en-US': {
    currency: {
      style: 'currency', currency: 'USD', notation: 'standard'
    },
    decimal: {
      style: 'decimal', minimumFractionDigits: 2, maximumFractionDigits: 2
    },
    percent: {
      style: 'percent', useGrouping: false
    }
  },
  'zh-CN': {
    currency: {
      style: 'currency', currency: 'CNY', useGrouping: true, currencyDisplay: 'symbol'
    },
    decimal: {
      style: 'decimal', minimumSignificantDigits: 3, maximumSignificantDigits: 5
    },
    percent: {
      style: 'percent', useGrouping: false
    }
  }
}
const numberFormats = {
  'en-US': {
    currency: {
      style: 'currency', currency: 'USD', notation: 'standard'
    },
    decimal: {
      style: 'decimal', minimumFractionDigits: 2, maximumFractionDigits: 2
    },
    percent: {
      style: 'percent', useGrouping: false
    }
  },
  'zh-CN': {
    currency: {
      style: 'currency', currency: 'CNY', useGrouping: true, currencyDisplay: 'symbol'
    },
    decimal: {
      style: 'decimal', minimumSignificantDigits: 3, maximumSignificantDigits: 5
    },
    percent: {
      style: 'percent', useGrouping: false
    }
  }
}

如上,你可以指定具名的 (例如:currency 等) 的数字格式,并且需要使用 ECMA-402 Intl.NumberFormat 的选项

之后,在使用区域设置消息时,您需要指定以下选项:numberFormatscreateI18n

js
const i18n = createI18n({
  numberFormats
})
const i18n = createI18n({
  numberFormats
})

以下是在模板中使用的示例:$n

html
<text>{{ $n(10000, 'currency') }}</text>
<text>{{ $n(10000, 'currency', 'zh-CN') }}</text>
<text>{{ $n(10000, 'currency', 'zh-CN', { useGrouping: false }) }}</text>
<text>{{ $n(987654321, 'currency', { notation: 'compact' }) }}</text>
<text>{{ $n(0.99123, 'percent') }}</text>
<text>{{ $n(0.99123, 'percent', { minimumFractionDigits: 2 }) }}</text>
<text>{{ $n(12.11612345, 'decimal') }}</text>
<text>{{ $n(12145281111, 'decimal', 'zh-CN') }}</text>
<text>{{ $n(10000, 'currency') }}</text>
<text>{{ $n(10000, 'currency', 'zh-CN') }}</text>
<text>{{ $n(10000, 'currency', 'zh-CN', { useGrouping: false }) }}</text>
<text>{{ $n(987654321, 'currency', { notation: 'compact' }) }}</text>
<text>{{ $n(0.99123, 'percent') }}</text>
<text>{{ $n(0.99123, 'percent', { minimumFractionDigits: 2 }) }}</text>
<text>{{ $n(12.11612345, 'decimal') }}</text>
<text>{{ $n(12145281111, 'decimal', 'zh-CN') }}</text>

第一个参数是作为参数的数值,第二个参数是作为参数的数字格式名称。最后一个参数 locale 值作为参数。

结果如下:

html
<text>$10,000.00</text>
<text>¥10,000.00</text>
<text>¥10,000.00</text>
<text>$988M</text>
<text>99%</text>
<text>99.12%</text>
<text>12.12</text>
<text>12,145,000,000</text>
<text>$10,000.00</text>
<text>¥10,000.00</text>
<text>¥10,000.00</text>
<text>$988M</text>
<text>99%</text>
<text>99.12%</text>
<text>12.12</text>
<text>12,145,000,000</text>

API

setLocaleMessage

getLocaleMessage

mergeLocaleMessage

getDateTimeFormat

setDateTimeFormat

mergeDateTimeFormat

getNumberFormat

setNumberFormat

mergeNumberFormat

setTabBar

getTabBar