51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

什么是JavaScript国际化API(I18n)?

英语是世界上使用最广泛的语言,但只有七分之一的人说英语。它是3.79亿人口的第一种(母语)语言,但是有9.17亿人说普通话,4.6亿人说西班牙语和3.41亿人说北印度语。

许多讲非英语的人居住在互联网指数增长的新兴市场。如果您的Web应用程序可以进行全球翻译,那么您的潜在目标市场可能会增加700%!

JavaScript Internationalization API(也称为i18n)使您可以以易于适应网页的方式来设计网页和应用程序,以支持使用不同语言的用户的需求。

在本文中,我们将研究API提供的各种方法,以及如何在代码中实现它们,以吸引更广泛的国际受众。

国际化(I18n)可能很棘手

国际化看起来很容易......直到您尝试这样做为止。

基于拉丁语的语言可能在表面上是相似的。例如,要求名称,电子邮件和日期的表单的翻译如下:

  • Spanish: nombre, email, fecha

  • French: nom, e-mail, date

  • German: name, email, datum

该Gettext的国际化和本地化系统已经存在了几十年,和库可用于大多数编程语言。

在较简单的情况下,可以使用某种形式的标记化。例如,以包含以下内容的HTML模板为例:

<label for="name">{{ NAME }}</label>

当用户将英语设置为主要语言时,该名称将动态替换为"名称"。不幸的是,这是用户界面出现问题的地方:

  1. 同一语言可以有不同的变体。西班牙所说的西班牙语与南美所说的并不相同。

  2. 一种语言的单词在另一种语言中可能更长。例如,"电子邮件"在俄语中翻译为"электронноописьмо"。

  3. 文本并不总是从左到右。有些是从右到左书写的,例如阿拉伯语,希伯来语,库尔德语和意第绪语。可以自上而下书写其他语言,例如中文,韩语,日语和台湾语。

许多问题可以通过保持文本到最低限度,采用CSS属性,如加以解决directionwriting-mode以及合理的尺寸布局。

Terminology Turmoil

当您的应用程序需要显示日期,时间,数字,货币或单位时,还会引起进一步的混乱。

考虑显示为" 12/03/24"的日期。它将被读取为:

  • 使用MDY格式的美国居民的" 2024年12月3日"

  • 使用DMY格式的欧洲,南美和亚洲居民的" 2024年3月12日",以及

  • 加拿大,中国,日本和匈牙利居民选择了" 2012年3月24日",他们选择了更为实用的YMD格式。

(请注意,日期分隔符斜杠在所有语言中并不常见!)

数字" 1,000"将表示为:

  • 美国,英国,加拿大,中国和日本的"一千"

  • 西班牙,法国,德国和俄罗斯的"一个(零点)",数字的小数点由逗号分隔。

单单用英语,情况甚至可能很复杂。术语" 1,000米"是指:

  • 距美国居民1公里(或0.62英里)

  • 收集了英国,加拿大和澳大利亚的一千种测量仪器!

JavaScript Intl API

鲜为人知的JavaScript Intl对象在大多数现代浏览器和运行时中都实现了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小时时间格式的English US:

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()

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>日期和时间 - Web前端之家www.jiangweishan.com</title>
 <style>
  * {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

form {
  display: flex;
  gap: 1em;
}

body {
  font-family: sans-serif;
  font-size: 1em;
  margin: 1em;
  color: #333;
  background-color: #fff;
}

h1 {
  font-size: 1.5em;
  font-weight: normal;
  margin-bottom: 0.5em;
}

input, select {
  display: block;
  min-width: 8em;
  font-family: inherit;
  font-size: 1em;
  padding: 0.2em;
}

label {
  display: block;
  font-size: 0.9em;
  padding: 0 0 0.2em;
  color: #666;
}

table {
  width: 100%;
  font-size: 0.9em;
  font-variant-numeric: tabular-nums;
  table-layout: fixed;
    border-spacing: 0;
    border-collapse: collapse;
    empty-cells: show;
  margin: 1em 0;
  border: 2px solid #999;
}

thead {
  border-bottom: 1px solid #999;
}

tr th:first-child {
  width: 6em;
  border-right: 1px solid #999;
}

th, td {
  vertical-align: top;
  text-align: right;
  padding: 0.2em 0.4em;
}

th {
  background-color: rgba(0,0,0,0.2);
}

td, th.value {
  text-align: left;
}

tbody tr:nth-child(2n) {
  background-color: rgba(0,0,0,0.05);
}

output {
  display: block;
  font-family: monospace;
  white-space: nowrap;
  padding: 0.5em;
  font-size: 1em;
  color: #0d0;
  background-color: #111;
  user-select: all;
  overflow: auto;
  border-radius: 5px;
}
 </style>
</head>
<body id="body">
    <h1>Locale date/time preview tool</h1>

    <form id="translate">
      
      <div>
        <label for="date">date</label>
        <input type="date" id="date" value="2024-03-12" required />
      </div>
      
      <div>
        <label for="time">time</label>
        <input type="time" id="time" value="01:23" required />
      </div>
      
      <div>
        <label for="datestyle">date style</label>
        <select id="datestyle">
          <option>full</option>
          <option>long</option>
          <option>medium</option>
          <option>short</option>
          <option value="">none</option>
        </select>
      </div>
      
      <div>
        <label for="timestyle">time style</label>
        <select id="timestyle">
          <option>full</option>
          <option>long</option>
          <option selected>medium</option>
          <option>short</option>
          <option value="">none</option>
        </select>
      </div>
      
    </form>
    
    <table summary="translation">
      <thead>
        <tr><th>locale</th><th class="value">date / time</th>
      </thead>
      <tbody id="result">
        <tr><th title="US English">en-US</th><td></td></tr>
        <tr><th title="UK English">en-GB</th><td></td></tr>
        <tr><th title="Canadian English">en-CA</th><td></td></tr>
        <tr><th title="Australian English">en-AU</th><td></td></tr>
        <tr><th title="Spanish">es-ES</th><td></td></tr>
        <tr><th title="Mexican Spanish">es-MX</th><td></td></tr>
        <tr><th title="French">fr-FR</th><td></td></tr>
        <tr><th title="German">de-DE</th><td></td></tr>
        <tr><th title="Italian">it-IT</th><td></td></tr>
        <tr><th title="Portuguese">pt-PT</th><td></td></tr>
        <tr><th title="Polish">pl-PL</th><td></td></tr>
        <tr><th title="Welsh">cy-GB</th><td></td></tr>
        <tr><th title="Icelandic">is-IS</th><td></td></tr>
        <tr><th title="Kazakh">kk-KZ</th><td></td></tr>
        <tr><th title="Afrikaans">af-AF</th><td></td></tr>
        <tr><th title="Zulu">zu-ZU</th><td></td></tr>
        <tr><th title="Russian">ru-RU</th><td></td></tr>
        <tr><th title="Arabic (Saudi Arabia)">ar-SA</th><td></td></tr>
        <tr><th title="Hebrew">he-HE</th><td></td></tr>
        <tr><th title="Bengali">bn-BN</th><td></td></tr>
        <tr><th title="Vietnamese">vi-VI</th><td></td></tr>
        <tr><th title="Chinese">zh-CN</th><td></td></tr>
        <tr><th title="Japanese">ja-JP</th><td></td></tr>
      </tbody>
    </table>
    
    <output id="code" />

    <script>
        // DOM nodes
const
  translate = document.getElementById('translate'),
  code = document.getElementById('code'),
  result = [];

Array.from(document.getElementById('result')
  .getElementsByTagName('th'))
  .forEach(r => result.push(
      { input: r.textContent, output: r.nextElementSibling }
    )
  );

// form event handlers
translate.addEventListener('submit', e => e.preventDefault());
translate.addEventListener('change', update);
update();

// update results
function update() {
  
  // get field values
  const
    field = getFields(translate),
    datetime = field.date + 'T' + field.time,
    date = new Date(datetime),
    opt = {};
  
  if (field.datestyle) opt.dateStyle = field.datestyle;
  if (field.timestyle) opt.timeStyle = field.timestyle;
  
  // update code snippet
  code.textContent = `new Intl.DateTimeFormat("[locale]", ${ JSON.stringify(opt) }).format( new Date("${ datetime }") );`;
  
  // update results
  result.forEach(r => {
    
    r.output.textContent = new Intl.DateTimeFormat(r.input, opt).format(date);
    
  });
  
}


// return an object with all form fields
function getFields(form) {
  
  const field = {};
  
  Array.from(form.elements).forEach(e => {
    if (e.id) field[e.id] = (e.value || '').trim();
  });
  
  return field;
  
}
    </script>

</body>
</html>

构造函数被传递给语言环境和一个options对象。它具有许多可能的属性,尽管您很少需要超过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") );

日期范围 {#dateranges}

一个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中实现。

相对时期 {#relativeperiods}

所述Intl.RelativeTimeFormat()对象可以显示相对于该时刻的时间段。该选项对象的选项较少:

| 参数 | 描述 | |-----------------|---------------------------------------------------------| | 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()用于格式化数字,货币,百分比和度量单位的示例:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>日期和时间 - Web前端之家www.jiangweishan.com</title>
 <style>
 * {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

form {
  display: flex;
  flex-wrap: wrap;
  gap: 1em;
}

body {
  font-family: sans-serif;
  font-size: 1em;
  margin: 1em;
  color: #333;
  background-color: #fff;
}

h1 {
  font-size: 1.5em;
  font-weight: normal;
  margin-bottom: 0.5em;
}

input, select {
  display: block;
  width: 8em;
  font-family: inherit;
  font-size: 1em;
  padding: 0.2em;
}

label {
  display: block;
  font-size: 0.9em;
  padding: 0 0 0.2em;
  color: #666;
}

table {
  width: 100%;
  font-size: 0.9em;
  font-variant-numeric: tabular-nums;
  table-layout: fixed;
    border-spacing: 0;
    border-collapse: collapse;
    empty-cells: show;
  margin: 1em 0;
  border: 2px solid #999;
}

thead {
  border-bottom: 1px solid #999;
}

tr th:first-child {
  width: 6em;
  border-right: 1px solid #999;
}

th, td {
  vertical-align: top;
  text-align: right;
  padding: 0.2em 0.4em;
}

th {
  background-color: rgba(0,0,0,0.2);
}

td, th.value {
  text-align: left;
}

tbody tr:nth-child(2n) {
  background-color: rgba(0,0,0,0.05);
}

output {
  display: block;
  font-family: monospace;
  white-space: nowrap;
  padding: 0.5em;
  font-size: 1em;
  color: #0d0;
  background-color: #111;
  user-select: all;
  overflow: auto;
  border-radius: 5px;
}

.currencyfield {
  display: none;
}

form.currency .currencyfield {
  display: block;
}

.unitfield {
  display: none;
}

form.unit .unitfield {
  display: block;
}
 </style>
</head>
<body id="body">
    <h1>Number preview tool</h1>

<form id="translate">
  
  <div>
    <label for="number">number</label>
    <input type="number" id="number" value="12345.6789" required />
  </div>
  
  <div>
    <label for="notation">notation</label>
    <select id="notation">
      <option>standard</option>
      <option>scientific</option>
      <option>engineering</option>
      <option>compact</option>
    </select>
  </div>
  
  <div>
    <label for="maximumfractiondigits">significant digits</label>
    <input type="number" id="maximumfractiondigits" value="2" min="0" max="9" step="1" required />
  </div>
  
  <div>
    <label for="style">style</label>
    <select id="style">
      <option>decimal</option>
      <option>currency</option>
      <option>percent</option>
      <option>unit</option>
    </select>
  </div>
  
  <div class="currencyfield">
    <label for="currency">currency</label>
    <select id="currency">
      <option>USD</option>
      <option>EUR</option>
      <option>GBP</option>
      <option>CAD</option>
      <option>AUD</option>
      <option>ZAR</option>
      <option>INR</option>
      <option>CNY</option>
      <option>JPY</option>
    </select>
  </div>
  
  <div class="currencyfield">
    <label for="currencydisplay">currency display</label>
    <select id="currencydisplay">
      <option>symbol</option>
      <option>narrowSymbol</option>
      <option>code</option>
      <option>name</option>
    </select>
  </div>
  
  <div class="unitfield">
    <label for="unit">unit</label>
    <select id="unit">
      <option>bit</option>
      <option>byte</option>
      <option>celsius</option>
      <option>centimeter</option>
      <option>day</option>
      <option>degree</option>
      <option>fahrenheit</option>
      <option>foot</option>
      <option>hour</option>
      <option>kilobyte</option>
      <option>liter</option>
      <option>meter</option>
      <option>mile</option>
      <option>month</option>
      <option>percent</option>
      <option>week</option>
      <option>year</option>
    </select>
  </div>
  
  <div class="unitfield">
    <label for="unitdisplay">unit display</label>
    <select id="unitdisplay">
      <option>long</option>
      <option>short</option>
      <option>narrow</option>
    </select>
  </div>
  
</form>

<table summary="translation">
  <thead>
    <tr><th>locale</th><th class="value">date / time</th>
  </thead>
  <tbody id="result">
    <tr><th title="US English">en-US</th><td></td></tr>
    <tr><th title="UK English">en-GB</th><td></td></tr>
    <tr><th title="Canadian English">en-CA</th><td></td></tr>
    <tr><th title="Australian English">en-AU</th><td></td></tr>
    <tr><th title="Spanish">es-ES</th><td></td></tr>
    <tr><th title="Mexican Spanish">es-MX</th><td></td></tr>
    <tr><th title="French">fr-FR</th><td></td></tr>
    <tr><th title="German">de-DE</th><td></td></tr>
    <tr><th title="Italian">it-IT</th><td></td></tr>
    <tr><th title="Portuguese">pt-PT</th><td></td></tr>
    <tr><th title="Polish">pl-PL</th><td></td></tr>
    <tr><th title="Welsh">cy-GB</th><td></td></tr>
    <tr><th title="Icelandic">is-IS</th><td></td></tr>
    <tr><th title="Kazakh">kk-KZ</th><td></td></tr>
    <tr><th title="Afrikaans">af-AF</th><td></td></tr>
    <tr><th title="Zulu">zu-ZU</th><td></td></tr>
    <tr><th title="Russian">ru-RU</th><td></td></tr>
    <tr><th title="Arabic (Saudi Arabia)">ar-SA</th><td></td></tr>
    <tr><th title="Hebrew">he-HE</th><td></td></tr>
    <tr><th title="Bengali">bn-BN</th><td></td></tr>
    <tr><th title="Vietnamese">vi-VI</th><td></td></tr>
    <tr><th title="Chinese">zh-CN</th><td></td></tr>
    <tr><th title="Japanese">ja-JP</th><td></td></tr>
  </tbody>
</table>

<output id="code" />

    <script>
        // DOM nodes
const
  translate = document.getElementById('translate'),
  code = document.getElementById('code'),
  result = [];

Array.from(document.getElementById('result')
  .getElementsByTagName('th'))
  .forEach(r => result.push(
      { input: r.textContent, output: r.nextElementSibling }
    )
  );

// form event handlers
translate.addEventListener('submit', e => e.preventDefault());
translate.addEventListener('change', update);
update();

// update results
function update() {
  
  // get field values
  const
    field = getFields(translate),
    value = parseFloat(field.number),
    opt = {
      notation: field.notation,
      maximumFractionDigits: parseFloat(field.maximumfractiondigits),
      style: field.style
    };
  
  translate.className = field.style;
  
  switch (field.style) {
      
    case 'currency':
      opt.currency = field.currency;
      opt.currencyDisplay = field.currencydisplay;
      break;
      
    case 'unit':
      opt.unit = field.unit;
      opt.unitDisplay = field.unitdisplay;
      break;
      
  }
  
  // update code snippet
  code.textContent = `new Intl.NumberFormat("[locale]", ${ JSON.stringify(opt) }).format( ${ value } );`;
  
  // update results
  result.forEach(r => {
    
    r.output.textContent = new Intl.NumberFormat(r.input, opt).format(value);
    
  });
  
}


// return an object with all form fields
function getFields(form) {
  
  const field = {};
  
  Array.from(form.elements).forEach(e => {
    if (e.id) field[e.id] = (e.value || '').trim();
  });
  
  return field;
  
}
    </script>

</body>
</html>

构造函数被传递给语言环境和一个options对象:

| 参数 | 描述 | |----------------------------|-----------------------------------------------------------| | 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()对象可以将一系列项目格式化为对语言敏感的列表。用英语来说,通常需要在最后一项之前加上"和"或"或"。

该选项对象可以设置以下属性:

| 财产 | 描述 | |---------|----------------------------------------------------| | type | 输出格式:"conjunction"对于和基于列表,"disjunction"对于或基于列表 | | 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()对象启用了复数敏感的语言规则,其中您有许多项。该选项对象可以设置type属性之一:

  • cardinal:事物的数量(默认值),或者

  • ordinal:对事物的排名,例如1st2nd3rd在英语

select()方法返回表示数的复数种类的英语字符串:要么zeroonetwofewmany,或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()对象启用对语言敏感的字符串比较。它的options对象可以设置以下属性:

| 参数 | 描述 | |---------------------|---------------------------------------| | collation | 某些语言环境的变体归类 | | numeric | 设置true数字排序规则,其中" 1" <" 2" <" 10" | | caseFirst | 任一"upper""lower"情况下第一 | | usage | 字符串"sort"(默认)或"search" | | sensitivity | "base" "accent" "case" "variant" 比较 | | ignorePunctuation | 设置true为忽略标点符号 |

compare()方法比较两个字符串。例如:

// German: returns 1new Intl.Collator('de').compare('z', 'ä');

Profit!

如果您使用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() );

仅此一项并不能使您的应用程序吸引国际用户,但距全球发行量仅一步之遥。

赞(0)
未经允许不得转载:工具盒子 » 什么是JavaScript国际化API(I18n)?