iT邦幫忙

2021 iThome 鐵人賽

DAY 6
0
Modern Web

前端工程師在工作中的各種實戰技能 (Vue 3)系列 第 6

[Day06] Vue i18n - Number Formatting (Currency 貨幣)

在本地化 (localize) 專案時,我們可能會遇到需要處理金錢、價錢等貨幣的問題,在顯示價錢時我們會需要依據當前的語系顯示相對應的貨幣符號 ,例如:

<p>NT$10,000</p> // 台幣
<p>$10,000</p>   // 美金
<p>¥10,000</p>  // 日幣

所以今天我們要來分享的就是可以幫我們達到這件事的 Number Formatting,事實上 Number Formatting 除了貨幣以外,它也可以處理純數字格式 (decimal)、百分比 (percent) 以及物理單位 (unit) 在不同語系的顯示,因為它背後的運作原理就是透過 JS 原生的 Intl.NumberFormat 來做到的,不過我們今天的重點只會在貨幣的部分。

配置屬性選項

export default createI18n({
 ...,
 numberFormats: {
  en: {
    currency: {
      style: 'currency',
      currency: 'USD',
      currencyDisplay: 'symbol',
      minimumFractionDigits: 0,
      maximumFractionDigits: 0,
      useGrouping: true
    }
  },
})

style 要使用的格式樣式,預設會是 decimal

  • currency : 貨幣格式。
  • decimal: 純十進制的數字格式。
  • percent: 百分比格式。
  • unit: 單位格式 (物理)。

currency 指定使用哪一種國際貨幣,常見的台幣 TWD, 美金 USD,詳細的完整列表可以參考 ISO 4217

currencyDisplay 以哪種方式顯示顯示貨幣。

  • symbol: 當地的貨幣符號,例如 NT$123,456。
  • narrowSymbol : 當地的窄格式貨幣符號,例如 $123,456。
  • code : ISO currency code,例如 TWD 123,456。
  • name : 當地的貨幣名稱,例如 123,456.79 新台幣。

minimumFractionDigits 最小的小數位數,可接受 0 到 20。

maximumFractionDigits 最大的小數位數,可接受 0 到 20,不過不能小於 minimumFractionDigits 。

useGrouping 是否使用分組分隔符,例如千/十萬/千萬分隔符。

事實上不同的 style 或多或少會有不同的屬性可以配置,不過這裡我們就只針對貨幣常使用的屬性做介紹,詳細完整的可參考 Intl.NumberFormat() constructor

基本用法

number formatting 所使用的 translation api 是 $n(value, key, locale)

  • value - 要本地化的數值。
  • key - 這邊的 key 指是 en 下一層的 currency,這是自己定義的,不是因為 style 是 currency,因此我們也可以定義好幾個格式。
  • locale - 指定要用哪一個語系來本地化,預設會是全局的 locale 值。
export default createI18n({
 ...,
 numberFormats: {
  en: {
    currency: {
      style: 'currency',
      currency: 'USD'
    },
    currencyNoGroup: {
      style: 'currency',
      currency: 'USD',
      minimumFractionDigits: 0,
      maximumFractionDigits: 0,
      useGrouping: false
    }
  },
})

所以在 template 的寫法會是:

<p>{{ $n(10000, 'currency') }}</p>
<p>{{ $n(10000, 'currencyNoGroup') }}</p>

得到的結果是:

<p>$10,000.00</p>
<p>$10000</p>

Custom Formatting

由於 $n 會直接回傳格式化的字串結果,我們只能作為一整體去使用,但有的時候我們會需要針對其中一部分去設定不同的樣式,例如下圖中貨幣符號和數值的大小不同,所以為了應對這種情況 vue i18n 有提供我們 NumberFormat 組件 (i18n-n) 來達到這件事。(有點像是我昨天介紹的 Component Interpolation)

https://ithelp.ithome.com.tw/upload/images/20210921/20113487Xs190AbzQb.png

i18n-n 的基本用法如下。 (此時得到的結果和用 $n 的結果一樣)

<i18n-n tag="span" :value="100" format="currency" locale="en"></i18n-n>

i18n-n 有四個 props :

tag 選擇根節點的 HTML tag。

value 要本地化的數值。

format 選用哪一個定義好的格式的 key (同 $n(value, key) 中的 key)。

locale 指定要用哪一個語系來本地化,預設會是全局的 locale 值。

如果想要個別控制每一個部分做到上面圖示中的樣子,我們要透過 slots 的方式,像是:

<i18n-n tag="span" :value="1000" format="currency">
  <template #currency="slotProps">
    <span class="currency">{{ slotProps.currency }}</span>
  </template>
  <template #integer="slotProps">
    <span class="integer">{{ slotProps.integer }}</span>
  </template>
  <template #group="slotProps">
    <span class="group">{{ slotProps.group }}</span>
  </template>
  <template #fraction="slotProps">
    <span class="fraction">{{ slotProps.fraction }}</span>
  </template>
  <template #decimal="slotProps">
    <span class="decimal">{{ slotProps.decimal }}</span>
  </template>
</i18n-n>

這樣得到的結果會是

// $1,000.00
<span>
  <span class="currency">$</span>
  <span class="integer">1</span>
  <span class="group">,</span>
  <span class="integer">000</span>
  <span class="decimal">.</span>
  <span class="fraction">00</span>
</span>

參考資料


今天的分享就到這邊,如果大家對我分享的內容有興趣歡迎點擊追蹤 & 訂閱系列文章,如果對內容有任何疑問,或是文章內容有錯誤,都非常歡迎留言討論或指教的!

明天要來分享的是 Vue i18n 主題的最後一篇 Datetime Formatting,那我們明天見!


上一篇
[Day05] Vue i18n - Component Interpolation
下一篇
[Day07] Vue i18n - Datetime Formatting
系列文
前端工程師在工作中的各種實戰技能 (Vue 3)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

0
TD
iT邦新手 4 級 ‧ 2021-09-21 21:49:08

看完內容覺得 i18n 好有趣啊!

Mia Yang iT邦新手 5 級 ‧ 2021-09-22 00:11:03 檢舉

TD 是真的蠻有趣的,今天分享的[Day07] Vue i18n - Datetime Formatting 也和這篇的 Number Formatting 有差不多的感覺!

0
TD
iT邦新手 4 級 ‧ 2021-09-21 21:49:31

這裡程式碼排版稍微跑掉了 :p

export default createI18n({
 ...,
 numberFormats: {
  en: {
    currency: {
      style: 'currency',
      currency: 'USD',
			currencyDisplay: 'symbol',
      minimumFractionDigits: 0,
      maximumFractionDigits: 0,
      useGrouping: true
    }
  },
})
Mia Yang iT邦新手 5 級 ‧ 2021-09-22 00:11:21 檢舉

感謝!我修正了

我要留言

立即登入留言