Singleton之我见(二)
在国际化软件的时间日期格式方面,我们耳熟能详的有Moment,GlobalizeJS等,那么Singleton又是如何解决该问题呢?
宏观上看,Singleton并没有使用嵌入源码的lib模式,而是提供了两个service(目前共发布了两个版本的API,v1做出初始版本已基本被弃用,v2经过与多个产品磨合后,成为了包含类型最多并且较接近Restful API风格的一版,本文所有效果都基于后者)。
Singleton的格式API,已经覆盖的国际化关注点包括了日期时间、数字、货币、计量单位、单复数,主要API包括以下两个。
第一个API通过语言+地区返回请求类型的模式数据。
GET /i18n/api/v2/formatting/patterns
请求参数包括:
language: (必填)string类型,请求模式的语言,例如en、en-CA、zh-Hans等(已对zh-CN进行了扩展,效果等同于zh-Hans)
region: (必填)string类型,请求模式的区域;例如US、CN等
scope: (必填)string类型,请求模式的类型,选项为“dates,numbers,currencies,plurals,measurements” 其中的一个或多个。若需要同时请求多个,需要以半角逗号(,)分隔。
返回值:(JSON对象)返回对应请求类型的模式数据。
以简体中文为例,做下列请求。
https://XXX/i18n/api/v2/formatting/patterns?language=zh-CN®ion=CN&scope=dates
返回结果如下。
{
"response": {
"code": 200,
"message": "OK",
"serverTime": ""
},
"signature": "",
"data": {
"localeID": "zh-Hans",
"language": "zh-CN",
"region": "CN",
"categories": {
"dates": {
"dayPeriodsFormat": {
"narrow": [
"上午",
"下午"
],
"abbreviated": [
"上午",
"下午"
],
"wide": [
"上午",
"下午"
]
},
"dayPeriodsStandalone": {
"narrow": [
"上午",
"下午"
],
"abbreviated": [
"上午",
"下午"
],
"wide": [
"上午",
"下午"
]
},
"daysFormat": {
"narrow": [
"日",
"一",
"二",
"三",
"四",
"五",
"六"
],
"abbreviated": [
"周日",
"周一",
"周二",
"周三",
"周四",
"周五",
"周六"
],
"wide": [
"星期日",
"星期一",
"星期二",
"星期三",
"星期四",
"星期五",
"星期六"
],
"short": [
"周日",
"周一",
"周二",
"周三",
"周四",
"周五",
"周六"
]
},
"daysStandalone": {
"narrow": [
"日",
"一",
"二",
"三",
"四",
"五",
"六"
],
"abbreviated": [
"周日",
"周一",
"周二",
"周三",
"周四",
"周五",
"周六"
],
"wide": [
"星期日",
"星期一",
"星期二",
"星期三",
"星期四",
"星期五",
"星期六"
],
"short": [
"周日",
"周一",
"周二",
"周三",
"周四",
"周五",
"周六"
]
},
"monthsFormat": {
"narrow": [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12"
],
"abbreviated": [
"1月",
"2月",
"3月",
"4月",
"5月",
"6月",
"7月",
"8月",
"9月",
"10月",
"11月",
"12月"
],
"wide": [
"一月",
"二月",
"三月",
"四月",
"五月",
"六月",
"七月",
"八月",
"九月",
"十月",
"十一月",
"十二月"
]
},
"monthsStandalone": {
"narrow": [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"11",
"12"
],
"abbreviated": [
"1月",
"2月",
"3月",
"4月",
"5月",
"6月",
"7月",
"8月",
"9月",
"10月",
"11月",
"12月"
],
"wide": [
"一月",
"二月",
"三月",
"四月",
"五月",
"六月",
"七月",
"八月",
"九月",
"十月",
"十一月",
"十二月"
]
},
"eras": {
"narrow": [
"公元前",
"公元"
],
"abbreviated": [
"公元前",
"公元"
],
"wide": [
"公元前",
"公元"
]
},
"firstDayOfWeek": 0,
"weekendRange": [
6,
0
],
"dateFormats": {
"short": "y/M/d",
"medium": "y年M月d日",
"long": "y年M月d日",
"full": "y年M月d日EEEE"
},
"timeFormats": {
"short": "ah:mm",
"medium": "ah:mm:ss",
"long": "z ah:mm:ss",
"full": "zzzz ah:mm:ss"
},
"dateTimeFormats": {
"short": "{1} {0}",
"medium": "{1} {0}",
"long": "{1} {0}",
"full": "{1} {0}",
"availableFormats": {
"Bh": "Bh时",
"Bhm": "Bh:mm",
"Bhms": "Bh:mm:ss",
"d": "d日",
"E": "ccc",
"EBhm": "EBh:mm",
"EBhms": "EBh:mm:ss",
"Ed": "d日E",
"Ehm": "Eah:mm",
"EHm": "EHH:mm",
"Ehms": "Eah:mm:ss",
"EHms": "EHH:mm:ss",
"Gy": "Gy年",
"GyMMM": "Gy年M月",
"GyMMMd": "Gy年M月d日",
"GyMMMEd": "Gy年M月d日E",
"H": "H时",
"h": "ah时",
"hm": "ah:mm",
"Hm": "HH:mm",
"hms": "ah:mm:ss",
"Hms": "HH:mm:ss",
"hmsv": "v ah:mm:ss",
"Hmsv": "v HH:mm:ss",
"hmv": "v ah:mm",
"Hmv": "v HH:mm",
"M": "M月",
"Md": "M/d",
"MEd": "M/dE",
"MMdd": "MM/dd",
"MMM": "LLL",
"MMMd": "M月d日",
"MMMEd": "M月d日E",
"MMMMd": "M月d日",
"MMMMW-count-other": "MMM第W周",
"ms": "mm:ss",
"y": "y年",
"yM": "y年M月",
"yMd": "y/M/d",
"yMEd": "y/M/dE",
"yMM": "y年M月",
"yMMM": "y年M月",
"yMMMd": "y年M月d日",
"yMMMEd": "y年M月d日E",
"yMMMM": "y年M月",
"yQQQ": "y年第Q季度",
"yQQQQ": "y年第Q季度",
"yw-count-other": "Y年第w周"
},
"appendItems": {
"Day": "{0} ({2}: {1})",
"Day-Of-Week": "{0} {1}",
"Era": "{1} {0}",
"Hour": "{0} ({2}: {1})",
"Minute": "{0} ({2}: {1})",
"Month": "{0} ({2}: {1})",
"Quarter": "{0} ({2}: {1})",
"Second": "{0} ({2}: {1})",
"Timezone": "{1}{0}",
"Week": "{0} ({2}: {1})",
"Year": "{1} {0}"
},
"intervalFormats": {
"d": {
"d": "d–d日"
},
"h": {
"a": "ah时至ah时",
"h": "ah时至h时"
},
"H": {
"H": "HH–HH"
},
"hm": {
"a": "ah:mm至ah:mm",
"h": "ah:mm至h:mm",
"m": "ah:mm至h:mm"
},
"Hm": {
"H": "HH:mm–HH:mm",
"m": "HH:mm–HH:mm"
},
"hmv": {
"a": "vah:mm至ah:mm",
"h": "vah:mm至h:mm",
"m": "vah:mm至h:mm"
},
"Hmv": {
"H": "v HH:mm–HH:mm",
"m": "v HH:mm–HH:mm"
},
"hv": {
"a": "vah时至ah时",
"h": "vah时至h时"
},
"Hv": {
"H": "v HH–HH"
},
"intervalFormatFallback": "{0} – {1}",
"M": {
"M": "M–M月"
},
"Md": {
"d": "M/d – M/d",
"M": "M/d – M/d"
},
"MEd": {
"d": "M/dE至M/dE",
"M": "M/dE至M/dE"
},
"MMM": {
"M": "MMM – MMM"
},
"MMMd": {
"d": "M月d日至d日",
"M": "M月d日至M月d日"
},
"MMMEd": {
"d": "M月d日E至d日E",
"M": "M月d日E至M月d日E"
},
"y": {
"y": "y–y年"
},
"yM": {
"y": "y年M月至y年M月",
"M": "y年M月至M月"
},
"yMd": {
"d": "y/M/d – y/M/d",
"y": "y/M/d – y/M/d",
"M": "y/M/d – y/M/d"
},
"yMEd": {
"d": "y/M/dE至y/M/dE",
"y": "y/M/dE至y/M/dE",
"M": "y/M/dE至y/M/dE"
},
"yMMM": {
"y": "y年M月至y年M月",
"M": "y年M月至M月"
},
"yMMMd": {
"d": "y年M月d日至d日",
"y": "y年M月d日至y年M月d日",
"M": "y年M月d日至M月d日"
},
"yMMMEd": {
"d": "y年M月d日E至d日E",
"y": "y年M月d日E至y年M月d日E",
"M": "y年M月d日E至M月d日E"
},
"yMMMM": {
"y": "y年M月至y年M月",
"M": "y年M月至M月"
}
}
}
},
"supplemental": {
"dates": null
}
}
}
}
在调用过程中需要注意以下几点:
- 请求的语言+地区如果是一个有效的组合(例如en-US、zh-Hans),返回的模式类型为此有效组合对应的数据
- 一旦请求的语言+地区无效(例如en-JP),此时返回的模式数据以地区为主,返回请求地区中最多人口使用的语言的模式数据(scope中的“plurals”除外)
- scope中的“plurals”,无论请求的语言和地区进行怎样的组合,始终以语言为判断依据
另一个则是通过提供预先组合好的区域设置,返回请求类型的模式数据。
GET /i18n/api/v2/formatting/patterns/locales/{locale}
请求参数:
locale: (必填)string类型,请求模式数据的区域,例如en,en-GB,zh-Hans,zh-Hans-CN等
scope: (必填)string类型,请求模式的类型,需要从“dates,numbers,currencies,plurals,measurements”中做出选择。若同时请求多个,以半角逗号(,)进行分隔。
这里我进行了zh-CN的货币请求,部分结果如下:
{
"response": {
"code": 200,
"message": "OK",
"serverTime": ""
},
"signature": "",
"data": {
"localeID": "zh-Hans",
"language": "zh",
"region": "CN",
"categories": {
"currencies": {
"AED": {
"symbol": "AED",
"displayName": "阿联酋迪拉姆",
"displayName-count-other": "阿联酋迪拉姆"
},
"CAD": {
"symbol": "CA$",
"displayName": "加拿大元",
"symbol-alt-narrow": "$",
"displayName-count-other": "加拿大元"
},
"CHE": {
"symbol": "CHE",
"displayName": "欧元 (WIR)",
"displayName-count-other": "欧元 (WIR)"
},
"CHF": {
"symbol": "CHF",
"displayName": "瑞士法郎",
"displayName-count-other": "瑞士法郎"
},
"CHW": {
"symbol": "CHW",
"displayName": "法郎 (WIR)",
"displayName-count-other": "法郎 (WIR)"
},
"CLE": {
"symbol": "CLE",
"displayName": "智利埃斯库多",
"displayName-count-other": "智利埃斯库多"
},
"CLF": {
"symbol": "CLF",
"displayName": "智利(资金)",
"displayName-count-other": "智利(资金)"
},
"CLP": {
"symbol": "CLP",
"displayName": "智利比索",
"symbol-alt-narrow": "$",
"displayName-count-other": "智利比索"
},
"CNH": {
"symbol": "CNH",
"displayName": "人民币(离岸)",
"displayName-count-other": "人民币(离岸)"
},
"CNX": {
"symbol": "CNX",
"displayName": "CNX"
},
"CNY": {
"symbol": "¥",
"displayName": "人民币",
"symbol-alt-narrow": "¥",
"displayName-count-other": "人民币"
},
"DEM": {
"symbol": "DEM",
"displayName": "德国马克",
"displayName-count-other": "德国马克"
},
"HKD": {
"symbol": "HK$",
"displayName": "港元",
"symbol-alt-narrow": "$",
"displayName-count-other": "港元"
},
"JPY": {
"symbol": "JP¥",
"displayName": "日元",
"symbol-alt-narrow": "¥",
"displayName-count-other": "日元"
},
"KPW": {
"symbol": "KPW",
"displayName": "朝鲜元",
"symbol-alt-narrow": "₩",
"displayName-count-other": "朝鲜元"
},
"KRH": {
"symbol": "KRH",
"displayName": "韩元 (1953–1962)"
},
"KRO": {
"symbol": "KRO",
"displayName": "韩元 (1945–1953)"
},
"KRW": {
"symbol": "₩",
"displayName": "韩元",
"symbol-alt-narrow": "₩",
"displayName-count-other": "韩元"
},
},
"region": {
…
"NL": "EUR",
"NO": "NOK",
"NP": "NPR",
"NR": "AUD",
"NU": "NZD",
"NZ": "NZD",
"OM": "OMR",
"PA": "USD",
"PE": "PEN",
"PF": "XPF",
"PG": "PGK",
"PH": "PHP",
"PK": "PKR",
"PL": "PLN",
"PM": "EUR",
"PN": "NZD"
}
}
}
}
}
}
而使用Moment处理同样问题的效果,我在18年的博文中已经进行了详述。对比之后不难发现,Moment作为较为大众的国际化时间日期库,优势在于其深度,不仅在时间日期方面有着优秀的表现,同时困扰国际化软件开发从业人员的calendar问题,也被囊括其中。而Singleton在面对该特定问题时,优势则在于其提供的微服务方式以及广度(灵活度),但各个国家地区的日历问题依然没有被解决,不得不说这是一个很大的遗憾。
上一篇: 美女进行时,看你最爱看的图片