修复单元测试和增加文档

This commit is contained in:
wxzhang 2022-08-22 18:27:22 +08:00
parent 525cb15f80
commit 8e9ee9ac35
15 changed files with 563 additions and 969 deletions

View File

@ -15,7 +15,12 @@ export default defineConfig({
locales: [['zh-CN', '中文']],
theme:{
"@c-heading": "#4569d4"
},
},
styles: [`
ul.__dumi-default-layout-toc > li[data-depth=2] {
font-weight: bold;
}
`],
scripts:[`
var _hmt = _hmt || [];
(function() {

View File

@ -188,6 +188,11 @@ myapp> voerkai18n compile
|-- en.js
|-- jp.js
|-- de.js
|-- formatters // 自定义扩展格式化器
|-- zh.js
|-- en.js
|-- jp.js
|-- de.js
|-- translates // 此文件夹包含了所有需要翻译的内容
|-- default.json
|-- package.json

View File

@ -2,26 +2,11 @@
## 概述
得益于`voerkai18n`强大的格式化机制,`@voerkai18n/runtime`内置了对强大灵活的日期时间处理机制,可以很轻松实现多语言场景下的灵活多变的日期时间显示。
`voerkai18n`支持丰富的格式化器用来支持本地化日期时间显示:
- `date`
- `time`
- `year`
- `quarter`
- `month`
- `day`
- `weekday`
- `hour`
- `hour12`
- `minute`
- `second`
- `millisecond`
- `timestamp`
得益于`voerkai18n`强大的格式化机制,`@voerkai18n/runtime`内置了对强大灵活的日期时间处理机制,可以很轻松实现多语言场景下的灵活多变的日期时间显示。
关于格式化器的更完整说明请[参阅](../advanced/customformatter)
关于格式化器的工作原理和配置说明请[参阅](../advanced/customformatter)
## 指南
### 基本用法
## 基本用法
当需要对日期和时间进行本地化显示时,请使用相对应的日期时间格式化器,可以在`t`函数中使用来对日期型变量进行本地化格式输出。
@ -52,116 +37,6 @@
```
根据指定的模板字符串进行插值后输出。模板字符串中可以使用如`YYYY``MM``DD``占位符`来表示日期时间中的年月日等,可用的模板占位符见本文最后。
### 配置方法
`voerkai18n`运行时已经内置了`zh``en`两种语言的日期时间相关的的格式化器。为了满足复杂的应用需要求,可以根据需要对日期时间格式化进行配置定制。
配置定制日期时间格式化非常简单,当使用`voerkai18n compile`后,项目结构中会生成`formatters`如下:
```javascript | pure
<myapp>
|--src
| |-- languages
| | |--
| | |-- formatters
| | | |-- zh.js
| | | |-- en.js
| | | |-- de.js
....
```
`formatters`文件夹中的`zh.js``en.js``de.js`文件中包括了您自定义的格式化器。
现在一般您可以选择:
- 修改内置的日期时间格式化
- 配置指定语言的日期时间格式化
#### **修改内置的日期时间格式**
由于`@voerkai18n/runtime`中已经内置了`zh``en`两种语言的日期时间格式化器,大多数情况下,我们会定时更新确保其有效工作,一般情况下,您是不需要修改`zh.js``en.js`这两个文件了。
但是如果内置的`zh``en`两种语言的日期时间格式化器不能满足要求,您可以选择性地修改`zh.js``en.js`这两个文件,这些文件会覆盖合并到内置的日期和时间格式化规则。
当您第一次打开`languages/formatters/<语言名称>.js`时会发现里面是空的,除了一些注释外。如下:
```javscript | pure
export default {
$config:{
}
}
```
现在假设我们需要将`zh`语言的日期时间`long`格式的输出从默认的`YYYY年MM月DD日 HH点mm分ss秒`调整为`北京时间: YYYY年MM月DD日 HH点mm分ss秒`,那么只需要修改 `languages/formatters/zh.js`,如下:
```javscript | pure
export default {
$config:{
datetime:{
date:{
long:"北京时间: YYYY年MM月DD日 HH点mm分ss秒"
}
}
}
}
```
`languages/formatters/zh.js`中的配置优先级最高,会合并覆盖内置的配置。
**为什么可以通过修改`$config.datetime.date`来修改默认的日期时间格式化?**
因为`date`格式化器是可配置的,当该格式化器会从`$config.datetime.date`读取模板字符串来进行格式化输出。因此,只需要覆盖`$config.datetime.date`参数即可实现自定义格式化。
事实上,`date`/`quarter`/`month`/`weekday`/`time`等格式化器均是可配置的,对应的配置位置是:
```javscript | pure
export default {
$config:{
datetime:{
date:{ ... },
quarter:{ ... },
month:{ ... },
weekday:{ ... },
time:{ ... },
}
}
}
```
按照这样的机制,我们就可分别配置在不种语言下,对日期时间等显示方式。
#### **配置指定语言的日期时间格式化**
默认情况下,`en`语言的日期时间格式化器被注册到全局,当任何一种语言的指定格式化器没有定义时,会在全局格式化器中查找,因此`en`语言的日期时间格式化器是适用于所有语言。
如果`en`语言的日期时间格式化不符合`de`语言的要求,修改`languages/formatters/de.js`文件。
```javscript | pure
export default {
$config:{
datetime:{
date:{
long:"<de语言的长日期时间格式模板>"
short:"<de语言的长日期时间格式模板>"
format:"long"
}
}
}
}
```
这样,当切换到`de`语言时date格式化器就会读取`languages/formatters/de.js`文件中的配置,从而实现符合要求的`de`语言的日期时间格式化。
### 格式模板占位符
| 占位符 | 说明 |
| --- | --- |
|YYYY | 2018 年,四位数|
|YY | 18 年,两位数 |
|MMM | Jan-Dec 月,英文缩写|
|MM | 01-12 月,两位数字|
|M | 1-12 月从1开始|
|DD | 01-31 日,两位数|
|D | 1-31 日|
|HH | 00-23 24小时两位数|
|H | 0-23 24小时|
|hh | 01-12 12小时两位数|
|h | 1-12 12小时|
|mm | 00-59 分钟,两位数|
|m | 0-59 分钟|
|ss | 00-59 秒,两位数|
|s | 0-59 秒|
|SSS | 000-999 毫秒,三位数|
|A | AM / PM 上/下午,大写|
|a | am / pm 上/下午,小写|
## 格式化器
### 日期 - `date`
@ -209,12 +84,12 @@ t("{ value | date('YYYY-MM-DD') }",1661084229790)
| --- | --- |
| `t("现在是{ value }",NOW)` | `现在是2022/8/12 10:12:36`|
| `t("现在是{ value \| date }",NOW)` | `现在是2022/8/12 10:12:36`|
| `t("现在是{ value \| date('local') }",NOW)` | `` |
| `t("现在是{ value \| date('local') }",NOW)` | `现在是2022/8/12 10:12:36` |
| `t("现在是{ value \| date('long') }",NOW)` | `现在是2022年08月12日 10点12分36秒` |
| `t("现在是{ value \| date('short') }",NOW)` | `现在是2022/08/12` |
| `t("现在是{ value \| date('iso') }",NOW)` | `` |
| `t("现在是{ value \| date('gmt') }",NOW)` | `` |
| `t("现在是{ value \| date('utc') }",NOW)` | `` |
| `t("现在是{ value \| date('iso') }",NOW)` | `现在是2022-08-12T02:12:36.000Z` |
| `t("现在是{ value \| date('gmt') }",NOW)` | `现在是Fri, 12 Aug 2022 02:12:36 GMT` |
| `t("现在是{ value \| date('utc') }",NOW)` | `现在是Fri, 12 Aug 2022 02:12:36 GMT` |
| **自定义格式** | |
| `t("现在是{ value \| date('YYYY-MM-DD HH:mm:ss')}",NOW)`| `现在是2022-08-12 10:12:36`|
| `t("现在是{ value \| date('YYYY/MM/DD') }",NOW)",NOW)` | `现在是2022-08-12`|
@ -225,12 +100,12 @@ t("{ value | date('YYYY-MM-DD') }",1661084229790)
| --- | --- |
| `t("现在是 { value }",NOW)` | `Now is 2022/8/12 10:12:36`|
| `t("现在是 { value \| date }",NOW)` | `Now is 2022/8/12 10:12:36`|
| `t("现在是 { value \| date('local') }",NOW)` | `Now is ` |
| `t("现在是 { value \| date('local') }",NOW)` | `Now is 2022/8/12 10:12:36` |
| `t("现在是 { value \| date('long') }",NOW)` | `Now is 2022/08/12 10:12:36` |
| `t("现在是 { value \| date('short') }",NOW)` | `Now is 2022/08/12` |
| `t("现在是 { value \| date('iso') }",NOW)` | `Now is ` |
| `t("现在是 { value \| date('gmt') }",NOW)` | `Now is ` |
| `t("现在是 { value \| date('utc') }",NOW)` | `Now is ` |
| `t("现在是 { value \| date('iso') }",NOW)` | `Now is 2022-08-12T02:12:36.000Z` |
| `t("现在是 { value \| date('gmt') }",NOW)` | `Now is Fri, 12 Aug 2022 02:12:36 GMT` |
| `t("现在是 { value \| date('utc') }",NOW)` | `Now is Fri, 12 Aug 2022 02:12:36 GMT` |
| **自定义格式** | |
| `t("现在是 { value \| date('YYYY-MM-DD HH:mm:ss') }",NOW`| `Now is 2022-08-12 10:12:36`|
| `t("现在是 { value \| date('YYYY/MM/DD')}",NOW"),` | `Now is 2022-08-12`|
@ -238,16 +113,40 @@ t("{ value | date('YYYY-MM-DD') }",1661084229790)
#### **配置**
除了`local`,`iso`,`gmt`,`utc`是调用`Date原型方法`外,`long`,`short`两种预设的格式是采用可配置的模板字符串来定义的。默认情况下其预设格式是
除了`local`,`iso`,`gmt`,`utc`是调用`Date原型方法`外,`date`格式化器的支持以下配置
| 格式名称 | 中文(zh) | 英文(en) |
| --- | --- | --- |
| `long` | `YYYY年MM月DD日 HH点mm分ss秒` | `YYYY/MM/DD HH:mm:ss` |
| `short` | `YYYY/MM/DD` | `YYYY/MM/DD` |
- **配置文件**`languages/formatters/<语言名称>.js`
- **配置位置** `$config.datetime.date`
- **配置参数**
```javascript
export default {
$config:{
datetime:{
date:{
long:"<模板字符串>",
short:"<模板字符串>",
format:"<local | iso | gmt | utc | long | short | [模板字符串]>"
}
}
}
}
```
### 时间 - `time`
`date`格式化器用来对日期类型的变量进行格式化。`date`格式化器支持参数:
#### 用法
```javascript | pure
t("{ value | time }",new Date())
t("{ value | time('local') }","2022/12/9 09:12:36")
t("{ value | timetime('long') }",new Date())
t("{ value | time('short') }","2022/12/9 09:12:36")
t("{ value | time('timestamp')}",1661084229790)
t("{ value | time('HH点mm分ss秒') }",1661084229790)
t("{ value | time('HH:mms:ss') }",1661084229790)
```
#### 参数
| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
@ -263,11 +162,12 @@ t("{ value | date('YYYY-MM-DD') }",1661084229790)
**当`activeLanguage == "zh"`时:**
| 翻译 | 输出 |
| --- | --- |
| `t("现在时间 - { value \| time }",NOW)` | `现在时间 - ` |
| `t("现在时间 - { value \| time('local') }",NOW)` | `现在时间 - ` |
| `t("现在时间 - { value \| time }",NOW)` | `现在时间 - 10:12:36` |
| `t("现在时间 - { value \| time('local') }",NOW)` | `现在时间 - 10:12:36` |
| `t("现在时间 - { value \| time('long') }",NOW)` | `现在时间 - 10点12分36秒` |
| `t("现在时间 - { value \| time('short') }",NOW)` | `现在时间 - 10:12:36` |
| `t("现在时间 - { value \| time('timestamp') }", ",NOW)` | `现在时间 - 1660270356000` |
| **自定义格式**
| `t("现在时间 - { value \| time('HH:mm:ss') }",NOW)` | `现在时间 - 10:12:36` |
| `t("现在时间 - { value \| time('mm:ss') }",NOW)` | `现在时间 - 12:36` |
@ -276,8 +176,8 @@ t("{ value | date('YYYY-MM-DD') }",1661084229790)
**当`activeLanguage == "en"`时:**
| 翻译 | 输出 |
| --- | --- |
| `t("现在时间 - { value \| time }",NOW)` | `Now is - ` |
| `t("现在时间 - { value \| time('local') }",NOW)` | `Now is - ` |
| `t("现在时间 - { value \| time }",NOW)` | `Now is - 10:12:36` |
| `t("现在时间 - { value \| time('local') }",NOW)` | `Now is - 10:12:36` |
| `t("现在时间 - { value \| time('long') }",NOW)` | `Now is - 10点12分36秒` |
| `t("现在时间 - { value \| time('short') }",NOW)` | `Now is - 10:12:36` |
| `t("现在时间 - { value \| time('timestamp') }",NOW)` | `Now is - 1660270356000` |
@ -288,12 +188,33 @@ t("{ value | date('YYYY-MM-DD') }",1661084229790)
#### 配置
`time`格式化器的配置方式同`date`格式化器。
- **配置文件**`languages/formatters/<语言名称>.js`
- **配置位置** `$config.datetime.time`
- **配置参数**
```javascript
export default {
$config:{
datetime:{
time:{
long:"<模板字符串>",
short:"<模板字符串>",
format:"<local | long | short | [模板字符串]>"
}
}
}
}
```
### 年份 - `year`
简单输出年份数值,如`t("现在是{ value | year}",new Date())`输出`现在是2022`
### 季度 - `quarter`
输出一年中第几个季度。
#### 用法
```javascript | pure
t("{ value | quarter }",new Date())
t("{ value | quarter('long') }",new Date())
t("{ value | quarter('short') }","2022/12/9 09:12:36")
t("{ value | quarter('number') }","2022/12/9 09:12:36")
```
#### 参数
| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
@ -311,32 +232,43 @@ t("{ value | date('YYYY-MM-DD') }",1661084229790)
**当`activeLanguage == "en"`时:**
| 文本 | 输出 |
| --- | --- |
| `t("今年{ value \| quarter }",NOW)` | `First Quarter of this year` |
| `t("今年{ value \| quarter }",NOW)` | `Q1 of this year` |
| `t("今年{ value \| quarter("long") }",NOW)` | `First Quarter of this year` |
| `t("今年{ value \| quarter("short") }",NOW)` | `Q1 of this year` |
| `t("今年{ value \| quarter("number") }",NOW)` | `1 of this year` |
#### 配置
配置方式同`date`格式化器。可以选择性地修改`languages/formatters/<语言名称>.js`
```javascript | pure
export default {
$config:{
datetime:{
quarter{
long:["Q1","Q2","Q3","Q4"],
short:["Q1","Q2","Q3","Q4"],
format : "short",
- **配置文件**`languages/formatters/<语言名称>.js`
- **配置位置** `$config.datetime.quarter`
- **配置参数**
```javascript
export default {
$config:{
datetime:{
quarter:{
long:"<模板字符串>",
short:"<模板字符串>",
format:"< 0:long | 1:short | 2:number>"
}
}
}
}
}
```
}
```
### 月份 - `month`
输出月份
`month`格式化器用来输出月份。
#### 用法
```javascript | pure
t("{ value | month }",new Date())
t("{ value | month('long') }",new Date())
t("{ value | month('short') }","2022/12/9 09:12:36")
t("{ value | month('number') }","2022/12/9 09:12:36")
```
#### 参数
| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
@ -368,26 +300,33 @@ export default {
#### 配置
`month`格式化器的配置方式同`date`格式化器。
可以选择性地修改`languages/formatters/<语言名称>.js`
```javascript | pure
export default {
$config:{
datetime:{
month{
long : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
short : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"],
format : "short",
- **配置文件**`languages/formatters/<语言名称>.js`
- **配置位置** `$config.datetime.month`
- **配置参数**
```javascript
export default {
$config:{
datetime:{
month:{
long:["一月",...,"十二月"],
short:["1月",...,"12月"],
format:"< 0:long | 1:short | 2:number>"
}
}
}
}
}
```
}
```
### 天 - `day`
输出每个月的几号。如`t("现在是{ value | day }号",new Date())`输出`现在是28号`
### 星期 - `weekday`
输出一星期中的第几天,如星期一、星期二、...星期日。
#### 用法
```javascript | pure
t("{ value | weekday }",new Date())
t("{ value | weekday('long') }",new Date())
t("{ value | weekday('short') }","2022/12/9 09:12:36")
t("{ value | weekday('number') }","2022/12/9 09:12:36")
```
#### 参数
| 参数 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
@ -400,7 +339,7 @@ export default {
| --- | --- |
| `t("今天是{ value \| weekday }",NOW)` | `今天是星期一 ` |
| `t("今天是{ value \| weekday("long") }",NOW)` | `今天是星期一 ` |
| `t("今天是{ value \| weekday("short") }",NOW)` | `今天是一 ` |
| `t("今天是{ value \| weekday("short") }",NOW)` | `今天是一 ` |
| `t("今天是{ value \| weekday("number") }",NOW)` | `今天是1` |
**当`activeLanguage == "en"`时:**
@ -413,24 +352,170 @@ export default {
| `t("今天是{ value \| weekday("number") }",NOW)` | `Today is 1` |
#### 配置
配置方式同`date`格式化器。可以选择性地修改`languages/formatters/<语言名称>.js`
- **配置文件**`languages/formatters/<语言名称>.js`
- **配置位置** `$config.datetime.weekday`
- **配置参数**
```javascript
export default {
$config:{
datetime:{
weekday:{
long:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],
short:["周日","周一","周二","周三","周四","周五","周六"],
format:"< 0:long | 1:short | 2:number>"
}
}
}
}
```
```javascript | pure
## 扩展配置
`voerkai18n`运行时已经内置了`zh``en`两种语言的日期时间相关的的格式化器。
为了满足复杂的应用需要求,日期时间格式化器被设计为可以进行配置。当以上格式化器不能满足要求,或者缺少某种语言的日期时间格式化时,可以非常容易地进行扩展。
扩展支持不同语言言的日期时间格式化非常简单,当使用`voerkai18n compile`后,项目结构中会生成`formatters`如下:
```javascript | pure
<myapp>
|--src
| |-- languages
| | |--
| | |-- formatters
| | | |-- zh.js
| | | |-- en.js
| | | |-- de.js
....
```
`formatters`文件夹中的`zh.js``en.js``de.js`文件中包括了您自定义的格式化器。
当您第一次打开这些文件时,会发现里面除了一些注释来引导您如何编写扩展格式化器外,并没有其他有效的内容。
如果您对现有的日期格式化器的输出不满意,或者缺少某种语言的日期时间格式化,您可以按下面介绍的方式来进行扩展。
**放心**,整个扩展过程非常简单,大部分情况下,只需要配置一些模板字符串即可。
以下开始介绍内容:
- **通过简单的配置修改内置的日期时间格式化规则**
- **为运行时没有支持的语言增加日期时间格式化规则**
- **自定义预设的规则**
- **编写日期时间格式化模板**
### **修改内置规则**
由于`@voerkai18n/runtime`中已经内置了`zh``en`两种语言的日期时间格式化器,大多数情况下,我们会定时更新确保其有效工作,一般情况下,您是不需要修改`zh.js``en.js`这两个文件了。
但是如果内置的`zh``en`两种语言的日期时间格式化器不能满足要求,您可以选择性地修改`zh.js``en.js`这两个文件,这些文件会覆盖合并到内置的日期和时间格式化规则。
当您第一次打开`languages/formatters/<语言名称>.js`时会发现里面是空的(除了一些注释外)。内容大概如下:
```javascript | pure
export default {
$config:{
}
}
```
现在假设我们需要将`zh`语言的日期时间`long`格式的输出从默认的`YYYY年MM月DD日 HH点mm分ss秒`调整为`北京时间: YYYY年MM月DD日 HH点mm分ss秒`,那么只需要修改 `languages/formatters/zh.js`,如下:
```javascript | pure
export default {
$config:{
datetime:{
long :["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
short : ["Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat"],
format : 0, // 默认格式: 0:long-长名称1:short-短名称2:number-数字
date:{
long:"北京时间: YYYY年MM月DD日 HH点mm分ss秒"
}
}
}
}
}
}
```
`languages/formatters/zh.js`中的配置优先级最高,会覆盖内置的格式化规则。
**为什么可以通过修改`$config.datetime.date`来修改默认的日期时间格式化?**
因为`date`格式化器是可配置的,该格式化器函数会从`$config.datetime.date`读取模板字符串来进行格式化输出。因此,只需要修改`$config.datetime.date`中的配置参数即可实现自定义格式化。
事实上,`date`/`quarter`/`month`/`weekday`/`time`等格式化器均是可配置的,对应的配置位置是:
```javascript | pure
export default {
$config:{
datetime:{
date:{ ... },
quarter:{ ... },
month:{ ... },
weekday:{ ... },
time:{ ... },
}
}
}
```
按照这样的机制,我们就可以很容易分别配置在不种语言下对日期时间等显示方式。并且在多包模下,这种修改只会对当前应用或库生效。
### **增加格式化规则**
由于开发者对各语种日期时间格式化知识的缺失。目前,`voerkai18n`只内置了`zh`,`en`两种语言的日期时间规则支持。
其中,`en`语言的日期时间格式化器被注册到全局。当切换到`zh`,`en`两种语言之外的其他语言时,会使用`en`语言的日期时间格式化规则。
很明显,`en`语言的日期时间格式化规则并不能适应所有语言的要求,在官方提供该语言支持前,您可以自行配置语言支持。
方法很简单,以`de`语言为例,打开`languages/formatters/de.js`文件。
```javascript | pure
export default {
$config:{
datetime:{
date:{
long:"<de语言的长日期时间格式模板>"
short:"<de语言的长日期时间格式模板>"
format:"long"
}
}
}
}
```
这样,当切换到`de`语言时date格式化器就会读取`languages/formatters/de.js`文件中的配置,从而实现符合要求的`de`语言的日期时间格式化。
最后,欢迎大家贡献其他语种的日期时间格式化规则,贡献方法可以直接提交在[issues](https://gitee.com/zhangfisher/voerka-i18n/issues),也可以通过[源码方式](https://gitee.com/zhangfisher/voerka-i18n)提交PR。
### **扩展预设规则**
除了预设的`long``short``number`等规则外,您可以通过模板字符串来自定义更加灵活的格式化规则。
您也可以自己定义一个预设格式化规则。
比如可以为`date`格式化器定义一个`full`的规则来显示更加完整的日期时间:
```javascript | pure
t("现在是{ value | date('full') }") // 北京时间2022年08月12日 10点12分36秒 上午
```
### 小时 - `hour`
方法如下:
`languages/formatters/zh.json`中,增加一个`full`配置项即可。
```javascript | pure
export default {
$config: {
full: "北京时间YYYY年MM月DD日 HH点mm分ss秒 a"
}
}
```
有了自定义的`full`预设规则,应用中就可以直接使用`t("现在是{ value | date('full') }") `进行格式化,而不需要使用自定义模板字符串的形式。
### 自定义模板
### 分钟 - `minute`
### 秒 - `second`
### 毫秒 - `millisecond`
### 时间戳 - `timestamp`
日期时间格式化时可以自定义显示格式模板,模板字符串中可以使用以下占位符:
| 占位符 | 说明 |
| --- | --- |
|YYYY | 2018 年,四位数|
|YY | 18 年,两位数 |
|MMM | Jan-Dec 月,英文缩写|
|MM | 01-12 月,两位数字|
|M | 1-12 月从1开始|
|DD | 01-31 日,两位数|
|D | 1-31 日|
|HH | 00-23 24小时两位数|
|H | 0-23 24小时|
|hh | 01-12 12小时两位数|
|h | 1-12 12小时|
|mm | 00-59 分钟,两位数|
|m | 0-59 分钟|
|ss | 00-59 秒,两位数|
|s | 0-59 秒|
|SSS | 000-999 毫秒,三位数|
|A | AM / PM 上/下午,大写|
|a | am / pm 上/下午,小写|

View File

@ -17,10 +17,15 @@ module.exports = {
// clearMocks: false,
// Indicates whether the coverage information should be collected while executing the test
// collectCoverage: false,
// collectCoverage: true,
// An array of glob patterns indicating a set of files for which coverage information should be collected
// collectCoverageFrom: undefined,
// collectCoverageFrom: [
// "./packages/runtime/dist/runtime.cjs",
// "./packages/runtime/**/*.js",
//"!./packages/runtime/dist/**",
//"!./packages/runtime/node_modules/**",
//],
// The directory where Jest should output its coverage files
// coverageDirectory: undefined,
@ -34,12 +39,12 @@ module.exports = {
coverageProvider: "v8",
// A list of reporter names that Jest uses when writing coverage reports
// coverageReporters: [
// "json",
// "text",
// "lcov",
// "clover"
// ],
coverageReporters: [
//"json",
// "text",
"lcov",
// "clover"
],
// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,

View File

@ -6,10 +6,11 @@
"scripts": {
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules node node_modules/jest/bin/jest.js ",
"test:app": "cross-env NODE_OPTIONS=--experimental-vm-modules node node_modules/jest/bin/jest.js -- app",
"test:runtime": "cross-env NODE_OPTIONS=--experimental-vm-modules jest translate --coverage --collectCoverageFrom packages/runtime/dist/runtime.cjs",
"list:package": "node ./packages/autopublish/index.js list",
"autopublish": "node ./packages/autopublish/index.js -a --no-ask",
"docs:build": "cross-env NODE_OPTIONS=--openssl-legacy-provider && dumi build",
"docs:dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider && dumi dev "
"docs:build": "cross-env NODE_OPTIONS=--openssl-legacy-provider dumi build",
"docs:dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider dumi dev "
},
"author": "",
"license": "ISC",
@ -23,7 +24,7 @@
"cross-env": "^7.0.3",
"dayjs": "^1.11.0",
"deepmerge": "^4.2.2",
"dumi": "^1.0.13",
"dumi": "^1.1.47",
"fs-extra": "^10.0.1",
"gulp": "^4.0.2",
"jest": "^27.5.1",

View File

@ -1,547 +0,0 @@
const {i18nScope, translate, getInterpolatedVars } = require('../dist/runtime.cjs.js')
const dayjs = require('dayjs');
function toLanguageDict(values,startIndex=0){
return values.reduce((result,curValue,i)=>{
result[i+startIndex] = curValue;
return result
},{})
}
function toLanguageIdMap(values,startIndex=0){
return values.reduce((result,curValue,i)=>{
result[curValue] = i+startIndex
return result
},{})
}
// 显示两个数组哪一行不同
function diffArray(arr1,arr2){
let diffs = []
arr1.forEach((v,i)=>{
if(v!=arr2[i]) diffs.push([i,[v,arr2[i]]])
})
return diffs
}
const NOW = new Date("2022/08/12 10:12:36")
const zhDatetimes =[
"现在是{ value }",
"现在是{ value | date }",
"现在是{ value | date('local') }",
"现在是{ value | date('long') }",
"现在是{ value | date('short') }",
"现在是{ value | date('iso') }",
"现在是{ value | date('gmt') }",
"现在是{ value | date('utc') }",
"现在是{ value | date(0) }", // local
"现在是{ value | date(1) }", // long
"现在是{ value | date(2) }", // short
"现在是{ value | date(3) }", // iso
"现在是{ value | date(4) }", // gmt
"现在是{ value | date(5) }", // utc
"现在是{ value | date('YYYY-MM-DD HH:mm:ss')}",
"现在是{ value | date('YYYY-MM-DD')}",
"现在是{ value | date('HH:mm:ss')}",
"现在是{ value | month }",
"现在是{ value | month('long')}",
"现在是{ value | month('short')}",
"现在是{ value | month('number')}",
"现在是{ value | month(0)}",
"现在是{ value | month(1)}",
"现在是{ value | month(2)}",
"现在是{ value | weekday }",
"现在是{ value | weekday('long')}",
"现在是{ value | weekday('short')}",
"现在是{ value | weekday('number')}",
"现在是{ value | weekday(0)}",
"现在是{ value | weekday(1)}",
"现在是{ value | weekday(2)}",
// 时间
"现在时间 - { value | time }",
"现在时间 - { value | time('local') }",
"现在时间 - { value | time('long') }",
"现在时间 - { value | time('short') }",
"现在时间 - { value | time('timestamp') }",
"现在时间 - { value | time(0) }",
"现在时间 - { value | time(1) }",
"现在时间 - { value | time(2) }",
"现在时间 - { value | time(3) }",
"现在时间 - { value | time('HH:mm:ss') }",
"现在时间 - { value | time('mm:ss') }",
"现在时间 - { value | time('ss') }"
]
//
const expectZhDatetimes =[
"现在是2022/8/12 10:12:36", // { value }
"现在是2022/8/12 10:12:36", // { value | date }
`现在是${NOW.toLocaleString()}`, // { value | date('local') }
"现在是2022年08月12日 10点12分36秒", // { value | date('long') }
"现在是2022/08/12", // { value | date('short') }
`现在是${NOW.toISOString()}`, // { value | date('iso') }
`现在是${NOW.toGMTString()}`, // { value | date('gmt') }
`现在是${NOW.toUTCString()}`, // { value | date('utc') }
`现在是${NOW.toLocaleString()}`, // { value | date(0) } // local
"现在是2022年08月12日 10点12分36秒", // { value | date(1) } // long
"现在是2022/08/12", // { value | date(2) } // short
`现在是${NOW.toISOString()}`, // { value | date(3) } // iso
`现在是${NOW.toGMTString()}`, // { value | date(4) } // gmt
`现在是${NOW.toUTCString()}`, // { value | date(5) } // utc
"现在是2022-08-12 10:12:36", // { value | date('YYYY-MM-DD HH:mm:ss')}
"现在是2022-08-12", // { value | date('YYYY-MM-DD')}
"现在是10:12:36", // { value | date('HH:mm:ss')}
"现在是八月", // { value | month }
"现在是八月", // { value | month('long')}
"现在是八", // { value | month('short')}
"现在是8", // { value | month('number')}
"现在是八月", // { value | month(0)}
"现在是八", // { value | month(1)}
"现在是8", // { value | month(2)}
"现在是星期五", // { value | weekday }
"现在是星期五", // { value | weekday('long')}
"现在是五", // { value | weekday('short')}
"现在是5", // { value | weekday('number')}
"现在是星期五", // { value | weekday(0)}
"现在是五", // { value | weekday(1)}
"现在是5", // { value | weekday(2)}
// 时间
`现在时间 - ${NOW.toLocaleTimeString()}`, // { value | time }
`现在时间 - ${NOW.toLocaleTimeString()}`, // { value | time('local') }
"现在时间 - 10点12分36秒", // { value | time('long') }
"现在时间 - 10:12:36", // { value | time('short') }
"现在时间 - 1660270356000", // { value | time('timestamp') }
`现在时间 - ${NOW.toLocaleTimeString()}`, // { value | time(0) }
"现在时间 - 10点12分36秒", // { value | time(1) }
"现在时间 - 10:12:36", // { value | time(2) }
"现在时间 - 1660270356000", // { value | time(3) }
"现在时间 - 10:12:36", // { value | time('HH:mm:ss') }
"现在时间 - 12:36", // { value | time('mm:ss') }
"现在时间 - 36", // { value | time('ss') }"
]
const enDatetimes =[
"Now is { value }",
"Now is { value | date }",
"Now is { value | date('local') }",
"Now is { value | date('long') }",
"Now is { value | date('short') }",
"Now is { value | date('iso') }",
"Now is { value | date('gmt') }",
"Now is { value | date('utc') }",
"Now is { value | date(0) }", // local
"Now is { value | date(1) }", // long
"Now is { value | date(2) }", // short
"Now is { value | date(3) }", // iso
"Now is { value | date(4) }", // gmt
"Now is { value | date(5) }", // utc
"Now is { value | date('YYYY-MM-DD HH:mm:ss')}",
"Now is { value | date('YYYY-MM-DD')}",
"Now is { value | date('HH:mm:ss')}",
"Now is { value | month }",
"Now is { value | month('long')}",
"Now is { value | month('short')}",
"Now is { value | month('number')}",
"Now is { value | month(0)}",
"Now is { value | month(1)}",
"Now is { value | month(2)}",
"Now is { value | weekday }",
"Now is { value | weekday('long')}",
"Now is { value | weekday('short')}",
"Now is { value | weekday('number')}",
"Now is { value | weekday(0)}",
"Now is { value | weekday(1)}",
"Now is { value | weekday(2)}",
// 时间
"Now time: { value | time }",
"Now time: { value | time('local') }",
"Now time: { value | time('long') }",
"Now time: { value | time('short') }",
"Now time: { value | time('timestamp') }",
"Now time: { value | time(0) }",
"Now time: { value | time(1) }",
"Now time: { value | time(2) }",
"Now time: { value | time(3) }",
"Now time: { value | time('HH:mm:ss') }",
"Now time: { value | time('mm:ss') }",
"Now time: { value | time('ss') }"
]
const expectEnDatetimes =[
"Now is 2022/8/12 10:12:36", // { value }
"Now is 2022/8/12 10:12:36", // { value | date }
`Now is ${NOW.toLocaleString()}`, // { value | date('local') }
"Now is 2022/08/12 10:12:36", // { value | date('long') }
"Now is 2022/08/12", // { value | date('short') }
`Now is ${NOW.toISOString()}`, // { value | date('iso') }
`Now is ${NOW.toGMTString()}`, // { value | date('gmt') }
`Now is ${NOW.toUTCString()}`, // { value | date('utc') }
`Now is ${NOW.toLocaleString()}`, // { value | date(0) } // local
"Now is 2022/08/12 10:12:36", // { value | date(1) } // long
"Now is 2022/08/12", // { value | date(2) } // short
`Now is ${NOW.toISOString()}`, // { value | date(3) } // iso
`Now is ${NOW.toGMTString()}`, // { value | date(4) } // gmt
`Now is ${NOW.toUTCString()}`, // { value | date(5) } // utc
"Now is 2022-08-12 10:12:36", // { value | date('YYYY-MM-DD HH:mm:ss')}
"Now is 2022-08-12", // { value | date('YYYY-MM-DD')}
"Now is 10:12:36", // { value | date('HH:mm:ss')}
"Now is August", // { value | month }
"Now is August", // { value | month('long')}
"Now is Aug", // { value | month('short')}
"Now is 8", // { value | month('number')}
"Now is August", // { value | month(0)}
"Now is Aug", // { value | month(1)}
"Now is 8", // { value | month(2)}
"Now is Friday", // { value | weekday }
"Now is Friday", // { value | weekday('long')}
"Now is Fri", // { value | weekday('short')}
"Now is 5", // { value | weekday('number')}
"Now is Friday", // { value | weekday(0)}
"Now is Fri", // { value | weekday(1)}
"Now is 5", // { value | weekday(2)}
// 时间
`Now time: ${NOW.toLocaleTimeString()}`, // { value | time }
`Now time: ${NOW.toLocaleTimeString()}`, // { value | time('local') }
"Now time: 10:12:36", // { value | time('long') }
"Now time: 10:12:36", // { value | time('short') }
"Now time: 1660270356000", // { value | time('timestamp') }
`Now time: ${NOW.toLocaleTimeString()}`, // { value | time(0) }
"Now time: 10:12:36", // { value | time(1) }
"Now time: 10:12:36", // { value | time(2) }
"Now time: 1660270356000", // { value | time(3) }
"Now time: 10:12:36", // { value | time('HH:mm:ss') }
"Now time: 12:36", // { value | time('mm:ss') }
"Now time: 36", // { value | time('ss') }"
]
const MONEY = 123456789.88
const zhMoneys = [
"商品价格: { value | currency}", // 默认格式
// long
"商品价格: { value | currency('long')}", // 长格式
"商品价格: { value | currency('long',1)}", // 长格式: 万元
"商品价格: { value | currency('long',2)}", // 长格式: 亿
"商品价格: { value | currency('long',3)}", // 长格式: 万亿
"商品价格: { value | currency('long',4)}", // 长格式: 万万亿
// short
"商品价格: { value | currency('short')}", // 短格式
"商品价格: { value | currency('short',1)}", // 短格式 Thousands
"商品价格: { value | currency('short',2)}", // 短格式 Millions
"商品价格: { value | currency('short',3)}", // 短格式 Billions
"商品价格: { value | currency('short',4)}", // 短格式 Trillions
// 自定义货币格式
"商品价格: { value | currency({symbol:'¥¥'})}",
"商品价格: { value | currency({symbol:'¥¥',prefix:'人民币:'})}",
"商品价格: { value | currency({symbol:'¥¥',prefix:'人民币:',suffix:'元整'})}",
"商品价格: { value | currency({symbol:'¥¥',prefix:'人民币:',suffix:'元整',unit:2})}",
"商品价格: { value | currency({symbol:'¥¥',prefix:'人民币:',suffix:'元整',unit:2,precision:4})}",
"商品价格: { value | currency({symbol:'¥¥',prefix:'人民币:',suffix:'元整',unit:2,precision:4,format:'{prefix}*{symbol}*{value}*{unit}*{suffix}'})}"
]
const expectZhMoneys =[
"商品价格: ¥1,2345,6789.88", // { value | currency }
// long
"商品价格: RMB ¥1,2345,6789.88元", // { value | currency('long')}
"商品价格: RMB ¥1,2345.678988万元", // { value | currency('long',1)}
"商品价格: RMB ¥1.2345678988亿元", // { value | currency('long',2)}
"商品价格: RMB ¥0.00012345678988万亿元", // { value | currency('long',3)}
"商品价格: RMB ¥0.000000012345678988万万亿元", // { value | currency('long',4)}
// short
"商品价格: ¥1,2345,6789.88", // { value | currency('short')}
"商品价格: ¥1,2345.678988万", // { value | currency('short',1)}
"商品价格: ¥1.2345678988亿", // { value | currency('short',2)}
"商品价格: ¥0.00012345678988万亿", // { value | currency('short',3)}
"商品价格: ¥0.000000012345678988万万亿", // { value | currency('short',4)}
// 自定义货币格式
"商品价格: RMB ¥¥1,2345,6789.88元",
"商品价格: 人民币: ¥¥1,2345,6789.88元",
"商品价格: 人民币: ¥¥1,2345,6789.88元整",
"商品价格: 人民币: ¥¥1.2345678988亿元整",
"商品价格: 人民币: ¥¥1.2346+亿元整",
"商品价格: 人民币:*¥¥*1.2346+*亿*元整"
]
const enMoneys = [
"Price: { value | currency }", // 默认格式
// long
"Price: { value | currency('long') }", // 长格式
"Price: { value | currency('long',1) }", // 长格式: 万元
"Price: { value | currency('long',2) }", // 长格式: 亿
"Price: { value | currency('long',3) }", // 长格式: 万亿
"Price: { value | currency('long',4) }", // 长格式: 万万亿
// short
"Price: { value | currency('short') }", // 短格式
"Price: { value | currency('short',1) }", // 短格式 Thousands
"Price: { value | currency('short',2) }", // 短格式 Millions
"Price: { value | currency('short',3) }", // 短格式 Billions
"Price: { value | currency('short',4) }", // 短格式 Trillions
]
const expectEnMoneys =[
"Price: $123,456,789.88", // { value | currency }
// long
"Price: USD $123,456,789.88", // { value | currency('long')}
"Price: USD $123,456.78988 thousands", // { value | currency('long',1)}
"Price: USD $123.45678988 millions", // { value | currency('long',2)}
"Price: USD $0.12345678988 billions", // { value | currency('long',3)}
"Price: USD $0.00012345678988 trillions", // { value | currency('long',4)}
// short
"Price: $123,456,789.88", // { value | currency('short')}
"Price: $123,456.78988 thousands", // { value | currency('short',1)}
"Price: $123.45678988 millions", // { value | currency('short',2)}
"Price: $0.12345678988 billions", // { value | currency('short',3)}
"Price: $0.00012345678988 trillions", // { value | currency('short',4)}
]
const loaders = {
zh:{
1:"你好",
2:"现在是{ value | }",
3:"我出生于{year}年,今年{age}岁",
4:"我有{}个朋友",
...toLanguageDict(zhDatetimes,5),
},
en :{
1:"hello",
2:"Now is {}",
3:"I was born in {year}, now is {age} years old",
4:["I have no friends","I have one friends","I have two friends","I have {} friends"],
...toLanguageDict(enDatetimes,5),
}
}
const formatters = {
zh:{
$config:{},
$types:{},
book:(v)=>`${v}`,
},
en:{
$config:{},
$types:{ },
book:(v)=>`<${v}>`,
},
}
const idMap = {
"你好":1,
"现在是{ value | }":2,
"我出生于{year}年,今年{age}岁":3,
"我有{}个朋友":4,
...toLanguageIdMap(zhDatetimes,5)
}
const languages = [
{ name: "zh", title: "中文" },
{ name: "en", title: "英文" },
{ name: "de", title: "德语" },
{ name: "jp", title: "日语" }
]
const scope = new i18nScope({
id : "test",
defaultLanguage: "zh",
activeLanguage : "zh",
namespaces : {},
default : loaders.zh, // 默认语言包
messages : loaders.zh, // 当前语言包
languages, // 语言配置
idMap, // 消息id映射列表
formatters, // 扩展自定义格式化器
loaders // 语言包加载器
})
const t = translate.bind(scope)
// 适用于所有语言的格式化器,并且注册到全局
scope.registerFormatters({
"*":{
sum : (v,n=1)=>v+n,
double: (v)=>v*2,
upper : (v)=>v.toUpperCase()
}
},true)
describe("翻译函数",()=>{
beforeEach(() => {
scope.change("zh")
});
test("获取翻译内容中的插值变量",done=>{
const results = getInterpolatedVars("中华人民共和国成立于{date | year(1,2) | time('a','b') | rel }年,首都是{city}市");
expect(results.length).toEqual(2);
//
expect(results[0].name).toEqual("date");
expect(results[0].formatters.length).toEqual(3);
// year(1,2)
expect(results[0].formatters[0].name).toEqual("year");
expect(results[0].formatters[0].args).toEqual([1,2]);
// time('a','b')
expect(results[0].formatters[1].name).toEqual("time");
expect(results[0].formatters[1].args).toEqual(["a","b"]);
// rel
expect(results[0].formatters[2].name).toEqual("rel");
expect(results[0].formatters[2].args).toEqual([]);
expect(results[1].name).toEqual("city");
expect(results[1].formatters.length).toEqual(0);
done()
})
test("获取翻译内容中定义了重复的插值变量",done=>{
const results = getInterpolatedVars("{a}{a}{a|x}{a|x}{a|x|y}{a|x|y}");
expect(results.length).toEqual(3);
expect(results[0].name).toEqual("a");
expect(results[0].formatters.length).toEqual(0);
expect(results[1].name).toEqual("a");
expect(results[1].formatters.length).toEqual(1);
expect(results[1].formatters[0].name).toEqual("x");
expect(results[1].formatters[0].args).toEqual([]);
expect(results[2].name).toEqual("a");
expect(results[2].formatters.length).toEqual(2);
expect(results[2].formatters[0].name).toEqual("x");
expect(results[2].formatters[0].args).toEqual([]);
expect(results[2].formatters[1].name).toEqual("y");
expect(results[2].formatters[1].args).toEqual([]);
done()
})
test("替换翻译内容的位置插值变量",done=>{
expect(t("{}{}{}",1,2,3)).toBe("123");
expect(t("{a}{b}{c}",1,2,3)).toBe("123");
// 定义了一些无效的格式化器,直接忽略
expect(t("{a|xxx}{b|dd}{c|}",1,2,3)).toBe("123");
expect(t("{a|xxx}{b|dd}{c|}",1,2,3,4,5,6)).toBe("123");
expect(t("{ a|}{b|dd}{c|}{}",1,2,3)).toBe("123{}");
// 中文状态下true和false被转换成中文的"是"和"否"
expect(t("{}{}{}",1,"2",true)).toBe("12是");
expect(t("{|double}{}{}",1,"2",true)).toBe("22是");
done()
})
test("替换翻译内容的命名插值变量",done=>{
expect(t("{a}{b}{c}",{a:11,b:22,c:33})).toBe("112233");
expect(t("{a}{b}{c}{a}{b}{c}",{a:1,b:"2",c:3})).toBe("123123");
done()
})
test("命名插值变量使用格式化器",done=>{
// 提供无效的格式化器,直接忽略
expect(t("{a|x}{b|x|y}{c|}",{a:1,b:2,c:3})).toBe("123");
expect(t("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126");
// padStart和trim格式化器只是字符串的原型方法不需要额外定义可以直接使用
expect(t("{a|padStart(10)}",{a:"123"})).toBe(" 123");
expect(t("{a|padStart(10)|trim}",{a:"123"})).toBe("123");
done()
})
test("命名插值变量使用格式化器",done=>{
// 提供无效的格式化器,直接忽略
expect(t("{a|x}{b|x|y}{c|}",{a:1,b:2,c:3})).toBe("123");
expect(t("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126");
// 默认的字符串格式化器,不需要定义使用字符串方法
expect(t("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126");
expect(t("{a|padStart(10)}",{a:"123"})).toBe(" 123");
expect(t("{a|padStart(10)|trim}",{a:"123"})).toBe("123");
done()
})
test("切换到其他语言时的自动匹配同名格式化器",async ()=>{
expect(t("{a}",{a:true})).toBe("是");
expect(t("{name|book}是毛泽东思想的重要载体","毛泽东选集")).toBe("《毛泽东选集》是毛泽东思想的重要载体");
await scope.change("en")
expect(t("{a}",{a:false})).toBe("False");
expect(t("{name|book}是毛泽东思想的重要载体","毛泽东选集")).toBe("<毛泽东选集>是毛泽东思想的重要载体");
})
test("位置插值翻译文本内容",async ()=>{
const now = new Date()
expect(t("你好")).toBe("你好");
expect(t("现在是{ value | }",now)).toBe(`现在是${dayjs(now).format('YYYY/M/D HH:mm:ss')}`);
// 经babel自动码换后文本内容会根据idMap自动转为id
expect(t("1")).toBe("你好");
expect(t("2",now)).toBe(`现在是${dayjs(now).format('YYYY/M/D HH:mm:ss')}`);
await scope.change("en")
expect(t("你好")).toBe("hello");
expect(t("现在是{ value | }",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`);
expect(t("1")).toBe("hello");
expect(t("2",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`);
})
test("命名插值翻译文本内容",async ()=>{
const now = new Date()
expect(t("你好")).toBe("你好");
expect(t("现在是{ value | }",now)).toBe(`现在是${dayjs(now).format('YYYY/M/D HH:mm:ss')}`);
await scope.change("en")
expect(t("你好")).toBe("hello");
expect(t("现在是{ value | }",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`);
// 使用idMap
expect(t("1")).toBe("hello");
expect(t("2",now)).toBe(`Now is ${dayjs(now).format('YYYY/M/D HH:mm:ss')}`);
})
test("当没有对应的语言翻译时,保持原始输出",async ()=>{
expect(t("我是中国人")).toBe("我是中国人");
await scope.change("en")
expect(t("我是中国人")).toBe("我是中国人");
})
test("切换到未知语言时回退到默认语言",async ()=>{
expect(t("我是中国人")).toBe("我是中国人");
expect(async ()=>await scope.change("xn")).rejects.toThrow(Error);
expect(t("我是中国人")).toBe("我是中国人");
})
test("翻译复数支持",async ()=>{
await scope.change("en")
expect(t("我有{}个朋友",0)).toBe("I have no friends");
expect(t("我有{}个朋友",1)).toBe("I have one friends");
expect(t("我有{}个朋友",2)).toBe("I have two friends");
expect(t("我有{}个朋友",3)).toBe("I have 3 friends");
expect(t("我有{}个朋友",4)).toBe("I have 4 friends");
})
test("日期时间格式化器",async ()=>{
let zhTranslatedResults = zhDatetimes.map(v=>t(v,NOW))
expect(zhTranslatedResults).toStrictEqual(expectZhDatetimes)
await scope.change("en")
let enTranslatedResults = zhDatetimes.map(v=>t(v,NOW))
expect(enTranslatedResults).toStrictEqual(expectEnDatetimes)
})
test("货币格式化器",async ()=>{
let zhMoneysResults = zhMoneys.map(v=>t(v,MONEY))
expect(zhMoneysResults).toStrictEqual(expectZhMoneys)
await scope.change("en")
let enMoneysResults = enMoneys.map(v=>t(v,MONEY))
expect(enMoneysResults).toStrictEqual(expectEnMoneys)
})
})

View File

@ -7,9 +7,9 @@ const { isNumber } = require('./utils')
const CN_DATETIME_UNITS = ["年","季度","月","周","日","小时","分钟","秒","毫秒","微秒"]
const CN_WEEK_DAYS = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"]
const CN_SHORT_WEEK_DAYS =["日","一","二","三","四","五","六"]
const CN_SHORT_WEEK_DAYS =["日","一","二","三","四","五","六"]
const CN_MONTH_NAMES= ["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"]
const CN_SHORT_MONTH_NAMES = ["一","二","三","四","五","六","七","八","九","十","十一","十二"]
const CN_SHORT_MONTH_NAMES = ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"]
const CN_NUMBER_DIGITS = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
const CN_NUMBER_UNITS = ['', '十', '百', '千', '万', '十', '百', '千', '亿', '十', '百', '千', '兆', '十', '百', '千', '京', '十', '百', '千', '垓']

View File

@ -83,6 +83,8 @@ empty.paramCount = 2
{ value | error('ERROR:{ error}',) } == 显示error.constructor.name
* @param {*} value
* @param {*} escapeValue
* @param {*} next 下一步的行为取值break,ignore

View File

@ -3,118 +3,221 @@
*
*/
const { toDate,toCurrency,toNumber,isPlainObject,formatDatetime,formatTime } = require("../utils")
const { toDate,toCurrency,toNumber,isFunction,isPlainObject,formatDatetime,formatTime } = require("../utils")
const { Formatter } = require("../formatter")
/**
* 该类型的格式化器具有以下特点
*
* 1. 接受一个format参数
* 2. format参数取值可以是若干预设的值如long,short等也可能是一个模板字符串
* 3. 当format值时如果定义在$config[configKey]里面代表了$config[configKey][format]是一个模板字符串
* 4. 如果!(format in $config[configKey])则代表format值是一个模板字符串
* 5. 如果format in presets, 则要求presets[format ]是一个(value)=>{....}直接返回
*
**/
function createDateTimeFormatter(options={},transformer){
let opts = Object.assign({presets:{}},options)
return Formatter((value,format,$config)=>{
if((format in opts.presets) && isFunction(opts.presets[format])){
return opts.presets[format](value)
}else if((format in $config)){
format = $config[format]
}else if(format == "number"){
return value
}
try{
return format==null ? value : transformer(value,format)
}catch(e){
return value
}
},opts)
}
/**
* 日期格式化器
* format取值
* 0-local,1-long,2-short,3-iso,4-gmt,5-UTC
* 或者日期模板字符串
* 默认值是local
* - format取值local,long,short,iso,gmt,utc,<模板字符串>
* - 默认值由$config.datetime.date.format指定
*/
const dateFormatter = Formatter((value,format,$config)=>{
const optionals = ["local","long","short","iso","gmt","utc"]
// 处理参数:同时支持大小写名称和数字
const optionIndex = optionals.findIndex((v,i)=>{
if(typeof(format)=="string"){
return v==format || v== format.toUpperCase()
}else if(typeof(format)=="number"){
return format === i
}
})
switch(optionIndex){
case 0: // local
return value.toLocaleString()
case 1: // long
return formatDatetime(value,$config.long)
case 2: // short
return formatDatetime(value,$config.short)
case 3: // ISO
return value.toISOString()
case 4: // GMT
return value.toGMTString()
case 5: // UTC
return value.toUTCString()
default:
return formatDatetime(value,format)
}
},{
normalize: toDate, // 转换输入为Date类型
params : ['format'],
configKey: "datetime.date"
})
// 季度格式化器 format= 0=短格式 1=长格式 1=数字
const quarterFormatter = Formatter((value,format,$config)=>{
const month = value.getMonth() + 1
const quarter = Math.floor( ( month % 3 == 0 ? ( month / 3 ) : (month / 3 + 1 ) ))
if(typeof(format)==='string'){
format = ['short','long','number'].indexOf(format)
const dateFormatter = createDateTimeFormatter({
normalize: toDate,
params : ["format"],
configKey: "datetime.date",
presets : {
local: value=>value.toLocaleString(),
iso : value=>value.toISOString(),
utc : value=>value.toUTCString(),
gmt : value=>value.toGMTString()
}
if(format<0 && format>2) format = 0
return format==0 ? $config.short[quarter] : (format==1 ? $config.long[quarter] : quarter)
},{
normalize: toDate,
params : ['format'],
},formatDatetime)
/**
* 季度格式化器
* - format: long,short,number
* - 默认值是 short
*/
const quarterFormatter = createDateTimeFormatter({
normalize : value=>{
const month = value.getMonth() + 1
return Math.floor( ( month % 3 == 0 ? ( month / 3 ) : (month / 3 + 1 ) ))
},
params : ["format"],
configKey: "datetime.quarter"
})
},(quarter,format)=>format[quarter-1])
// 月份格式化器 format可以取值0,1,2也可以取字符串long,short,number
const monthFormatter = Formatter((value,format,$config)=>{
const month = value.getMonth()
if(typeof(format)==='string'){
format = ['long','short','number'].indexOf(format)
}
if(format<0 && format>2) format = 0
return format==0 ? $config.long[month] : (format==1 ? $config.short[month] : month+1)
},{
normalize: toDate,
params : ['format'],
/**
* 月份格式化器
* - format: long,short,number
* - 默认值是 short
*/
const monthFormatter = createDateTimeFormatter({
normalize: value=> value.getMonth() + 1,
params : ["format"],
configKey: "datetime.month"
})
},(month,format)=>format[month-1])
// 星期x格式化器 format可以取值0,1,2也可以取字符串long,short,number
const weekdayFormatter = Formatter((value,format,$config)=>{
const day = value.getDay()
if(typeof(format)==='string'){
format = ['long','short','number'].indexOf(format)
}
if(format<0 && format>2) format = 0
return format==0 ? $config.long[day] : (format==1 ? $config.short[day] : day)
},{
normalize: toDate,
params : ['format'],
/**
* 周格式化器
* - format: long,short,number
* - 默认值是 long
*/
const weekdayFormatter = createDateTimeFormatter({
normalize: value=> value.getDay(),
params : ["format"],
configKey: "datetime.weekday"
})
},(day,format)=>format[day])
/**
* 时间格式化器
* - format取值local,long,short,timestamp,<模板字符串>
* - 默认值由$config.datetime.time.format指定
*/
const timeFormatter = createDateTimeFormatter({
normalize : toDate,
params : ["format"],
configKey : "datetime.time",
presets : {
local : value=>value.toLocaleTimeString(),
timestamp: value=>value.getTime()
}
},formatTime)
// 时间格式化器 format可以取值0-local(默认),1-long,2-short,3-timestamp,也可以是一个插值表达式
const timeFormatter = Formatter((value,format,$config)=>{
const optionals = ['local','long','short','timestamp']
const optionIndex = optionals.findIndex((v,i)=>{
if(typeof(format)=="string"){
return v==format || v== format.toUpperCase()
}else if(typeof(format)=="number"){
return format === i
}
})
switch(optionIndex){
case 0: // local : toLocaleTimeString
return value.toLocaleTimeString()
case 1: // long
return formatTime(value,$config.long)
case 2: // short
return formatTime(value,$config.short)
case 3: // timestamp
return value.getTime()
default:
return formatTime(value,format)
}
},{
normalize: toDate,
params : ['format'],
configKey: "datetime.time"
})
// const dateFormatter = Formatter((value,format,$config)=>{
// const optionals = ["local","long","short","iso","gmt","utc"]
// // 处理参数:同时支持大小写名称和数字
// const optionIndex = optionals.findIndex((v,i)=>{
// if(typeof(format)=="string"){
// return v==format || v== format.toUpperCase()
// }else if(typeof(format)=="number"){
// return format === i
// }
// })
// // format名称不是optionals中的一个并且被配置在$config则视为扩展预设值
// if(optionIndex==-1 && typeof(format)=="string" && (format in $config)){
// format = $config[format]
// }
// switch(optionIndex){
// case 0: // local
// return value.toLocaleString()
// case 1: // long
// return formatDatetime(value,$config.long)
// case 2: // short
// return formatDatetime(value,$config.short)
// case 3: // ISO
// return value.toISOString()
// case 4: // GMT
// return value.toGMTString()
// case 5: // UTC
// return value.toUTCString()
// default:
// return formatDatetime(value,format)
// }
// },{
// normalize: toDate, // 转换输入为Date类型
// params : ['format'],
// configKey: "datetime.date"
// })
// // 季度格式化器 format= 0=短格式 1=长格式 1=数字
// const quarterFormatter = Formatter((value,format,$config)=>{
// const month = value.getMonth() + 1
// const quarter = Math.floor( ( month % 3 == 0 ? ( month / 3 ) : (month / 3 + 1 ) ))
// if(typeof(format)==='string'){
// format = ['short','long','number'].indexOf(format)
// }
// if(format<0 && format>2) format = 0
// return format==0 ? $config.short[quarter] : (format==1 ? $config.long[quarter] : quarter)
// },{
// normalize: toDate,
// params : ['format'],
// configKey: "datetime.quarter"
// })
// // 月份格式化器 format可以取值0,1,2也可以取字符串long,short,number
// const monthFormatter = Formatter((value,format,$config)=>{
// const month = value.getMonth()
// if(typeof(format)==='string'){
// format = ['long','short','number'].indexOf(format)
// }
// if(format<0 && format>2) format = 0
// return format==0 ? $config.long[month] : (format==1 ? $config.short[month] : month+1)
// },{
// normalize: toDate,
// params : ['format'],
// configKey: "datetime.month"
// })
// // 星期x格式化器 format可以取值0,1,2也可以取字符串long,short,number
// const weekdayFormatter = Formatter((value,format,$config)=>{
// const day = value.getDay()
// if(typeof(format)==='string'){
// format = ['long','short','number'].indexOf(format)
// }
// if(format<0 && format>2) format = 0
// return format==0 ? $config.long[day] : (format==1 ? $config.short[day] : day)
// },{
// normalize: toDate,
// params : ['format'],
// configKey: "datetime.weekday"
// })
// // 时间格式化器 format可以取值0-local(默认),1-long,2-short,3-timestamp,也可以是一个插值表达式
// const timeFormatter = Formatter((value,format,$config)=>{
// const optionals = ['local','long','short','timestamp']
// const optionIndex = optionals.findIndex((v,i)=>{
// if(typeof(format)=="string"){
// return v==format || v== format.toUpperCase()
// }else if(typeof(format)=="number"){
// return format === i
// }
// })
// // format名称不是optionals中的一个并且被配置在$config则视为扩展预设值
// if(optionIndex==-1 && typeof(format)=="string" && (format in $config)){
// format = $config[format]
// }
// switch(optionIndex){
// case 0: // local : toLocaleTimeString
// return value.toLocaleTimeString()
// case 1: // long
// return formatTime(value,$config.long)
// case 2: // short
// return formatTime(value,$config.short)
// case 3: // timestamp
// return value.getTime()
// default:
// return formatTime(value,format)
// }
// },{
// normalize: toDate,
// params : ['format'],
// configKey: "datetime.time"
// })
// 货币格式化器, CNY $13,456.00
/**
@ -175,7 +278,6 @@ const currencyFormatter = Formatter((value,...args) =>{
})
module.exports = {
// 配置参数
$config:{
@ -194,18 +296,23 @@ module.exports = {
month:{
long : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
short : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"],
format : 0 // 0-长名称1-短名称2-数字
format : "long" // 0-长名称1-短名称2-数字
},
weekday:{
long : ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
short : ["Sun", "Mon", "Tues", "Wed", "Thur", "Fri", "Sat"],
format : 0, // 0-长名称1-短名称2-数字
format : "long", // 0-长名称1-短名称2-数字
},
time : {
long : "HH:mm:ss",
short : "HH:mm:ss",
format : 'local'
},
},
timeslots : {
slots : [12],
lowercase : ["AM","PM"]
uppercase : ["AM","PM"]
}
},
currency : {
default : "{symbol}{value}{unit}",
@ -254,19 +361,12 @@ module.exports = {
// 以下是格式化定义
// ******************* 日期 *******************
date : dateFormatter,
time : timeFormatter,
year : value => toDate(value).getFullYear(),
quarter : quarterFormatter,
month : monthFormatter,
weekday : weekdayFormatter,
day : value => toDate(value).getDate(),
// ******************* 时间 *******************
hour : value => toDate(value).getHours(),
hour12 : value => {const hour = toDate(value).getHours(); return hour > 12 ? hour - 12 : thour},
minute : value => toDate(value).getMinutes(),
second : value => toDate(value).getSeconds(),
millisecond : value => toDate(value).getMilliseconds(),
timestamp : value => toDate(value).getTime(),
time : timeFormatter,
// ******************* 货币 *******************
currency : currencyFormatter,
// 数字,如,使用分割符

View File

@ -22,19 +22,23 @@ module.exports = {
format : "short" // 0-短格式,1-长格式,2-数字
},
month:{
long : CN_MONTH_NAMES,
long : CN_MONTH_NAMES,
short : CN_SHORT_MONTH_NAMES,
format : 0, // 0-长名称1-短名称2-数字
format : "long", // 0-长名称1-短名称2-数字
},
weekday:{
short : CN_WEEK_DAYS,
long : CN_SHORT_WEEK_DAYS,
format : 0, // 0-长名称1-短名称2-数字
long : CN_WEEK_DAYS,
short : CN_SHORT_WEEK_DAYS,
format : "long", // 0-长名称1-短名称2-数字
},
time:{
long : "HH点mm分ss秒",
short : "HH:mm:ss",
format : 'local'
},
timeslots : {
slots : [6,9,11,13,18],
long : ["凌晨","早上","上午","中午","下午","晚上"]
}
},

View File

@ -1,4 +1,4 @@
const {getDataTypeName,isNumber,isPlainObject,isFunction,isNothing,deepMerge,deepMixin} = require("./utils")
const {DataTypes,getDataTypeName,isNumber,isPlainObject,isFunction,isNothing,deepMerge,deepMixin} = require("./utils")
const {getInterpolatedVars,replaceInterpolatedVars} = require("./interpolate")
const {createFormatter,Formatter} = require("./formatter")
const EventEmitter = require("./eventemitter")
@ -7,8 +7,6 @@ const i18nScope = require("./scope")
const { translate } = require("./translate")
const DataTypes = ["String","Number","Boolean","Object","Array","Function","Error","Symbol","RegExp","Date","Null","Undefined","Set","Map","WeakSet","WeakMap"]
// 默认语言配置
const defaultLanguageSettings = {
debug : true,

View File

@ -1,19 +1,4 @@
const { isPlainObject, isFunction, getByPath, deepMixin,deepClone } = require("./utils");
const DataTypes = [
"String",
"Number",
"Boolean",
"Object",
"Array",
"Function",
"Null",
"Undefined",
"Symbol",
"Date",
"RegExp",
"Error",
];
const { DataTypes,isPlainObject, isFunction, getByPath, deepMixin,deepClone } = require("./utils");
module.exports = class i18nScope {
constructor(options = {}, callback) {

View File

@ -128,7 +128,7 @@ function toDate(value) {
try {
return value instanceof Date ? value : new Date(value)
} catch {
return value
return parseInt(value)
}
}
/**
@ -281,10 +281,10 @@ function formatDatetime(value,templ="YYYY/MM/DD HH:mm:ss"){
["M", month], // 1-12 月从1开始
["DD", day.padStart(2, "0")], // 01-31 日,两位数
["D", day], // 1-31 日
["HH", hour.padStart(2, "0")], // 00-23 24小时两位数
["H", hour], // 0-23 24小时
["HH", hour.padStart(2, "0")], // 00-23 24小时两位数
["H", hour], // 0-23 24小时
["hh", String(hourNum > 12 ? hourNum - 12 : hourNum).padStart(2, "0")], // 01-12 12小时两位数
["h", String(hourNum > 12 ? hourNum - 12 : hourNum)], // 1-12 12小时
["h", String(hourNum > 12 ? hourNum - 12 : hourNum)], // 1-12 12小时
["mm", minute.padStart(2, "0")], // 00-59 分钟,两位数
["m", minute], // 0-59 分钟
["ss", second.padStart(2, "0")], // 00-59 秒,两位数
@ -304,8 +304,8 @@ function formatTime(value,templ="HH:mm:ss"){
const hour = String(hourNum),minute = String(v.getMinutes()),second = String(v.getSeconds()),millisecond=String(v.getMilliseconds())
let result = templ
const vars = [
["HH", hour.padStart(2, "0")], // 00-23 24小时两位数
["H", hour], // 0-23 24小时
["HH", hour.padStart(2, "0")], // 00-23 24小时两位数
["H", hour], // 0-23 24小时
["hh", String(hour > 12 ? hour - 12 : hour).padStart(2, "0")], // 01-12 12小时两位数
["h", String(hour > 12 ? hour - 12 : hour)], // 1-12 12小时
["mm", minute.padStart(2, "0")], // 00-59 分钟,两位数
@ -322,21 +322,16 @@ function formatTime(value,templ="HH:mm:ss"){
/**
* 替换所有字符串
* 低版本ES未提供replaceAll,此函数用来替代
*
*
* @param {*} str
* @param {*} findValue
* @param {*} replaceValue
*/
function replaceAll(str,findValue,replaceValue){
if(typeof(str)!=="string" || findValue=="" || findValue==replaceValue) return str
let result = str
try{
while(result.includes(findValue)){
result = result.replace(findValue,replaceValue)
}
return str.replace(new RegExp(escapeRegexpStr(findValue),"g"),replaceValue)
}catch{}
return result
return str
}
/**
* 使用正则表达式解析非标JOSN
@ -387,8 +382,10 @@ function safeParseJson(str){
}
return JSON.parse(str)
}
const DataTypes = ["String","Number","Boolean","Object","Array","Function","Error","Symbol","RegExp","Date","Null","Undefined","Set","Map","WeakSet","WeakMap"]
module.exports ={
DataTypes,
isPlainObject,
isFunction,
isNumber,

2
pnpm-lock.yaml generated
View File

@ -13,7 +13,7 @@ importers:
cross-env: ^7.0.3
dayjs: ^1.11.0
deepmerge: ^4.2.2
dumi: ^1.0.13
dumi: ^1.1.47
fs-extra: ^10.0.1
gulp: ^4.0.2
inquirer: ^8.2.2

View File

@ -34,12 +34,6 @@ const zhDatetimes =[
"现在是{ value | date('iso') }",
"现在是{ value | date('gmt') }",
"现在是{ value | date('utc') }",
"现在是{ value | date(0) }", // local
"现在是{ value | date(1) }", // long
"现在是{ value | date(2) }", // short
"现在是{ value | date(3) }", // iso
"现在是{ value | date(4) }", // gmt
"现在是{ value | date(5) }", // utc
"现在是{ value | date('YYYY-MM-DD HH:mm:ss')}",
"现在是{ value | date('YYYY-MM-DD')}",
"现在是{ value | date('HH:mm:ss')}",
@ -47,26 +41,21 @@ const zhDatetimes =[
"现在是{ value | month('long')}",
"现在是{ value | month('short')}",
"现在是{ value | month('number')}",
"现在是{ value | month(0)}",
"现在是{ value | month(1)}",
"现在是{ value | month(2)}",
"现在是{ value | weekday }",
"现在是{ value | weekday('long')}",
"现在是{ value | weekday('short')}",
"现在是{ value | weekday('number')}",
"现在是{ value | weekday(0)}",
"现在是{ value | weekday(1)}",
"现在是{ value | weekday(2)}",
"现在是{ value | quarter }",
"现在是{ value | quarter('long')}",
"现在是{ value | quarter('short')}",
"现在是{ value | quarter('number')}",
// 时间
"现在时间 - { value | time }",
"现在时间 - { value | time('local') }",
"现在时间 - { value | time('long') }",
"现在时间 - { value | time('short') }",
"现在时间 - { value | time('timestamp') }",
"现在时间 - { value | time(0) }",
"现在时间 - { value | time(1) }",
"现在时间 - { value | time(2) }",
"现在时间 - { value | time(3) }",
"现在时间 - { value | time('HH:mm:ss') }",
"现在时间 - { value | time('mm:ss') }",
"现在时间 - { value | time('ss') }"
@ -82,39 +71,28 @@ const expectZhDatetimes =[
`现在是${NOW.toISOString()}`, // { value | date('iso') }
`现在是${NOW.toGMTString()}`, // { value | date('gmt') }
`现在是${NOW.toUTCString()}`, // { value | date('utc') }
`现在是${NOW.toLocaleString()}`, // { value | date(0) } // local
"现在是2022年08月12日 10点12分36秒", // { value | date(1) } // long
"现在是2022/08/12", // { value | date(2) } // short
`现在是${NOW.toISOString()}`, // { value | date(3) } // iso
`现在是${NOW.toGMTString()}`, // { value | date(4) } // gmt
`现在是${NOW.toUTCString()}`, // { value | date(5) } // utc
"现在是2022-08-12 10:12:36", // { value | date('YYYY-MM-DD HH:mm:ss')}
"现在是2022-08-12", // { value | date('YYYY-MM-DD')}
"现在是10:12:36", // { value | date('HH:mm:ss')}
"现在是八月", // { value | month }
"现在是八月", // { value | month('long')}
"现在是八", // { value | month('short')}
"现在是8月", // { value | month('short')}
"现在是8", // { value | month('number')}
"现在是八月", // { value | month(0)}
"现在是八", // { value | month(1)}
"现在是8", // { value | month(2)}
"现在是星期五", // { value | weekday }
"现在是星期五", // { value | weekday('long')}
"现在是五", // { value | weekday('short')}
"现在是周五", // { value | weekday('short')}
"现在是5", // { value | weekday('number')}
"现在是星期五", // { value | weekday(0)}
"现在是五", // { value | weekday(1)}
"现在是5", // { value | weekday(2)}
"现在是Q3", // { value | quarter }
"现在是三季度", // { value | quarter('long')}
"现在是Q3", // { value | quarter('short')}
"现在是3", // { value | quarter('number')}
// 时间
`现在时间 - ${NOW.toLocaleTimeString()}`, // { value | time }
`现在时间 - ${NOW.toLocaleTimeString()}`, // { value | time('local') }
"现在时间 - 10点12分36秒", // { value | time('long') }
"现在时间 - 10:12:36", // { value | time('short') }
"现在时间 - 1660270356000", // { value | time('timestamp') }
`现在时间 - ${NOW.toLocaleTimeString()}`, // { value | time(0) }
"现在时间 - 10点12分36秒", // { value | time(1) }
"现在时间 - 10:12:36", // { value | time(2) }
"现在时间 - 1660270356000", // { value | time(3) }
"现在时间 - 10:12:36", // { value | time('HH:mm:ss') }
"现在时间 - 12:36", // { value | time('mm:ss') }
"现在时间 - 36", // { value | time('ss') }"
@ -130,12 +108,6 @@ const enDatetimes =[
"Now is { value | date('iso') }",
"Now is { value | date('gmt') }",
"Now is { value | date('utc') }",
"Now is { value | date(0) }", // local
"Now is { value | date(1) }", // long
"Now is { value | date(2) }", // short
"Now is { value | date(3) }", // iso
"Now is { value | date(4) }", // gmt
"Now is { value | date(5) }", // utc
"Now is { value | date('YYYY-MM-DD HH:mm:ss')}",
"Now is { value | date('YYYY-MM-DD')}",
"Now is { value | date('HH:mm:ss')}",
@ -143,26 +115,20 @@ const enDatetimes =[
"Now is { value | month('long')}",
"Now is { value | month('short')}",
"Now is { value | month('number')}",
"Now is { value | month(0)}",
"Now is { value | month(1)}",
"Now is { value | month(2)}",
"Now is { value | weekday }",
"Now is { value | weekday('long')}",
"Now is { value | weekday('short')}",
"Now is { value | weekday('number')}",
"Now is { value | weekday(0)}",
"Now is { value | weekday(1)}",
"Now is { value | weekday(2)}",
"Now is { value | quarter }",
"Now is { value | quarter('long')}",
"Now is { value | quarter('short')}",
"Now is { value | quarter('number')}",
// 时间
"Now time: { value | time }",
"Now time: { value | time('local') }",
"Now time: { value | time('long') }",
"Now time: { value | time('short') }",
"Now time: { value | time('timestamp') }",
"Now time: { value | time(0) }",
"Now time: { value | time(1) }",
"Now time: { value | time(2) }",
"Now time: { value | time(3) }",
"Now time: { value | time('HH:mm:ss') }",
"Now time: { value | time('mm:ss') }",
"Now time: { value | time('ss') }"
@ -177,12 +143,6 @@ const expectEnDatetimes =[
`Now is ${NOW.toISOString()}`, // { value | date('iso') }
`Now is ${NOW.toGMTString()}`, // { value | date('gmt') }
`Now is ${NOW.toUTCString()}`, // { value | date('utc') }
`Now is ${NOW.toLocaleString()}`, // { value | date(0) } // local
"Now is 2022/08/12 10:12:36", // { value | date(1) } // long
"Now is 2022/08/12", // { value | date(2) } // short
`Now is ${NOW.toISOString()}`, // { value | date(3) } // iso
`Now is ${NOW.toGMTString()}`, // { value | date(4) } // gmt
`Now is ${NOW.toUTCString()}`, // { value | date(5) } // utc
"Now is 2022-08-12 10:12:36", // { value | date('YYYY-MM-DD HH:mm:ss')}
"Now is 2022-08-12", // { value | date('YYYY-MM-DD')}
"Now is 10:12:36", // { value | date('HH:mm:ss')}
@ -190,26 +150,22 @@ const expectEnDatetimes =[
"Now is August", // { value | month('long')}
"Now is Aug", // { value | month('short')}
"Now is 8", // { value | month('number')}
"Now is August", // { value | month(0)}
"Now is Aug", // { value | month(1)}
"Now is 8", // { value | month(2)}
"Now is Friday", // { value | weekday }
"Now is Friday", // { value | weekday('long')}
"Now is Fri", // { value | weekday('short')}
"Now is 5", // { value | weekday('number')}
"Now is Friday", // { value | weekday(0)}
"Now is Fri", // { value | weekday(1)}
"Now is 5", // { value | weekday(2)}
"Now is Q3", // { value | quarter }
"Now is Third Quarter", // { value | quarter('long')}
"Now is Q3", // { value | quarter('short')}
"Now is 3", // { value | quarter('number')}
// 时间
`Now time: ${NOW.toLocaleTimeString()}`, // { value | time }
`Now time: ${NOW.toLocaleTimeString()}`, // { value | time('local') }
"Now time: 10:12:36", // { value | time('long') }
"Now time: 10:12:36", // { value | time('short') }
"Now time: 1660270356000", // { value | time('timestamp') }
`Now time: ${NOW.toLocaleTimeString()}`, // { value | time(0) }
"Now time: 10:12:36", // { value | time(1) }
"Now time: 10:12:36", // { value | time(2) }
"Now time: 1660270356000", // { value | time(3) }
"Now time: 10:12:36", // { value | time('HH:mm:ss') }
"Now time: 12:36", // { value | time('mm:ss') }
"Now time: 36", // { value | time('ss') }"
@ -393,7 +349,6 @@ test("获取翻译内容中的插值变量",done=>{
expect(results[0].formatters[2].name).toEqual("rel");
expect(results[0].formatters[2].args).toEqual([]);
expect(results[1].name).toEqual("city");
expect(results[1].formatters.length).toEqual(0);
@ -526,8 +481,7 @@ test("翻译复数支持",async ()=>{
expect(t("我有{}个朋友",3)).toBe("I have 3 friends");
expect(t("我有{}个朋友",4)).toBe("I have 4 friends");
})
test("日期时间格式化器",async ()=>{
test("日期时间格式化器",async ()=>{
let zhTranslatedResults = zhDatetimes.map(v=>t(v,NOW))
expect(zhTranslatedResults).toStrictEqual(expectZhDatetimes)
await scope.change("en")