固态
由React Intl & FormatJS所启发的Solid通用国际化(i18n).
快开始
安装它 :
npm i @cookbook/solid-intl
# or
yarn add @cookbook/solid-intl
# or
pnpm add @cookbook/solid-intl
用 <IntlProvider />
import { IntlProvider } from '@cookbook/solid-intl'
// usersLocale = 'en', 'en-US', 'pt-BR', so on...
// translationsForUsersLocale = translations for selected locale
render(() =>
<IntlProvider locale={usersLocale} messages={translationsForUsersLocale}>
<App />
</IntlProvider>,
document.getElementById("root")!);
创建您的消息并使用它 intl.formatMessage
import { defineMessages, useIntl } from '@cookbook/solid-intl';
const messages = defineMessages({
greeting: {
id: "app.greeting",
defaultMessage: "Hello world!",
},
});
function Component(props) {
const { intl } = useIntl();
return intl.formatMessage(messages.greeting) // outputs: Hello world!
}
目录
API 密码
<IntlProvider />
Solid Intl使用提供商模式将一i18n上下文范围到一棵组件树上. 这样可以像当前地块和被翻译的字符串/消息集这样的配置在组件树的根上提供,并提供给"使用Intl ()"的钩子方法. 此组件用于为一棵树设置i18n上下文. 通常,这个组件会包起一个app的根组件,这样整个app就会在所配置的i18n上下文内. 以下为可以设置的i18n配置道具:
interface IntlConfig {
locale: Locale;
timeZone?: string;
fallbackOnEmptyString?: boolean;
formats?: CustomFormats;
messages: Record<MessageIds, string> | Record<MessageIds, MessageFormatElement[]>;
defaultLocale?: string;
defaultFormats?: CustomFormats;
defaultRichTextElements?: Record<string, FormatXMLElementFn<JSXElement>>;
onError(err: MissingTranslationError | MessageFormatError | MissingDataError | InvalidConfigError | UnsupportedFormatterError | FormatError)?: void;
onWarn(warning: string)?: void;
}
语言、格式和消息
用户的当前地块, 以及该应用程序应该提供的内容 .
虽然 defaultLocale 财务报告和审定财务报表 defaultFormats 用于倒置或开发期间,并代表应用程序的默认值.
注意没有 defaultMessages,这是因为每个信件描述符提供了默认的Message.
默认本地和默认格式
未翻译信件的默认语言格式( F) messages) (中文(简体) ).
defaultLocale 应该是那个地方 defaultMessages 以便判决在一个地方一致。 无 defaultLocale 和/或如果设置错误,你可能会遇到这样的情况:句子是英文,但嵌入式日期/时间是西班牙文.
默认 Rich 文本元素
富文本格式化函数的标签地图 。 这样做是为了提供一种集中方式来格式化常见标记,例如: <b>, (中文(简体) ), <p>...或执行代码库中的某些设计系统(例如标准化) <a> 或者说 <button>(......) (中文(简体) ).
见 https://github.com/formatjs/formatjs/issues/1752 (中文(简体) ) 为更多背景.
错误
允许用户提供自定义错误处理器.
默认情况下,错误消息会使用 console.error 若为 NODE_ENV 未设定为 production。 。 。 .
警告时
允许用户提供自定义警告处理器.
默认情况下,警告信件会使用 console.warning 若为 NODE_ENV 未设定为 production。 。 。 .
useIntl() 钩子
格式 日期
function formatDate(
value: number | Date,
options?: Intl.DateTimeFormatOptions & {format?: string}
): string
此函数将返回格式化的日期字符串 .
它期望一个 value 它可以被解析为一个日期(即, isFinite(new Date(value))),并接受 options 符合 DateTimeFormatOptions。 。 。 .
intl.formatDate(Date.now(), {
year: 'numeric',
month: 'numeric',
day: 'numeric',
})
// outputs: 04/01/2023
格式时间
function formatTime(
value: number | Date,
options?: Intl.DateTimeFormatOptions & {format?: string}
): string
此函数将返回格式化的日期字符串,但它与 formatDate 使用下列默认选项:
{
hour: 'numeric',
minute: 'numeric',
}
它期望一个 value 它可以被解析为一个日期(即, isFinite(new Date(value))),并接受符合 DateTimeFormatOptions。 。 。 .
intl.formatTime(Date.now())
// outputs: "4:03 PM"
格式化时间
布鲁塞尔支持数字 :
这需要 内通. 相对时间格式 它的浏览器支持有限. 请用我们的 多边填充 如果你打算支持他们.
type Unit =
| 'second'
| 'minute'
| 'hour'
| 'day'
| 'week'
| 'month'
| 'quarter'
| 'year'
type RelativeTimeFormatOptions = {
numeric?: 'always' | 'auto'
style?: 'long' | 'short' | 'narrow'
}
function formatRelativeTime(
value: number,
unit: Unit,
options?: Intl.RelativeTimeFormatOptions & {
format?: string
}
): string
此函数将返回格式化的相对时间字符串( 如“ 1 hour ago” ) 。 它期望一个 value 是一个数字, a unit 财务报告和审定财务报表 options 符合 Intl.RelativeTimeFormatOptions。 。 。 .
intl.formatRelativeTime(0)
// outputs: in 0 seconds
intl.formatRelativeTime(-24, 'hour', {style: 'narrow'})
// outputs: 24 hr ago
数量
此函数使用 内通. 数字格式 选项.
function formatNumber(
value: number,
options?: Intl.NumberFormatOptions & {format?: string}
): string
此函数将返回格式化的数字字符串 .
它期望一个 value 可解析为数字,并接受 options 符合 NumberFormatOptions。 。 。 .
intl.formatNumber(1000, {style: 'currency', currency: 'USD'})
// outputs: US$1,000.00
使用单位格式编号
目前,这是ES2020的一部分 数字格式。 。 。 .
我们提供了 多边填充 这里和 @formatjs/intl 类型允许用户在 被制裁单位数字 :
intl.formatNumber(1000, {
style: 'unit',
unit: 'kilobyte',
unitDisplay: 'narrow',
})
// outputs: 1,000kB
intl.formatNumber(1000, {
unit: 'fahrenheit',
unitDisplay: 'long',
style: 'unit',
})
// outputs: 1,000 degrees Fahrenheit
格式图
type PluralFormatOptions = {
type?: 'cardinal' | 'ordinal' = 'cardinal'
}
function formatPlural(
value: number,
options?: Intl.PluralFormatOptions
): 'zero' | 'one' | 'two' | 'few' | 'many' | 'other'
此函数将返回复数类字符串 : "zero", (中文(简体) ), "one", (中文(简体) ), "two", (中文(简体) ), "few", (中文(简体) ), "many",或 "other"。 。 。 .
它期望一个 value 可解析为数字,并接受 options 符合 PluralFormatOptions。 。 。 .
这是一种低级的用途,其产出可提供给 switch 语句来选择要显示的特定字符串.
intl.formatPlural(1)
// outputs: one
intl.formatPlural(3, {style: 'ordinal'})
// outputs: one
多种语文支助
此函数只应用于只需要支持一种语言的app. 如果您的应用程序支持多种语言,则使用Message格式.
格式列表
布鲁塞尔支持
此函数允许您以 i18n- safe 的方式加入列表 。 例如,当地方是 en数字 :
intl.formatList(['Me', 'myself', 'I'], {type: 'conjunction'})
// outputs: Me, myself and I
intl.formatList(['5 hours', '3 minutes'], {type: 'unit'})
// outputs: 5 hours, 3 minutes
格式显示Name
布鲁塞尔支持
type FormatDisplayNameOptions = {
style?: 'narrow' | 'short' | 'long'
type?: 'language' | 'region' | 'script' | 'currency'
fallback?: 'code' | 'none'
}
function formatDisplayName(
value: string | number | Record<string, unknown>,
options: FormatDisplayNameOptions
): string | undefined
用法示例:
intl.formatDisplayName('zh-Hans-SG', {type: 'language'})
// outputs: Simplified Chinese (Singapore)
// ISO-15924 four letters script code to localized display name
intl.formatDisplayName('Deva', {type: 'script'})
// outputs: Devanagari
// ISO-4217 currency code to localized display name
intl.formatDisplayName('CNY', {type: 'currency'})
// outputs: Chinese Yuan
// ISO-3166 two letters region code to localized display name
intl.formatDisplayName('UN', {type: 'region'})
// outputs: United Nations
格式
type MessageFormatPrimitiveValue = string | number | boolean | null | undefined
function formatMessage(
descriptor: MessageDescriptor,
values?: Record<string, MessageFormatPrimitiveValue>
): string
function formatMessage(
descriptor: MessageDescriptor,
values?: Record<
string,
MessageFormatPrimitiveValue | JSX.Element | FormatXMLElementFn
>
): string | JSX.Element[]
此函数将返回格式化信件字符串 .
它期望一个 MessageDescriptor 并接受浅层 values 用于在信件中填入占位符的对象.
如果有翻译信件 id 已经转交给 <IntlProvider> 通过其 messages prop 它将被格式化, 否则它会回落到格式化 defaultMessage。 。 。 .
见数字 : 信件格式倒置 更多细节.
function () {
const messages = defineMessages({
greeting: {
id: 'app.greeting',
defaultMessage: 'Hello, {name}!',
},
})
return intl.formatMessage(messages.greeting, {name: 'Eric'})
// outputs: Hello, Eric!
}
与 JSX.Element
function () {
const messages = defineMessages({
greeting: {
id: 'app.greeting',
defaultMessage: 'Hello, {name}!',
},
})
return intl.formatMessage(messages.greeting, {name: <b>Eric</b>})
// outputs: Hello, <b>Eric</b>!
}
有丰富的文本格式
function () {
const messages = defineMessages({
greeting: {
id: 'app.greeting',
defaultMessage: 'Hello, {name}!',
},
})
return intl.formatMessage(messages.greeting, {
name: 'Eric',
bold: str => <b>{str}</b>,
})
// outputs: Hello, <b>Eric</b>!
}
定义
interface MessageDescriptor {
id?: string
description?: string | object
defaultMessage?: string
}
function defineMessages(
messageDescriptors: Record<string, MessageDescriptor>
): Record<string, MessageDescriptor>
function defineMessage(messageDescriptor: MessageDescriptor): MessageDescriptor
这些职能从下列来源再出口: @formatjs/intl 软件包,并且只是我们编译 JavaScript 源文件定义的默认信件时使用的 CLI & bail/ TS 插件的钩子 .
此函数仅返回已通过的信件描述符映射对象 .
import {defineMessages, defineMessage} from '@cookbook/solid-intl'
const messages = defineMessages({
greeting: {
id: 'app.home.greeting',
defaultMessage: 'Hello, {name}!',
},
})
const msg = defineMessage({
id: 'single',
description: 'header',
})
信件提取
现在你已经宣布了一些信息, 现在是提取它们的时候了.
npm i @formatjs/cli
# or
yarn add @formatjs/cli
# or
pnpm add @formatjs/cli
采掘业
将以下命令添加到您的 package.json scripts数字 :
{
"scripts": {
"extract": "formatjs extract"
}
}
执行它:
npm run extract -- 'src/**/*.ts*' --ignore='**/*.d.ts' --out-file lang/en.json'
包含以下消息的文件 :
import { useIntl } from '@cookbook/solid-intl'
export function List(props) {
const intl = useIntl();
return (
<section>
<header>
{intl.formatMessage({
id: 'settings.list.header',
defaultMessage: 'Control Panel',
})}
</header>
<ul>
<li>
<button>
{intl.formatMessage({
id: 'settings.list.button.delete',
defaultMessage: 'Delete user {name}',
}, {
name: props.name,
})}
</button>
</li>
<PasswordChange />
</ul>
</section>
)
}
运行上述命令将创建一个名为`lang/en.json'的文件:
{
"settings.list.header": "Control Panel",
"settings.list.button.delete": "Delete user {name}"
}
基本国际化原则
国际化有什么意义?
国际化软件支持全世界人民的语言和文化风俗. 网络遍布世界各地。 国际化网络应用为各地民众提供了良好的用户体验.
本地化软件通过将文本翻译成用户语言,并按照用户的期望格式化数据来适应特定语言和文化. 一个应用程序一般是本地化的,用于一组小地方.
这个 ECMA-402 JavaScript 国际化规格 有一个很好的概览.
语言和地区
一个"地"指一个地区的语言和文化期望. 它使用定义于 UTS LDML 数据。 。 。 .
此代码由几个由连字符相隔的部分(-)组成. 第一部分是代表语言的短弦. 第二段,可选部分,是代表区域的短弦. 此外,还可以指定各种扩展和变体.
通常,网络应用是本地化的,只为语言或语言-区域组合. 这类地块代码的例子有:
-
en联合国 -
en-US在美国讲的英语 -
en-GB在联合王国发言的英语 -
es-AR在阿根廷发言的西班牙语 -
ar-001全世界讲阿拉伯语的人 -
ar-AE在阿拉伯联合酋长国发言的阿拉伯语 -
大多数国际化的应用只支持少量的地产列表.
翻译字符串
您的应用程序中可能有一些文本, 使用英语或日语等自然语言 。 为了支持其它地块, 您需要翻译这些字符串 .
FormatJS提供了一个机制,可以让你写出应用程序的核心"软件",而不为不同的翻译提供特殊代码. 您的翻译字符串和我们的图书馆中包含了每个地方的考虑.
const messages = {
en: {
GREETING: 'Hello {name}',
},
fr: {
GREETING: 'Bonjour {name}',
},
}
我们使用 ICU 信件语法 用于Java、C、PHP和其他各种平台.
信件语法
字符串/信使格式化是Solid Intl的首要特征,它建立在 ICU 信件格式 使用 ICU 信件语法。 。 。 . 此消息语法允许简单到复杂的消息被定义,翻译,然后在运行时格式化.
简单消息 :
Hello everyone
简单参数
你可以使用一个 {key} 在信件中设置一个值的参数.
在输入数据中查找密钥,并用其值来插出字符串.
Hello, {name}
复杂消息 :
Hello, {name}, you have {itemCount, plural,
=0 {no items}
one {# item}
other {# items}
}.
信件描述符
Solid Intl 有一个信件描述器概念,用于定义您的应用程序的默认信件/字符串 . 信件描述符非常有助于提供翻译字符串/消息所需的数据,它们包含以下属性:
id: 消息的独特而稳定的标识符description: 翻译者在UI中如何使用的背景defaultMessage: 默认信件(可能是英文)
interface MessageDescriptor {
id?: MessageIds;
description?: string | object;
defaultMessage?: string | MessageFormatElement[];
}
信件格式倒置
将API格式化的信息走出一英里,为格式化失败的常见情况提供倒计时; 至少应该总是返回一个非空字符串.
以下是信息格式化倒置算法:
- 查找和格式化 id 的已翻译信件, 传递给 .
- 回落到默认Message格式化中 .
- 回落到 id 源头的翻译消息 .
- 回落到默认Message源 .
- 倒向文字信息id.
格式化信件参数
数值也可以根据其类型格式化. 你用一个 {key, type, format} 说到做到.
论点的要点是:
key在输入数据中查找数据的位置type如何解释数值(见下文)format是可选的,是对如何显示这类数据的进一步改进
I have {numCats, number} cats.
number 格式化
该类型用于以对地语敏感的方式格式化数字.
它理解以下可选值: format 论点的要素:
I have {numCats, number} cats.
Almost {pctBlack, number, ::percent} of them are black.
内部使用INTl. Number Format API. 您可以定义格式元素的自定义值,这些值将传递到 Intl 。 数字格式构建器.
有时嵌入数字将如何格式化,为翻译提供了很好的上下文. 我们也支持ICU Number Skeletons使用相同的语法:
The price of this bagel is {num, number, ::sign-always compact-short currency/GBP}
你可以多读读这个 这里。 。 。 .
date 格式化
该类型用于格式化日期的方式对地语敏感. 它理解参数的可选格式元素的以下值:
short用于以尽可能短的方式格式化日期medium用于格式化以短文本表示月份的日期long用于格式化以长文本表示月份的日期full用于格式化最详细的日期
Sale begins {start, date, medium}
内部使用 Intl.DateTimeFormat API (英语). 您可以定义格式元素的自定义值,这些值将传递给 Intl.DateTimeFormat 建筑师.
time 格式化
这种类型用于格式化时间的方式对地语敏感. 它理解参数的可选格式元素的以下值:
short用于以小时和分钟格式化时间medium用于以小时、分和秒格式化时间long用于以小时、分、秒和时区格式化时间full和长短一样
Coupon expires at {expires, time, short}
内部使用 Intl.DateTimeFormat API (英语). 您可以定义格式元素的自定义值,这些值将传递给 Intl.DateTimeFormat 建筑师.
支持的日期时间 Skeleton
类似 number 类型,我们也支持ICU DateTime骨架.
伊斯兰法院联盟提供 多种图案 自定义日期时间格式.
然而,并非所有的都通过ECMA402的Intl API提供.
因此,我们只支持以下模式:
| 符号 | 含义 | 页:1 |
|---|---|---|
| G级 | 大纪元代号 | |
| 尔 | 年份 | |
| 联合国 | 年数月数 | |
| L | 独立月数 | |
| d. 国家 | 月数 | |
| 页:1 | 每周天数 | |
| 电子 | 当地周日 | e. eee 不支持 |
| c. 国家 | 独立当地周日 | c.ccc 不支持 |
| (单位:千美元) | AM/PM标记 | |
| 页:1 | 小时 [-1-12] | |
| 页:1 | 小时 [0-23] | |
| K级 | 小时 [0-11] | |
| 页:1 | 小时 [1-24] | |
| 页:1 | 分钟 | |
| 编号 | 第二届 | |
| 页:1 | 时区 |
{select} 格式
这个 {key, select, matches} 用于选择输出,将一个值匹配到许多选择中的一个.
(这类似于 switch 语句可用一些编程语言。 )
在输入数据中查找密钥 .
对应值被匹配到匹配值之一并返回对应输出.
关键论点必须遵循 Unicode 模式 语法。 。 。 .
这个 matches 是一个空格分隔的列表 matches。 。 。 .
匹配的格式匹配 {output}。 。 。 .
(匹配类似于一些编程语言中发现的开关的大小写
这个 match 是一个字面价值.
如果它与值相同 key 然后相应 output 将被使用.
输出本身就是一种信息,所以它可以是字面字符串,也可以在其内部有较多的参数.
这个 other 匹配是特殊的,在没有其他匹配的情况下使用。 (这类似于一些编程语言中发现的开关的默认情况. )
危险
other需要根据icu4j执行。 如果select未使用other。 。 。 .
{gender, select,
male {He}
female {She}
other {They}
} will respond shortly.
以下为巢道辩之例.
{taxableArea, select,
yes {An additional {taxRate, number, percent} tax will be collected.}
other {No taxes apply.}
}
{plural} 格式
这个 {key, plural, matches} 用于根据当前地块的复数规则选择输出。 和我们家一样 {select} 上方的格式,但数值预计为数字并被映射成复数类.
匹配是一个字面价值,并被匹配到其中一个复数类别. 并非所有语言都使用所有的复数类别.
zero:这一类用于有专为零个项的语法语言. (例子有阿拉伯语和拉脱维亚语。 )one:这一类用于具有专门用于某一项的语法语言. 许多语言,但不是全部,都使用这个复数类. (许多受欢迎的亚洲语言,如汉语和日语,不使用这一类two:这一类用于具有特有语法的两种语言. (例子有阿拉伯语和威尔士语. )few:这一类用于有专门针对少数项的语法语言. 对于一些语言来说,这用于2-4项,用于约3-10项,而其他语言则有更复杂的规则.many:这一类用于有专门针对更多项的语法语言. (例子有阿拉伯语、波兰语和俄语。 )other: 如果值与其他复数类之一不相匹配,则使用此类. 注意,这个用于"平分",用于语言(如英语)具有简单的"单分"与"平分"两种.=value:这用于匹配特定值,无论当前地块的复数类别如何.
危险
other需要根据icu4j执行。 如果select未使用other。 。 。 .
Cart: {itemCount} {itemCount, plural,
one {item}
other {items}
}
You have {itemCount, plural,
=0 {no items}
one {1 item}
other {{itemCount} items}
}.
在那个 output 比赛中 # 特殊令牌可以用作数值的占位符,并将格式化为 {key, number}。 。 。 .
{selectordinal} 格式
这个 {key, selectordinal, matches} 用于根据当前地块的正数复数规则(第1个、第2个、第3个等)选择输出。 它与上面的{plural}格式非常相近,只是该值被映射为正数复数类.
匹配是一个字面价值,并被匹配到其中一个复数类别. 并非所有语言都使用所有的复数类别.
zero:这一类用于有专为零个项的语法语言. (例子有阿拉伯语和拉脱维亚语。 )one:这一类用于具有专门用于某一项的语法语言. 许多语言,但不是全部,都使用这个复数类. (许多受欢迎的亚洲语言,如汉语和日语,不使用这一类two:这一类用于具有特有语法的两种语言. (例子有阿拉伯语和威尔士语. )few:这一类用于有专门针对少数项的语法语言. 对于一些语言来说,这用于2-4项,用于约3-10项,而其他语言则有更复杂的规则.many:这一类用于有专门针对更多项的语法语言. (例子有阿拉伯语、波兰语和俄语。 )other: 如果值与其他复数类之一不相匹配,则使用此类. 注意,这个用于"平分",用于语言(如英语)具有简单的"单分"与"平分"两种.=value:这用于匹配特定值,无论当前地块的复数类别如何.
危险
other需要根据icu4j执行。 如果select未使用other。 。 。 .
在产出中 match,则 # 特殊令牌可以用作数值的占位符,并将格式化为 {key, number}。 。 。 .
It's my cat's {year, selectordinal,
one {#st}
two {#nd}
few {#rd}
other {#th}
} birthday!
丰富文本格式
我们也支持使用标记在信件中嵌入丰富的文本格式. 这样可以让开发者尽可能多地嵌入文字,这样句子就不必被分割成块
注: 这不是 XML/ HTML 标签
Our price is <boldThis>{price, number, ::currency/USD precision-integer}</boldThis>
with <link>{pct, number, ::percent} discount</link>
引用/出逃
ASCII 缩水 ' (U+0027)可以用来逃避消息中文本部分的语法字符. 单个apostrope在紧接后逃脱了一个语法字符;一对apostrope逃脱了彼此之间包裹的每一个语法字符:
"This is not an interpolation: '{word}"
//→ "This is not an interpolation: {word}"
"These are not interpolations: '{word1} {word2}'"
//→ "These are not interpolations: {word1} {word2}"
"'<notATag>"
//→ "<notATag>"
"'<notATag>hello</notATag>'"
//→ "<notATag>hello</notATag>"
连续两个ASCII层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层层 %% 内 printf 代表一个 %然而,我们建议使用卷曲接力 ’ (U+2019)用于人可读字符串并只使用ASCII apostrope ' (U+0027)在ICU消息语法中.
"This '{isn''t}' obvious."
//→ "This {isn't} obvious."