JavaScript 国际化 API(也称为 I18n)允许您设计网页和应用程序,以便它们可以轻松适应使用不同语言的用户的需求。
在本文中,我们将了解 API 提供的各种方法,以及如何在代码中实现它们以覆盖更广泛、更国际化的受众。
国际化 (I18n) 可能很棘手
国际化看起来很容易……除非你尝试去做。
基于拉丁语的语言可能表面上相似。例如,请求姓名、电子邮件和日期的表单翻译如下:
- 西班牙语: nombre, email, fecha
- 法语:nom,电子邮件,日期
- 德语:姓名、电子邮件、数据
Gettext国际化和本地化系统已经存在了几十年,并且库可用于大多数编程语言。
在更简单的情况下,您可以使用某种形式的标记化。例如,采用包含以下内容的 HTML 模板:
<label for="name">{{ NAME }}</label>
当用户将英语设置为其主要语言时,这将被“名称”动态替换。不幸的是,这就是您的用户界面问题开始的地方:
- 同一种语言可以有不同的变体。在西班牙使用的西班牙语与在南美洲使用的西班牙语不同。
- 一种语言中的单词在其他语言中可能会更长。例如,“电子邮件”在俄语中翻译为“электронное письмо”。
- 文本并不总是从左到右。有些是从右向左书写的——例如阿拉伯语、希伯来语、库尔德语和意第绪语。其他的可以从上到下写,比如中文、韩文、日文和台湾文。
许多问题可以通过将文本保持在最低限度并采用 CSS 属性(例如direction、writing-mode和逻辑尺寸进行布局)来解决。
术语混乱
当您的应用程序需要显示日期、时间、数字、货币或单位时,将会出现进一步的混乱。
考虑显示为“12/03/24”的日期。它将被读作:
- 使用 MDY 格式的美国居民的“2024 年 12 月 3 日”
- 使用 DMY 格式的欧洲、南美和亚洲居民的“2024 年 3 月 12 日”,以及
- 加拿大、中国、日本和匈牙利居民的“2012 年 3 月 24 日”,他们选择了实用得多的 YMD 格式。
(请注意,日期分隔符斜线并非在所有语言中都很常见!)
数字“1,000”将被解读为:
- 美国、英国、加拿大、中国和日本的“一千”,以及
- 西班牙、法国、德国和俄罗斯的“一个(零点)”,其中数字的小数部分用逗号分隔。
仅用英语,情况甚至可能很复杂。术语“1,000 米”是指:
- 1 公里(或 0.62 英里)到美国居民
- 向英国、加拿大和澳大利亚的测量仪器收集一千件!
JavaScript 国际 API
鲜为人知的 JavaScriptIntl对象在大多数现代浏览器和运行时中实现了 ECMAScript 国际化 API。支持一般都不错,甚至IE11也有很多比较有用的方法。对于较旧的浏览器,有一个polyfill,可以像这样检测 API:
if (window.Intl) {
// Intl supported
}
API 有点不寻常。它为日期、时间、数字和列表提供了几个对象构造函数,它们被传递一个语言环境和一个包含配置参数的可选对象。例如,这是一个DateTime指定美国英语的对象:
const dateFormatter = new Intl.DateTimeFormat('en-US');
这个对象可以被多次使用来调用传递一个Date()值的各种方法(或者一个ES6 Temporal,如果可用)。该format方法通常是最实用的选择。例如:
const valentinesDay = dateFormatter.format( new Date('2022-02-14') );
// returns US format "2/14/2022"
const starwarsDay = dateFormatter.format( new Date('2022-05-04') );
// returns US format "5/4/2022"
或者,您可以Intl在一行代码中创建对象并运行方法:
const starwarsDay = new Intl.DateTimeFormat('en-US').format( new Date('2022-05-04') );
除了format()方法之外,一些对象还支持这些:
- formatToParts():返回一个包含格式化字符串的对象数组,例如{ type: 'weekday', value: 'Monday' }
- resolvedOptions(): 返回一个新对象,其属性反映所使用的语言环境和格式选项,例如dateFormatter.resolvedOptions().locale.
定义语言环境
所有Intl对象都需要一个语言环境参数。这是一个字符串,它标识:
- 语言子标签
- 脚本子标签(可选)
- 地区(或国家)子标签(可选)
- 一个或多个变体子标签(可选)
- 一个或多个 BCP 47 扩展序列(可选)
- 私人使用的扩展序列(可选)
语言和地区通常就足够了。例如,"en-US"、"fr-FR"等。
除了使用字符串外,Intl.locale对象还可用于构造语言环境,例如具有 12 小时时间格式的美国英语:
const us = new Intl.Locale('en', {
region: 'US', hourCycle: 'h12', calendar: 'gregory'
});
这可以在另一个Intl构造函数中使用。例如:
new Intl.DateTimeFormat(us, { timeStyle: 'medium' })
.format( new Date('2022-05-04T13:00:00') );
// "1:00:00 PM"
如果未定义区域设置,则使用设备的当前语言和区域设置。例如:
new Intl.DateTimeFormat().format( new Date('2022-05-04') );
这会"5/4/2022"在具有美国设置"04/05/2022"的设备和具有英国设置的设备上返回。
日期和时间
以下工具显示了使用格式的日期和时间示例(如果您的语言或地区未列出,请致歉!):Intl.DateTimeFormat()
构造函数被传递了语言环境和一个选项对象。这有许多可能的属性,尽管您很少需要超过dateStyle和/或timeStyle:
财产 |
描述 |
dateStyle |
日期样式:"full" "long" "medium" "short" |
timeStyle |
时间风格:"full" "long" "medium" "short" |
calendar |
选项包括: "chinese" "gregory" "hebrew" "indian" "islamic"等。 |
dayPeriod |
时期表达:"narrow" "short" "long" |
numberingSystem |
编号系统:"arab" "beng" "fullwide" "latn"等 |
localeMatcher |
语言环境匹配算法:"lookup" "best fit" |
timeZone |
时区:"America/New_York" "Europe/Paris"等 |
hour12 |
设置true为使用 12 小时制时间表示法 |
hourCycle |
小时周期:"h11" "h12" "h23" "h24" |
formatMatcher |
格式匹配算法:"basic" "best fit" |
weekday |
工作日格式:"long" "short" "narrow" |
era |
时代格式:"long" "short" "narrow" |
year |
年份格式:"numeric" "2-digit" |
month |
月份格式:"numeric" "2-digit" "long" "short" "narrow" |
day |
日格式:"numeric" "2-digit" |
hour |
小时格式:"numeric" "2-digit" |
minute |
分钟格式:"numeric" "2-digit" |
second |
第二种格式:"numeric" "2-digit" |
timeZoneName |
任何一个:"long" "short" |
例子:
// Japanese short date, no time: "2022/05/04"
new Intl.DateTimeFormat("ja-JP", { dateStyle: "short" })
.format( new Date("2022-05-04T13:00") );
// US short date and time: "5/4/22, 1:00 PM"
new Intl.DateTimeFormat("en-US", { dateStyle: "short", timeStyle: "short" })
.format( new Date("2022-05-04T13:00") );
// UK long date, short time: "4 May 2022 at 13:00"
new Intl.DateTimeFormat("en-GB", { dateStyle: "long", timeStyle: "short" })
.format( new Date("2022-05-04T13:00") );
// Spanish full date and time (dependent on your local time zone)
// "miércoles, 4 de mayo de 2022, 13:00:00 (hora de verano británica)"
new Intl.DateTimeFormat("es-ES", { dateStyle: "full", timeStyle: "full" })
.format( new Date("2022-05-04T13:00") );
日期范围
一种formatRange()方法需要两个日期,并根据语言环境和选项以最简洁的方式格式化句点。例如:
// result: "4 May 2022, 13:00–14:00"
new Intl.DateTimeFormat("en-US", { dateStyle: "long", timeStyle: "short" })
.formatRange(new Date("2022-05-04T13:00"), new Date("2022-05-04T14:00"))
此方法对浏览器的支持更有限,但在 Chrome 76 中实现。
相对时期
该Intl.RelativeTimeFormat()对象可以显示与该时刻相关的周期。options 对象的选项较少:
财产 |
描述 |
localeMatcher |
语言环境匹配算法:"lookup" "best fit" |
numeric |
要么"always",例如,"1 day ago"要么"auto",例如"yesterday" |
style |
格式:"long" "short" "narrow" |
该format()方法传递一个数值和一个单位:"year", "quarter", "month", "week", "day", "hour", "minute", or "second"。例子:
// US 1 day ago, numeric: "1 day ago"
new Intl.RelativeTimeFormat("en-US")
.format( -1, "day" );
// US in one 1 day, auto: "tomorrow"
new Intl.RelativeTimeFormat("en-US", { numeric: "auto" })
.format( -1, "day" );
// German, next month auto: "n?chsten Monat"
new Intl.RelativeTimeFormat("de-DE", { numeric: "auto" })
.format( 1, "month" );
数字、货币、百分比和单位
以下工具显示了Intl.NumberFormat()用于格式化数字、货币、百分比和度量单位的示例:
构造函数被传递了语言环境和一个选项对象:
财产 |
描述 |
numberingSystem |
选项包括"arab" "beng" "deva" "fullwide" "latn"等。 |
notation |
类型:"standard" "scientific" "engineering" "compact" |
style |
格式化:"decimal" "currency" "percent" "unit"——这决定了可以设置哪些其他选项 |
currency |
货币代码:"USD" "EUR" "GBP"等 |
currencyDisplay |
货币格式:"symbol" "narrowSymbol" "code" "name" |
currencySign |
对于负货币值、"standard"减号或"accounting"括号 |
unit |
单位类型:等"centimeter" "inch" "hour" |
unitDisplay |
单位格式:"long" "short" "narrow" |
useGrouping |
设置 false 以禁用千位分隔符 |
minimumIntegerDigits |
最小整数位数 |
minimumFractionDigits |
最小小数位数 |
maximumFractionDigits |
最大小数位数 |
minimumSignificantDigits |
最小有效位数 |
maximumSignificantDigits |
最大有效位数 |
例子:
// US number rounded to 2 decimal places: "12,345.68"
new Intl.NumberFormat("en-US", { maximumSignificantDigits: 2 })
.format( 12345.6789 );
// French number rounded to 3 decimal places: "12?345,689"
new Intl.NumberFormat("fr-FR", { maximumSignificantDigits: 3 })
.format( 12345.6789 );
// US compact number, 0 decimal places: "12K"
new Intl.NumberFormat("en-US", { notation: "compact", maximumSignificantDigits: 0 })
.format( 12345.6789 );
// Spanish US dollar value: "12.345,68 US$"
new Intl.NumberFormat("es-ES", {
style: "currency",
currency: "USD",
currencyDisplay: "symbol"
})
.format( 12345.6789 );
// UK meters in long format, 0 decimal places: "12,346 metres"
new Intl.NumberFormat("en-GB", {
maximumSignificantDigits: 0,
style: "unit",
unit: "meter",
unitDisplay: "long"
})
.format( 12345.6789 );
列表
一个Intl.ListFormat()对象可以将一组项目格式化为一个语言敏感的列表。在英语中,这通常需要在最后一项之前使用“and”或“or” 。
选项对象可以设置以下属性:
财产 |
描述 |
type |
输出格式:基于"conjunction"for和 –的列表,基于"disjunction"for或-的列表 |
style |
格式化:"long" "short" "narrow" |
例子:
const browsers = ['Chrome', 'Firefox', 'Edge', 'Safari'];
// US English: "Chrome, Firefox, Edge, and Safari"
new Intl.ListFormat("en-US", { type: "conjunction" }).format(browsers);
// US English: "Chrome, Firefox, Edge, or Safari"
new Intl.ListFormat("en-US", { type: "disjunction" }).format(browsers);
// French: "Chrome, Firefox, Edge, et Safari"
new Intl.ListFormat("fr-FR", { type: "conjunction" }).format(browsers);
// French: "Chrome, Firefox, Edge, ou Safari"
new Intl.ListFormat("fr-FR", { type: "disjunction" }).format(browsers);
复数
稍微奇怪的Intl.PluralRules()对象启用复数敏感的语言规则,其中您有许多项目。options 对象可以将属性设置type为:
- cardinal:事物的数量(默认),或
- ordinal: 事物的排名,如1st, 2nd, 或3rd英文
该select()方法返回一个表示数字复数类别的英文字符串:every zero, one, two, few, many, or other。
例子:
// US English zero cardinal: "other"
new Intl.PluralRules("en-US", { type: "cardinal" }).select(0);
// US English zero ordinal: "other"
new Intl.PluralRules("en-US", { type: "ordinal" }).select(0);
// US English 1 cardinal: "one"
new Intl.PluralRules("en-US", { type: "cardinal" }).select(1);
// US English 1 ordinal: "one"
new Intl.PluralRules("en-US", { type: "ordinal" }).select(1);
// US English 2 cardinal: "other"
new Intl.PluralRules("en-US", { type: "cardinal" }).select(2);
// US English 2 ordinal: "two"
new Intl.PluralRules("en-US", { type: "ordinal" }).select(2);
// US English 3 cardinal: "other"
new Intl.PluralRules("en-US", { type: "cardinal" }).select(3);
// US English 3 ordinal: "few"
new Intl.PluralRules("en-US", { type: "ordinal" }).select(3);
字符串比较
最后,该Intl.Collator()对象启用对语言敏感的字符串比较。它的选项对象可以设置以下属性:
财产 |
描述 |
collation |
某些语言环境的变体排序规则 |
numeric |
设置true数字排序规则,其中“1”<“2”<“10” |
caseFirst |
要么"upper"或"lower"案例优先 |
usage |
字符串"sort"(默认)或"search" |
sensitivity |
"base" "accent" "case" "variant"比较 |
ignorePunctuation |
设置true为忽略标点符号 |
该compare()方法比较两个字符串。例如:
// German: returns 1
new Intl.Collator('de').compare('z', '?');
利润!
如果您使用 JavaScript 显示数据,那么使用用户的本地格式显示信息应该很简单。例如,以下代码定义了一个dateFormat()使用Intl短日期格式的函数,或者在不受支持时回退到YYYY-MM-DD :
// date formatting function
const dateFormat = (Intl && Intl.DateTimeFormat ?
date => new Intl.DateTimeFormat({ dateStyle: 'short' }).format(date) :
date => date.toISOString().slice(0, 10)
);
// insert today's date into DOM #today element
document.getElementById('today').textContent = dateFormat( new Date() );
仅这一点并不能让您的应用程序易于为国际用户所接受,但它离全球发行更近了一步。
如若转载,请注明出处:https://www.daxuejiayuan.com/19992.html